{"model_name":"gpt-5.5-xhigh","codes":{"1":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Rect {\n    int a, b, c, d;\n};\n\nstatic uint64_t splitmix64_hash(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nclass Solver {\n    static constexpr int SZ = 10000;\n    static constexpr double TIME_LIMIT = 4.80;\n\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    FastRNG rng;\n    Timer timer;\n\n    struct State {\n        vector<Rect> rect;\n        vector<double> val;\n        double total = 0.0;\n    };\n\n    struct Move {\n        bool ok = false;\n        int dir = 0;\n        int coord = 0;\n        double newScore = 0.0;\n        double delta = 0.0;\n    };\n\n    struct SplitCand {\n        int orient; // 0: vertical, 1: horizontal\n        int k;\n        int t;\n        double cost;\n    };\n\n    long long rectArea(const Rect& rc) const {\n        return 1LL * (rc.c - rc.a) * (rc.d - rc.b);\n    }\n\n    double scoreOne(int i, long long s) const {\n        double ratio;\n        if (s <= r[i]) ratio = (double)s / (double)r[i];\n        else ratio = (double)r[i] / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    static double scoreRatio(long long s, long long target) {\n        double ratio;\n        if (s <= target) ratio = (double)s / (double)target;\n        else ratio = (double)target / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    State makeState(const vector<Rect>& rects) const {\n        State st;\n        st.rect = rects;\n        st.val.assign(n, 0.0);\n        st.total = 0.0;\n        for (int i = 0; i < n; i++) {\n            st.val[i] = scoreOne(i, rectArea(st.rect[i]));\n            st.total += st.val[i];\n        }\n        return st;\n    }\n\n    int clampLL(long long v, int lo, int hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return (int)v;\n    }\n\n    void sortIds(vector<int>& ord, int orient) const {\n        if (orient == 0) {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (x[u] != x[v]) return x[u] < x[v];\n                return y[u] < y[v];\n            });\n        } else {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (y[u] != y[v]) return y[u] < y[v];\n                return x[u] < x[v];\n            });\n        }\n    }\n\n    void buildRec(const vector<int>& ids, const Rect& box, vector<Rect>& out, double temp) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return;\n        }\n\n        long long totalR = 0;\n        for (int id : ids) totalR += r[id];\n\n        long long A = rectArea(box);\n        int W = box.c - box.a;\n        int H = box.d - box.b;\n\n        vector<SplitCand> cands;\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<int> ord = ids;\n            sortIds(ord, orient);\n\n            long long pref = 0;\n            for (int k = 1; k < m; k++) {\n                pref += r[ord[k - 1]];\n\n                int lo, hi;\n                if (orient == 0) {\n                    int xl = x[ord[k - 1]];\n                    int xr = x[ord[k]];\n                    lo = max(box.a + 1, xl + 1);\n                    hi = min(box.c - 1, xr);\n                } else {\n                    int yl = y[ord[k - 1]];\n                    int yr = y[ord[k]];\n                    lo = max(box.b + 1, yl + 1);\n                    hi = min(box.d - 1, yr);\n                }\n\n                if (lo > hi) continue;\n\n                vector<int> ts;\n                auto addT = [&](int t) {\n                    if (t < lo || t > hi) return;\n                    for (int u : ts) if (u == t) return;\n                    ts.push_back(t);\n                };\n                auto addReal = [&](long double real) {\n                    long long f = (long long)floorl(real);\n                    for (long long v = f - 2; v <= f + 2; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                    long long rr = (long long)llroundl(real);\n                    for (long long v = rr - 1; v <= rr + 1; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                };\n\n                if (orient == 0) {\n                    long double prop = box.a + ((long double)A * pref / totalR) / H;\n                    long double exactL = box.a + (long double)pref / H;\n                    long double exactR = box.a + ((long double)A - (long double)(totalR - pref)) / H;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                } else {\n                    long double prop = box.b + ((long double)A * pref / totalR) / W;\n                    long double exactL = box.b + (long double)pref / W;\n                    long double exactR = box.b + ((long double)A - (long double)(totalR - pref)) / W;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                }\n\n                addT(lo);\n                addT(hi);\n\n                for (int t : ts) {\n                    long long leftA;\n                    if (orient == 0) leftA = 1LL * (t - box.a) * H;\n                    else leftA = 1LL * W * (t - box.b);\n\n                    long long rightA = A - leftA;\n                    if (leftA <= 0 || rightA <= 0) continue;\n\n                    double sc =\n                        k * scoreRatio(leftA, pref) +\n                        (m - k) * scoreRatio(rightA, totalR - pref);\n\n                    double loss = 1.0 - sc / m;\n\n                    auto aspectPenalty = [&](int ww, int hh, int cnt) -> double {\n                        if (cnt <= 1) return 0.0;\n                        double ar = max((double)ww / hh, (double)hh / ww);\n                        return 0.00025 * (cnt / (double)m) * max(0.0, log(ar) - 2.0);\n                    };\n\n                    double cost = loss;\n                    cost += 0.00020 * abs(m - 2 * k) / (double)m;\n\n                    if (orient == 0) {\n                        cost += aspectPenalty(t - box.a, H, k);\n                        cost += aspectPenalty(box.c - t, H, m - k);\n                    } else {\n                        cost += aspectPenalty(W, t - box.b, k);\n                        cost += aspectPenalty(W, box.d - t, m - k);\n                    }\n\n                    cands.push_back({orient, k, t, cost});\n                }\n            }\n        }\n\n        if (cands.empty()) {\n            // Extremely unlikely fallback. Unit cells are always valid inside this box.\n            for (int id : ids) {\n                out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            }\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int chosen = 0;\n        if (temp > 1e-12) {\n            double bestCost = cands[0].cost;\n            double maxDiff = max(0.03, temp * 12.0);\n\n            vector<pair<int, double>> cumulative;\n            double sum = 0.0;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                double diff = cands[i].cost - bestCost;\n                if (diff > maxDiff) continue;\n                double w = exp(-diff / temp);\n                if (w < 1e-12) continue;\n                sum += w;\n                cumulative.push_back({i, sum});\n            }\n\n            if (sum > 0.0) {\n                double z = rng.nextDouble() * sum;\n                for (auto [idx, cum] : cumulative) {\n                    if (z <= cum) {\n                        chosen = idx;\n                        break;\n                    }\n                }\n            }\n        }\n\n        SplitCand sp = cands[chosen];\n\n        vector<int> ord = ids;\n        sortIds(ord, sp.orient);\n\n        vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n        vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n        if (sp.orient == 0) {\n            Rect L{box.a, box.b, sp.t, box.d};\n            Rect R{sp.t, box.b, box.c, box.d};\n            buildRec(leftIds, L, out, temp);\n            buildRec(rightIds, R, out, temp);\n        } else {\n            Rect B{box.a, box.b, box.c, sp.t};\n            Rect T{box.a, sp.t, box.c, box.d};\n            buildRec(leftIds, B, out, temp);\n            buildRec(rightIds, T, out, temp);\n        }\n    }\n\n    vector<Rect> buildRecursive(double temp) {\n        vector<Rect> out(n);\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        buildRec(ids, Rect{0, 0, SZ, SZ}, out, temp);\n        return out;\n    }\n\n    vector<Rect> buildUnit() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; i++) {\n            rects[i] = {x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        return rects;\n    }\n\n    bool yOverlap(const Rect& p, const Rect& q) const {\n        return max(p.b, q.b) < min(p.d, q.d);\n    }\n\n    bool xOverlap(const Rect& p, const Rect& q) const {\n        return max(p.a, q.a) < min(p.c, q.c);\n    }\n\n    pair<int, int> legalInterval(const State& st, int i, int dir) const {\n        const Rect& ri = st.rect[i];\n\n        if (dir == 0) { // left\n            int lo = 0;\n            int hi = min(x[i], ri.c - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.a < ri.c) {\n                    lo = max(lo, rj.c);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 1) { // right\n            int lo = max(x[i] + 1, ri.a + 1);\n            int hi = SZ;\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.c > ri.a) {\n                    hi = min(hi, rj.a);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 2) { // bottom\n            int lo = 0;\n            int hi = min(y[i], ri.d - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (xOverlap(ri, rj) && rj.b < ri.d) {\n                    lo = max(lo, rj.d);\n                }\n            }\n            return {lo, hi};\n        }\n\n        // top\n        int lo = max(y[i] + 1, ri.b + 1);\n        int hi = SZ;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& rj = st.rect[j];\n            if (xOverlap(ri, rj) && rj.d > ri.b) {\n                hi = min(hi, rj.b);\n            }\n        }\n        return {lo, hi};\n    }\n\n    int getCoord(const Rect& rc, int dir) const {\n        if (dir == 0) return rc.a;\n        if (dir == 1) return rc.c;\n        if (dir == 2) return rc.b;\n        return rc.d;\n    }\n\n    void setCoord(Rect& rc, int dir, int v) {\n        if (dir == 0) rc.a = v;\n        else if (dir == 1) rc.c = v;\n        else if (dir == 2) rc.b = v;\n        else rc.d = v;\n    }\n\n    long long areaAfterCoord(const Rect& rc, int dir, int coord) const {\n        if (dir == 0) return 1LL * (rc.c - coord) * (rc.d - rc.b);\n        if (dir == 1) return 1LL * (coord - rc.a) * (rc.d - rc.b);\n        if (dir == 2) return 1LL * (rc.c - rc.a) * (rc.d - coord);\n        return 1LL * (rc.c - rc.a) * (coord - rc.b);\n    }\n\n    Move bestEdgeDir(const State& st, int i, int dir) const {\n        Move mv;\n        mv.ok = false;\n\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return mv;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n\n        mv.ok = true;\n        mv.dir = dir;\n        mv.coord = cur;\n        mv.newScore = st.val[i];\n        mv.delta = 0.0;\n\n        int cand[40];\n        int cnt = 0;\n\n        auto addCand = [&](int v) {\n            if (v < lo) v = lo;\n            if (v > hi) v = hi;\n            for (int k = 0; k < cnt; k++) if (cand[k] == v) return;\n            cand[cnt++] = v;\n        };\n\n        addCand(cur);\n        addCand(lo);\n        addCand(hi);\n\n        long double real;\n        if (dir == 0 || dir == 1) {\n            int h = rc.d - rc.b;\n            long double wantW = (long double)r[i] / h;\n            if (dir == 0) real = rc.c - wantW;\n            else real = rc.a + wantW;\n        } else {\n            int w = rc.c - rc.a;\n            long double wantH = (long double)r[i] / w;\n            if (dir == 2) real = rc.d - wantH;\n            else real = rc.b + wantH;\n        }\n\n        long long f = (long long)floorl(real);\n        for (long long v = f - 4; v <= f + 4; v++) {\n            addCand(clampLL(v, lo, hi));\n        }\n\n        double bestScore = st.val[i];\n        int bestCoord = cur;\n\n        for (int k = 0; k < cnt; k++) {\n            int v = cand[k];\n            long long ar = areaAfterCoord(rc, dir, v);\n            double ns = scoreOne(i, ar);\n            if (ns > bestScore + 1e-15) {\n                bestScore = ns;\n                bestCoord = v;\n            }\n        }\n\n        mv.coord = bestCoord;\n        mv.newScore = bestScore;\n        mv.delta = bestScore - st.val[i];\n        return mv;\n    }\n\n    Move bestMove(const State& st, int i) const {\n        Move best;\n        best.ok = false;\n        best.delta = 0.0;\n        best.newScore = st.val[i];\n\n        for (int dir = 0; dir < 4; dir++) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) continue;\n            if (!best.ok || mv.delta > best.delta) best = mv;\n        }\n        return best;\n    }\n\n    void applyCoord(State& st, int i, int dir, int coord, double newScore) {\n        setCoord(st.rect[i], dir, coord);\n        st.total += newScore - st.val[i];\n        st.val[i] = newScore;\n    }\n\n    void applyMove(State& st, int i, const Move& mv) {\n        applyCoord(st, i, mv.dir, mv.coord, mv.newScore);\n    }\n\n    void shuffleVector(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int selectBad(const State& st) {\n        int best = rng.nextInt(n);\n        double bv = st.val[best];\n\n        int K = min(n, 6);\n        for (int k = 1; k < K; k++) {\n            int j = rng.nextInt(n);\n            if (st.val[j] < bv) {\n                bv = st.val[j];\n                best = j;\n            }\n        }\n        return best;\n    }\n\n    void greedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return;\n            shuffleVector(ord);\n\n            bool any = false;\n            for (int id : ord) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            if (!any) break;\n        }\n    }\n\n    void randomGreedyOps(State& st, int ops, double stopTime) {\n        for (int op = 0; op < ops; op++) {\n            if ((op & 255) == 0 && timer.elapsed() > stopTime) break;\n\n            int i;\n            if (rng.nextDouble() < 0.85) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Move mv = bestMove(st, i);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyMove(st, i, mv);\n            }\n        }\n    }\n\n    bool randomResize(State& st, double temp, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.55) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return false;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n        if (lo == hi) return false;\n\n        int coord = cur;\n        double q = rng.nextDouble();\n\n        if (q < 0.25) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) return false;\n            coord = mv.coord;\n        } else if (q < 0.80) {\n            long long ar = rectArea(rc);\n            bool under = ar < r[i];\n            bool preferImprove = rng.nextDouble() < 0.72;\n\n            int sign;\n            if (dir == 0 || dir == 2) {\n                sign = under ? -1 : +1;\n            } else {\n                sign = under ? +1 : -1;\n            }\n            if (!preferImprove) sign = -sign;\n\n            int maxd = (sign < 0 ? cur - lo : hi - cur);\n            if (maxd <= 0) {\n                sign = -sign;\n                maxd = (sign < 0 ? cur - lo : hi - cur);\n            }\n\n            if (maxd > 0) {\n                int step = 1 + (int)(3000.0 * (1.0 - progress) * (1.0 - progress));\n                int d = 1 + rng.nextInt(min(maxd, step));\n                coord = cur + sign * d;\n            } else {\n                coord = lo + rng.nextInt(hi - lo + 1);\n            }\n        } else {\n            coord = lo + rng.nextInt(hi - lo + 1);\n        }\n\n        if (coord == cur) return false;\n\n        long long newArea = areaAfterCoord(rc, dir, coord);\n        double ns = scoreOne(i, newArea);\n        double delta = ns - st.val[i];\n\n        if (delta >= 0.0 || rng.nextDouble() < exp(delta / max(temp, 1e-9))) {\n            applyCoord(st, i, dir, coord, ns);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomShift(State& st, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.5) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int orient = rng.nextInt(2);\n        Rect& ri = st.rect[i];\n\n        int lo, hi;\n\n        if (orient == 0) {\n            lo = max(-ri.a, x[i] + 1 - ri.c);\n            hi = min(SZ - ri.c, x[i] - ri.a);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!yOverlap(ri, rj)) continue;\n\n                if (rj.c <= ri.a) lo = max(lo, rj.c - ri.a);\n                else if (rj.a >= ri.c) hi = min(hi, rj.a - ri.c);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.a += d;\n            ri.c += d;\n            return true;\n        } else {\n            lo = max(-ri.b, y[i] + 1 - ri.d);\n            hi = min(SZ - ri.d, y[i] - ri.b);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!xOverlap(ri, rj)) continue;\n\n                if (rj.d <= ri.b) lo = max(lo, rj.d - ri.b);\n                else if (rj.b >= ri.d) hi = min(hi, rj.b - ri.d);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.b += d;\n            ri.d += d;\n            return true;\n        }\n    }\n\n    State initialSolution() {\n        constexpr double INIT_END = 0.70;\n\n        State best;\n        bool hasBest = false;\n\n        auto consider = [&](State& st) {\n            if (!hasBest || st.total > best.total) {\n                best = st;\n                hasBest = true;\n            }\n        };\n\n        {\n            vector<Rect> rects = buildRecursive(0.0);\n            State st = makeState(rects);\n            greedyPasses(st, 6, INIT_END);\n            randomGreedyOps(st, 10 * n, INIT_END);\n            consider(st);\n        }\n\n        if (timer.elapsed() < INIT_END) {\n            vector<Rect> rects = buildUnit();\n            State st = makeState(rects);\n            greedyPasses(st, 8, INIT_END);\n            randomGreedyOps(st, 20 * n, INIT_END);\n            consider(st);\n        }\n\n        while (timer.elapsed() < INIT_END) {\n            double temp = 0.0005 * pow(80.0, rng.nextDouble());\n            vector<Rect> rects = buildRecursive(temp);\n            State st = makeState(rects);\n\n            greedyPasses(st, 2, INIT_END);\n            randomGreedyOps(st, 3 * n, INIT_END);\n            consider(st);\n        }\n\n        return best;\n    }\n\n    State improve(State bestState) {\n        State cur = bestState;\n\n        double saStart = timer.elapsed();\n        double saEnd = TIME_LIMIT - 0.22;\n\n        int iter = 0;\n        double progress = 0.0;\n        double temp = 0.05;\n\n        while (true) {\n            if ((iter & 1023) == 0) {\n                double now = timer.elapsed();\n                if (now > saEnd) break;\n\n                progress = (now - saStart) / max(1e-9, saEnd - saStart);\n                progress = min(1.0, max(0.0, progress));\n\n                double T0 = 0.050;\n                double T1 = 0.00001;\n                temp = T0 * pow(T1 / T0, progress);\n            }\n\n            double q = rng.nextDouble();\n\n            if (q < 0.08) {\n                randomShift(cur, progress);\n            } else if (q < 0.55) {\n                int i;\n                if (rng.nextDouble() < 0.82) i = selectBad(cur);\n                else i = rng.nextInt(n);\n\n                Move mv = bestMove(cur, i);\n                if (mv.ok && mv.delta > 1e-12) {\n                    applyMove(cur, i, mv);\n                }\n            } else {\n                randomResize(cur, temp, progress);\n            }\n\n            if (cur.total > bestState.total + 1e-12) {\n                bestState = cur;\n            }\n\n            if ((iter & 65535) == 0) {\n                double threshold = max(1.0, 0.015 * n);\n                if (cur.total < bestState.total - threshold) {\n                    cur = bestState;\n                }\n            }\n\n            iter++;\n        }\n\n        if (cur.total < bestState.total - 0.5) cur = bestState;\n\n        int stagnant = 0;\n        while (timer.elapsed() < TIME_LIMIT) {\n            bool imp = false;\n            for (int k = 0; k < 512; k++) {\n                int i;\n                if (rng.nextDouble() < 0.90) i = selectBad(cur);\n                else i = rng.nextInt(n);\n\n                Move mv = bestMove(cur, i);\n                if (mv.ok && mv.delta > 1e-12) {\n                    applyMove(cur, i, mv);\n                    imp = true;\n                    if (cur.total > bestState.total + 1e-12) {\n                        bestState = cur;\n                    }\n                }\n            }\n\n            if (!imp) {\n                stagnant++;\n                if (stagnant >= 30) break;\n            } else {\n                stagnant = 0;\n            }\n        }\n\n        return bestState;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n);\n        y.resize(n);\n        r.resize(n);\n\n        uint64_t seed = 1234567891234567ULL;\n        for (int i = 0; i < n; i++) {\n            cin >> x[i] >> y[i] >> r[i];\n            uint64_t z = ((uint64_t)x[i] << 32) ^ ((uint64_t)y[i] << 16) ^ (uint64_t)r[i];\n            seed ^= splitmix64_hash(z + seed);\n        }\n        rng = FastRNG(seed);\n\n        timer.reset();\n\n        State bestState = initialSolution();\n        bestState = improve(bestState);\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = bestState.rect[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc002":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int V = N * N;\n    static constexpr int MAXT = V + 5;\n    static constexpr int MAXB = (V + 63) / 64;\n\n    int si, sj;\n    int startCell;\n    int M;\n\n    int tile[V];\n    int val[V];\n    int tilePot[MAXT];\n\n    int adj[V][4];\n    char adjMove[V][4];\n    int adjN[V];\n    int borderDist[V];\n\n    int vis[MAXT];\n    int visitToken = 1;\n\n    int seenCell[V];\n    int seenTile[MAXT];\n    int seenBest[MAXT];\n    int bfsStamp = 1;\n    int que[V];\n\n    Timer timer;\n    RNG rng;\n\n    double TL = 1.90;\n\n    vector<int> bestCells;\n    vector<int> bestCum;\n    int bestScore = 0;\n\n    vector<int> curCells;\n\n    struct Params {\n        int reachW = 0;\n        int scoreW = 0;\n        int degW = 0;\n        int noise = 0;\n        int locW = 0;\n        int lossW = 0;\n        int endPenalty = 0;\n        int borderW = 0;\n        int straightW = 0;\n        int cntW = 0;\n    };\n\n    struct FloodResult {\n        int pot;\n        int cnt;\n    };\n\n    void buildAdj() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                adjN[c] = 0;\n                borderDist[c] = min(min(i, N - 1 - i), min(j, N - 1 - j));\n\n                auto add = [&](int to, char mv) {\n                    adj[c][adjN[c]] = to;\n                    adjMove[c][adjN[c]] = mv;\n                    adjN[c]++;\n                };\n\n                if (i > 0) add(c - N, 'U');\n                if (i + 1 < N) add(c + N, 'D');\n                if (j > 0) add(c - 1, 'L');\n                if (j + 1 < N) add(c + 1, 'R');\n            }\n        }\n    }\n\n    void read() {\n        cin >> si >> sj;\n        startCell = si * N + sj;\n\n        uint64_t h = 0x123456789abcdefULL;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix(si);\n        mix(sj);\n\n        int maxTid = -1;\n        for (int i = 0; i < V; i++) {\n            cin >> tile[i];\n            maxTid = max(maxTid, tile[i]);\n            mix((uint64_t)tile[i] + 1009);\n        }\n\n        M = maxTid + 1;\n\n        for (int i = 0; i < V; i++) {\n            cin >> val[i];\n            mix((uint64_t)val[i] + 9176);\n        }\n\n        fill(tilePot, tilePot + MAXT, 0);\n        for (int i = 0; i < V; i++) {\n            tilePot[tile[i]] = max(tilePot[tile[i]], val[i]);\n        }\n\n        memset(vis, 0, sizeof(vis));\n        memset(seenCell, 0, sizeof(seenCell));\n        memset(seenTile, 0, sizeof(seenTile));\n\n        rng = RNG(h);\n        buildAdj();\n    }\n\n    int newVisitToken() {\n        ++visitToken;\n        if (visitToken == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            visitToken = 1;\n        }\n        return visitToken;\n    }\n\n    int newBfsStamp() {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            memset(seenCell, 0, sizeof(seenCell));\n            memset(seenTile, 0, sizeof(seenTile));\n            bfsStamp = 1;\n        }\n        return bfsStamp;\n    }\n\n    inline int degreeAfter(int cell, int forbidTid, int token) {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localNeighborSum(int cell, int forbidTid, int token) {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    FloodResult floodPotential(int start, int forbidTid, int token) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (tid == forbidTid) continue;\n                if (vis[tid] == token) continue;\n                if (tid == vtid) continue; // cannot move inside the same domino tile\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    Params makeParams(bool flood) {\n        Params p;\n\n        if (flood) {\n            int rwArr[4] = {6, 8, 10, 12};\n            int exArr[5] = {0, 0, 2, 4, 6};\n\n            p.reachW = rwArr[rng.nextInt(4)];\n            p.scoreW = p.reachW + exArr[rng.nextInt(5)];\n\n            if (rng.nextInt(10) < 8) {\n                p.degW = 40 + rng.nextInt(260);\n            } else {\n                p.degW = -(20 + rng.nextInt(100));\n            }\n\n            p.noise = 20 + rng.nextInt(250);\n            p.locW = (rng.nextInt(4) == 0 ? 1 : 0);\n            p.cntW = rng.nextInt(6);\n\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(16) : -rng.nextInt(8));\n            p.straightW = rng.nextInt(101) - 50;\n        } else {\n            p.scoreW = 4 + rng.nextInt(18);\n\n            int mode = rng.nextInt(10);\n            if (mode < 5) {\n                p.degW = 200 + rng.nextInt(700);\n            } else if (mode < 8) {\n                p.degW = 50 + rng.nextInt(250);\n            } else {\n                p.degW = -(20 + rng.nextInt(120));\n            }\n\n            p.noise = 100 + rng.nextInt(900);\n            p.locW = rng.nextInt(4);\n            p.lossW = rng.nextInt(8);\n            p.endPenalty = 3000 + rng.nextInt(7000);\n\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(25) : -rng.nextInt(10));\n            p.straightW = rng.nextInt(121) - 60;\n        }\n\n        return p;\n    }\n\n    int runGreedy(int cut, bool useFlood, const Params& par) {\n        int token = newVisitToken();\n\n        curCells.clear();\n\n        int L = (int)bestCells.size();\n        cut = max(0, min(cut, L - 1));\n        int len = cut + 1;\n\n        for (int i = 0; i < len; i++) {\n            int c = bestCells[i];\n            curCells.push_back(c);\n            vis[tile[c]] = token;\n        }\n\n        int score = bestCum[len - 1];\n        int pos = curCells.back();\n\n        int iter = 0;\n\n        while (true) {\n            if ((iter++ & 15) == 0 && timer.elapsed() > TL) break;\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (vis[tid] != token) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int prev = -1;\n            int lastDiff = 999999;\n            if ((int)curCells.size() >= 2) {\n                prev = curCells[(int)curCells.size() - 2];\n                lastDiff = pos - prev;\n            }\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfter(cell, tid, token);\n                int loc = (par.locW ? localNeighborSum(cell, tid, token) : 0);\n\n                long long ev = 0;\n\n                if (useFlood) {\n                    FloodResult fr = floodPotential(cell, tid, token);\n                    ev += 1LL * par.reachW * fr.pot;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.cntW * fr.cnt;\n                } else {\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                    if (deg == 0 && nc > 1) {\n                        ev -= par.endPenalty;\n                    }\n                }\n\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                if (par.noise > 0) {\n                    ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n                }\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            vis[tid] = token;\n            score += val[nxt];\n            curCells.push_back(nxt);\n            pos = nxt;\n        }\n\n        return score;\n    }\n\n    void setBestFrom(const vector<int>& cells, int /*score*/) {\n        bestCells = cells;\n\n        bestCum.resize(bestCells.size());\n        int s = 0;\n        for (int i = 0; i < (int)bestCells.size(); i++) {\n            s += val[bestCells[i]];\n            bestCum[i] = s;\n        }\n        bestScore = s;\n    }\n\n    void considerCurrent(int score) {\n        if (score > bestScore || (score == bestScore && curCells.size() > bestCells.size())) {\n            setBestFrom(curCells, score);\n        }\n    }\n\n    int chooseCut() {\n        int L = (int)bestCells.size();\n        if (L <= 1) return 0;\n\n        int r = rng.nextInt(100);\n\n        if (r < 30) return 0;\n\n        int cut = 0;\n\n        if (r < 65) {\n            int maxSuf = min(L - 1, 800);\n            int a = 1 + rng.nextInt(maxSuf);\n            int b = 1 + rng.nextInt(maxSuf);\n            int suf;\n            if (rng.nextInt(100) < 75) {\n                suf = min(a, b); // usually cut near the end\n            } else {\n                suf = max(a, b);\n            }\n            cut = L - 1 - suf;\n        } else if (r < 85) {\n            int a = rng.nextInt(L - 1);\n            int b = rng.nextInt(L - 1);\n            cut = max(a, b);\n        } else {\n            cut = rng.nextInt(L - 1);\n        }\n\n        return max(0, min(cut, L - 2));\n    }\n\n    inline bool bitTest(const array<uint64_t, MAXB>& bits, int tid) const {\n        return (bits[tid >> 6] >> (tid & 63)) & 1ULL;\n    }\n\n    inline void bitSet(array<uint64_t, MAXB>& bits, int tid) {\n        bits[tid >> 6] |= 1ULL << (tid & 63);\n    }\n\n    int degreeBits(const array<uint64_t, MAXB>& bits, int cell) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) cnt++;\n        }\n        return cnt;\n    }\n\n    int localSumBits(const array<uint64_t, MAXB>& bits, int cell) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) s += val[nb];\n        }\n        return s;\n    }\n\n    struct BeamNode {\n        int parent;\n        int cell;\n        int score;\n    };\n\n    struct BeamState {\n        array<uint64_t, MAXB> bits;\n        int pos;\n        int score;\n        int node;\n        long long eval;\n    };\n\n    void runBeam(double endTime, int width) {\n        if (timer.elapsed() >= endTime) return;\n\n        vector<BeamNode> nodes;\n        nodes.reserve(width * 2000);\n\n        vector<BeamState> cur, nxt, cand;\n        cur.reserve(width);\n        nxt.reserve(width);\n        cand.reserve(width * 4 + 10);\n\n        BeamState init;\n        init.bits.fill(0);\n        bitSet(init.bits, tile[startCell]);\n        init.pos = startCell;\n        init.score = val[startCell];\n        init.node = 0;\n        init.eval = init.score;\n\n        nodes.push_back({-1, startCell, val[startCell]});\n        cur.push_back(init);\n\n        int localBestScore = val[startCell];\n        int localBestNode = 0;\n\n        int degBias = -120 + rng.nextInt(241);\n        int noise = 2000 + rng.nextInt(4000);\n\n        for (int depth = 0; depth < M && !cur.empty(); depth++) {\n            if (timer.elapsed() >= endTime) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    int tid = tile[nb];\n\n                    if (bitTest(st.bits, tid)) continue;\n\n                    BeamState ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.pos = nb;\n                    ch.score = st.score + val[nb];\n                    ch.node = st.node; // parent node, overwritten after pruning\n\n                    int deg = degreeBits(ch.bits, nb);\n                    int loc = localSumBits(ch.bits, nb);\n\n                    long long ev = 1LL * ch.score * 100;\n                    ev += 3LL * loc;\n                    ev += 1LL * degBias * deg;\n                    ev -= 10LL * borderDist[nb];\n\n                    if (deg == 0) ev -= 4000;\n                    ev += rng.nextInt(noise);\n\n                    ch.eval = ev;\n                    cand.push_back(ch);\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            nxt.clear();\n\n            for (auto& ch : cand) {\n                int parent = ch.node;\n                nodes.push_back({parent, ch.pos, ch.score});\n                ch.node = (int)nodes.size() - 1;\n\n                if (ch.score > localBestScore) {\n                    localBestScore = ch.score;\n                    localBestNode = ch.node;\n                }\n\n                nxt.push_back(std::move(ch));\n            }\n\n            cur.swap(nxt);\n        }\n\n        if (localBestScore >= bestScore) {\n            vector<int> cells;\n            int x = localBestNode;\n            while (x != -1) {\n                cells.push_back(nodes[x].cell);\n                x = nodes[x].parent;\n            }\n            reverse(cells.begin(), cells.end());\n\n            if (localBestScore > bestScore ||\n                (localBestScore == bestScore && cells.size() > bestCells.size())) {\n                setBestFrom(cells, localBestScore);\n            }\n        }\n    }\n\n    string cellsToMoves(const vector<int>& cells) const {\n        string s;\n        s.reserve(cells.size());\n\n        for (int i = 1; i < (int)cells.size(); i++) {\n            int d = cells[i] - cells[i - 1];\n\n            if (d == -N) s.push_back('U');\n            else if (d == N) s.push_back('D');\n            else if (d == -1) s.push_back('L');\n            else if (d == 1) s.push_back('R');\n        }\n\n        return s;\n    }\n\n    string solve() {\n        timer.reset();\n\n        bestCells.clear();\n        bestCum.clear();\n\n        bestCells.push_back(startCell);\n        bestCum.push_back(val[startCell]);\n        bestScore = val[startCell];\n\n        curCells.reserve(V);\n\n        // Initial randomized greedy attempts.\n        for (int i = 0; i < 25 && timer.elapsed() < 0.10; i++) {\n            bool flood = (i % 7 == 0);\n            Params par = makeParams(flood);\n            int sc = runGreedy(0, flood, par);\n            considerCurrent(sc);\n        }\n\n        // A small beam-search phase for high-score prefixes.\n        runBeam(0.30, 260);\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            double e = timer.elapsed();\n\n            int floodProb = (e < 0.70 ? 40 : 55);\n            bool flood = (rng.nextInt(100) < floodProb);\n\n            int cut;\n            if (iter < 30 || bestCells.size() < 2 || rng.nextInt(100) < 30) {\n                cut = 0;\n            } else {\n                cut = chooseCut();\n            }\n\n            Params par = makeParams(flood);\n            int sc = runGreedy(cut, flood, par);\n            considerCurrent(sc);\n\n            iter++;\n        }\n\n        return cellsToMoves(bestCells);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read();\n\n    cout << solver.solve() << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int LINE_VARS = 2 * N;          // 30 horizontal rows + 30 vertical cols\nstatic constexpr int BINS = 4;\nstatic constexpr int HBIN_VARS = N * BINS;\nstatic constexpr int BIN_VARS = 2 * N * BINS;\nstatic constexpr int EXPLORE_TURNS = 100;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    return min(hi, max(lo, x));\n}\n\nstruct RidgeModel {\n    int n;\n    vector<double> ata;\n    vector<double> atb;\n\n    RidgeModel(int n_ = 0) : n(n_), ata(n_ * n_, 0.0), atb(n_, 0.0) {}\n\n    void addObservation(const vector<pair<int, int>>& counts, int steps, double result) {\n        if (steps <= 0) return;\n\n        vector<pair<int, double>> f;\n        f.reserve(counts.size());\n        double inv_steps = 1.0 / steps;\n        for (auto [idx, cnt] : counts) {\n            if (cnt > 0) f.push_back({idx, cnt * inv_steps});\n        }\n\n        double target = result * inv_steps;\n        double weight = 1.0;\n\n        for (auto [ia, va] : f) {\n            double wva = weight * va;\n            atb[ia] += wva * target;\n            double* row = &ata[ia * n];\n            for (auto [ib, vb] : f) {\n                row[ib] += wva * vb;\n            }\n        }\n    }\n\n    void solve(const vector<double>& prior, double lambda, vector<double>& out) const {\n        vector<double> a = ata;\n        vector<double> b(n);\n\n        for (int i = 0; i < n; i++) {\n            a[i * n + i] += lambda;\n            b[i] = atb[i] + lambda * prior[i];\n        }\n\n        // Cholesky decomposition: a = L L^T, stored in lower triangle.\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j <= i; j++) {\n                double sum = a[i * n + j];\n                for (int k = 0; k < j; k++) {\n                    sum -= a[i * n + k] * a[j * n + k];\n                }\n\n                if (i == j) {\n                    if (sum < 1e-9) sum = 1e-9;\n                    a[i * n + j] = sqrt(sum);\n                } else {\n                    a[i * n + j] = sum / a[j * n + j];\n                }\n            }\n        }\n\n        vector<double> y(n);\n        for (int i = 0; i < n; i++) {\n            double sum = b[i];\n            for (int k = 0; k < i; k++) {\n                sum -= a[i * n + k] * y[k];\n            }\n            y[i] = sum / a[i * n + i];\n        }\n\n        out.assign(n, 0.0);\n        for (int i = n - 1; i >= 0; i--) {\n            double sum = y[i];\n            for (int k = i + 1; k < n; k++) {\n                sum -= a[k * n + i] * out[k];\n            }\n            out[i] = sum / a[i * n + i];\n            out[i] = clampd(out[i], 1000.0, 9000.0);\n        }\n    }\n};\n\nstruct Solver {\n    RidgeModel lineModel;\n    RidgeModel binModel;\n\n    vector<double> lineEst;\n    vector<double> binDelta;\n\n    array<int, LINE_VARS> lineSeen{};\n    mt19937 rng;\n\n    int turn = 0;\n\n    Solver()\n        : lineModel(LINE_VARS),\n          binModel(BIN_VARS),\n          lineEst(LINE_VARS, 5000.0),\n          binDelta(BIN_VARS, 0.0),\n          rng(1234567) {\n        lineSeen.fill(0);\n    }\n\n    static int hVar(int i, int j) {\n        // horizontal edge (i,j)-(i,j+1), j=0..28\n        int q = j * BINS / (N - 1);\n        return i * BINS + q;\n    }\n\n    static int vVar(int i, int j) {\n        // vertical edge (i,j)-(i+1,j), i=0..28\n        int q = i * BINS / (N - 1);\n        return HBIN_VARS + j * BINS + q;\n    }\n\n    double globalWeight() const {\n        return clampd(turn / 300.0, 0.0, 1.0);\n    }\n\n    double binWeight() const {\n        return clampd((turn - 80) / 420.0, 0.0, 1.0);\n    }\n\n    double hCost(int i, int j) const {\n        int li = i;\n        int bi = hVar(i, j);\n\n        double raw = lineEst[li] + binWeight() * binDelta[bi];\n        raw = clampd(raw, 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCost(int i, int j) const {\n        int li = N + j;\n        int bi = vVar(i, j);\n\n        double raw = lineEst[li] + binWeight() * binDelta[bi];\n        raw = clampd(raw, 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    string makeDirect(int si, int sj, int ti, int tj, bool horizontalFirst) const {\n        string s;\n\n        auto addHorizontal = [&]() {\n            if (tj > sj) s.append(tj - sj, 'R');\n            else s.append(sj - tj, 'L');\n        };\n        auto addVertical = [&]() {\n            if (ti > si) s.append(ti - si, 'D');\n            else s.append(si - ti, 'U');\n        };\n\n        if (horizontalFirst) {\n            addHorizontal();\n            addVertical();\n        } else {\n            addVertical();\n            addHorizontal();\n        }\n\n        return s;\n    }\n\n    double estimatePathCost(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCost(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCost(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCost(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCost(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    int directSeenScore(int si, int sj, int ti, int tj, bool horizontalFirst) const {\n        int score = 0;\n\n        if (horizontalFirst) {\n            if (sj != tj) score += lineSeen[si];\n            if (si != ti) score += lineSeen[N + tj];\n        } else {\n            if (si != ti) score += lineSeen[N + sj];\n            if (sj != tj) score += lineSeen[ti];\n        }\n\n        return score;\n    }\n\n    string chooseBestDirect(int si, int sj, int ti, int tj) const {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        return (c1 <= c2 ? p1 : p2);\n    }\n\n    string chooseExplorationPath(int si, int sj, int ti, int tj) {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        int s1 = directSeenScore(si, sj, ti, tj, true);\n        int s2 = directSeenScore(si, sj, ti, tj, false);\n\n        double bonus = 2500.0 * (1.0 - turn / double(EXPLORE_TURNS));\n\n        double v1 = c1 + bonus * s1;\n        double v2 = c2 + bonus * s2;\n\n        if (abs(v1 - v2) < 1e-9) {\n            return (rng() & 1) ? p1 : p2;\n        }\n        return (v1 <= v2 ? p1 : p2);\n    }\n\n    string dijkstra(int si, int sj, int ti, int tj) const {\n        int S = si * N + sj;\n        int T = ti * N + tj;\n\n        const double INF = 1e100;\n        vector<double> dist(N * N, INF);\n        vector<int> pre(N * N, -1);\n        vector<char> pmove(N * N, 0);\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[S] = 0.0;\n        pre[S] = S;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n\n            if (d > dist[u] + 1e-9) continue;\n            if (u == T) break;\n\n            int r = u / N;\n            int c = u % N;\n\n            int dirs[4];\n            bool used[4] = {};\n            int m = 0;\n\n            auto addDir = [&](int x) {\n                if (!used[x]) {\n                    used[x] = true;\n                    dirs[m++] = x;\n                }\n            };\n\n            // Prefer directions roughly toward the target for nicer tie-breaking.\n            if (ti < r) addDir(0); // U\n            if (ti > r) addDir(1); // D\n            if (tj < c) addDir(2); // L\n            if (tj > c) addDir(3); // R\n            for (int x = 0; x < 4; x++) addDir(x);\n\n            for (int idx = 0; idx < 4; idx++) {\n                int dir = dirs[idx];\n\n                int nr = r, nc = c;\n                char mv = '?';\n                double w = 0.0;\n\n                if (dir == 0) {\n                    if (r == 0) continue;\n                    nr = r - 1;\n                    mv = 'U';\n                    w = vCost(r - 1, c);\n                } else if (dir == 1) {\n                    if (r == N - 1) continue;\n                    nr = r + 1;\n                    mv = 'D';\n                    w = vCost(r, c);\n                } else if (dir == 2) {\n                    if (c == 0) continue;\n                    nc = c - 1;\n                    mv = 'L';\n                    w = hCost(r, c - 1);\n                } else {\n                    if (c == N - 1) continue;\n                    nc = c + 1;\n                    mv = 'R';\n                    w = hCost(r, c);\n                }\n\n                int v = nr * N + nc;\n                double nd = d + w;\n\n                if (nd + 1e-9 < dist[v]) {\n                    dist[v] = nd;\n                    pre[v] = u;\n                    pmove[v] = mv;\n                    pq.push({nd, v});\n                }\n            }\n        }\n\n        if (pre[T] == -1) return \"\";\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmove[cur]);\n            cur = pre[cur];\n            if (cur < 0) return \"\";\n        }\n\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    string choosePath(int si, int sj, int ti, int tj) {\n        if (turn < EXPLORE_TURNS) {\n            return chooseExplorationPath(si, sj, ti, tj);\n        }\n\n        string p = dijkstra(si, sj, ti, tj);\n        if (p.empty()) {\n            return chooseBestDirect(si, sj, ti, tj);\n        }\n\n        // Early safeguard against excessive detours caused by noisy estimates.\n        int manhattan = abs(si - ti) + abs(sj - tj);\n        int extraLimit = 1000000;\n        if (turn < 200) extraLimit = 12;\n        else if (turn < 350) extraLimit = 25;\n        else if (turn < 500) extraLimit = 45;\n\n        if ((int)p.size() > manhattan + extraLimit) {\n            return chooseBestDirect(si, sj, ti, tj);\n        }\n\n        return p;\n    }\n\n    void updateModelsWithResult(int si, int sj, const string& path, int result) {\n        array<int, LINE_VARS> lineCnt{};\n        array<int, BIN_VARS> binCnt{};\n\n        int r = si;\n        int c = sj;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                lineCnt[r]++;\n                binCnt[hVar(r, c)]++;\n                c++;\n            } else if (ch == 'L') {\n                c--;\n                lineCnt[r]++;\n                binCnt[hVar(r, c)]++;\n            } else if (ch == 'D') {\n                lineCnt[N + c]++;\n                binCnt[vVar(r, c)]++;\n                r++;\n            } else if (ch == 'U') {\n                r--;\n                lineCnt[N + c]++;\n                binCnt[vVar(r, c)]++;\n            }\n        }\n\n        vector<pair<int, int>> lf;\n        vector<pair<int, int>> bf;\n\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lineCnt[i] > 0) {\n                lf.push_back({i, lineCnt[i]});\n                lineSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (binCnt[i] > 0) {\n                bf.push_back({i, binCnt[i]});\n            }\n        }\n\n        int steps = (int)path.size();\n        lineModel.addObservation(lf, steps, result);\n        binModel.addObservation(bf, steps, result);\n    }\n\n    void solveModels(int observations) {\n        vector<double> priorLine(LINE_VARS, 5000.0);\n        lineModel.solve(priorLine, 0.1, lineEst);\n\n        int period = (observations < 300 ? 10 : 20);\n        if (observations % period != 0) return;\n\n        vector<double> priorBin(BIN_VARS);\n\n        for (int i = 0; i < N; i++) {\n            for (int q = 0; q < BINS; q++) {\n                priorBin[i * BINS + q] = lineEst[i];\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            for (int q = 0; q < BINS; q++) {\n                priorBin[HBIN_VARS + j * BINS + q] = lineEst[N + j];\n            }\n        }\n\n        double prog = min(1.0, observations / 800.0);\n        double lambdaBin = 1.5 - prog; // 1.5 -> 0.5\n\n        vector<double> absBin;\n        binModel.solve(priorBin, lambdaBin, absBin);\n\n        for (int i = 0; i < BIN_VARS; i++) {\n            binDelta[i] = absBin[i] - priorBin[i];\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.turn = k;\n\n        string path = solver.choosePath(si, sj, ti, tj);\n\n        cout << path << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n        if (result < 0) return 0;\n\n        solver.updateModelsWithResult(si, sj, path, result);\n        solver.solveModels(k + 1);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int SZ = 20;\nstatic const int CELLS = 400;\nstatic const int POS = 800;\nstatic const int DOT = 8;\nstatic const int MAXPLEN = 20;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int randint(int n) {\n        return (int)(next() % n);\n    }\n    double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\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\nint M_input;\nint U;\nint TOTAL;\ndouble avgLen = 0.0;\nint maxLenInput = 0;\n\nvector<string> uniqStr;\nvector<vector<uint8_t>> S;\nvector<int> Ls, W;\n\nuint16_t posCell[POS][MAXPLEN];\nvector<uint32_t> cellIncs[CELLS];\n\nXorShift rng;\n\ninline int countDotsVec(const vector<uint8_t>& g) {\n    int d = 0;\n    for (auto x : g) if (x == DOT) d++;\n    return d;\n}\n\nvoid initPosCells() {\n    for (int pos = 0; pos < POS; pos++) {\n        for (int p = 0; p < MAXPLEN; p++) {\n            if (pos < 400) {\n                int r = pos / SZ;\n                int c = pos % SZ;\n                posCell[pos][p] = r * SZ + (c + p) % SZ;\n            } else {\n                int q = pos - 400;\n                int r = q / SZ;\n                int c = q % SZ;\n                posCell[pos][p] = ((r + p) % SZ) * SZ + c;\n            }\n        }\n    }\n}\n\nvoid buildIncidences() {\n    long long totalInc = 0;\n    for (int i = 0; i < U; i++) totalInc += 1LL * POS * Ls[i];\n    int reserveEach = (int)(totalInc / CELLS + 100);\n    for (int c = 0; c < CELLS; c++) cellIncs[c].reserve(reserveEach);\n\n    for (int sid = 0; sid < U; sid++) {\n        int base = sid * POS;\n        for (int pos = 0; pos < POS; pos++) {\n            int pid = base + pos;\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[pos][p];\n                uint32_t code = (uint32_t(pid) << 3) | uint32_t(S[sid][p]);\n                cellIncs[cell].push_back(code);\n            }\n        }\n    }\n}\n\nstruct State {\n    vector<uint8_t> grid;\n    vector<uint8_t> mism;\n    vector<uint16_t> cover;\n    int obj = 0;\n\n    vector<int> markP, markS;\n    vector<int16_t> deltaM, deltaC;\n    vector<int> touchedP, touchedS;\n    int tagP = 1, tagS = 1;\n\n    void init() {\n        int Ptot = U * POS;\n        grid.assign(CELLS, DOT);\n        mism.assign(Ptot, 0);\n        cover.assign(U, 0);\n        markP.assign(Ptot, 0);\n        markS.assign(U, 0);\n        deltaM.assign(Ptot, 0);\n        deltaC.assign(U, 0);\n        touchedP.reserve(250000);\n        touchedS.reserve(U);\n    }\n\n    void nextTagP() {\n        ++tagP;\n        if (tagP == INT_MAX) {\n            fill(markP.begin(), markP.end(), 0);\n            tagP = 1;\n        }\n    }\n\n    void nextTagS() {\n        ++tagS;\n        if (tagS == INT_MAX) {\n            fill(markS.begin(), markS.end(), 0);\n            tagS = 1;\n        }\n    }\n\n    void build(const vector<uint8_t>& g) {\n        grid = g;\n        fill(cover.begin(), cover.end(), 0);\n        obj = 0;\n\n        for (int sid = 0; sid < U; sid++) {\n            int base = sid * POS;\n            int cov = 0;\n            const auto& str = S[sid];\n            int len = Ls[sid];\n            for (int pos = 0; pos < POS; pos++) {\n                int m = 0;\n                for (int p = 0; p < len; p++) {\n                    if (grid[posCell[pos][p]] != str[p]) m++;\n                }\n                mism[base + pos] = (uint8_t)m;\n                if (m == 0) cov++;\n            }\n            cover[sid] = (uint16_t)cov;\n            if (cov > 0) obj += W[sid];\n        }\n    }\n\n    int evalChanges(const int cells[], const uint8_t vals[], int cnt) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        auto addSid = [&](int sid, int dc) {\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                deltaC[sid] = 0;\n                touchedS.push_back(sid);\n            }\n            deltaC[sid] += (int16_t)dc;\n        };\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (oldm == 0 && newm > 0) addSid(sid, -1);\n            else if (oldm > 0 && newm == 0) addSid(sid, +1);\n        }\n\n        int delta = 0;\n        for (int sid : touchedS) {\n            int cc = cover[sid];\n            int nc = cc + deltaC[sid];\n            if (cc == 0 && nc > 0) delta += W[sid];\n            else if (cc > 0 && nc == 0) delta -= W[sid];\n        }\n        return delta;\n    }\n\n    void changeCell(int cell, uint8_t newc) {\n        int oldc = grid[cell];\n        if (oldc == newc) return;\n\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            bool was = (oldc != req);\n            bool now = (newc != req);\n            if (was == now) continue;\n\n            int sid = pid / POS;\n            int m = mism[pid];\n\n            if (!was && now) {\n                if (m == 0) {\n                    cover[sid]--;\n                    if (cover[sid] == 0) obj -= W[sid];\n                }\n                mism[pid] = (uint8_t)(m + 1);\n            } else {\n                if (m == 1) {\n                    if (cover[sid] == 0) obj += W[sid];\n                    cover[sid]++;\n                }\n                mism[pid] = (uint8_t)(m - 1);\n            }\n        }\n\n        grid[cell] = newc;\n    }\n\n    void applyChanges(const int cells[], const uint8_t vals[], int cnt) {\n        for (int i = 0; i < cnt; i++) changeCell(cells[i], vals[i]);\n    }\n};\n\nstruct Best {\n    int obj = -1;\n    int dots = 1000000000;\n    vector<uint8_t> grid;\n\n    void consider(const State& st) {\n        int d = countDotsVec(st.grid);\n        bool upd = false;\n        if (st.obj > obj) upd = true;\n        else if (st.obj == obj) {\n            if (st.obj == TOTAL) {\n                if (d > dots) upd = true;\n            } else {\n                if (grid.empty() || d < dots) upd = true;\n            }\n        }\n\n        if (upd) {\n            obj = st.obj;\n            dots = d;\n            grid = st.grid;\n        }\n    }\n};\n\nvector<uint8_t> strToVec(const string& s) {\n    vector<uint8_t> v;\n    v.reserve(s.size());\n    for (char c : s) v.push_back((uint8_t)(c - 'A'));\n    return v;\n}\n\nstring mergeLinear(const string& a, const string& b, int& ovOut) {\n    if (a.empty()) {\n        ovOut = 0;\n        return b;\n    }\n    if (b.empty()) {\n        ovOut = 0;\n        return a;\n    }\n\n    if (a.find(b) != string::npos) {\n        ovOut = (int)b.size();\n        return a;\n    }\n    if (b.find(a) != string::npos) {\n        ovOut = (int)a.size();\n        return b;\n    }\n\n    int bestOv = -1;\n    string best;\n\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            a.compare(a.size() - ov, ov, b, 0, ov) == 0) {\n            bestOv = ov;\n            best = a + b.substr(ov);\n            break;\n        }\n    }\n\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            b.compare(b.size() - ov, ov, a, 0, ov) == 0) {\n            if (ov > bestOv) {\n                bestOv = ov;\n                best = b + a.substr(ov);\n            }\n            break;\n        }\n    }\n\n    if (bestOv >= 0) {\n        ovOut = bestOv;\n        return best;\n    }\n\n    if ((int)a.size() + (int)b.size() <= MAXPLEN) {\n        ovOut = 0;\n        return a + b;\n    }\n\n    ovOut = -1;\n    return \"\";\n}\n\nbool containsInSegment(const string& seg, const string& sub) {\n    if ((int)sub.size() > MAXPLEN) return false;\n    if ((int)seg.size() == SZ) {\n        string t = seg + seg.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    } else {\n        if (sub.size() > seg.size()) return false;\n        return seg.find(sub) != string::npos;\n    }\n}\n\nstruct Segment {\n    vector<uint8_t> ch;\n    int val;\n};\n\nvector<Segment> generateSegments() {\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int minOv;\n    if (avgLen >= 8.0) minOv = 4;\n    else if (avgLen >= 6.0) minOv = 3;\n    else minOv = 2;\n\n    vector<string> segs;\n\n    for (int id : ids) {\n        const string& s = uniqStr[id];\n        bool contained = false;\n        int bestIdx = -1;\n        int bestOv = -1;\n        string bestMerged;\n\n        for (int i = 0; i < (int)segs.size(); i++) {\n            if (segs[i].find(s) != string::npos) {\n                contained = true;\n                break;\n            }\n\n            int ov;\n            string merged = mergeLinear(segs[i], s, ov);\n            if (!merged.empty() && (int)merged.size() <= MAXPLEN && ov > bestOv) {\n                bestOv = ov;\n                bestIdx = i;\n                bestMerged = merged;\n            }\n        }\n\n        if (contained) continue;\n\n        if (bestIdx != -1 && bestOv >= minOv) {\n            segs[bestIdx] = bestMerged;\n        } else {\n            segs.push_back(s);\n        }\n    }\n\n    sort(segs.begin(), segs.end());\n    segs.erase(unique(segs.begin(), segs.end()), segs.end());\n\n    vector<Segment> res;\n    for (auto& seg : segs) {\n        int val = 0;\n        for (int i = 0; i < U; i++) {\n            if (containsInSegment(seg, uniqStr[i])) val += W[i];\n        }\n        if (val >= 2) {\n            Segment sg;\n            sg.ch = strToVec(seg);\n            sg.val = val;\n            res.push_back(std::move(sg));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Segment& a, const Segment& b) {\n        if (a.val != b.val) return a.val > b.val;\n        return a.ch.size() > b.ch.size();\n    });\n\n    if ((int)res.size() > 220) res.resize(220);\n    return res;\n}\n\nstruct CItem {\n    int type; // 0: original, 1: segment\n    int idx;\n    int len;\n    int val;\n    int group;\n    uint32_t rnd;\n};\n\nconst vector<uint8_t>& getItemChars(const CItem& it, const vector<Segment>& segs) {\n    if (it.type == 0) return S[it.idx];\n    return segs[it.idx].ch;\n}\n\nvector<uint8_t> constructGreedy(int mode, const vector<Segment>& segs, Timer& timer, double endTime) {\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<CItem> items;\n\n    if (mode == 1 || mode == 2) {\n        int lim = min((int)segs.size(), avgLen >= 7.0 ? 100 : 160);\n        for (int i = 0; i < lim; i++) {\n            items.push_back({1, i, (int)segs[i].ch.size(), segs[i].val,\n                             mode == 1 ? 0 : 0, (uint32_t)rng.next()});\n        }\n    }\n\n    for (int sid = 0; sid < U; sid++) {\n        items.push_back({0, sid, Ls[sid], W[sid],\n                         mode == 1 ? 1 : 0, (uint32_t)rng.next()});\n    }\n\n    sort(items.begin(), items.end(), [](const CItem& a, const CItem& b) {\n        if (a.group != b.group) return a.group < b.group;\n        if (a.len != b.len) return a.len > b.len;\n        if (a.val != b.val) return a.val > b.val;\n        return a.rnd < b.rnd;\n    });\n\n    int processed = 0;\n    for (const CItem& it : items) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n\n        const auto& ch = getItemChars(it, segs);\n        int len = (int)ch.size();\n\n        int bestPos = -1;\n        int bestScore = INT_MIN;\n        bool already = false;\n\n        for (int pos = 0; pos < POS; pos++) {\n            int match = 0;\n            bool conflict = false;\n\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[pos][p];\n                int g = grid[cell];\n                if (g == DOT) continue;\n                if (g == ch[p]) match++;\n                else {\n                    conflict = true;\n                    break;\n                }\n            }\n\n            if (!conflict) {\n                if (match == len) {\n                    already = true;\n                    break;\n                }\n\n                int score = match * 10000 - (len - match) * 5 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestPos = pos;\n                }\n            }\n        }\n\n        if (already) continue;\n\n        if (bestPos != -1) {\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n    }\n\n    return grid;\n}\n\nbool lineContains(const string& line, const string& sub) {\n    if (line.empty()) return false;\n    if ((int)line.size() == SZ) {\n        string t = line + line.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    }\n    if (sub.size() > line.size()) return false;\n    return line.find(sub) != string::npos;\n}\n\nvector<uint8_t> constructRowPack(Timer& timer, double endTime) {\n    vector<string> rows(SZ, \"\");\n\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    vector<uint32_t> rk(U);\n    for (int i = 0; i < U; i++) rk[i] = (uint32_t)rng.next();\n\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        if (W[a] != W[b]) return W[a] > W[b];\n        return rk[a] < rk[b];\n    });\n\n    int processed = 0;\n    for (int sid : ids) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n        const string& s = uniqStr[sid];\n\n        bool covered = false;\n        for (auto& row : rows) {\n            if (lineContains(row, s)) {\n                covered = true;\n                break;\n            }\n        }\n        if (covered) continue;\n\n        int bestR = -1;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        for (int r = 0; r < SZ; r++) {\n            int ov;\n            string merged;\n            if (rows[r].empty()) {\n                ov = 0;\n                merged = s;\n            } else {\n                merged = mergeLinear(rows[r], s, ov);\n            }\n\n            if (merged.empty() || (int)merged.size() > SZ) continue;\n\n            int score = ov * 1000 + (rows[r].empty() ? 0 : 100) - (int)merged.size();\n            if (score > bestScore) {\n                bestScore = score;\n                bestR = r;\n                bestMerged = merged;\n            }\n        }\n\n        if (bestR != -1) rows[bestR] = bestMerged;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nint makePlacementChanges(const State& st, int sid, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    const auto& str = S[sid];\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = str[p];\n        if (st.grid[cell] != ch) {\n            cells[cnt] = cell;\n            vals[cnt] = ch;\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nbool tryInsert(State& st, int sid, int K, int maxChange, bool allowZero, double temp, int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    const int MAXK = 12;\n    K = min(K, MAXK);\n\n    int candPos[MAXK];\n    uint32_t candKey[MAXK];\n    int candN = 0;\n\n    auto updateWorst = [&]() {\n        int wi = 0;\n        for (int i = 1; i < candN; i++) {\n            if (candKey[i] > candKey[wi]) wi = i;\n        }\n        return wi;\n    };\n\n    int base = sid * POS;\n\n    for (int pos = 0; pos < POS; pos++) {\n        int m = st.mism[base + pos];\n        if (m == 0) return false;\n        if (m > maxChange) continue;\n\n        uint32_t key = (uint32_t(m) << 20) | uint32_t(rng.next() & ((1u << 20) - 1));\n        if (candN < K) {\n            candPos[candN] = pos;\n            candKey[candN] = key;\n            candN++;\n        } else {\n            int wi = updateWorst();\n            if (key < candKey[wi]) {\n                candPos[wi] = pos;\n                candKey[wi] = key;\n            }\n        }\n    }\n\n    if (candN == 0) return false;\n\n    int bestD = INT_MIN;\n    int bestCnt = 0;\n    int bestCells[20];\n    uint8_t bestVals[20];\n\n    int tmpCells[20];\n    uint8_t tmpVals[20];\n\n    for (int i = 0; i < candN; i++) {\n        int cnt = makePlacementChanges(st, sid, candPos[i], tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 30) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nvoid shuffleVec(vector<int>& v) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nint repairPass(State& st, Timer& timer, double endTime, int K, int maxChange,\n               bool allowZero, double temp, Best& best) {\n    vector<int> ids;\n    ids.reserve(U);\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] == 0) ids.push_back(sid);\n    }\n    if (ids.empty()) return 0;\n\n    shuffleVec(ids);\n    stable_sort(ids.begin(), ids.end(), [](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int before = st.obj;\n    int applied = 0;\n\n    for (int sid : ids) {\n        if (timer.elapsed() > endTime) break;\n        if (st.cover[sid] > 0) continue;\n\n        int d;\n        if (tryInsert(st, sid, K, maxChange, allowZero, temp, d)) {\n            applied++;\n            if (d > 0 || st.obj == TOTAL) best.consider(st);\n            if (st.obj == TOTAL) break;\n        }\n    }\n\n    best.consider(st);\n    return st.obj - before + applied / 1000000;\n}\n\nvoid fillDots(State& st, Timer& timer, double endTime, Best& best) {\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] != DOT) continue;\n\n        int bestD = INT_MIN;\n        int bestCh = 0;\n        oneCell[0] = cell;\n\n        for (int ch = 0; ch < 8; ch++) {\n            oneVal[0] = (uint8_t)ch;\n            int d = st.evalChanges(oneCell, oneVal, 1);\n            if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n                bestD = d;\n                bestCh = ch;\n            }\n        }\n\n        oneVal[0] = (uint8_t)bestCh;\n        st.applyChanges(oneCell, oneVal, 1);\n        best.consider(st);\n\n        if (st.obj == TOTAL) return;\n    }\n\n    best.consider(st);\n}\n\nint cellHillSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int totalImp = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int imp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            int bestD = 0;\n            int bestCh = old;\n\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                int d = st.evalChanges(oneCell, oneVal, 1);\n                if (d > bestD || (d == bestD && d > 0 && rng.randint(2) == 0)) {\n                    bestD = d;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestD > 0) {\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                imp += bestD;\n                best.consider(st);\n                if (st.obj == TOTAL) return totalImp + imp;\n            }\n        }\n\n        totalImp += imp;\n        if (imp == 0) break;\n    }\n\n    best.consider(st);\n    return totalImp;\n}\n\nbool hasDots(const vector<uint8_t>& g) {\n    for (auto x : g) if (x == DOT) return true;\n    return false;\n}\n\nvoid localSearch(State& st, Timer& timer, double endTime, Best& best) {\n    best.consider(st);\n    if (st.obj == TOTAL) return;\n\n    int maxChFull = (avgLen >= 8.0 ? 5 : 6);\n\n    if (hasDots(st.grid)) {\n        for (int pass = 0; pass < 2 && timer.elapsed() < endTime; pass++) {\n            int before = st.obj;\n            repairPass(st, timer, endTime, 3, maxLenInput, false, -1.0, best);\n            if (st.obj == TOTAL) return;\n            if (st.obj == before) break;\n        }\n    }\n\n    if (st.obj == TOTAL) return;\n\n    if (hasDots(st.grid)) {\n        fillDots(st, timer, endTime, best);\n        if (st.obj == TOTAL) return;\n    }\n\n    for (int cyc = 0; cyc < 2 && timer.elapsed() < endTime; cyc++) {\n        int before = st.obj;\n        repairPass(st, timer, endTime, 5, maxChFull, false, -1.0, best);\n        if (st.obj == TOTAL) return;\n\n        cellHillSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n\n        if (st.obj <= before && cyc > 0) break;\n    }\n\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    double start = timer.elapsed();\n    int stagnant = 0;\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) if (st.cover[sid] == 0) unc.push_back(sid);\n        if (unc.empty()) break;\n\n        int sid = unc[rng.randint((int)unc.size())];\n\n        double remFrac = (endTime - timer.elapsed()) / max(1e-9, endTime - start);\n        double temp = 0.55 * max(0.0, remFrac);\n\n        int d;\n        bool applied = tryInsert(st, sid, 4, maxChFull, true, temp, d);\n\n        if (applied) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                stagnant = 0;\n            } else {\n                stagnant++;\n            }\n\n            if (st.obj == TOTAL) return;\n\n            if (st.obj < localBestObj - 8 && rng.randint(100) < 25) {\n                st.build(localBestGrid);\n            }\n        } else {\n            stagnant++;\n        }\n\n        if (stagnant > 120 && st.obj < localBestObj) {\n            st.build(localBestGrid);\n            stagnant = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nvoid dotMaximize(Best& best, State& st, Timer& timer, double endTime) {\n    if (best.obj < TOTAL) return;\n\n    st.build(best.grid);\n    if (st.obj < TOTAL) return;\n\n    vector<pair<int,int>> order;\n    order.reserve(CELLS);\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (st.grid[cell] == DOT) continue;\n\n        int impact = 0;\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            if (st.grid[cell] == req && st.mism[pid] == 0) {\n                int sid = pid / POS;\n                impact += (st.cover[sid] <= 1 ? 1000 * W[sid] : 1);\n            }\n        }\n        impact = impact * 1024 + rng.randint(1024);\n        order.push_back({impact, cell});\n    }\n\n    sort(order.begin(), order.end());\n\n    int oneCell[1];\n    uint8_t oneVal[1] = {(uint8_t)DOT};\n\n    for (auto [_, cell] : order) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] == DOT) continue;\n\n        oneCell[0] = cell;\n        int d = st.evalChanges(oneCell, oneVal, 1);\n        if (st.obj + d == TOTAL) {\n            st.applyChanges(oneCell, oneVal, 1);\n        }\n    }\n\n    best.consider(st);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin;\n    cin >> Nin >> M_input;\n\n    vector<string> input(M_input);\n    uint64_t h = 1469598103934665603ULL;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M_input * 2);\n\n    int totalLen = 0;\n    for (int i = 0; i < M_input; i++) {\n        cin >> input[i];\n        mp[input[i]]++;\n        totalLen += (int)input[i].size();\n        maxLenInput = max(maxLenInput, (int)input[i].size());\n        for (char c : input[i]) {\n            h ^= (uint64_t)c;\n            h *= 1099511628211ULL;\n        }\n    }\n\n    rng = XorShift(88172645463325252ULL ^ h);\n\n    vector<pair<string,int>> pairs;\n    pairs.reserve(mp.size());\n    for (auto& kv : mp) pairs.push_back(kv);\n    sort(pairs.begin(), pairs.end());\n\n    U = (int)pairs.size();\n    TOTAL = M_input;\n    avgLen = (double)totalLen / M_input;\n\n    uniqStr.reserve(U);\n    S.reserve(U);\n    Ls.reserve(U);\n    W.reserve(U);\n\n    for (auto& kv : pairs) {\n        uniqStr.push_back(kv.first);\n        S.push_back(strToVec(kv.first));\n        Ls.push_back((int)kv.first.size());\n        W.push_back(kv.second);\n    }\n\n    Timer timer;\n\n    initPosCells();\n    buildIncidences();\n\n    vector<Segment> segments = generateSegments();\n\n    State st;\n    st.init();\n\n    Best best;\n\n    vector<int> modes;\n    if (avgLen <= 5.0) modes = {0, 3, 1};\n    else modes = {1, 0, 3};\n\n    const double SEARCH_END = 2.60;\n    const double FINAL_END = 2.85;\n\n    for (int r = 0; r < (int)modes.size() && timer.elapsed() < SEARCH_END; r++) {\n        vector<uint8_t> grid;\n\n        if (modes[r] == 3) {\n            grid = constructRowPack(timer, SEARCH_END);\n        } else {\n            grid = constructGreedy(modes[r], segments, timer, SEARCH_END);\n        }\n\n        st.build(grid);\n\n        double rem = SEARCH_END - timer.elapsed();\n        int left = (int)modes.size() - r;\n        double slice = max(0.05, rem / max(1, left));\n        double endTime = min(SEARCH_END, timer.elapsed() + slice);\n\n        localSearch(st, timer, endTime, best);\n\n        if (best.obj == TOTAL) break;\n    }\n\n    if (best.grid.empty()) {\n        vector<uint8_t> g(CELLS);\n        for (int i = 0; i < CELLS; i++) g[i] = rng.randint(8);\n        st.build(g);\n        best.consider(st);\n    }\n\n    if (best.obj == TOTAL) {\n        dotMaximize(best, st, timer, FINAL_END);\n    } else {\n        st.build(best.grid);\n\n        if (hasDots(st.grid)) {\n            fillDots(st, timer, FINAL_END, best);\n        }\n\n        if (st.obj == TOTAL) {\n            best.consider(st);\n            dotMaximize(best, st, timer, FINAL_END);\n        } else {\n            cellHillSweep(st, timer, FINAL_END, best, 3);\n            if (st.obj == TOTAL) {\n                best.consider(st);\n                dotMaximize(best, st, timer, FINAL_END);\n            }\n        }\n    }\n\n    if (best.obj < TOTAL) {\n        for (auto& x : best.grid) {\n            if (x == DOT) x = rng.randint(8);\n        }\n    }\n\n    for (int r = 0; r < SZ; r++) {\n        string line;\n        line.reserve(SZ);\n        for (int c = 0; c < SZ; c++) {\n            uint8_t x = best.grid[r * SZ + c];\n            if (x == DOT) line.push_back('.');\n            else line.push_back(char('A' + x));\n        }\n        cout << line << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Dinic {\n    struct Edge {\n        int to, rev;\n        long long cap;\n    };\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic(int n = 0) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, long long cap) {\n        Edge a{to, (int)g[to].size(), cap};\n        Edge b{fr, (int)g[fr].size(), 0};\n        g[fr].push_back(a);\n        g[to].push_back(b);\n    }\n\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    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n        for (int &i = it[v]; i < (int)g[v].size(); i++) {\n            Edge &e = g[v][i];\n            if (e.cap <= 0 || level[v] + 1 != level[e.to]) continue;\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if (ret > 0) {\n                e.cap -= ret;\n                g[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n        return 0;\n    }\n\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        const long long INF = (1LL << 60);\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n            while (true) {\n                long long f = dfs(s, t, INF);\n                if (!f) break;\n                flow += f;\n            }\n        }\n        return flow;\n    }\n\n    vector<int> reachable_from(int s) {\n        vector<int> 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 Solver {\n    static constexpr int INF16 = 65535;\n\n    Timer timer;\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0, S = 0;\n    vector<vector<int>> id;\n    vector<int> rr, cc, wt;\n    vector<array<int, 4>> nbr;\n\n    vector<uint16_t> distMat, parMat;\n\n    vector<int> hid, vid;\n    vector<vector<int>> hCells, vCells;\n    vector<int> visVal;\n    vector<int> segMinH, segMinV;\n\n    vector<int> bestSafeSeq, bestFinalSeq;\n    long long bestSafeCost = (1LL << 60);\n    long long bestFinalCost = (1LL << 60);\n\n    inline int D(int a, int b) const {\n        return distMat[(size_t)a * R + b];\n    }\n\n    inline int Sym(int a, int b) const {\n        return D(a, b) + wt[a];\n    }\n\n    char moveChar(int a, int b) const {\n        if (rr[b] == rr[a] - 1) return 'U';\n        if (rr[b] == rr[a] + 1) return 'D';\n        if (cc[b] == cc[a] - 1) return 'L';\n        return 'R';\n    }\n\n    void readInput() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void buildRoadGraph() {\n        id.assign(N, vector<int>(N, -1));\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    rr.push_back(i);\n                    cc.push_back(j);\n                    wt.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n        S = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        int di[4] = {-1, 1, 0, 0};\n        int dj[4] = {0, 0, -1, 1};\n        for (int v = 0; v < R; v++) {\n            int i = rr[v], j = cc[v];\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 && id[ni][nj] >= 0) {\n                    nbr[v][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void buildSegments() {\n        hid.assign(R, -1);\n        vid.assign(R, -1);\n\n        for (int i = 0; i < N; i++) {\n            int j = 0;\n            while (j < N) {\n                if (id[i][j] < 0) {\n                    j++;\n                    continue;\n                }\n                int h = (int)hCells.size();\n                hCells.push_back({});\n                while (j < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    hid[v] = h;\n                    hCells.back().push_back(v);\n                    j++;\n                }\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            int i = 0;\n            while (i < N) {\n                if (id[i][j] < 0) {\n                    i++;\n                    continue;\n                }\n                int vseg = (int)vCells.size();\n                vCells.push_back({});\n                while (i < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    vid[v] = vseg;\n                    vCells.back().push_back(v);\n                    i++;\n                }\n            }\n        }\n\n        visVal.assign(R, 0);\n        for (int v = 0; v < R; v++) {\n            visVal[v] = (int)hCells[hid[v]].size() + (int)vCells[vid[v]].size() - 1;\n        }\n    }\n\n    void computeAPSP() {\n        distMat.assign((size_t)R * R, INF16);\n        parMat.assign((size_t)R * R, 0);\n\n        vector<uint16_t> dist(R), par(R);\n        vector<int> score(R);\n        vector<unsigned char> used(R);\n        vector<vector<int>> buckets(10);\n        for (auto &b : buckets) b.reserve(max(1, R / 2));\n\n        for (int s = 0; s < R; s++) {\n            fill(dist.begin(), dist.end(), (uint16_t)INF16);\n            fill(par.begin(), par.end(), 0);\n            fill(score.begin(), score.end(), -1);\n            fill(used.begin(), used.end(), 0);\n            for (auto &b : buckets) b.clear();\n\n            dist[s] = 0;\n            par[s] = s;\n            score[s] = visVal[s];\n            buckets[0].push_back(s);\n\n            int cur = 0, done = 0;\n            while (done < R) {\n                auto &bk = buckets[cur % 10];\n                if (bk.empty()) {\n                    cur++;\n                    continue;\n                }\n\n                int v = bk.back();\n                bk.pop_back();\n\n                if (used[v] || dist[v] != cur) continue;\n                used[v] = 1;\n                done++;\n\n                for (int k = 0; k < 4; k++) {\n                    int to = nbr[v][k];\n                    if (to < 0 || used[to]) continue;\n\n                    int nd = cur + wt[to];\n                    int ns = score[v] + visVal[to];\n                    if (nd < dist[to] || (nd == dist[to] && ns > score[to])) {\n                        dist[to] = (uint16_t)nd;\n                        par[to] = (uint16_t)v;\n                        score[to] = ns;\n                        buckets[nd % 10].push_back(to);\n                    }\n                }\n            }\n\n            memcpy(distMat.data() + (size_t)s * R, dist.data(), sizeof(uint16_t) * R);\n            memcpy(parMat.data() + (size_t)s * R, par.data(), sizeof(uint16_t) * R);\n        }\n    }\n\n    void computeSegmentApprox() {\n        segMinH.assign(hCells.size(), 1e9);\n        segMinV.assign(vCells.size(), 1e9);\n        for (int v = 0; v < R; v++) {\n            int rt = D(S, v) + D(v, S);\n            segMinH[hid[v]] = min(segMinH[hid[v]], rt);\n            segMinV[vid[v]] = min(segMinV[vid[v]], rt);\n        }\n    }\n\n    void getPathCellsUnordered(int a, int b, vector<int> &out) const {\n        out.clear();\n        if (a == b) return;\n        int cur = b;\n        int cnt = 0;\n        while (cur != a) {\n            out.push_back(cur);\n            int p = parMat[(size_t)a * R + cur];\n            cur = p;\n            if (++cnt > R + 5) {\n                out.clear();\n                return;\n            }\n        }\n    }\n\n    void getPathCellsOrdered(int a, int b, vector<int> &out) const {\n        getPathCellsUnordered(a, b, out);\n        reverse(out.begin(), out.end());\n    }\n\n    long long routeCost(const vector<int> &seq) const {\n        if (seq.empty()) return (1LL << 60);\n        long long ret = 0;\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            ret += D(seq[i], seq[(i + 1) % m]);\n        }\n        return ret;\n    }\n\n    struct Cover {\n        const Solver *sol = nullptr;\n        vector<int> cntH, cntV;\n        int bad = 0;\n\n        void init(const Solver *s) {\n            sol = s;\n            cntH.assign(sol->hCells.size(), 0);\n            cntV.assign(sol->vCells.size(), 0);\n            bad = sol->R;\n        }\n\n        void addH(int h, int delta) {\n            int old = cntH[h];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad++;\n                }\n            }\n\n            cntH[h] = neu;\n        }\n\n        void addV(int v, int delta) {\n            int old = cntV[v];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad++;\n                }\n            }\n\n            cntV[v] = neu;\n        }\n\n        void addCell(int p, int delta) {\n            addH(sol->hid[p], delta);\n            addV(sol->vid[p], delta);\n        }\n    };\n\n    bool checkpointFull(const vector<int> &seq) const {\n        Cover cov;\n        cov.init(this);\n        for (int p : seq) cov.addCell(p, +1);\n        return cov.bad == 0;\n    }\n\n    bool actualFull(const vector<int> &seq) const {\n        if (seq.empty()) return false;\n        Cover cov;\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        vector<int> path;\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, path);\n            for (int p : path) cov.addCell(p, +1);\n        }\n        return cov.bad == 0;\n    }\n\n    vector<int> constructCellCover(double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<unsigned char> covered(R, 0);\n        vector<int> remH(hCells.size()), remV(vCells.size());\n        for (int h = 0; h < (int)hCells.size(); h++) remH[h] = (int)hCells[h].size();\n        for (int v = 0; v < (int)vCells.size(); v++) remV[v] = (int)vCells[v].size();\n\n        int uncovered = R;\n\n        auto mark = [&](int q) {\n            if (!covered[q]) {\n                covered[q] = 1;\n                uncovered--;\n                remH[hid[q]]--;\n                remV[vid[q]]--;\n            }\n        };\n\n        auto addCover = [&](int p) {\n            for (int q : hCells[hid[p]]) mark(q);\n            for (int q : vCells[vid[p]]) mark(q);\n        };\n\n        addCover(S);\n\n        vector<double> gp(R + 1, 1.0);\n        for (int g = 1; g <= R; g++) gp[g] = pow((double)g, alpha);\n\n        while (uncovered > 0) {\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = remH[hid[p]] + remV[vid[p]] - (covered[p] ? 0 : 1);\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int p = 0; p < R; p++) {\n                    if (!covered[p]) {\n                        bestP = p;\n                        bestPos = 0;\n                        break;\n                    }\n                }\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            addCover(bestP);\n        }\n\n        return seq;\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCover(int type) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<long long> wH(nH), wV(nV);\n\n        auto calcW = [&](int minRT, int len, int tp) -> long long {\n            if (tp == 0) return 1;\n            if (tp == 1) return 100 + minRT / 40;\n            if (tp == 2) return 1 + minRT / 20;\n            if (tp == 3) return 1 + minRT / max(1, len);\n            return 1 + minRT / max(1, (int)(8.0 * sqrt((double)max(1, len))));\n        };\n\n        long long sumW = 0;\n        for (int h = 0; h < nH; h++) {\n            wH[h] = calcW(segMinH[h], (int)hCells[h].size(), type);\n            sumW += wH[h];\n        }\n        for (int v = 0; v < nV; v++) {\n            wV[v] = calcW(segMinV[v], (int)vCells[v].size(), type);\n            sumW += wV[v];\n        }\n\n        int SRC = 0;\n        int offH = 1;\n        int offV = offH + nH;\n        int SNK = offV + nV;\n        Dinic din(SNK + 1);\n\n        for (int h = 0; h < nH; h++) din.add_edge(SRC, offH + h, wH[h]);\n        for (int v = 0; v < nV; v++) din.add_edge(offV + v, SNK, wV[v]);\n\n        long long INF = sumW + 1;\n        for (int p = 0; p < R; p++) {\n            din.add_edge(offH + hid[p], offV + vid[p], INF);\n        }\n\n        din.max_flow(SRC, SNK);\n        vector<int> reach = din.reachable_from(SRC);\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n        for (int h = 0; h < nH; h++) selH[h] = !reach[offH + h];\n        for (int v = 0; v < nV; v++) selV[v] = reach[offV + v];\n\n        for (int p = 0; p < R; p++) {\n            if (!selH[hid[p]] && !selV[vid[p]]) selH[hid[p]] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    vector<int> constructSegmentCover(const vector<char> &selH, const vector<char> &selV,\n                                      double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<char> touchH(hCells.size(), 0), touchV(vCells.size(), 0);\n        int remain = 0;\n        for (char x : selH) if (x) remain++;\n        for (char x : selV) if (x) remain++;\n\n        auto touch = [&](int p) {\n            int h = hid[p], v = vid[p];\n            if (selH[h] && !touchH[h]) {\n                touchH[h] = 1;\n                remain--;\n            }\n            if (selV[v] && !touchV[v]) {\n                touchV[v] = 1;\n                remain--;\n            }\n        };\n\n        touch(S);\n\n        double gp[3] = {1.0, 1.0, pow(2.0, alpha)};\n\n        while (remain > 0) {\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = 0;\n                if (selH[hid[p]] && !touchH[hid[p]]) gain++;\n                if (selV[vid[p]] && !touchV[vid[p]]) gain++;\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int h = 0; h < (int)selH.size() && bestP < 0; h++) {\n                    if (selH[h] && !touchH[h]) bestP = hCells[h][0];\n                }\n                for (int v = 0; v < (int)selV.size() && bestP < 0; v++) {\n                    if (selV[v] && !touchV[v]) bestP = vCells[v][0];\n                }\n                bestPos = 0;\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            touch(bestP);\n        }\n\n        return seq;\n    }\n\n    bool twoOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n        for (int i = 0; i < m - 1; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            for (int k = i + 2; k < m; k++) {\n                if (i == 0 && k == m - 1) continue;\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            reverse(seq.begin() + bi + 1, seq.begin() + bk + 1);\n            return true;\n        }\n        return false;\n    }\n\n    bool orOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        int bestDelta = 0, bi = -1, bj = -1;\n        for (int i = 1; i < m; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int removeCost = Sym(prev, x) + Sym(x, next) - Sym(prev, next);\n\n            for (int j = 0; j < m; j++) {\n                if (j == i || j == i - 1) continue;\n                int a = seq[j], b = seq[(j + 1) % m];\n                int addCost = Sym(a, x) + Sym(x, b) - Sym(a, b);\n                int delta = addCost - removeCost;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            int x = seq[bi];\n            seq.erase(seq.begin() + bi);\n            int pos;\n            if (bj > bi) pos = bj;\n            else pos = bj + 1;\n            seq.insert(seq.begin() + pos, x);\n            return true;\n        }\n        return false;\n    }\n\n    void optimizeOrder(vector<int> &seq, double limit) {\n        while (timer.elapsed() < limit) {\n            bool improved = false;\n            if (twoOptOnce(seq)) improved = true;\n            if (timer.elapsed() >= limit) break;\n            if (orOptOnce(seq)) improved = true;\n            if (!improved) break;\n        }\n    }\n\n    void safeRemove(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n\n            for (int i = 1; i < m; i++) {\n                int x = seq[i];\n                cov.addCell(x, -1);\n                if (cov.bad == 0) {\n                    int prev = seq[i - 1];\n                    int next = seq[(i + 1) % m];\n                    int save = D(prev, x) + D(x, next) - D(prev, next);\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestIdx = i;\n                    }\n                }\n                cov.addCell(x, +1);\n            }\n\n            if (bestIdx < 0) break;\n            cov.addCell(seq[bestIdx], -1);\n            seq.erase(seq.begin() + bestIdx);\n        }\n    }\n\n    void improveReplace(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                token++;\n                if (token == INT_MAX) {\n                    fill(seen.begin(), seen.end(), 0);\n                    token = 1;\n                }\n\n                cov.addCell(old, -1);\n\n                auto evalCand = [&](int p) {\n                    if (seen[p] == token) return;\n                    seen[p] = token;\n                    if (p == old) return;\n\n                    int newCost = D(prev, p) + D(p, next);\n                    int delta = newCost - oldCost;\n                    if (delta >= bestDelta) return;\n\n                    cov.addCell(p, +1);\n                    if (cov.bad == 0) {\n                        bestDelta = delta;\n                        bestIdx = i;\n                        bestP = p;\n                    }\n                    cov.addCell(p, -1);\n                };\n\n                for (int p : hCells[hid[old]]) evalCand(p);\n                for (int p : vCells[vid[old]]) evalCand(p);\n\n                cov.addCell(old, +1);\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    void buildActualCover(const vector<int> &seq, Cover &cov, vector<vector<int>> &edgeCells) const {\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n        edgeCells.assign(m, {});\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, edgeCells[i]);\n            for (int p : edgeCells[i]) cov.addCell(p, +1);\n        }\n    }\n\n    void applyPath(Cover &cov, const vector<int> &path, int delta) const {\n        for (int p : path) cov.addCell(p, delta);\n    }\n\n    bool pathRemove(vector<int> &seq, double limit) {\n        if (seq.empty()) return false;\n\n        Cover cov;\n        vector<vector<int>> edgeCells;\n        buildActualCover(seq, cov, edgeCells);\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n            vector<int> bestNewPath;\n\n            for (int i = 1; i < m; i++) {\n                int prev = seq[i - 1];\n                int x = seq[i];\n                int next = seq[(i + 1) % m];\n\n                int save = D(prev, x) + D(x, next) - D(prev, next);\n                if (save < bestSave) continue;\n\n                vector<int> np;\n                getPathCellsUnordered(prev, next, np);\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n                applyPath(cov, np, +1);\n\n                if (cov.bad == 0 && save > bestSave) {\n                    bestSave = save;\n                    bestIdx = i;\n                    bestNewPath = np;\n                }\n\n                applyPath(cov, np, -1);\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            applyPath(cov, edgeCells[bestIdx - 1], -1);\n            applyPath(cov, edgeCells[bestIdx], -1);\n            applyPath(cov, bestNewPath, +1);\n\n            seq.erase(seq.begin() + bestIdx);\n            edgeCells[bestIdx - 1] = bestNewPath;\n            edgeCells.erase(edgeCells.begin() + bestIdx);\n        }\n\n        return cov.bad == 0;\n    }\n\n    void updateFinal(const vector<int> &seq) {\n        long long c = routeCost(seq);\n        if (c < bestFinalCost) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n        }\n    }\n\n    void updateSafe(const vector<int> &seq) {\n        if (!checkpointFull(seq)) return;\n        long long c = routeCost(seq);\n        if (c < bestSafeCost) {\n            bestSafeCost = c;\n            bestSafeSeq = seq;\n        }\n        updateFinal(seq);\n    }\n\n    void processCandidate(vector<int> seq, bool heavy) {\n        if (seq.empty()) return;\n\n        double lim = min(2.50, timer.elapsed() + (heavy ? 0.22 : 0.08));\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n        if (timer.elapsed() < lim) safeRemove(seq, lim);\n        if (heavy && timer.elapsed() < lim) {\n            improveReplace(seq, lim);\n            safeRemove(seq, lim);\n        }\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.60) {\n            vector<int> pseq = seq;\n            double plim = min(2.63, timer.elapsed() + 0.06);\n            if (pathRemove(pseq, plim)) updateFinal(pseq);\n        }\n    }\n\n    string buildOutput(const vector<int> &seq) const {\n        string ans;\n        ans.reserve(200000);\n\n        vector<int> path;\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsOrdered(a, b, path);\n\n            int cur = a;\n            for (int p : path) {\n                ans.push_back(moveChar(cur, p));\n                cur = p;\n            }\n        }\n\n        return ans;\n    }\n\n    string dfsFallback() const {\n        vector<vector<int>> child(R);\n        vector<int> par(R, -1);\n        queue<int> q;\n        par[S] = S;\n        q.push(S);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n                if (to >= 0 && par[to] < 0) {\n                    par[to] = v;\n                    child[v].push_back(to);\n                    q.push(to);\n                }\n            }\n        }\n\n        string ans;\n        ans.reserve(max(0, 2 * (R - 1)));\n\n        function<void(int)> dfs = [&](int v) {\n            for (int to : child[v]) {\n                ans.push_back(moveChar(v, to));\n                dfs(to);\n                ans.push_back(moveChar(to, v));\n            }\n        };\n        dfs(S);\n        return ans;\n    }\n\n    void finalPolish() {\n        if (bestSafeSeq.empty() || timer.elapsed() > 2.80) return;\n\n        vector<int> seq = bestSafeSeq;\n        double lim = 2.86;\n\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n        improveReplace(seq, lim);\n        safeRemove(seq, lim);\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.90) {\n            vector<int> pseq = seq;\n            if (pathRemove(pseq, 2.93)) updateFinal(pseq);\n        }\n    }\n\n    void solve() {\n        readInput();\n        buildRoadGraph();\n        buildSegments();\n        computeAPSP();\n        computeSegmentApprox();\n\n        vector<pair<double, double>> cellParams = {\n            {1.25, 0.0},\n            {1.00, 0.0},\n            {1.50, 0.0},\n            {0.75, 0.0},\n            {1.25, 30.0},\n            {1.70, 80.0}\n        };\n\n        for (int i = 0; i < (int)cellParams.size(); i++) {\n            if (i > 0 && timer.elapsed() > 2.30) break;\n            auto [a, l] = cellParams[i];\n            vector<int> seq = constructCellCover(a, l);\n            processCandidate(seq, i == 0);\n        }\n\n        vector<int> vcTypes = {0, 2, 3, 1};\n        for (int tp : vcTypes) {\n            if (timer.elapsed() > 2.35) break;\n\n            auto [selH, selV] = weightedVertexCover(tp);\n            vector<int> seq = constructSegmentCover(selH, selV, 1.0, 25.0);\n            processCandidate(seq, false);\n\n            if (timer.elapsed() > 2.35) break;\n            if (tp == 0) {\n                vector<int> seq2 = constructSegmentCover(selH, selV, 1.0, 0.0);\n                processCandidate(seq2, false);\n            }\n        }\n\n        finalPolish();\n\n        if (!bestFinalSeq.empty() && actualFull(bestFinalSeq)) {\n            cout << buildOutput(bestFinalSeq) << '\\n';\n        } else if (!bestSafeSeq.empty() && actualFull(bestSafeSeq)) {\n            cout << buildOutput(bestSafeSeq) << '\\n';\n        } else {\n            cout << dfsFallback() << '\\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\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconst int MAXN = 1000;\nconst int MAXM = 20;\nconst int MAXK = 20;\n\nint N, M, K, R;\nint reqv[MAXN][MAXK];\n\nvector<int> children_[MAXN];\n\nint statusTask[MAXN]; // 0: unstarted, 1: running, 2: done\nint remDep[MAXN];\nint readyDay[MAXN];\n\nint sumReq[MAXN];\nint descCnt[MAXN];\n\ndouble baseDur[MAXN];\ndouble predDur[MAXM][MAXN];\ndouble sumPred[MAXN];\ndouble upRank_[MAXN];\n\ndouble priorSkill[MAXK];\nint initSkill[MAXK];\nint upperSkill[MAXK];\n\nstatic bitset<MAXN> reachBits[MAXN];\n\nstruct Member {\n    int skill[MAXK];\n    vector<int> obsTask;\n    vector<int> obsDur;\n    int task = -1;\n    int startDay = 0;\n};\n\nMember members_[MAXM];\n\ninline double expectedTimeFromW(int w) {\n    if (w <= 0) return 1.0;\n    if (w == 1) return 13.0 / 7.0;\n    if (w == 2) return 17.0 / 7.0;\n    if (w == 3) return 22.0 / 7.0;\n    return (double)w;\n}\n\ninline int calcW(int task, const int skill[]) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        if (reqv[task][k] > skill[k]) {\n            w += reqv[task][k] - skill[k];\n        }\n    }\n    return w;\n}\n\ninline double durationWithSkill(int task, const int skill[]) {\n    return expectedTimeFromW(calcW(task, skill));\n}\n\ninline double obsLoss(int w, int t) {\n    double p = expectedTimeFromW(w);\n    double diff = p - t;\n    return diff * diff;\n}\n\nconst double PRIOR_W = 0.003;\n\ninline double priorLossComp(int k, int v) {\n    double diff = v - priorSkill[k];\n    return PRIOR_W * diff * diff;\n}\n\nvoid optimizeMember(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return;\n\n    vector<int> w(O);\n    for (int i = 0; i < O; i++) {\n        w[i] = calcW(mem.obsTask[i], mem.skill);\n    }\n\n    double curPrior = 0.0;\n    for (int k = 0; k < K; k++) {\n        curPrior += priorLossComp(k, mem.skill[k]);\n    }\n\n    double curObj = curPrior;\n    for (int i = 0; i < O; i++) {\n        curObj += obsLoss(w[i], mem.obsDur[i]);\n    }\n\n    const int MAX_PASS = 4;\n\n    for (int pass = 0; pass < MAX_PASS; pass++) {\n        bool improved = false;\n\n        for (int k = 0; k < K; k++) {\n            int oldVal = mem.skill[k];\n            double priorExcept = curPrior - priorLossComp(k, oldVal);\n\n            int bestVal = oldVal;\n            double bestObj = curObj;\n\n            for (int v = 0; v <= upperSkill[k]; v++) {\n                if (v == oldVal) continue;\n\n                double obj = priorExcept + priorLossComp(k, v);\n\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > v) {\n                        newContrib = reqv[task][k] - v;\n                    }\n\n                    int nw = w[i] - oldContrib + newContrib;\n                    obj += obsLoss(nw, mem.obsDur[i]);\n\n                    if (obj >= bestObj) break;\n                }\n\n                if (obj + 1e-9 < bestObj) {\n                    bestObj = obj;\n                    bestVal = v;\n                }\n            }\n\n            if (bestVal != oldVal) {\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > bestVal) {\n                        newContrib = reqv[task][k] - bestVal;\n                    }\n\n                    w[i] += newContrib - oldContrib;\n                }\n\n                mem.skill[k] = bestVal;\n                curPrior = priorExcept + priorLossComp(k, bestVal);\n                curObj = bestObj;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid updateMemberPredictions(int j) {\n    Member &mem = members_[j];\n\n    double nobs = (double)mem.obsTask.size();\n    double trust = 0.0;\n    if (nobs > 0) trust = nobs / (nobs + 3.0);\n\n    for (int i = 0; i < N; i++) {\n        double pSkill = durationWithSkill(i, mem.skill);\n        double np = trust * pSkill + (1.0 - trust) * baseDur[i];\n\n        sumPred[i] += np - predDur[j][i];\n        predDur[j][i] = np;\n    }\n}\n\nvoid recomputeRanks() {\n    for (int i = N - 1; i >= 0; i--) {\n        if (statusTask[i] == 2) {\n            upRank_[i] = 0.0;\n            continue;\n        }\n\n        double mx = 0.0;\n        for (int v : children_[i]) {\n            if (statusTask[v] != 2) {\n                mx = max(mx, upRank_[v]);\n            }\n        }\n\n        double avg = sumPred[i] / M;\n        upRank_[i] = avg + 0.015 * sumReq[i] + mx;\n    }\n}\n\ndouble taskPriority(int task, int day) {\n    double pr = upRank_[task];\n\n    pr += 0.015 * descCnt[task];\n    pr += 0.25 * (double)children_[task].size();\n\n    int unlock = 0;\n    for (int v : children_[task]) {\n        if (statusTask[v] == 0 && remDep[v] == 1) unlock++;\n    }\n    pr += 2.0 * unlock;\n\n    if (readyDay[task] > 0) {\n        pr += 0.015 * max(0, day - readyDay[task]);\n    }\n\n    return pr;\n}\n\ndouble edgeScore(int member, int task, double prio) {\n    double avg = sumPred[task] / M;\n    double p = predDur[member][task];\n\n    // High priority, globally long tasks, and good personal match are preferred.\n    return prio + 0.4 * avg - p;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n\n    int V;\n    vector<vector<Edge>> graph;\n\n    MinCostFlow(int n = 0) {\n        init(n);\n    }\n\n    void init(int n) {\n        V = n;\n        graph.assign(V, {});\n    }\n\n    void addEdge(int fr, int to, int cap, ll cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge r{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(r);\n    }\n\n    pair<int, ll> minCostFlow(int s, int t, int maxf) {\n        const ll INF = (1LL << 62);\n\n        int flow = 0;\n        ll cost = 0;\n\n        vector<ll> h(V, 0), dist(V);\n        vector<int> prevv(V), preve(V);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != cd) continue;\n\n                for (int i = 0; i < (int)graph[v].size(); i++) {\n                    Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n\n                    ll nd = dist[v] + e.cost + h[v] - h[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INF) break;\n\n            for (int v = 0; v < V; v++) {\n                if (dist[v] < INF) h[v] += dist[v];\n            }\n\n            int add = maxf - flow;\n            ll pathCost = 0;\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                add = min(add, e.cap);\n                pathCost += e.cost;\n            }\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= add;\n                graph[v][e.rev].cap += add;\n            }\n\n            flow += add;\n            cost += pathCost * add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> K >> R)) return 0;\n\n    for (int i = 0; i < N; i++) {\n        sumReq[i] = 0;\n        for (int k = 0; k < K; k++) {\n            cin >> reqv[i][k];\n            sumReq[i] += reqv[i][k];\n        }\n    }\n\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u;\n        --v;\n        children_[u].push_back(v);\n        remDep[v]++;\n    }\n\n    double pi = acos(-1.0);\n    double priorComp = 40.0 * sqrt(2.0 / (pi * K));\n\n    for (int k = 0; k < K; k++) {\n        priorSkill[k] = priorComp;\n        initSkill[k] = (int)round(priorComp);\n        initSkill[k] = max(0, min(60, initSkill[k]));\n        upperSkill[k] = 60;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int k = 0; k < K; k++) {\n            members_[j].skill[k] = initSkill[k];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        baseDur[i] = durationWithSkill(i, initSkill);\n        sumPred[i] = 0.0;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int i = 0; i < N; i++) {\n            predDur[j][i] = baseDur[i];\n            sumPred[i] += predDur[j][i];\n        }\n    }\n\n    for (int i = N - 1; i >= 0; i--) {\n        for (int v : children_[i]) {\n            reachBits[i] |= reachBits[v];\n            reachBits[i].set(v);\n        }\n        descCnt[i] = (int)reachBits[i].count();\n    }\n\n    for (int i = 0; i < N; i++) {\n        statusTask[i] = 0;\n        readyDay[i] = (remDep[i] == 0 ? 1 : -1);\n    }\n\n    static double prioArr[MAXN];\n\n    for (int day = 1;; day++) {\n        recomputeRanks();\n\n        vector<int> idle;\n        for (int j = 0; j < M; j++) {\n            if (members_[j].task < 0) idle.push_back(j);\n        }\n\n        vector<int> readyTasks;\n        for (int i = 0; i < N; i++) {\n            if (statusTask[i] == 0 && remDep[i] == 0) {\n                readyTasks.push_back(i);\n            }\n        }\n\n        vector<pair<int, int>> assignments;\n\n        if (!idle.empty() && !readyTasks.empty()) {\n            for (int task : readyTasks) {\n                prioArr[task] = taskPriority(task, day);\n            }\n\n            vector<int> sortedReady = readyTasks;\n            sort(sortedReady.begin(), sortedReady.end(), [&](int a, int b) {\n                if (prioArr[a] != prioArr[b]) return prioArr[a] > prioArr[b];\n                return a < b;\n            });\n\n            vector<int> candidates;\n            vector<char> inCand(N, 0);\n\n            auto addCandidate = [&](int task) {\n                if (!inCand[task]) {\n                    inCand[task] = 1;\n                    candidates.push_back(task);\n                }\n            };\n\n            int topC = min((int)sortedReady.size(), max(200, (int)idle.size() * 10));\n            for (int i = 0; i < topC; i++) {\n                addCandidate(sortedReady[i]);\n            }\n\n            const int BEST_PER_MEMBER = 10;\n\n            for (int member : idle) {\n                priority_queue<\n                    pair<double, int>,\n                    vector<pair<double, int>>,\n                    greater<pair<double, int>>\n                > pq;\n\n                for (int task : readyTasks) {\n                    double sc = edgeScore(member, task, prioArr[task]);\n                    if ((int)pq.size() < BEST_PER_MEMBER) {\n                        pq.push({sc, task});\n                    } else if (sc > pq.top().first) {\n                        pq.pop();\n                        pq.push({sc, task});\n                    }\n                }\n\n                while (!pq.empty()) {\n                    addCandidate(pq.top().second);\n                    pq.pop();\n                }\n            }\n\n            int I = (int)idle.size();\n            int C = (int)candidates.size();\n            int F = min(I, min(C, (int)readyTasks.size()));\n\n            if (F > 0) {\n                int S = 0;\n                int memberBase = 1;\n                int taskBase = memberBase + I;\n                int T = taskBase + C;\n\n                MinCostFlow mcf(T + 1);\n\n                for (int i = 0; i < I; i++) {\n                    mcf.addEdge(S, memberBase + i, 1, 0);\n                }\n\n                for (int c = 0; c < C; c++) {\n                    mcf.addEdge(taskBase + c, T, 1, 0);\n                }\n\n                const ll SCALE = 1000;\n                const ll OFFSET = 1000000000000000LL;\n\n                for (int i = 0; i < I; i++) {\n                    int member = idle[i];\n                    for (int c = 0; c < C; c++) {\n                        int task = candidates[c];\n                        double sc = edgeScore(member, task, prioArr[task]);\n                        ll isc = llround(sc * SCALE);\n                        ll cost = OFFSET - isc;\n                        if (cost < 0) cost = 0;\n                        mcf.addEdge(memberBase + i, taskBase + c, 1, cost);\n                    }\n                }\n\n                mcf.minCostFlow(S, T, F);\n\n                for (int i = 0; i < I; i++) {\n                    int node = memberBase + i;\n\n                    for (auto &e : mcf.graph[node]) {\n                        if (e.to >= taskBase && e.to < taskBase + C && e.cap == 0) {\n                            int member = idle[i];\n                            int task = candidates[e.to - taskBase];\n\n                            if (members_[member].task < 0 &&\n                                statusTask[task] == 0 &&\n                                remDep[task] == 0) {\n                                assignments.push_back({member, task});\n                            }\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        for (auto [member, task] : assignments) {\n            members_[member].task = task;\n            members_[member].startDay = day;\n            statusTask[task] = 1;\n        }\n\n        cout << assignments.size();\n        for (auto [member, task] : assignments) {\n            cout << ' ' << member + 1 << ' ' << task + 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int nFinished;\n        if (!(cin >> nFinished)) return 0;\n        if (nFinished == -1) return 0;\n\n        for (int x = 0; x < nFinished; x++) {\n            int f;\n            cin >> f;\n            --f;\n\n            int task = members_[f].task;\n            if (task < 0) continue;\n\n            int dur = day - members_[f].startDay + 1;\n\n            statusTask[task] = 2;\n            members_[f].task = -1;\n\n            members_[f].obsTask.push_back(task);\n            members_[f].obsDur.push_back(dur);\n\n            optimizeMember(f);\n            updateMemberPredictions(f);\n\n            for (int v : children_[task]) {\n                remDep[v]--;\n                if (remDep[v] == 0 && statusTask[v] == 0) {\n                    readyDay[v] = day + 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NORD = 1000;\nstatic constexpr int OFF = 1000;\nstatic constexpr int NID = 2001;\nstatic constexpr int INF = 1e9;\n\nint X[NID], Y[NID];\nvector<unsigned short> distMat;\n\ninline int distId(int a, int b) {\n    return distMat[a * NID + b];\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct InsertRes {\n    int delta;\n    int p;\n    int q;\n};\n\nstruct Solution {\n    vector<int> route;\n    vector<char> selected;\n    int len = INF;\n};\n\nint routeCost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distId(route[i], route[i + 1]);\n    }\n    return s;\n}\n\nInsertRes bestInsertion(const vector<int>& route, int oid) {\n    static constexpr int MAXG = 120;\n\n    int G = (int)route.size() - 1;\n    int P = oid;\n    int D = OFF + oid;\n    int pd = distId(P, D);\n\n    int addP[MAXG], addD[MAXG], consec[MAXG];\n    int suf[MAXG + 1], sufIdx[MAXG + 1];\n\n    for (int g = 0; g < G; g++) {\n        int A = route[g];\n        int B = route[g + 1];\n        int base = distId(A, B);\n\n        int dAP = distId(A, P);\n        int dPB = distId(P, B);\n        int dAD = distId(A, D);\n        int dDB = distId(D, B);\n\n        addP[g] = dAP + dPB - base;\n        addD[g] = dAD + dDB - base;\n        consec[g] = dAP + pd + dDB - base;\n    }\n\n    suf[G] = INF;\n    sufIdx[G] = -1;\n    for (int g = G - 1; g >= 0; g--) {\n        if (addD[g] <= suf[g + 1]) {\n            suf[g] = addD[g];\n            sufIdx[g] = g;\n        } else {\n            suf[g] = suf[g + 1];\n            sufIdx[g] = sufIdx[g + 1];\n        }\n    }\n\n    InsertRes best{INF, 0, 0};\n\n    for (int p = 0; p < G; p++) {\n        if (consec[p] < best.delta) {\n            best = {consec[p], p, p};\n        }\n        if (p + 1 < G) {\n            int cost = addP[p] + suf[p + 1];\n            if (cost < best.delta) {\n                best = {cost, p, sufIdx[p + 1]};\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid insertOrder(vector<int>& route, int oid, const InsertRes& res) {\n    int P = oid;\n    int D = OFF + oid;\n\n    if (res.q == res.p) {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.p + 2, D);\n    } else {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.q + 2, D);\n    }\n}\n\nvector<int> selectedList(const Solution& sol) {\n    vector<int> v;\n    v.reserve(50);\n    for (int i = 1; i <= NORD; i++) {\n        if (sol.selected[i]) v.push_back(i);\n    }\n    return v;\n}\n\nint selectedCount(const Solution& sol) {\n    int c = 0;\n    for (int i = 1; i <= NORD; i++) c += sol.selected[i];\n    return c;\n}\n\nSolution buildGreedy(int seed) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.assign(NORD + 1, 0);\n    sol.len = 0;\n\n    int cnt = 0;\n\n    auto add = [&](int oid, const InsertRes& res) {\n        insertOrder(sol.route, oid, res);\n        sol.selected[oid] = 1;\n        sol.len += res.delta;\n        cnt++;\n    };\n\n    if (seed > 0) {\n        InsertRes res = bestInsertion(sol.route, seed);\n        add(seed, res);\n    }\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected[oid]) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = distId(0, oid) + distId(0, OFF + oid);\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        add(bestOid, best);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildFromPool(const vector<int>& pool) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.assign(NORD + 1, 0);\n    sol.len = 0;\n\n    int cnt = 0;\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid : pool) {\n            if (sol.selected[oid]) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = distId(0, oid) + distId(0, OFF + oid);\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        if (bestOid == -1) {\n            for (int oid = 1; oid <= NORD; oid++) {\n                if (sol.selected[oid]) continue;\n\n                InsertRes res = bestInsertion(sol.route, oid);\n                int tie = distId(0, oid) + distId(0, OFF + oid);\n\n                if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                    best = res;\n                    bestOid = oid;\n                    bestTie = tie;\n                }\n            }\n        }\n\n        insertOrder(sol.route, bestOid, best);\n        sol.selected[bestOid] = 1;\n        sol.len += best.delta;\n        cnt++;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nvector<int> removeOrderRoute(const vector<int>& route, int oid) {\n    vector<int> nr;\n    nr.reserve(route.size() - 2);\n\n    int P = oid;\n    int D = OFF + oid;\n\n    for (int id : route) {\n        if (id != P && id != D) nr.push_back(id);\n    }\n    return nr;\n}\n\nbool twoOptDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n    vector<int> sel = selectedList(sol);\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n\n        for (int l = 1; l <= n - 3; l++) {\n            int A = sol.route[l - 1];\n            int B = sol.route[l];\n            int oldAB = distId(A, B);\n\n            for (int r = l + 1; r <= n - 2; r++) {\n                int C = sol.route[r];\n                int D = sol.route[r + 1];\n\n                int delta = distId(A, C) + distId(B, D) - oldAB - distId(C, D);\n                if (delta >= bestDelta) continue;\n\n                bool ok = true;\n                for (int oid : sel) {\n                    int pp = pos[oid];\n                    int dd = pos[OFF + oid];\n\n                    // Reversing an interval containing both pickup and delivery\n                    // would invert their order, so it is forbidden.\n                    if (l <= pp && dd <= r) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta < 0) {\n            reverse(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n    }\n\n    return any;\n}\n\nbool findAndApplyBestPairMove(Solution& sol, Timer& timer, double deadline) {\n    int cur = sol.len;\n    vector<int> sel = selectedList(sol);\n\n    int bestNewLen = cur;\n    int bestRem = -1;\n    int bestIns = -1;\n\n    for (int idx = 0; idx < (int)sel.size(); idx++) {\n        if (timer.elapsed() >= deadline) break;\n\n        int rem = sel[idx];\n        vector<int> tmp = removeOrderRoute(sol.route, rem);\n        int lenTmp = routeCost(tmp);\n\n        // Relocate the same order.\n        {\n            InsertRes res = bestInsertion(tmp, rem);\n            int nl = lenTmp + res.delta;\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = rem;\n            }\n        }\n\n        // Replace by an unselected order.\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected[oid]) continue;\n\n            InsertRes res = bestInsertion(tmp, oid);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = oid;\n            }\n        }\n    }\n\n    if (bestRem == -1) return false;\n\n    vector<int> tmp = removeOrderRoute(sol.route, bestRem);\n\n    if (bestIns != bestRem) {\n        sol.selected[bestRem] = 0;\n        sol.selected[bestIns] = 1;\n    }\n\n    InsertRes res = bestInsertion(tmp, bestIns);\n    insertOrder(tmp, bestIns, res);\n\n    sol.route.swap(tmp);\n    sol.len = routeCost(sol.route);\n\n    return sol.len < cur;\n}\n\nvoid localImprove(Solution& sol, Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        twoOptDescent(sol, timer, deadline);\n\n        if (timer.elapsed() >= deadline) break;\n\n        bool moved = findAndApplyBestPairMove(sol, timer, deadline);\n        if (!moved) break;\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nstruct Cand {\n    int rankCost;\n    int oid;\n    InsertRes res;\n};\n\nSolution ruinRecreate(const Solution& base, int k, XorShift& rng, Timer& timer, double deadline) {\n    Solution sol = base;\n    vector<int> sel = selectedList(base);\n    k = min(k, (int)sel.size());\n\n    vector<pair<int, int>> savings;\n    savings.reserve(sel.size());\n\n    for (int oid : sel) {\n        vector<int> tmp = removeOrderRoute(base.route, oid);\n        int l = routeCost(tmp);\n        savings.push_back({base.len - l, oid});\n    }\n\n    sort(savings.begin(), savings.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n\n    vector<char> rem(NORD + 1, 0);\n    int chosen = 0;\n    int topLimit = min(25, (int)savings.size());\n\n    for (int attempts = 0; chosen < k && attempts < 1000; attempts++) {\n        int idx;\n        if ((rng.next() % 100) < 70) idx = rng.next() % topLimit;\n        else idx = rng.next() % savings.size();\n\n        int oid = savings[idx].second;\n        if (!rem[oid]) {\n            rem[oid] = 1;\n            chosen++;\n        }\n    }\n\n    for (auto [sv, oid] : savings) {\n        if (chosen >= k) break;\n        if (!rem[oid]) {\n            rem[oid] = 1;\n            chosen++;\n        }\n    }\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (rem[oid]) sol.selected[oid] = 0;\n    }\n\n    vector<int> nr;\n    nr.reserve(base.route.size());\n\n    for (int id : base.route) {\n        if (id == 0) {\n            nr.push_back(id);\n        } else {\n            int oid = (id <= OFF ? id : id - OFF);\n            if (!rem[oid]) nr.push_back(id);\n        }\n    }\n\n    sol.route.swap(nr);\n    sol.len = routeCost(sol.route);\n\n    int removedPenalty = 5 + (int)(rng.next() % 25);\n\n    for (int t = 0; t < k; t++) {\n        static constexpr int R = 5;\n        Cand top[R];\n        int topSize = 0;\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected[oid]) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rankCost = res.delta + (rem[oid] ? removedPenalty : 0);\n\n            Cand c{rankCost, oid, res};\n\n            if (topSize < R) {\n                top[topSize++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < R; i++) {\n                    if (top[i].rankCost > top[worst].rankCost) worst = i;\n                }\n                if (c.rankCost < top[worst].rankCost) {\n                    top[worst] = c;\n                }\n            }\n        }\n\n        for (int i = 0; i < topSize; i++) {\n            for (int j = i + 1; j < topSize; j++) {\n                if (top[j].rankCost < top[i].rankCost) {\n                    swap(top[i], top[j]);\n                }\n            }\n        }\n\n        int pick = 0;\n        if (topSize > 1) {\n            int roll = rng.next() % 100;\n            if (roll < 65) pick = 0;\n            else if (roll < 85) pick = min(1, topSize - 1);\n            else pick = rng.next() % topSize;\n        }\n\n        Cand c = top[pick];\n\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected[c.oid] = 1;\n        sol.len += c.res.delta;\n    }\n\n    if (timer.elapsed() < deadline) {\n        twoOptDescent(sol, timer, deadline);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nbool validate(const Solution& sol) {\n    if (selectedCount(sol) != 50) return false;\n    if (sol.route.empty()) return false;\n    if (sol.route.front() != 0 || sol.route.back() != 0) return false;\n\n    vector<int> pp(NORD + 1, -1), dd(NORD + 1, -1);\n\n    for (int i = 0; i < (int)sol.route.size(); i++) {\n        int id = sol.route[i];\n\n        if (id == 0) continue;\n        if (1 <= id && id <= NORD) pp[id] = i;\n        else if (OFF < id && id <= OFF + NORD) dd[id - OFF] = i;\n        else return false;\n    }\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (!sol.selected[oid]) continue;\n        if (pp[oid] == -1 || dd[oid] == -1) return false;\n        if (pp[oid] >= dd[oid]) return false;\n    }\n\n    return true;\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    for (int i = 1; i <= NORD; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n\n        X[i] = a;\n        Y[i] = b;\n        X[OFF + i] = c;\n        Y[OFF + i] = d;\n    }\n\n    distMat.assign(NID * NID, 0);\n\n    for (int i = 0; i < NID; i++) {\n        for (int j = 0; j <= i; j++) {\n            int v = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n            distMat[i * NID + j] = distMat[j * NID + i] = (unsigned short)v;\n        }\n    }\n\n    Timer timer;\n\n    vector<pair<int, int>> firstCost;\n    firstCost.reserve(NORD);\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        int cost = distId(0, oid) + distId(oid, OFF + oid) + distId(OFF + oid, 0);\n        firstCost.push_back({cost, oid});\n    }\n\n    sort(firstCost.begin(), firstCost.end());\n\n    vector<Solution> candidates;\n\n    const double INIT_DEAD = 0.35;\n\n    auto addCandidate = [&](Solution sol) {\n        if (timer.elapsed() < INIT_DEAD) {\n            twoOptDescent(sol, timer, INIT_DEAD);\n        }\n        sol.len = routeCost(sol.route);\n        candidates.push_back(std::move(sol));\n    };\n\n    // Guaranteed first candidate.\n    addCandidate(buildGreedy(firstCost[0].second));\n\n    // Centrality-based pools.\n    for (int mode = 0; mode < 4 && timer.elapsed() < INIT_DEAD; mode++) {\n        vector<pair<int, int>> score;\n        score.reserve(NORD);\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            int dP = distId(0, oid);\n            int dD = distId(0, OFF + oid);\n            int sc;\n\n            if (mode == 0) {\n                sc = dP + dD;\n            } else if (mode == 1) {\n                sc = max(dP, dD) * 2000 + dP + dD;\n            } else if (mode == 2) {\n                sc = dP + dD + distId(oid, OFF + oid);\n            } else {\n                int linf = max({\n                    abs(X[oid] - 400),\n                    abs(Y[oid] - 400),\n                    abs(X[OFF + oid] - 400),\n                    abs(Y[OFF + oid] - 400)\n                });\n                sc = linf * 2000 + dP + dD;\n            }\n\n            score.push_back({sc, oid});\n        }\n\n        sort(score.begin(), score.end());\n\n        vector<int> pool;\n        int poolSize = min(120, NORD);\n        pool.reserve(poolSize);\n\n        for (int i = 0; i < poolSize; i++) {\n            pool.push_back(score[i].second);\n        }\n\n        addCandidate(buildFromPool(pool));\n    }\n\n    // Multiple greedy starts.\n    for (int idx = 1; idx < 25 && timer.elapsed() < INIT_DEAD; idx++) {\n        addCandidate(buildGreedy(firstCost[idx].second));\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    Solution bestOverall = candidates[0];\n\n    const double LOCAL_DEAD = 1.55;\n\n    int starts = min(3, (int)candidates.size());\n    for (int i = 0; i < starts && timer.elapsed() < LOCAL_DEAD; i++) {\n        Solution sol = candidates[i];\n        localImprove(sol, timer, LOCAL_DEAD);\n\n        if (sol.len < bestOverall.len) {\n            bestOverall = std::move(sol);\n        }\n    }\n\n    XorShift rng(1234567891234567ull);\n    Solution current = bestOverall;\n\n    const double LNS_DEAD = 1.82;\n\n    while (timer.elapsed() < LNS_DEAD) {\n        if (LNS_DEAD - timer.elapsed() < 0.03) break;\n\n        int k = 2 + (int)(rng.next() % 6); // 2..7\n\n        const Solution& base = ((rng.next() % 4) == 0 ? current : bestOverall);\n        Solution cand = ruinRecreate(base, k, rng, timer, LNS_DEAD);\n\n        if (cand.len < bestOverall.len) {\n            bestOverall = std::move(cand);\n            localImprove(bestOverall, timer, LNS_DEAD);\n            current = bestOverall;\n        } else {\n            int diff = cand.len - current.len;\n            double progress = min(1.0, timer.elapsed() / LNS_DEAD);\n            double temp = 25.0 * (1.0 - progress) + 2.0;\n\n            if (diff < 0 || rng.nextDouble() < exp(-(double)diff / temp)) {\n                current = std::move(cand);\n            }\n\n            if (current.len > bestOverall.len + 250) {\n                current = bestOverall;\n            }\n        }\n    }\n\n    const double FINAL_DEAD = 1.88;\n    localImprove(bestOverall, timer, FINAL_DEAD);\n\n    bestOverall.len = routeCost(bestOverall.route);\n\n    if (!validate(bestOverall)) {\n        bestOverall = buildGreedy(firstCost[0].second);\n    }\n\n    cout << 50;\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (bestOverall.selected[oid]) {\n            cout << ' ' << oid;\n        }\n    }\n    cout << '\\n';\n\n    cout << bestOverall.route.size();\n    for (int id : bestOverall.route) {\n        cout << ' ' << X[id] << ' ' << Y[id];\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 SAMPLES = 64;\nstatic constexpr int INF = 1e9;\n\n// Blend between clairvoyant Monte Carlo estimate and deterministic expected-weight estimate.\nstatic constexpr double BLEND = 0.22;\n\nstruct DSU {\n    int p[N];\n    int comps;\n\n    void init() {\n        comps = N;\n        for (int i = 0; i < N; i++) p[i] = -1;\n    }\n\n    int find(int x) const {\n        while (p[x] >= 0) x = p[x];\n        return x;\n    }\n\n    bool same(int a, int b) const {\n        return find(a) == find(b);\n    }\n\n    bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (p[a] > p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        comps--;\n        return true;\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next() % uint64_t(r - l + 1));\n    }\n};\n\nint xcoord[N], ycoord[N];\nint U[M], V[M], D[M];\n\nstatic int sampleW[SAMPLES][M];\nstatic int orderSample[SAMPLES][M];\nstatic int orderMean[M];\n\nint bottleneck_sample(int s, int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderSample[s][pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return sampleW[s][e];\n        }\n    }\n    return INF;\n}\n\nint bottleneck_mean(int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderMean[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return 2 * D[e];\n        }\n    }\n    return INF;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 0; i < N; i++) {\n        cin >> xcoord[i] >> ycoord[i];\n    }\n\n    uint64_t seed = 123456789;\n    for (int i = 0; i < N; i++) {\n        seed ^= uint64_t(xcoord[i] + 1009) * 0x9e3779b97f4a7c15ULL;\n        seed ^= uint64_t(ycoord[i] + 9176) * 0xbf58476d1ce4e5b9ULL;\n    }\n\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n\n        long long dx = xcoord[U[i]] - xcoord[V[i]];\n        long long dy = ycoord[U[i]] - ycoord[V[i]];\n        D[i] = int(sqrt(double(dx * dx + dy * dy)) + 0.5);\n\n        seed ^= uint64_t(U[i] + 1) * 0x94d049bb133111ebULL;\n        seed ^= uint64_t(V[i] + 1) * 0x2545f4914f6cdd1dULL;\n    }\n\n    SplitMix64 rng(seed);\n\n    // Antithetic Monte Carlo samples.\n    for (int s = 0; s < SAMPLES; s += 2) {\n        for (int e = 0; e < M; e++) {\n            int range = 2 * D[e] + 1;\n            int k = int(rng.next() % uint64_t(range));\n            sampleW[s][e] = D[e] + k;\n            sampleW[s + 1][e] = 3 * D[e] - k;\n        }\n    }\n\n    vector<int> ids(M);\n    iota(ids.begin(), ids.end(), 0);\n\n    for (int s = 0; s < SAMPLES; s++) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (sampleW[s][a] != sampleW[s][b]) return sampleW[s][a] < sampleW[s][b];\n            return a < b;\n        });\n        for (int i = 0; i < M; i++) orderSample[s][i] = ids[i];\n    }\n\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n    for (int i = 0; i < M; i++) orderMean[i] = ids[i];\n\n    DSU accepted;\n    accepted.init();\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        cin >> l;\n\n        int ans = 0;\n\n        if (!accepted.same(U[i], V[i])) {\n            int det = bottleneck_mean(i, U[i], V[i], accepted);\n\n            if (det >= INF) {\n                // This edge is necessary for future connectivity.\n                ans = 1;\n            } else {\n                long long sum = 0;\n                for (int s = 0; s < SAMPLES; s++) {\n                    int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                    sum += b;\n                }\n\n                double mc = double(sum) / SAMPLES;\n                double threshold = mc + BLEND * (double(det) - mc);\n\n                if (double(l) <= threshold) ans = 1;\n            }\n\n            if (ans) accepted.unite(U[i], V[i]);\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int G = 30;\nconst int INF = 1e9;\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar DIR_CH[4] = {'U', 'D', 'L', 'R'};\n\nint dirId(char ch) {\n    ch = toupper(ch);\n    if (ch == 'U') return 0;\n    if (ch == 'D') return 1;\n    if (ch == 'L') return 2;\n    return 3;\n}\n\nbool inside(int r, int c) {\n    return 0 <= r && r < G && 0 <= c && c < G;\n}\n\nstruct Pet {\n    int r, c, t;\n};\n\npair<int,int> toPhysCoord(int r, int c, int ori) {\n    if (ori == 0) return {r, c};             // corridor = bottom\n    if (ori == 1) return {G - 1 - r, c};     // corridor = top\n    if (ori == 2) return {c, r};             // corridor = right\n    return {c, G - 1 - r};                   // corridor = left\n}\n\npair<int,int> toLogCoord(int pr, int pc, int ori) {\n    if (ori == 0) return {pr, pc};\n    if (ori == 1) return {G - 1 - pr, pc};\n    if (ori == 2) return {pc, pr};\n    return {G - 1 - pc, pr};\n}\n\nint chooseOrientation(const vector<Pet>& petsPhys, const vector<pair<int,int>>& humansPhys) {\n    double best = 1e100;\n    int bestOri = 0;\n\n    for (int ori = 0; ori < 4; ori++) {\n        double cost = 0.0;\n\n        for (auto p : petsPhys) {\n            auto [r, c] = toLogCoord(p.r, p.c, ori);\n            int distCorr = G - 1 - r;\n\n            double w = 1.0;\n            if (p.t == 4) w = 3.0;      // dog\n            else if (p.t == 3) w = 1.5;\n            else if (p.t == 5) w = 1.4;\n            else if (p.t == 2) w = 1.2;\n\n            int near = max(0, 12 - distCorr);\n            cost += w * near * near;\n            if (r >= 28) cost += 100.0 * w;\n        }\n\n        for (auto h : humansPhys) {\n            auto [r, c] = toLogCoord(h.first, h.second, ori);\n            int bestStand = 100;\n            for (int s = 2; s <= 26; s += 4) {\n                bestStand = min(bestStand, abs(c - s));\n            }\n            cost += 0.5 * (G - 1 - r) + 0.2 * bestStand;\n        }\n\n        if (cost < best) {\n            best = cost;\n            bestOri = ori;\n        }\n    }\n\n    return bestOri;\n}\n\nstruct Task {\n    int stand;\n    vector<int> walls;\n    int assigned = -1; // -1: free, >=0: human id, -2: finished\n};\n\nstruct HState {\n    int task = -1;\n    int phase = 0;\n    int wait = 0;\n    int home = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, ori;\n    int turnNo = 0;\n\n    vector<Pet> pets;\n    vector<pair<int,int>> humans;\n\n    bool blocked[G][G]{};\n    bool petOcc[G][G]{};\n    bool humanOcc[G][G]{};\n    bool resBuild[G][G]{};\n    bool resMove[G][G]{};\n\n    vector<Task> tasks;\n    vector<HState> hs;\n\n    char logToPhys[256]{};\n    char physToLog[256]{};\n\n    static constexpr int FREE = 0;\n    static constexpr int GO = 1;\n    static constexpr int UP = 2;\n    static constexpr int DOWN = 3;\n    static constexpr int RET = 4;\n\n    static constexpr int ASSIGN_LIMIT = 190;\n    static constexpr int BUILD_LIMIT = 265;\n    static constexpr int WAIT_UNTIL = 230;\n    static constexpr int WAIT_LIMIT = 2;\n\n    Solver(int n,\n           const vector<Pet>& petsPhys,\n           int m,\n           const vector<pair<int,int>>& humansPhys,\n           int orientation)\n        : N(n), M(m), ori(orientation)\n    {\n        initDirectionMaps();\n\n        pets.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto [r, c] = toLogCoord(petsPhys[i].r, petsPhys[i].c, ori);\n            pets[i] = {r, c, petsPhys[i].t};\n        }\n\n        humans.resize(M);\n        for (int i = 0; i < M; i++) {\n            humans[i] = toLogCoord(humansPhys[i].first, humansPhys[i].second, ori);\n        }\n\n        initTasks();\n\n        hs.resize(M);\n        for (int i = 0; i < M; i++) {\n            hs[i].home = (i + 1) * G / (M + 1);\n        }\n    }\n\n    void initDirectionMaps() {\n        memset(logToPhys, 0, sizeof(logToPhys));\n        memset(physToLog, 0, sizeof(physToLog));\n\n        int br = 15, bc = 15;\n        for (char ch : string(\"UDLR\")) {\n            int d = dirId(ch);\n            auto p1 = toPhysCoord(br, bc, ori);\n            auto p2 = toPhysCoord(br + DR[d], bc + DC[d], ori);\n            int rr = p2.first - p1.first;\n            int cc = p2.second - p1.second;\n\n            char pc = '?';\n            if (rr == -1 && cc == 0) pc = 'U';\n            if (rr == 1 && cc == 0) pc = 'D';\n            if (rr == 0 && cc == -1) pc = 'L';\n            if (rr == 0 && cc == 1) pc = 'R';\n\n            logToPhys[(int)ch] = pc;\n            physToLog[(int)pc] = ch;\n        }\n    }\n\n    void initTasks() {\n        // Logical wall columns: 1,3,5,...,27.\n        // Each task uses an even stand column and builds both adjacent walls.\n        for (int s = 2; s <= 26; s += 4) {\n            Task t;\n            t.stand = s;\n            t.walls = {s - 1, s + 1};\n            tasks.push_back(t);\n        }\n    }\n\n    void buildOcc() {\n        memset(petOcc, 0, sizeof(petOcc));\n        memset(humanOcc, 0, sizeof(humanOcc));\n\n        for (auto &p : pets) {\n            if (inside(p.r, p.c)) petOcc[p.r][p.c] = true;\n        }\n        for (auto &h : humans) {\n            if (inside(h.first, h.second)) humanOcc[h.first][h.second] = true;\n        }\n    }\n\n    void resetReservations() {\n        memset(resBuild, 0, sizeof(resBuild));\n        memset(resMove, 0, sizeof(resMove));\n    }\n\n    bool canBuild(int i, char lowerDir) {\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (petOcc[r][c]) return false;\n        if (humanOcc[r][c]) return false;\n        if (resMove[r][c]) return false;\n\n        for (int k = 0; k < 4; k++) {\n            int nr = r + DR[k], nc = c + DC[k];\n            if (inside(nr, nc) && petOcc[nr][nc]) return false;\n        }\n\n        return true;\n    }\n\n    bool canMove(int i, char upperDir) {\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (blocked[r][c]) return false;\n        if (resBuild[r][c]) return false;\n        return true;\n    }\n\n    bool issueBuild(int i, char lowerDir, vector<char>& act) {\n        lowerDir = tolower(lowerDir);\n        if (!canBuild(i, lowerDir)) return false;\n\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = lowerDir;\n        resBuild[r][c] = true;\n        return true;\n    }\n\n    bool issueMove(int i, char upperDir, vector<char>& act) {\n        upperDir = toupper(upperDir);\n        if (!canMove(i, upperDir)) return false;\n\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = upperDir;\n        resMove[r][c] = true;\n        return true;\n    }\n\n    bool taskComplete(int tid) {\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) return false;\n            }\n        }\n        return true;\n    }\n\n    int countRemainingBuilds(int tid) {\n        int cnt = 0;\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int shortestDist(pair<int,int> st, pair<int,int> goal) {\n        if (!inside(goal.first, goal.second)) return INF;\n        if (blocked[goal.first][goal.second]) return INF;\n\n        int dist[G][G];\n        for (int r = 0; r < G; r++) for (int c = 0; c < G; c++) dist[r][c] = -1;\n\n        queue<pair<int,int>> q;\n        dist[st.first][st.second] = 0;\n        q.push(st);\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            if (r == goal.first && c == goal.second) return dist[r][c];\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (dist[nr][nc] != -1) continue;\n\n                dist[nr][nc] = dist[r][c] + 1;\n                q.push({nr, nc});\n            }\n        }\n\n        return INF;\n    }\n\n    char bfsMove(int i, const vector<pair<int,int>>& goals) {\n        bool goal[G][G]{};\n        int goalCnt = 0;\n\n        for (auto [r, c] : goals) {\n            if (!inside(r, c)) continue;\n            if (blocked[r][c]) continue;\n            if (resBuild[r][c]) continue;\n            if (!goal[r][c]) {\n                goal[r][c] = true;\n                goalCnt++;\n            }\n        }\n\n        if (goalCnt == 0) return '.';\n\n        int sr = humans[i].first;\n        int sc = humans[i].second;\n\n        if (goal[sr][sc]) return '.';\n\n        bool vis[G][G]{};\n        char first[G][G]{};\n\n        queue<pair<int,int>> q;\n        vis[sr][sc] = true;\n        q.push({sr, sc});\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (resBuild[nr][nc]) continue;\n                if (vis[nr][nc]) continue;\n\n                vis[nr][nc] = true;\n                first[nr][nc] = (r == sr && c == sc ? DIR_CH[d] : first[r][c]);\n\n                if (goal[nr][nc]) return first[nr][nc];\n\n                q.push({nr, nc});\n            }\n        }\n\n        return '.';\n    }\n\n    int taskPriority(int tid) {\n        int s = tasks[tid].stand;\n        int pr = 0;\n\n        for (auto &p : pets) {\n            int w = 1;\n            if (p.t == 4) w = 6;\n            else if (p.t == 5) w = 3;\n            else if (p.t == 3) w = 3;\n            else if (p.t == 2) w = 2;\n\n            if (p.r <= 28) {\n                int dc = abs(p.c - s);\n                if (dc <= 2) pr += w * (3 - dc);\n                else if (dc <= 4) pr += 1;\n            } else {\n                if (abs(p.c - s) <= 2) pr += 1;\n            }\n        }\n\n        return pr;\n    }\n\n    void normalizeStates() {\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task == -1) continue;\n\n            int tid = hs[i].task;\n            bool comp = taskComplete(tid);\n\n            if (comp) hs[i].phase = RET;\n            if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n            if (humans[i].first == 29 && hs[i].phase == RET) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n            }\n        }\n    }\n\n    void assignTasks() {\n        if (turnNo > ASSIGN_LIMIT) return;\n\n        while (true) {\n            int bestI = -1, bestT = -1;\n            double bestVal = -1e100;\n\n            for (int i = 0; i < M; i++) {\n                if (hs[i].task != -1) continue;\n\n                for (int tid = 0; tid < (int)tasks.size(); tid++) {\n                    if (tasks[tid].assigned != -1) continue;\n                    if (taskComplete(tid)) continue;\n\n                    int stand = tasks[tid].stand;\n                    if (blocked[28][stand]) continue;\n\n                    int dist = shortestDist(humans[i], {29, stand});\n                    if (dist >= INF) continue;\n\n                    int rem = countRemainingBuilds(tid);\n                    int estimate = dist + rem + 58;\n                    if (turnNo + estimate > BUILD_LIMIT + 8) continue;\n\n                    double val = 50.0 * taskPriority(tid) - dist;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestI = i;\n                        bestT = tid;\n                    }\n                }\n            }\n\n            if (bestI == -1) break;\n\n            hs[bestI].task = bestT;\n            hs[bestI].phase = GO;\n            hs[bestI].wait = 0;\n            tasks[bestT].assigned = bestI;\n        }\n    }\n\n    array<bool, G> computeDoorTargets() {\n        array<bool, G> need;\n        need.fill(false);\n\n        struct Comp {\n            int area = 0;\n            int pets = 0;\n            bool protect = false;\n            vector<int> doors;\n        };\n\n        int compId[G][G];\n        for (int r = 0; r < G; r++) {\n            for (int c = 0; c < G; c++) compId[r][c] = -1;\n        }\n\n        vector<Comp> comps;\n\n        for (int sr = 0; sr <= 28; sr++) {\n            for (int sc = 0; sc < G; sc++) {\n                if (blocked[sr][sc]) continue;\n                if (compId[sr][sc] != -1) continue;\n\n                int id = (int)comps.size();\n                comps.push_back(Comp());\n\n                queue<pair<int,int>> q;\n                compId[sr][sc] = id;\n                q.push({sr, sc});\n\n                while (!q.empty()) {\n                    auto [r, c] = q.front();\n                    q.pop();\n\n                    comps[id].area++;\n\n                    if (r == 28 && !blocked[29][c]) {\n                        comps[id].doors.push_back(c);\n                    }\n\n                    for (int d = 0; d < 4; d++) {\n                        int nr = r + DR[d], nc = c + DC[d];\n                        if (!inside(nr, nc)) continue;\n                        if (nr == 29) continue; // bottom corridor excluded\n                        if (blocked[nr][nc]) continue;\n                        if (compId[nr][nc] != -1) continue;\n\n                        compId[nr][nc] = id;\n                        q.push({nr, nc});\n                    }\n                }\n            }\n        }\n\n        int corridorPets = 0;\n\n        for (auto &p : pets) {\n            if (p.r == 29) {\n                corridorPets++;\n            } else if (0 <= p.r && p.r <= 28) {\n                int id = compId[p.r][p.c];\n                if (id >= 0) comps[id].pets++;\n            }\n        }\n\n        for (auto &h : humans) {\n            if (h.first <= 28) {\n                int id = compId[h.first][h.second];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        // Protect components currently needed by active builders.\n        for (int i = 0; i < M; i++) {\n            int tid = hs[i].task;\n            if (tid == -1) continue;\n            if (hs[i].phase == RET) continue;\n            if (taskComplete(tid)) continue;\n\n            int s = tasks[tid].stand;\n            if (!blocked[28][s]) {\n                int id = compId[28][s];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        int baseArea = 0;\n        for (int c = 0; c < G; c++) {\n            if (!blocked[29][c]) baseArea++;\n        }\n\n        int basePets = corridorPets;\n        (void)basePets; // constant for subset choice\n\n        struct Item {\n            int comp;\n            int area;\n            int pets;\n        };\n\n        vector<Item> items;\n\n        for (int id = 0; id < (int)comps.size(); id++) {\n            auto &cp = comps[id];\n\n            if (cp.doors.empty()) continue; // already isolated from corridor\n\n            if (cp.protect || cp.pets == 0) {\n                baseArea += cp.area;\n                basePets += cp.pets;\n            } else {\n                items.push_back({id, cp.area, cp.pets});\n            }\n        }\n\n        int K = (int)items.size();\n        int maxP = N;\n\n        vector<vector<int>> dp(K + 1, vector<int>(maxP + 1, -INF));\n        vector<vector<int>> pre(K + 1, vector<int>(maxP + 1, -1));\n        vector<vector<char>> take(K + 1, vector<char>(maxP + 1, 0));\n\n        dp[0][0] = baseArea;\n\n        for (int k = 0; k < K; k++) {\n            int a = items[k].area;\n            int p = items[k].pets;\n\n            for (int q = 0; q <= maxP; q++) {\n                if (dp[k][q] < 0) continue;\n\n                // Close this component.\n                if (dp[k][q] > dp[k + 1][q]) {\n                    dp[k + 1][q] = dp[k][q];\n                    pre[k + 1][q] = q;\n                    take[k + 1][q] = 0;\n                }\n\n                // Leave it open.\n                if (q + p <= maxP && dp[k][q] + a > dp[k + 1][q + p]) {\n                    dp[k + 1][q + p] = dp[k][q] + a;\n                    pre[k + 1][q + p] = q;\n                    take[k + 1][q + p] = 1;\n                }\n            }\n        }\n\n        int bestQ = 0;\n        double bestScore = -1.0;\n\n        for (int q = 0; q <= maxP; q++) {\n            if (dp[K][q] < 0) continue;\n            double val = ldexp((double)dp[K][q], -q);\n            if (val > bestScore) {\n                bestScore = val;\n                bestQ = q;\n            }\n        }\n\n        vector<bool> include(K, false);\n        int q = bestQ;\n        for (int k = K; k >= 1; k--) {\n            include[k - 1] = take[k][q];\n            q = pre[k][q];\n            if (q < 0) break;\n        }\n\n        for (int k = 0; k < K; k++) {\n            if (include[k]) continue;\n\n            int id = items[k].comp;\n            for (int c : comps[id].doors) {\n                if (!blocked[28][c]) need[c] = true;\n            }\n        }\n\n        return need;\n    }\n\n    int tryBuildCurrentRow(int i, int tid, vector<char>& act) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (!(0 <= r && r <= 28)) return 0;\n        if (c != stand) return 0;\n\n        bool anyUnbuilt = false;\n\n        for (int wc : tasks[tid].walls) {\n            if (blocked[r][wc]) continue;\n\n            anyUnbuilt = true;\n            char low = (wc < stand ? 'l' : 'r');\n\n            if (!resBuild[r][wc] && canBuild(i, low)) {\n                issueBuild(i, low, act);\n                return 1;\n            }\n        }\n\n        return anyUnbuilt ? -1 : 0;\n    }\n\n    void moveToGoals(int i, const vector<pair<int,int>>& goals, vector<char>& act) {\n        char mv = bfsMove(i, goals);\n        if (mv != '.') issueMove(i, mv, act);\n    }\n\n    void actBuilder(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int tid = hs[i].task;\n\n        if (tid == -1) {\n            actFree(i, act, needDoor);\n            return;\n        }\n\n        bool comp = taskComplete(tid);\n        if (comp) hs[i].phase = RET;\n        if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (hs[i].phase == RET) {\n            if (r == 29) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n                actFree(i, act, needDoor);\n                return;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col = 0; col < G; col++) {\n                if (!blocked[29][col]) goals.push_back({29, col});\n            }\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        if (hs[i].phase == GO) {\n            if (!(r == 29 && c == stand)) {\n                moveToGoals(i, {{29, stand}}, act);\n                return;\n            }\n            hs[i].phase = UP;\n        }\n\n        if (c != stand) {\n            hs[i].phase = GO;\n            moveToGoals(i, {{29, stand}}, act);\n            return;\n        }\n\n        if (hs[i].phase == UP) {\n            if (r == 29) {\n                hs[i].wait = 0;\n                issueMove(i, 'U', act);\n                return;\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r > 0) {\n                issueMove(i, 'U', act);\n                return;\n            } else {\n                hs[i].phase = DOWN;\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n\n        if (hs[i].phase == DOWN) {\n            if (r == 29) {\n                if (taskComplete(tid)) {\n                    hs[i].phase = RET;\n                    actBuilder(i, act, needDoor);\n                    return;\n                } else {\n                    hs[i].phase = UP;\n                    issueMove(i, 'U', act);\n                    return;\n                }\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r < 28) {\n                issueMove(i, 'D', act);\n                return;\n            } else {\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n    }\n\n    void actFree(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n\n        if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c]) {\n            if (canBuild(i, 'u')) {\n                issueBuild(i, 'u', act);\n                return;\n            }\n        }\n\n        vector<int> cols;\n        for (int col = 0; col < G; col++) {\n            if (needDoor[col] && !blocked[28][col] && !resBuild[28][col]) {\n                cols.push_back(col);\n            }\n        }\n\n        if (!cols.empty()) {\n            bool curIllegal = false;\n            if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c] && !canBuild(i, 'u')) {\n                curIllegal = true;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col : cols) {\n                if (curIllegal && col == c && cols.size() >= 2) continue;\n                goals.push_back({29, col});\n            }\n\n            if (goals.empty()) goals.push_back({29, c});\n\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        moveToGoals(i, {{29, hs[i].home}}, act);\n    }\n\n    string decideActions() {\n        buildOcc();\n        resetReservations();\n\n        normalizeStates();\n        assignTasks();\n\n        auto needDoor = computeDoorTargets();\n\n        vector<char> act(M, '.');\n\n        vector<int> order;\n        for (int i = 0; i < M; i++) if (hs[i].task != -1) order.push_back(i);\n        for (int i = 0; i < M; i++) if (hs[i].task == -1) order.push_back(i);\n\n        for (int i : order) {\n            if (hs[i].task != -1) actBuilder(i, act, needDoor);\n            else actFree(i, act, needDoor);\n        }\n\n        string s;\n        s.reserve(M);\n        for (int i = 0; i < M; i++) s.push_back(act[i]);\n        return s;\n    }\n\n    char convertAction(char ch) {\n        if (ch == '.') return '.';\n\n        bool low = islower((unsigned char)ch);\n        char up = toupper(ch);\n        char p = logToPhys[(int)up];\n\n        if (low) p = tolower(p);\n        return p;\n    }\n\n    string toPhysicalOutput(const string& logAct) {\n        string out;\n        out.reserve(logAct.size());\n\n        for (char ch : logAct) {\n            out.push_back(convertAction(ch));\n        }\n\n        return out;\n    }\n\n    void applyActions(const string& logAct) {\n        auto oldHumans = humans;\n        auto newHumans = humans;\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('a' <= a && a <= 'z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) blocked[r][c] = true;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('A' <= a && a <= 'Z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) newHumans[i] = {r, c};\n            }\n        }\n\n        humans = newHumans;\n    }\n\n    bool readPetMovesAndUpdate() {\n        for (int i = 0; i < N; i++) {\n            string s;\n            if (!(cin >> s)) return false;\n\n            if (s == \".\") continue;\n\n            for (char pc : s) {\n                if (pc == '.') continue;\n\n                char lc = physToLog[(int)pc];\n                int d = dirId(lc);\n\n                pets[i].r += DR[d];\n                pets[i].c += DC[d];\n            }\n        }\n\n        return true;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<Pet> petsPhys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> petsPhys[i].r >> petsPhys[i].c >> petsPhys[i].t;\n        petsPhys[i].r--;\n        petsPhys[i].c--;\n    }\n\n    int M;\n    cin >> M;\n\n    vector<pair<int,int>> humansPhys(M);\n    for (int i = 0; i < M; i++) {\n        cin >> humansPhys[i].first >> humansPhys[i].second;\n        humansPhys[i].first--;\n        humansPhys[i].second--;\n    }\n\n    int ori = chooseOrientation(petsPhys, humansPhys);\n    Solver solver(N, petsPhys, M, humansPhys, ori);\n\n    for (int turn = 0; turn < 300; turn++) {\n        solver.turnNo = turn;\n\n        string logAct = solver.decideActions();\n        string out = solver.toPhysicalOutput(logAct);\n\n        cout << out << endl;\n        cout.flush();\n\n        solver.applyActions(logAct);\n\n        if (!solver.readPetMovesAndUpdate()) return 0;\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 20;\nstatic constexpr int W = 20;\nstatic constexpr int N = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr int MAXD = 400;\n\nint si_, sj_, ti_, tj_;\nint SID, TID;\ndouble pForget, qRemember;\nstring hwall[H], vwall[H - 1];\n\nint goTo[4][N]; // U D L R\nint distT[N];\n\ndouble pot[MAXL + 1][MAXD + 1];\n\ndouble pref[MAXL + 1][N];\ndouble suff[MAXL + 1][N];\ndouble prefScore[MAXL + 1];\n\nchrono::steady_clock::time_point startTime;\nconst double HARD_LIMIT = 1.90;\nconst double EPS = 1e-10;\nconst string DIRS = \"UDLR\";\n\ninline int id(int i, int j) {\n    return i * W + j;\n}\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n}\n\nvoid buildGo() {\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x = id(i, j);\n            goTo[0][x] = (i > 0 && vwall[i - 1][j] == '0') ? id(i - 1, j) : x;\n            goTo[1][x] = (i + 1 < H && vwall[i][j] == '0') ? id(i + 1, j) : x;\n            goTo[2][x] = (j > 0 && hwall[i][j - 1] == '0') ? id(i, j - 1) : x;\n            goTo[3][x] = (j + 1 < W && hwall[i][j] == '0') ? id(i, j + 1) : x;\n        }\n    }\n}\n\nvoid bfsDist() {\n    fill(distT, distT + N, -1);\n    queue<int> que;\n    distT[TID] = 0;\n    que.push(TID);\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n            if (distT[y] == -1) {\n                distT[y] = distT[x] + 1;\n                que.push(y);\n            }\n        }\n    }\n    for (int i = 0; i < N; i++) {\n        if (distT[i] < 0) distT[i] = MAXD;\n    }\n}\n\nvoid buildPotential() {\n    for (int d = 0; d <= MAXD; d++) pot[MAXL][d] = 0.0;\n    pot[MAXL][0] = 401 - MAXL; // 201\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        pot[l][0] = 401 - l;\n        for (int d = 1; d <= MAXD; d++) {\n            pot[l][d] = qRemember * pot[l + 1][d - 1] + pForget * pot[l + 1][d];\n        }\n    }\n}\n\ndouble evaluate(const vector<int>& seq) {\n    static double dp[N], ndp[N];\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    double score = 0.0;\n    int L = (int)seq.size();\n\n    for (int k = 0; k < L; k++) {\n        fill(ndp, ndp + N, 0.0);\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k; // 401 - (k+1)\n\n        for (int v = 0; v < N; v++) {\n            double m = dp[v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n            if (u == TID) {\n                hit += m * qRemember;\n                ndp[v] += m * pForget;\n            } else if (u == v) {\n                ndp[v] += m;\n            } else {\n                ndp[v] += m * pForget;\n                ndp[u] += m * qRemember;\n            }\n        }\n\n        score += reward * hit;\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return score;\n}\n\nvoid computePrefixSuffix(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(pref[0], pref[0] + N, 0.0);\n    pref[0][SID] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int k = 0; k < L; k++) {\n        fill(pref[k + 1], pref[k + 1] + N, 0.0);\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = pref[k][v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n            if (u == TID) {\n                hit += m * qRemember;\n                pref[k + 1][v] += m * pForget;\n            } else if (u == v) {\n                pref[k + 1][v] += m;\n            } else {\n                pref[k + 1][v] += m * pForget;\n                pref[k + 1][u] += m * qRemember;\n            }\n        }\n\n        prefScore[k + 1] = prefScore[k] + reward * hit;\n    }\n\n    fill(suff[L], suff[L] + N, 0.0);\n\n    for (int k = L - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                suff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n            if (u == TID) {\n                suff[k][v] = qRemember * reward + pForget * suff[k + 1][v];\n            } else if (u == v) {\n                suff[k][v] = suff[k + 1][v];\n            } else {\n                suff[k][v] = pForget * suff[k + 1][v] + qRemember * suff[k + 1][u];\n            }\n        }\n    }\n}\n\nbool tryWindow(vector<int>& seq, int win, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    int masks = 1 << (2 * win);\n\n    static double buf1[N], buf2[N];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 7) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        for (int mask = 0; mask < masks; mask++) {\n            if (mask == curMask) continue;\n\n            memcpy(buf1, pref[k], sizeof(double) * N);\n            double* dp = buf1;\n            double* ndp = buf2;\n            double sc = prefScore[k];\n\n            int mm = mask;\n            for (int r = 0; r < win; r++) {\n                int a = mm & 3;\n                mm >>= 2;\n\n                fill(ndp, ndp + N, 0.0);\n                double hit = 0.0;\n                double reward = 400 - (k + r);\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        ndp[v] += m * pForget;\n                    } else if (u == v) {\n                        ndp[v] += m;\n                    } else {\n                        ndp[v] += m * pForget;\n                        ndp[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp, ndp);\n            }\n\n            double total = sc;\n            const double* sw = suff[k + win];\n            for (int v = 0; v < N; v++) {\n                total += dp[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = mask;\n            }\n        }\n    }\n\n    if (bestK != -1) {\n        int mm = bestMask;\n        for (int r = 0; r < win; r++) {\n            seq[bestK + r] = mm & 3;\n            mm >>= 2;\n        }\n        newScore = best;\n        return true;\n    }\n\n    return false;\n}\n\ndouble improve(vector<int>& seq, double deadline) {\n    int L = (int)seq.size();\n    double curScore = evaluate(seq);\n\n    while (elapsedSec() < deadline) {\n        computePrefixSuffix(seq);\n        curScore = prefScore[L];\n\n        double bestScore = curScore;\n        int bestK = -1;\n        int bestC = -1;\n\n        for (int k = 0; k < L; k++) {\n            const double* row = pref[k];\n            const double* sw = suff[k + 1];\n            double base = prefScore[k];\n            double reward = 400 - k;\n\n            for (int c = 0; c < 4; c++) {\n                if (c == seq[k]) continue;\n\n                double total = base;\n\n                for (int v = 0; v < N; v++) {\n                    double m = row[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[c][v];\n                    double val;\n                    if (u == TID) {\n                        val = qRemember * reward + pForget * sw[v];\n                    } else if (u == v) {\n                        val = sw[v];\n                    } else {\n                        val = pForget * sw[v] + qRemember * sw[u];\n                    }\n                    total += m * val;\n                }\n\n                if (total > bestScore + EPS) {\n                    bestScore = total;\n                    bestK = k;\n                    bestC = c;\n                }\n            }\n        }\n\n        if (bestK != -1) {\n            seq[bestK] = bestC;\n            curScore = bestScore;\n            continue;\n        }\n\n        bool changed = false;\n        for (int w = 2; w <= 4; w++) {\n            if (elapsedSec() > deadline - 0.03) break;\n            double ns;\n            if (tryWindow(seq, w, curScore, deadline, ns)) {\n                curScore = ns;\n                changed = true;\n                break;\n            }\n        }\n\n        if (!changed) break;\n    }\n\n    return curScore;\n}\n\nstruct BeamNode {\n    float prob[N];\n    double score;\n    double est;\n    unsigned char seq[MAXL];\n    BeamNode() {}\n};\n\nvector<vector<int>> beamSearch(int topCount) {\n    int initialWidth = 450;\n    int width = initialWidth;\n\n    vector<BeamNode> cur, nxt, selected;\n    vector<int> idx;\n\n    cur.reserve(initialWidth);\n    nxt.reserve(initialWidth * 4);\n    selected.reserve(initialWidth);\n    idx.reserve(initialWidth * 4);\n\n    BeamNode root;\n    fill(root.prob, root.prob + N, 0.0f);\n    root.prob[SID] = 1.0f;\n    root.score = 0.0;\n    root.est = pot[0][distT[SID]];\n    cur.push_back(root);\n\n    for (int l = 0; l < MAXL; l++) {\n        if ((l % 5) == 0) {\n            double e = elapsedSec();\n            if (e > 1.15) width = min(width, 100);\n            else if (e > 0.90) width = min(width, 200);\n            else if (e > 0.70) width = min(width, 320);\n        }\n\n        nxt.clear();\n\n        for (const BeamNode& par : cur) {\n            for (int a = 0; a < 4; a++) {\n                BeamNode& ch = nxt.emplace_back();\n\n                fill(ch.prob, ch.prob + N, 0.0f);\n                if (l > 0) memcpy(ch.seq, par.seq, l * sizeof(unsigned char));\n                ch.seq[l] = (unsigned char)a;\n\n                double hit = 0.0;\n                double future = 0.0;\n                const double* potRow = pot[l + 1];\n\n                for (int v = 0; v < N; v++) {\n                    float mf = par.prob[v];\n                    if (mf == 0.0f) continue;\n                    double m = mf;\n\n                    int u = goTo[a][v];\n                    if (u == TID) {\n                        double stay = m * pForget;\n                        hit += m * qRemember;\n                        ch.prob[v] += (float)stay;\n                        future += stay * potRow[distT[v]];\n                    } else if (u == v) {\n                        ch.prob[v] += mf;\n                        future += m * potRow[distT[v]];\n                    } else {\n                        double stay = m * pForget;\n                        double mv = m * qRemember;\n                        ch.prob[v] += (float)stay;\n                        ch.prob[u] += (float)mv;\n                        future += stay * potRow[distT[v]];\n                        future += mv * potRow[distT[u]];\n                    }\n                }\n\n                ch.score = par.score + (400 - l) * hit;\n                ch.est = ch.score + future;\n            }\n        }\n\n        int n = (int)nxt.size();\n        if (n > width) {\n            idx.resize(n);\n            iota(idx.begin(), idx.end(), 0);\n\n            auto cmp = [&](int x, int y) {\n                if (nxt[x].est != nxt[y].est) return nxt[x].est > nxt[y].est;\n                return nxt[x].score > nxt[y].score;\n            };\n\n            nth_element(idx.begin(), idx.begin() + width, idx.end(), cmp);\n\n            selected.clear();\n            for (int i = 0; i < width; i++) {\n                selected.push_back(nxt[idx[i]]);\n            }\n            cur.swap(selected);\n        } else {\n            cur.swap(nxt);\n        }\n    }\n\n    vector<vector<int>> res;\n    int n = (int)cur.size();\n    idx.resize(n);\n    iota(idx.begin(), idx.end(), 0);\n\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        return cur[x].score > cur[y].score;\n    });\n\n    int take = min(topCount, n);\n    for (int r = 0; r < take; r++) {\n        vector<int> s(MAXL);\n        const BeamNode& node = cur[idx[r]];\n        for (int k = 0; k < MAXL; k++) s[k] = node.seq[k];\n        res.push_back(move(s));\n    }\n\n    return res;\n}\n\nvector<int> shortestPath() {\n    vector<int> par(N, -1), parA(N, -1);\n    queue<int> que;\n    par[SID] = SID;\n    que.push(SID);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n        if (x == TID) break;\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n            if (par[y] == -1) {\n                par[y] = x;\n                parA[y] = a;\n                que.push(y);\n            }\n        }\n    }\n\n    vector<int> path;\n    if (par[TID] == -1) {\n        path = {1, 3};\n        return path;\n    }\n\n    int x = TID;\n    while (x != SID) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nint repCost(int d, double z) {\n    if (d <= 0) return 0;\n    double val = d / qRemember + z * sqrt(max(0.0, d * pForget)) / qRemember;\n    int r = (int)ceil(val - 1e-9);\n    r = max(r, d);\n    r = max(r, 1);\n    return r;\n}\n\npair<int, int> slideResult(int cell, int a) {\n    int c = cell;\n    int d = 0;\n    while (true) {\n        int u = goTo[a][c];\n        if (u == c) break;\n        c = u;\n        d++;\n        if (c == TID) break;\n    }\n    return {c, d};\n}\n\nvector<int> slideCandidate(double z) {\n    const double INF = 1e100;\n\n    vector<double> dc(N, INF);\n    vector<int> pre(N, -1), preA(N, -1), preD(N, 0);\n\n    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n    dc[SID] = 0.0;\n    pq.push({0.0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n        if (cd != dc[x]) continue;\n        if (x == TID) break;\n\n        for (int a = 0; a < 4; a++) {\n            auto [to, d] = slideResult(x, a);\n            if (d == 0) continue;\n\n            double nd = cd + repCost(d, z);\n            if (nd < dc[to]) {\n                dc[to] = nd;\n                pre[to] = x;\n                preA[to] = a;\n                preD[to] = d;\n                pq.push({nd, to});\n            }\n        }\n    }\n\n    if (pre[TID] == -1) return {};\n\n    vector<pair<int, int>> segs;\n    int x = TID;\n    while (x != SID) {\n        segs.push_back({preA[x], preD[x]});\n        x = pre[x];\n    }\n    reverse(segs.begin(), segs.end());\n\n    vector<int> seq;\n    for (auto [a, d] : segs) {\n        int r = repCost(d, z);\n        for (int i = 0; i < r && (int)seq.size() < MAXL; i++) {\n            seq.push_back(a);\n        }\n    }\n\n    return seq;\n}\n\nstruct Candidate {\n    vector<int> seq;\n    double score;\n};\n\nvoid normalizeSeq(vector<int>& s) {\n    if (s.empty()) s.push_back(1); // D\n    if ((int)s.size() > MAXL) s.resize(MAXL);\n    while ((int)s.size() < MAXL) s.push_back(s.back());\n}\n\nvoid addCandidate(vector<Candidate>& cands, vector<int> s) {\n    normalizeSeq(s);\n\n    for (const auto& c : cands) {\n        if (c.seq == s) return;\n    }\n\n    double sc = evaluate(s);\n    cands.push_back({move(s), sc});\n}\n\nvoid addPathCandidates(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    {\n        vector<int> s = path;\n        addCandidate(cands, s);\n    }\n\n    {\n        vector<int> s;\n        for (int i = 0; i < MAXL; i++) s.push_back(path[i % path.size()]);\n        addCandidate(cands, s);\n    }\n\n    for (int rep : {2, 3, 4}) {\n        vector<int> s;\n        for (int a : path) {\n            for (int r = 0; r < rep && (int)s.size() < MAXL; r++) {\n                s.push_back(a);\n            }\n            if ((int)s.size() >= MAXL) break;\n        }\n        int ptr = 0;\n        while ((int)s.size() < MAXL) {\n            s.push_back(path[ptr % path.size()]);\n            ptr++;\n        }\n        addCandidate(cands, s);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si_ >> sj_ >> ti_ >> tj_ >> pForget;\n    qRemember = 1.0 - pForget;\n\n    for (int i = 0; i < H; i++) cin >> hwall[i];\n    for (int i = 0; i < H - 1; i++) cin >> vwall[i];\n\n    SID = id(si_, sj_);\n    TID = id(ti_, tj_);\n\n    startTime = chrono::steady_clock::now();\n\n    buildGo();\n    bfsDist();\n    buildPotential();\n\n    vector<Candidate> cands;\n\n    vector<int> sp = shortestPath();\n    addPathCandidates(cands, sp);\n\n    for (double z : {0.0, 0.5, 1.0, 1.5, 2.0}) {\n        vector<int> s = slideCandidate(z);\n        if (!s.empty()) addCandidate(cands, s);\n    }\n\n    vector<vector<int>> beams = beamSearch(6);\n    for (auto& s : beams) addCandidate(cands, s);\n\n    if (cands.empty()) {\n        vector<int> fallback(MAXL, 1);\n        addCandidate(cands, fallback);\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        return a.score > b.score;\n    });\n\n    vector<int> bestSeq = cands[0].seq;\n    double bestScore = cands[0].score;\n\n    int starts = min<int>(5, cands.size());\n    for (int i = 0; i < starts; i++) {\n        if (elapsedSec() > HARD_LIMIT - 0.05) break;\n\n        vector<int> seq = cands[i].seq;\n        double sc = improve(seq, HARD_LIMIT);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    mt19937 rng(1234567);\n    int attempts = 0;\n    while (elapsedSec() < HARD_LIMIT - 0.15 && attempts < 2) {\n        vector<int> seq = bestSeq;\n        int changes = 3 + attempts * 3;\n        for (int i = 0; i < changes; i++) {\n            int pos = rng() % MAXL;\n            int a = rng() % 4;\n            seq[pos] = a;\n        }\n\n        double sc = improve(seq, HARD_LIMIT);\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n        attempts++;\n    }\n\n    normalizeSeq(bestSeq);\n\n    string out;\n    out.reserve(MAXL);\n    for (int a : bestSeq) out.push_back(DIRS[a]);\n    cout << out << '\\n';\n\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int CELLS = N * N;\nconstexpr int PORTS = CELLS * 4;\nconstexpr int MAXLEN = 1800;\nconstexpr int MAXCOMP = 4005;\n\nusing StateArr = array<unsigned char, CELLS>;\n\nint pairDir[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\nint maskState[8];\nint segCnt[8];\nint segA[8][2], segB[8][2];\n\nint adjPort[PORTS];\nint neighCell[CELLS][4];\n\nint baseTile[CELLS];\nint optCnt[CELLS];\nint optState[CELLS][4];\n\nint di[4] = {0, -1, 0, 1};\nint dj[4] = {-1, 0, 1, 0};\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = seed ? seed : 88172645463325252ULL;\n        for (int i = 0; i < 20; i++) next();\n    }\n    inline uint64_t next() {\n        x ^= x << 13;\n        x ^= x >> 7;\n        x ^= x << 17;\n        return x;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct BIT {\n    int bit[MAXLEN + 2];\n    int total;\n\n    void reset() {\n        memset(bit, 0, sizeof(bit));\n        total = 0;\n    }\n\n    void add(int idx, int delta) {\n        if (idx <= 0) return;\n        total += delta;\n        for (int i = idx; i <= MAXLEN; i += i & -i) bit[i] += delta;\n    }\n\n    int kth(int k) const {\n        int idx = 0;\n        for (int pw = 2048; pw; pw >>= 1) {\n            int ni = idx + pw;\n            if (ni <= MAXLEN && bit[ni] < k) {\n                idx = ni;\n                k -= bit[ni];\n            }\n        }\n        return idx + 1;\n    }\n};\n\nstruct Stats {\n    int l1 = 0, l2 = 0;\n    int c1 = 0, c2 = 0;\n    int loops = 0;\n    int broken = 0;\n    long long score = 0;\n    long long loopSq = 0;\n};\n\nstruct Manager {\n    unsigned char st[CELLS];\n\n    int comp[PORTS];\n    vector<int> ports[MAXCOMP];\n    bool alive[MAXCOMP];\n    int compLen[MAXCOMP];\n    int compBroken[MAXCOMP];\n\n    int nextId = 0;\n    vector<int> freeIds;\n\n    BIT compBIT, loopBIT;\n    long long loopSq = 0;\n    int brokenTotal = 0;\n\n    int stackBuf[PORTS];\n\n    Manager() {\n        freeIds.reserve(MAXCOMP);\n        memset(alive, 0, sizeof(alive));\n    }\n\n    inline bool active(int p) const {\n        return pairDir[st[p >> 2]][p & 3] >= 0;\n    }\n\n    inline int internalPort(int p) const {\n        return (p & ~3) | pairDir[st[p >> 2]][p & 3];\n    }\n\n    int allocId() {\n        int id;\n        if (!freeIds.empty()) {\n            id = freeIds.back();\n            freeIds.pop_back();\n        } else {\n            id = nextId++;\n        }\n        alive[id] = true;\n        ports[id].clear();\n        return id;\n    }\n\n    void addStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, 1);\n        brokenTotal += br;\n        if (br == 0) {\n            loopBIT.add(len, 1);\n            loopSq += 1LL * len * len;\n        }\n    }\n\n    void removeStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, -1);\n        brokenTotal -= br;\n        if (br == 0) {\n            loopBIT.add(len, -1);\n            loopSq -= 1LL * len * len;\n        }\n    }\n\n    void removeComp(int id) {\n        if (id < 0 || !alive[id]) return;\n\n        removeStats(id);\n\n        for (int p : ports[id]) comp[p] = -1;\n        ports[id].clear();\n        alive[id] = false;\n        freeIds.push_back(id);\n    }\n\n    void addComponent(int start) {\n        int id = allocId();\n\n        int top = 0;\n        stackBuf[top++] = start;\n        comp[start] = id;\n        ports[id].push_back(start);\n\n        int broken = 0;\n\n        while (top) {\n            int p = stackBuf[--top];\n\n            int q = internalPort(p);\n            if (comp[q] == -1) {\n                comp[q] = id;\n                ports[id].push_back(q);\n                stackBuf[top++] = q;\n            }\n\n            int e = adjPort[p];\n            if (e != -1 && active(e)) {\n                if (comp[e] == -1) {\n                    comp[e] = id;\n                    ports[id].push_back(e);\n                    stackBuf[top++] = e;\n                }\n            } else {\n                broken++;\n            }\n        }\n\n        compLen[id] = (int)ports[id].size() / 2;\n        compBroken[id] = broken;\n        addStats(id);\n    }\n\n    void build(const StateArr &arr) {\n        for (int i = 0; i < nextId; i++) {\n            ports[i].clear();\n            alive[i] = false;\n        }\n        nextId = 0;\n        freeIds.clear();\n\n        compBIT.reset();\n        loopBIT.reset();\n        loopSq = 0;\n        brokenTotal = 0;\n\n        for (int i = 0; i < CELLS; i++) st[i] = arr[i];\n        fill(comp, comp + PORTS, -1);\n\n        for (int p = 0; p < PORTS; p++) {\n            if (active(p) && comp[p] == -1) addComponent(p);\n        }\n    }\n\n    void updateCell(int cell, int newState) {\n        if (st[cell] == newState) return;\n\n        int ids[20];\n        int cnt = 0;\n\n        auto addId = [&](int id) {\n            if (id < 0 || !alive[id]) return;\n            for (int k = 0; k < cnt; k++) {\n                if (ids[k] == id) return;\n            }\n            ids[cnt++] = id;\n        };\n\n        int base = cell * 4;\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            addId(comp[p]);\n            int e = adjPort[p];\n            if (e != -1) addId(comp[e]);\n        }\n\n        for (int k = 0; k < cnt; k++) removeComp(ids[k]);\n\n        st[cell] = (unsigned char)newState;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            if (active(p) && comp[p] == -1) addComponent(p);\n\n            int e = adjPort[p];\n            if (e != -1 && active(e) && comp[e] == -1) addComponent(e);\n        }\n    }\n\n    Stats getStats() const {\n        Stats s;\n        s.loops = loopBIT.total;\n        if (loopBIT.total >= 1) s.l1 = loopBIT.kth(loopBIT.total);\n        if (loopBIT.total >= 2) s.l2 = loopBIT.kth(loopBIT.total - 1);\n\n        if (compBIT.total >= 1) s.c1 = compBIT.kth(compBIT.total);\n        if (compBIT.total >= 2) s.c2 = compBIT.kth(compBIT.total - 1);\n\n        s.score = 1LL * s.l1 * s.l2;\n        s.loopSq = loopSq;\n        s.broken = brokenTotal;\n        return s;\n    }\n\n    void exportState(StateArr &out) const {\n        for (int i = 0; i < CELLS; i++) out[i] = st[i];\n    }\n};\n\nvoid initGlobals() {\n    for (int t = 0; t < 8; t++) {\n        maskState[t] = 0;\n        segCnt[t] = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (pairDir[t][d] != -1) maskState[t] |= 1 << d;\n        }\n\n        for (int d = 0; d < 4; d++) {\n            int e = pairDir[t][d];\n            if (e != -1 && d < e) {\n                int k = segCnt[t]++;\n                segA[t][k] = d;\n                segB[t][k] = e;\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                    neighCell[id][d] = -1;\n                    adjPort[id * 4 + d] = -1;\n                } else {\n                    int nb = ni * N + nj;\n                    neighCell[id][d] = nb;\n                    adjPort[id * 4 + d] = nb * 4 + (d ^ 2);\n                }\n            }\n        }\n    }\n}\n\nint localQuality(const unsigned char *arr, int id, int candState) {\n    bool nbAct[4];\n\n    for (int d = 0; d < 4; d++) {\n        int nb = neighCell[id][d];\n        nbAct[d] = false;\n        if (nb != -1) {\n            int ns = arr[nb];\n            nbAct[d] = (maskState[ns] >> (d ^ 2)) & 1;\n        }\n    }\n\n    int cm = maskState[candState];\n    int q = 0;\n\n    for (int d = 0; d < 4; d++) {\n        bool ca = (cm >> d) & 1;\n        bool na = nbAct[d];\n        if (ca && na) q += 6;\n        else if (ca || na) q -= 4;\n    }\n\n    for (int k = 0; k < segCnt[candState]; k++) {\n        int a = segA[candState][k];\n        int b = segB[candState][k];\n        int c = (nbAct[a] ? 1 : 0) + (nbAct[b] ? 1 : 0);\n\n        if (c == 2) q += 20;\n        else if (c == 1) q -= 3;\n        else q -= 8;\n    }\n\n    return q;\n}\n\nvoid greedyImprove(StateArr &cand, RNG &rng, int sweeps) {\n    int steps = sweeps * CELLS;\n    for (int it = 0; it < steps; it++) {\n        int id = rng.nextInt(CELLS);\n\n        int bestSt = cand[id];\n        int bestQ = -1e9;\n        int ties = 0;\n\n        for (int k = 0; k < optCnt[id]; k++) {\n            int s = optState[id][k];\n            int q = localQuality(cand.data(), id, s);\n\n            if (q > bestQ) {\n                bestQ = q;\n                bestSt = s;\n                ties = 1;\n            } else if (q == bestQ) {\n                ties++;\n                if (rng.nextInt(ties) == 0) bestSt = s;\n            }\n        }\n\n        cand[id] = (unsigned char)bestSt;\n    }\n}\n\nlong long startValue(const Stats &s) {\n    long long compProd = 1LL * s.c1 * s.c2;\n    return s.score * 1500LL + s.loopSq * 25LL + compProd * 6LL - 120LL * s.broken;\n}\n\nlong long energyValue(const Stats &s, double progress) {\n    long long compProd = 1LL * s.c1 * s.c2;\n\n    if (progress < 0.60) {\n        return s.score * 400LL\n             + s.loopSq * 30LL\n             + compProd * 8LL\n             + 1LL * s.l1 * s.l1 * 10LL\n             + 1LL * s.l2 * s.l2 * 10LL\n             - 120LL * s.broken;\n    } else {\n        return s.score * 2000LL\n             + s.loopSq * 4LL\n             + 1LL * s.l1 * s.l1 * 2LL\n             + 1LL * s.l2 * s.l2 * 2LL\n             + compProd / 3LL\n             - 5LL * s.broken;\n    }\n}\n\nlong long finalValue(const Stats &s) {\n    return s.score * 1000000LL\n         + 1LL * s.l1 * 2000LL\n         + 1LL * s.l2 * 1000LL\n         + s.loopSq\n         - 10LL * s.broken;\n}\n\nbool betterStats(const Stats &s, long long bestScore, int bestL1, int bestL2) {\n    if (s.score != bestScore) return s.score > bestScore;\n    return s.l1 + s.l2 > bestL1 + bestL2;\n}\n\nvoid updateBestWithState(\n    const StateArr &arr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        bestState = arr;\n    }\n}\n\nvoid updateBestWithManager(\n    const Manager &mgr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        mgr.exportState(bestState);\n    }\n}\n\nvoid runSA(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    double startTime = timer.elapsed();\n    if (endTime - startTime < 0.01) return;\n\n    Stats initS = mgr.getStats();\n    updateBestWithManager(mgr, initS, bestState, bestScore, bestL1, bestL2);\n\n    int iter = 0;\n    double now = startTime;\n    double progress = 0.0;\n    double temp = 5e6;\n\n    while (true) {\n        if ((iter & 255) == 0) {\n            now = timer.elapsed();\n            if (now >= endTime) break;\n\n            progress = (now - startTime) / (endTime - startTime);\n            progress = min(1.0, max(0.0, progress));\n            temp = 5e6 * pow(2e3 / 5e6, progress);\n        }\n\n        int id = rng.nextInt(CELLS);\n        int cur = mgr.st[id];\n        int ns = cur;\n        int cnt = optCnt[id];\n\n        if ((rng.next() & 3ULL) == 0) {\n            int bestQ = -1e9;\n            int ties = 0;\n            for (int k = 0; k < cnt; k++) {\n                int s = optState[id][k];\n                if (s == cur) continue;\n                int q = localQuality(mgr.st, id, s);\n                if (q > bestQ) {\n                    bestQ = q;\n                    ns = s;\n                    ties = 1;\n                } else if (q == bestQ) {\n                    ties++;\n                    if (rng.nextInt(ties) == 0) ns = s;\n                }\n            }\n        } else {\n            do {\n                ns = optState[id][rng.nextInt(cnt)];\n            } while (ns == cur);\n        }\n\n        if (ns == cur) {\n            iter++;\n            continue;\n        }\n\n        Stats oldS = mgr.getStats();\n        long long oldE = energyValue(oldS, progress);\n\n        mgr.updateCell(id, ns);\n\n        Stats newS = mgr.getStats();\n        long long newE = energyValue(newS, progress);\n\n        long long diff = newE - oldE;\n        bool accept = false;\n\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            double x = (double)diff / temp;\n            if (x > -30.0 && rng.nextDouble() < exp(x)) accept = true;\n        }\n\n        if (accept) {\n            updateBestWithManager(mgr, newS, bestState, bestScore, bestL1, bestL2);\n        } else {\n            mgr.updateCell(id, cur);\n        }\n\n        iter++;\n    }\n}\n\nvoid runHillClimb(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    mgr.build(bestState);\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 31) == 0) {\n            if (timer.elapsed() >= endTime) break;\n        }\n\n        int id = rng.nextInt(CELLS);\n        int cur = mgr.st[id];\n\n        Stats baseS = mgr.getStats();\n        long long bestVal = finalValue(baseS);\n        int bestSt = cur;\n\n        for (int k = 0; k < optCnt[id]; k++) {\n            int s = optState[id][k];\n            if (s == cur) continue;\n\n            mgr.updateCell(id, s);\n            Stats ns = mgr.getStats();\n            long long v = finalValue(ns);\n\n            if (v > bestVal) {\n                bestVal = v;\n                bestSt = s;\n            }\n\n            mgr.updateCell(id, cur);\n        }\n\n        if (bestSt != cur) {\n            mgr.updateCell(id, bestSt);\n            Stats s = mgr.getStats();\n            updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n        }\n\n        iter++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initGlobals();\n\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        string row;\n        cin >> row;\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            int t = row[j] - '0';\n            baseTile[id] = t;\n            seed = seed * 1000003ULL + (uint64_t)(t + 17);\n        }\n    }\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n\n        if (b < 4) {\n            optCnt[id] = 4;\n            for (int k = 0; k < 4; k++) optState[id][k] = k;\n        } else if (b < 6) {\n            optCnt[id] = 2;\n            optState[id][0] = 4;\n            optState[id][1] = 5;\n        } else {\n            optCnt[id] = 2;\n            optState[id][0] = 6;\n            optState[id][1] = 7;\n        }\n    }\n\n    Timer timer;\n    RNG rng(seed);\n\n    Manager mgr;\n\n    StateArr bestState{};\n    long long bestScore = -1;\n    int bestL1 = 0, bestL2 = 0;\n\n    vector<pair<long long, StateArr>> topStarts;\n\n    auto insertTop = [&](long long val, const StateArr &s) {\n        topStarts.push_back({val, s});\n        sort(topStarts.begin(), topStarts.end(),\n             [](const auto &a, const auto &b) { return a.first > b.first; });\n        if ((int)topStarts.size() > 6) topStarts.pop_back();\n    };\n\n    constexpr int CAND_LIMIT = 80;\n\n    for (int c = 0; c < CAND_LIMIT; c++) {\n        if (c > 10 && timer.elapsed() > 0.22) break;\n\n        StateArr cand;\n\n        if (c == 0 || c == 1) {\n            for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n        } else {\n            for (int id = 0; id < CELLS; id++) {\n                cand[id] = optState[id][rng.nextInt(optCnt[id])];\n            }\n        }\n\n        if (c != 0) {\n            int sweeps = 7 + (c % 3);\n            greedyImprove(cand, rng, sweeps);\n        }\n\n        mgr.build(cand);\n        Stats s = mgr.getStats();\n\n        updateBestWithState(cand, s, bestState, bestScore, bestL1, bestL2);\n        insertTop(startValue(s), cand);\n    }\n\n    vector<StateArr> starts;\n\n    auto addUniqueStart = [&](const StateArr &s) {\n        for (const auto &t : starts) {\n            if (t == s) return;\n        }\n        starts.push_back(s);\n    };\n\n    addUniqueStart(bestState);\n    for (auto &p : topStarts) addUniqueStart(p.second);\n\n    if (starts.empty()) {\n        StateArr init;\n        for (int id = 0; id < CELLS; id++) init[id] = baseTile[id];\n        starts.push_back(init);\n        bestState = init;\n    }\n\n    double SA_END = 1.60;\n    double HILL_END = 1.84;\n\n    int runs = min(4, (int)starts.size());\n\n    for (int r = 0; r < runs; r++) {\n        double now = timer.elapsed();\n        if (now >= SA_END) break;\n\n        double endTime = now + (SA_END - now) / (runs - r);\n\n        mgr.build(starts[r]);\n        runSA(mgr, timer, endTime, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    if (timer.elapsed() < HILL_END) {\n        runHillClimb(mgr, timer, HILL_END, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    string ans;\n    ans.reserve(CELLS);\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n        int f = bestState[id];\n        int r;\n\n        if (b < 4) {\n            r = (f - b + 4) % 4;\n        } else {\n            r = (f == b ? 0 : 1);\n        }\n\n        ans.push_back(char('0' + r));\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#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\nint N, T, NN, M;\nvector<int> initBoard;\nint initBlank;\nint nbCell[105][4];\n\nconst int DR[4] = {-1, 1, 0, 0};\nconst int DC[4] = {0, 0, -1, 1};\nconst char DCH[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\nint targetCntArr[16];\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\nint hexVal(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return c - 'a' + 10;\n}\n\nstruct FastDSU {\n    int p[105], sz[105];\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    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 Eval {\n    int S;\n    int edges;\n};\n\nEval evalBoard(const vector<int>& bd) {\n    FastDSU dsu;\n    dsu.init(NN);\n    vector<pair<int,int>> edges;\n    edges.reserve(2 * NN);\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            if (bd[id] == 0) continue;\n            if (c + 1 < N) {\n                int j = id + 1;\n                if (bd[j] != 0 && (bd[id] & 4) && (bd[j] & 1)) {\n                    dsu.unite(id, j);\n                    edges.push_back({id, j});\n                }\n            }\n            if (r + 1 < N) {\n                int j = id + N;\n                if (bd[j] != 0 && (bd[id] & 8) && (bd[j] & 2)) {\n                    dsu.unite(id, j);\n                    edges.push_back({id, j});\n                }\n            }\n        }\n    }\n\n    int vcnt[105] = {};\n    int ecnt[105] = {};\n    for (int i = 0; i < NN; i++) {\n        if (bd[i] != 0) vcnt[dsu.find(i)]++;\n    }\n    for (auto [u, v] : edges) {\n        ecnt[dsu.find(u)]++;\n    }\n\n    int best = 0;\n    for (int i = 0; i < NN; i++) {\n        if (dsu.find(i) == i && vcnt[i] > 0 && ecnt[i] == vcnt[i] - 1) {\n            best = max(best, vcnt[i]);\n        }\n    }\n    return {best, (int)edges.size()};\n}\n\nlong long scoreFromEval(const Eval& e, int K) {\n    if (e.S == M) {\n        return llround(500000.0 * (2.0 - (double)K / T));\n    } else {\n        return llround(500000.0 * (double)e.S / M);\n    }\n}\n\nbool applyDir(vector<int>& bd, int& blank, int d) {\n    int nb = nbCell[blank][d];\n    if (nb < 0) return false;\n    swap(bd[blank], bd[nb]);\n    blank = nb;\n    return true;\n}\n\nvector<int> simulateMoves(const string& moves) {\n    vector<int> bd = initBoard;\n    int blank = initBlank;\n    for (char ch : moves) {\n        int d = dirIndex(ch);\n        if (!applyDir(bd, blank, d)) break;\n    }\n    return bd;\n}\n\nstring simplifyMoves(const string& s) {\n    string res;\n    for (char ch : s) {\n        int d = dirIndex(ch);\n        if (!res.empty() && dirIndex(res.back()) == OPP[d]) {\n            res.pop_back();\n        } else {\n            res.push_back(ch);\n        }\n    }\n    return res;\n}\n\nstruct BestAns {\n    string moves;\n    long long score = -1;\n    int S = 0;\n};\n\nvoid updateBest(BestAns& best, string mv) {\n    mv = simplifyMoves(mv);\n    if ((int)mv.size() > T) mv.resize(T);\n    vector<int> bd = simulateMoves(mv);\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nvoid updateBestKnownBoard(BestAns& best, const string& mv0, const vector<int>& bd) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nuint64_t hashBoard(const vector<int>& bd) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int x : bd) {\n        h ^= (uint64_t)(x + 1);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nbool countsMatch(const vector<int>& bd) {\n    int cnt[16] = {};\n    int z = 0;\n    for (int x : bd) {\n        if (x == 0) z++;\n        else cnt[x]++;\n    }\n    if (z != 1) return false;\n    for (int i = 0; i < 16; i++) {\n        if (cnt[i] != targetCntArr[i]) return false;\n    }\n    return true;\n}\n\nstruct Candidate {\n    vector<int> board;\n    int blank;\n    int estCost;\n    int expectedS;\n    uint64_t hash;\n};\n\nint candValue(const Candidate& c) {\n    return c.expectedS * 10000 - c.estCost;\n}\n\nvoid addCandidate(vector<Candidate>& cands, const vector<int>& bd, int estCost) {\n    if (!countsMatch(bd)) return;\n    int z = -1;\n    for (int i = 0; i < NN; i++) if (bd[i] == 0) z = i;\n    Eval e = evalBoard(bd);\n    uint64_t h = hashBoard(bd);\n    for (auto& c : cands) {\n        if (c.hash == h && c.board == bd) return;\n    }\n    Candidate nc{bd, z, estCost, e.S, h};\n    const int MAX_CAND = 30;\n    if ((int)cands.size() < MAX_CAND) {\n        cands.push_back(nc);\n    } else {\n        int worst = 0;\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (candValue(cands[i]) < candValue(cands[worst])) worst = i;\n        }\n        if (candValue(nc) > candValue(cands[worst])) cands[worst] = nc;\n    }\n}\n\nstruct Edge {\n    int a, b;\n    int ba, bb;\n};\n\nconst int DIFF_W = 1000;\nconst int POS_W = 3;\n\nstruct Change {\n    int vc = 0;\n    int verts[4];\n    int oldm[4];\n    int newm[4];\n    int dcnt[16];\n    int diffD = 0;\n    int posD = 0;\n    int energyD = 0;\n};\n\nstruct TreeState {\n    int blank;\n    vector<Edge> edges;\n    int E;\n    vector<char> inTree;\n    vector<vector<int>> adj;\n    vector<int> mask;\n    vector<int> comp;\n    int cnt[16];\n    int diff = 0;\n    int bitCost = 0;\n\n    vector<int> par, pare, qbuf, path;\n\n    TreeState(int b, const vector<int>& compMask) : blank(b), comp(compMask) {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                if (id == blank) continue;\n                if (c + 1 < N) {\n                    int j = id + 1;\n                    if (j != blank) edges.push_back({id, j, 4, 1});\n                }\n                if (r + 1 < N) {\n                    int j = id + N;\n                    if (j != blank) edges.push_back({id, j, 8, 2});\n                }\n            }\n        }\n        E = (int)edges.size();\n        inTree.assign(E, 0);\n        adj.assign(NN, {});\n        mask.assign(NN, 0);\n        par.resize(NN);\n        pare.resize(NN);\n        qbuf.reserve(NN);\n        path.reserve(NN);\n    }\n\n    int other(int eid, int v) const {\n        const Edge& e = edges[eid];\n        return e.a == v ? e.b : e.a;\n    }\n\n    void addInitialEdge(int eid) {\n        const Edge& e = edges[eid];\n        inTree[eid] = 1;\n        adj[e.a].push_back(eid);\n        adj[e.b].push_back(eid);\n        mask[e.a] |= e.ba;\n        mask[e.b] |= e.bb;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(inTree.begin(), inTree.end(), 0);\n        for (auto& v : adj) v.clear();\n        fill(mask.begin(), mask.end(), 0);\n        memset(cnt, 0, sizeof(cnt));\n        diff = 0;\n        bitCost = 0;\n\n        vector<pair<long long,int>> ord;\n        ord.reserve(E);\n        for (int i = 0; i < E; i++) {\n            const Edge& e = edges[i];\n            int w = 0;\n            if (mode > 0) {\n                bool ma = comp[e.a] & e.ba;\n                bool mb = comp[e.b] & e.bb;\n                w += ma ? 2 : -1;\n                w += mb ? 2 : -1;\n                if (ma && mb) w += 2;\n                if (mode == 2) w += (int)(rng() % 3) - 1;\n            }\n            long long noise = (long long)(rng() % 1000000000U);\n            long long key = noise - (long long)w * (mode == 1 ? 1000000000LL : 300000000LL);\n            if (mode == 0) key = noise;\n            ord.push_back({key, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        FastDSU dsu;\n        dsu.init(NN);\n        int selected = 0;\n        for (auto [key, id] : ord) {\n            (void)key;\n            const Edge& e = edges[id];\n            if (dsu.find(e.a) != dsu.find(e.b)) {\n                dsu.unite(e.a, e.b);\n                addInitialEdge(id);\n                selected++;\n                if (selected == M - 1) break;\n            }\n        }\n\n        for (int v = 0; v < NN; v++) {\n            if (v == blank) continue;\n            cnt[mask[v]]++;\n            bitCost += __builtin_popcount((unsigned)(mask[v] ^ comp[v]));\n        }\n        for (int t = 0; t < 16; t++) {\n            diff += abs(cnt[t] - targetCntArr[t]);\n        }\n    }\n\n    void getPath(int s, int t) {\n        fill(par.begin(), par.end(), -1);\n        qbuf.clear();\n        path.clear();\n        int head = 0;\n        par[s] = s;\n        qbuf.push_back(s);\n        while (head < (int)qbuf.size()) {\n            int v = qbuf[head++];\n            if (v == t) break;\n            for (int eid : adj[v]) {\n                if (!inTree[eid]) continue;\n                int u = other(eid, v);\n                if (par[u] == -1) {\n                    par[u] = v;\n                    pare[u] = eid;\n                    qbuf.push_back(u);\n                }\n            }\n        }\n        if (par[t] == -1) return;\n        int cur = t;\n        while (cur != s) {\n            path.push_back(pare[cur]);\n            cur = par[cur];\n        }\n    }\n\n    Change makeChange(int addId, int remId) const {\n        Change ch;\n        memset(ch.dcnt, 0, sizeof(ch.dcnt));\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < ch.vc; i++) {\n                if (ch.verts[i] == v) return i;\n            }\n            int i = ch.vc++;\n            ch.verts[i] = v;\n            ch.oldm[i] = mask[v];\n            ch.newm[i] = mask[v];\n            return i;\n        };\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        int ia = getIdx(ea.a);\n        ch.newm[ia] |= ea.ba;\n        int ib = getIdx(ea.b);\n        ch.newm[ib] |= ea.bb;\n\n        int ra = getIdx(er.a);\n        ch.newm[ra] &= ~er.ba;\n        int rb = getIdx(er.b);\n        ch.newm[rb] &= ~er.bb;\n\n        for (int i = 0; i < ch.vc; i++) {\n            if (ch.oldm[i] == ch.newm[i]) continue;\n            ch.dcnt[ch.oldm[i]]--;\n            ch.dcnt[ch.newm[i]]++;\n            int v = ch.verts[i];\n            ch.posD += __builtin_popcount((unsigned)(ch.newm[i] ^ comp[v]))\n                     - __builtin_popcount((unsigned)(ch.oldm[i] ^ comp[v]));\n        }\n        for (int t = 0; t < 16; t++) {\n            if (ch.dcnt[t]) {\n                ch.diffD += abs(cnt[t] + ch.dcnt[t] - targetCntArr[t])\n                          - abs(cnt[t] - targetCntArr[t]);\n            }\n        }\n        ch.energyD = ch.diffD * DIFF_W + ch.posD * POS_W;\n        return ch;\n    }\n\n    void removeAdj(int v, int eid) {\n        auto& a = adj[v];\n        for (int i = 0; i < (int)a.size(); i++) {\n            if (a[i] == eid) {\n                a[i] = a.back();\n                a.pop_back();\n                return;\n            }\n        }\n    }\n\n    void applySwap(int addId, int remId, const Change& ch) {\n        for (int t = 0; t < 16; t++) cnt[t] += ch.dcnt[t];\n        diff += ch.diffD;\n        bitCost += ch.posD;\n        for (int i = 0; i < ch.vc; i++) {\n            mask[ch.verts[i]] = ch.newm[i];\n        }\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        inTree[addId] = 1;\n        inTree[remId] = 0;\n        adj[ea.a].push_back(addId);\n        adj[ea.b].push_back(addId);\n        removeAdj(er.a, remId);\n        removeAdj(er.b, remId);\n    }\n\n    bool step(mt19937& rng, double temp) {\n        int addId;\n        do {\n            addId = (int)(rng() % E);\n        } while (inTree[addId]);\n\n        const Edge& e = edges[addId];\n        getPath(e.a, e.b);\n        if (path.empty()) return false;\n\n        int remId = -1;\n        Change bestCh;\n        int bestDelta = INT_MAX;\n\n        bool chooseBest = (rng() % 100) < 85;\n        if (chooseBest) {\n            for (int pe : path) {\n                Change ch = makeChange(addId, pe);\n                if (ch.energyD < bestDelta) {\n                    bestDelta = ch.energyD;\n                    bestCh = ch;\n                    remId = pe;\n                }\n            }\n        } else {\n            remId = path[rng() % path.size()];\n            bestCh = makeChange(addId, remId);\n            bestDelta = bestCh.energyD;\n        }\n\n        bool accept = false;\n        if (bestDelta <= 0) {\n            accept = true;\n        } else if (bestDelta < temp * 40.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-bestDelta / temp);\n        }\n\n        if (accept) {\n            applySwap(addId, remId, bestCh);\n            return true;\n        }\n        return false;\n    }\n\n    vector<int> getBoard() const {\n        vector<int> bd(NN, 0);\n        for (int i = 0; i < NN; i++) {\n            if (i != blank) bd[i] = mask[i];\n        }\n        return bd;\n    }\n};\n\nvector<int> makeCompMask(int targetBlank) {\n    vector<int> comp = initBoard;\n    if (initBlank != targetBlank) {\n        comp[initBlank] = initBoard[targetBlank];\n        comp[targetBlank] = 0;\n    }\n    return comp;\n}\n\nvector<int> blankChoices;\n\nvoid considerApprox(const TreeState& st, vector<int>& bestBoard, int& bestDiff, int& bestBit) {\n    if (st.diff < bestDiff || (st.diff == bestDiff && st.bitCost < bestBit)) {\n        bestDiff = st.diff;\n        bestBit = st.bitCost;\n        bestBoard = st.getBoard();\n    }\n}\n\nvoid runTreeSearch(double endTime, Timer& timer, mt19937& rng,\n                   vector<Candidate>& cands,\n                   vector<int>& bestApproxBoard,\n                   int& bestApproxDiff,\n                   int& bestApproxBit,\n                   int& restartCounter) {\n    while (timer.elapsed() < endTime) {\n        int b;\n        if (restartCounter < 5 || restartCounter % 5 != 0 || blankChoices.size() == 1) {\n            b = (N - 1) * N + (N - 1);\n        } else {\n            int idx = 1 + ((restartCounter / 5) % (blankChoices.size() - 1));\n            b = blankChoices[idx];\n        }\n\n        vector<int> comp = makeCompMask(b);\n        TreeState st(b, comp);\n\n        int mode;\n        if (restartCounter % 4 == 0) mode = 0;\n        else if (restartCounter % 4 == 1) mode = 1;\n        else mode = 2;\n\n        st.initRandom(mode, rng);\n        considerApprox(st, bestApproxBoard, bestApproxDiff, bestApproxBit);\n        if (st.diff == 0) addCandidate(cands, st.getBoard(), st.bitCost);\n\n        int maxIter = 26000 + N * 1200;\n        int localBestExact = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n            double p = (double)it / maxIter;\n            double temp = 4500.0 * pow(8.0 / 4500.0, p);\n\n            st.step(rng, temp);\n\n            if (st.diff < bestApproxDiff || (st.diff == bestApproxDiff && st.bitCost < bestApproxBit)) {\n                considerApprox(st, bestApproxBoard, bestApproxDiff, bestApproxBit);\n            }\n            if (st.diff == 0 && (st.bitCost < localBestExact || (it & 2047) == 0)) {\n                addCandidate(cands, st.getBoard(), st.bitCost);\n                localBestExact = min(localBestExact, st.bitCost);\n            }\n        }\n        if (st.diff == 0) addCandidate(cands, st.getBoard(), st.bitCost);\n        restartCounter++;\n    }\n}\n\nvector<int> adjustCountsToTarget(vector<int> bd) {\n    int cnt[16] = {};\n    for (int x : bd) if (x != 0) cnt[x]++;\n\n    while (true) {\n        vector<int> deficits;\n        bool done = true;\n        for (int t = 1; t < 16; t++) {\n            if (cnt[t] < targetCntArr[t]) deficits.push_back(t);\n            if (cnt[t] != targetCntArr[t]) done = false;\n        }\n        if (done) break;\n\n        int bestCell = -1, bestTo = -1;\n        int bestVal = INT_MIN;\n\n        for (int i = 0; i < NN; i++) {\n            int old = bd[i];\n            if (old == 0) continue;\n            if (cnt[old] <= targetCntArr[old]) continue;\n\n            for (int to : deficits) {\n                bd[i] = to;\n                Eval e = evalBoard(bd);\n                int val = e.S * 1000 + e.edges;\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestCell = i;\n                    bestTo = to;\n                }\n            }\n            bd[i] = old;\n        }\n\n        if (bestCell < 0) break;\n        int old = bd[bestCell];\n        bd[bestCell] = bestTo;\n        cnt[old]--;\n        cnt[bestTo]++;\n    }\n    return bd;\n}\n\nstruct SolveResult {\n    string moves;\n    bool reached;\n};\n\nstruct SlidingSolver {\n    vector<int> board;\n    vector<int> target;\n    vector<char> fixed;\n    string ops;\n    int blank;\n    int variant;\n    mt19937& rng;\n    Timer& timer;\n    double timeLimit;\n    int cap;\n    vector<int> dirOrder;\n    bool shuffleSources;\n\n    SlidingSolver(const vector<int>& tgt, int var, mt19937& rg, Timer& tm, double lim, int cp)\n        : board(initBoard), target(tgt), fixed(NN, 0), blank(initBlank),\n          variant(var), rng(rg), timer(tm), timeLimit(lim), cap(cp) {\n        dirOrder = {0, 1, 2, 3};\n        if (variant > 0) shuffle(dirOrder.begin(), dirOrder.end(), rng);\n        shuffleSources = variant > 0;\n    }\n\n    bool doDir(int d) {\n        int nb = nbCell[blank][d];\n        if (nb < 0) return false;\n        swap(board[blank], board[nb]);\n        blank = nb;\n        ops.push_back(DCH[d]);\n        return true;\n    }\n\n    bool placeTile(int qcell) {\n        int desired = target[qcell];\n        if (desired == 0) return false;\n\n        vector<int> sources;\n        for (int i = 0; i < NN; i++) {\n            if (!fixed[i] && i != blank && board[i] == desired) {\n                sources.push_back(i);\n            }\n        }\n        if (sources.empty()) return false;\n        if (shuffleSources) shuffle(sources.begin(), sources.end(), rng);\n\n        int total = NN * NN;\n        vector<int> parent(total, -1);\n        vector<unsigned char> pdir(total, 0);\n        vector<int> que;\n        que.reserve(total);\n\n        int goal = -1;\n        for (int p : sources) {\n            int id = p * NN + blank;\n            if (parent[id] == -1) {\n                parent[id] = -2;\n                que.push_back(id);\n                if (p == qcell) goal = id;\n            }\n        }\n\n        int head = 0;\n        while (goal == -1 && head < (int)que.size()) {\n            int id = que[head++];\n            int tile = id / NN;\n            int emp = id % NN;\n\n            for (int d : dirOrder) {\n                int nb = nbCell[emp][d];\n                if (nb < 0 || fixed[nb]) continue;\n\n                int ntile = tile;\n                int nemp = nb;\n                if (nb == tile) {\n                    ntile = emp;\n                    nemp = nb;\n                }\n\n                int nid = ntile * NN + nemp;\n                if (parent[nid] != -1) continue;\n                parent[nid] = id;\n                pdir[nid] = (unsigned char)d;\n                if (ntile == qcell) {\n                    goal = nid;\n                    break;\n                }\n                que.push_back(nid);\n            }\n        }\n\n        if (goal == -1) return false;\n\n        vector<int> path;\n        for (int cur = goal; parent[cur] != -2; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n        reverse(path.begin(), path.end());\n\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            doDir(d);\n        }\n\n        if (board[qcell] != desired) return false;\n        fixed[qcell] = 1;\n        return true;\n    }\n\n    uint64_t encodeBlock(const vector<int>& bd) const {\n        uint64_t code = 0;\n        int k = 0;\n        for (int r = N - 3; r < N; r++) {\n            for (int c = N - 3; c < N; c++) {\n                int id = r * N + c;\n                code |= (uint64_t)bd[id] << (4 * k);\n                k++;\n            }\n        }\n        return code;\n    }\n\n    int blankInCode(uint64_t code) const {\n        for (int k = 0; k < 9; k++) {\n            if (((code >> (4 * k)) & 15ULL) == 0) return k;\n        }\n        return -1;\n    }\n\n    uint64_t swapNibblesWithBlank(uint64_t code, int bk, int nk) const {\n        int val = (int)((code >> (4 * nk)) & 15ULL);\n        uint64_t maskB = 15ULL << (4 * bk);\n        uint64_t maskN = 15ULL << (4 * nk);\n        code &= ~maskB;\n        code &= ~maskN;\n        code |= (uint64_t)val << (4 * bk);\n        return code;\n    }\n\n    bool solveFinalBlock(bool targetFull) {\n        uint64_t start = encodeBlock(board);\n        uint64_t targetCode = encodeBlock(target);\n\n        if (targetFull && start == targetCode) return true;\n\n        int bnb[9][4];\n        for (int k = 0; k < 9; k++) {\n            int rr = k / 3, cc = k % 3;\n            for (int d = 0; d < 4; d++) {\n                int nr = rr + DR[d], nc = cc + DC[d];\n                if (nr < 0 || nr >= 3 || nc < 0 || nc >= 3) bnb[k][d] = -1;\n                else bnb[k][d] = nr * 3 + nc;\n            }\n        }\n\n        unordered_map<uint64_t, int> mp;\n        mp.reserve(400000);\n        mp.max_load_factor(0.7);\n\n        vector<uint64_t> states;\n        vector<int> parent;\n        vector<unsigned char> pdir;\n        states.reserve(200000);\n        parent.reserve(200000);\n        pdir.reserve(200000);\n\n        mp[start] = 0;\n        states.push_back(start);\n        parent.push_back(-1);\n        pdir.push_back(0);\n\n        int goal = -1;\n        int head = 0;\n        while (head < (int)states.size()) {\n            if ((head & 4095) == 0 && timer.elapsed() > timeLimit) break;\n            uint64_t code = states[head];\n            int bk = blankInCode(code);\n            for (int d = 0; d < 4; d++) {\n                int nk = bnb[bk][d];\n                if (nk < 0) continue;\n                uint64_t nc = swapNibblesWithBlank(code, bk, nk);\n                if (mp.find(nc) != mp.end()) continue;\n                int ni = (int)states.size();\n                mp[nc] = ni;\n                states.push_back(nc);\n                parent.push_back(head);\n                pdir.push_back((unsigned char)d);\n\n                if (targetFull && nc == targetCode) {\n                    goal = ni;\n                    head = (int)states.size();\n                    break;\n                }\n            }\n            head++;\n        }\n\n        int chosen = -1;\n        bool reached = false;\n\n        if (targetFull && goal != -1) {\n            chosen = goal;\n            reached = true;\n        } else {\n            // Choose best reachable final 3x3 state as fallback.\n            chosen = 0;\n            if (timer.elapsed() < timeLimit - 0.02) {\n                int blockIds[9];\n                int k = 0;\n                for (int r = N - 3; r < N; r++) {\n                    for (int c = N - 3; c < N; c++) {\n                        blockIds[k++] = r * N + c;\n                    }\n                }\n\n                vector<int> tmp = board;\n                int bestVal = INT_MIN;\n                for (int idx = 0; idx < (int)states.size(); idx++) {\n                    uint64_t code = states[idx];\n                    for (int j = 0; j < 9; j++) {\n                        tmp[blockIds[j]] = (int)((code >> (4 * j)) & 15ULL);\n                    }\n                    Eval e = evalBoard(tmp);\n                    int val = e.S * 1000 + e.edges;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        chosen = idx;\n                    }\n                }\n            }\n        }\n\n        vector<int> path;\n        for (int cur = chosen; parent[cur] != -1; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n        reverse(path.begin(), path.end());\n\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            doDir(d);\n        }\n\n        if (reached) {\n            for (int i = 0; i < NN; i++) {\n                if (board[i] != target[i]) return false;\n            }\n        }\n        return reached;\n    }\n\n    SolveResult run(bool targetFull) {\n        int rowMode = variant % 3;\n        int colMode = (variant / 3) % 4;\n\n        vector<int> order;\n        order.reserve(NN);\n\n        // Fix top N-3 rows.\n        for (int r = 0; r < N - 3; r++) {\n            bool rev = false;\n            if (rowMode == 1) rev = true;\n            if (rowMode == 2 && (r & 1)) rev = true;\n\n            if (!rev) {\n                for (int c = 0; c < N; c++) order.push_back(r * N + c);\n            } else {\n                for (int c = N - 1; c >= 0; c--) order.push_back(r * N + c);\n            }\n        }\n\n        // Fix left N-3 columns of the bottom 3 rows.\n        for (int c = 0; c < N - 3; c++) {\n            int a = N - 3, b = N - 2, d = N - 1;\n            vector<int> rows;\n            if (colMode == 0) rows = {a, b, d};\n            else if (colMode == 1) rows = {d, b, a};\n            else if (colMode == 2) rows = {a, d, b};\n            else rows = {b, a, d};\n\n            for (int r : rows) order.push_back(r * N + c);\n        }\n\n        for (int q : order) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                return {ops, false};\n            }\n            if (!placeTile(q)) {\n                return {ops, false};\n            }\n        }\n\n        bool reached = solveFinalBlock(targetFull);\n        return {ops, reached};\n    }\n};\n\nSolveResult solveTargetBoard(const vector<int>& target, int variant, bool targetFull,\n                             mt19937& rng, Timer& timer, double limit, int cap) {\n    SlidingSolver solver(target, variant, rng, timer, limit, cap);\n    return solver.run(targetFull);\n}\n\nvoid greedyImprove(BestAns& best, double endTime, Timer& timer, mt19937& rng) {\n    while (timer.elapsed() < endTime) {\n        vector<int> bd = initBoard;\n        int blank = initBlank;\n        string mv;\n        int last = -1;\n\n        for (int step = 0; step < T && timer.elapsed() < endTime; step++) {\n            vector<int> opts;\n            for (int d = 0; d < 4; d++) {\n                if (nbCell[blank][d] >= 0 && d != (last == -1 ? -1 : OPP[last])) {\n                    opts.push_back(d);\n                }\n            }\n            if (opts.empty()) {\n                for (int d = 0; d < 4; d++) if (nbCell[blank][d] >= 0) opts.push_back(d);\n            }\n\n            int bestD = opts[0];\n            double bestKey = -1e100;\n            Eval bestEval{0,0};\n\n            for (int d : opts) {\n                int oldBlank = blank;\n                int nb = nbCell[blank][d];\n                swap(bd[blank], bd[nb]);\n                blank = nb;\n\n                Eval e = evalBoard(bd);\n                int val = e.S * 1000 + e.edges;\n                double temp = 30.0 * (1.0 - (double)step / T) + 2.0;\n                double noise = ((rng() + 0.5) * (1.0 / 4294967296.0)) * temp * 20.0;\n                double key = val + noise;\n\n                if (key > bestKey) {\n                    bestKey = key;\n                    bestD = d;\n                    bestEval = e;\n                }\n\n                swap(bd[oldBlank], bd[blank]);\n                blank = oldBlank;\n            }\n\n            applyDir(bd, blank, bestD);\n            mv.push_back(DCH[bestD]);\n            last = bestD;\n\n            if (bestEval.S >= best.S || (step & 7) == 0) {\n                updateBestKnownBoard(best, mv, bd);\n            }\n        }\n        updateBestKnownBoard(best, mv, bd);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    NN = N * N;\n    M = NN - 1;\n    initBoard.assign(NN, 0);\n    memset(targetCntArr, 0, sizeof(targetCntArr));\n\n    for (int r = 0; r < N; r++) {\n        string s;\n        cin >> s;\n        for (int c = 0; c < N; c++) {\n            int v = hexVal(s[c]);\n            int id = r * N + c;\n            initBoard[id] = v;\n            if (v == 0) initBlank = id;\n            else targetCntArr[v]++;\n        }\n    }\n\n    for (int id = 0; id < NN; id++) {\n        int r = id / N, c = id % N;\n        for (int d = 0; d < 4; d++) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) nbCell[id][d] = -1;\n            else nbCell[id][d] = nr * N + nc;\n        }\n    }\n\n    Timer timer;\n\n    uint64_t seed = 88172645463393265ULL;\n    for (int x : initBoard) seed = seed * 1315423911ULL + x + 1;\n    seed += N * 1000003ULL;\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n    BestAns best;\n    updateBest(best, \"\");\n    if (best.S == M) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    // Blank candidates are restricted to the final 3x3 block.\n    int br = (N - 1) * N + (N - 1);\n    blankChoices.push_back(br);\n    vector<int> others;\n    for (int r = N - 3; r < N; r++) {\n        for (int c = N - 3; c < N; c++) {\n            int id = r * N + c;\n            if (id != br) others.push_back(id);\n        }\n    }\n    sort(others.begin(), others.end(), [&](int a, int b) {\n        int ar = a / N, ac = a % N;\n        int br2 = b / N, bc = b % N;\n        int da = abs(ar - initBlank / N) + abs(ac - initBlank % N);\n        int db = abs(br2 - initBlank / N) + abs(bc - initBlank % N);\n        return da < db;\n    });\n    for (int x : others) blankChoices.push_back(x);\n\n    vector<Candidate> candidates;\n    vector<int> bestApproxBoard;\n    int bestApproxDiff = INT_MAX;\n    int bestApproxBit = INT_MAX;\n    int restartCounter = 0;\n\n    runTreeSearch(1.85, timer, rng, candidates, bestApproxBoard, bestApproxDiff, bestApproxBit, restartCounter);\n\n    int fullCand = 0;\n    for (auto& c : candidates) if (c.expectedS == M) fullCand++;\n\n    if (fullCand == 0 && timer.elapsed() < 2.35) {\n        runTreeSearch(2.35, timer, rng, candidates, bestApproxBoard, bestApproxDiff, bestApproxBit, restartCounter);\n    } else if (fullCand < 4 && timer.elapsed() < 2.10) {\n        runTreeSearch(2.10, timer, rng, candidates, bestApproxBoard, bestApproxDiff, bestApproxBit, restartCounter);\n    }\n\n    if (!bestApproxBoard.empty()) {\n        vector<int> adj = adjustCountsToTarget(bestApproxBoard);\n        addCandidate(candidates, adj, bestApproxBit + bestApproxDiff * 100);\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n        bool af = a.expectedS == M;\n        bool bf = b.expectedS == M;\n        if (af != bf) return af > bf;\n        if (a.expectedS != b.expectedS) return a.expectedS > b.expectedS;\n        return a.estCost < b.estCost;\n    });\n\n    int candLimit = min((int)candidates.size(), 18);\n    for (int ci = 0; ci < candLimit && timer.elapsed() < 2.80; ci++) {\n        int varMax;\n        if (ci < 3) varMax = 12;\n        else if (ci < 8) varMax = 6;\n        else varMax = 3;\n\n        bool targetFull = candidates[ci].expectedS == M;\n        for (int v = 0; v < varMax && timer.elapsed() < 2.80; v++) {\n            SolveResult res = solveTargetBoard(\n                candidates[ci].board,\n                v,\n                targetFull,\n                rng,\n                timer,\n                2.82,\n                T + 200\n            );\n            updateBest(best, res.moves);\n        }\n    }\n\n    if (best.score < 500000 && timer.elapsed() < 2.83) {\n        greedyImprove(best, 2.84, timer, rng);\n    }\n\n    if ((int)best.moves.size() > T) best.moves.resize(T);\n    cout << best.moves << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint N, K_input, MAX_CUTS;\nint targetA[11];\nvector<int> Xs, Ys;\nint M_attendees;\n\nchrono::steady_clock::time_point START_TIME;\nconst double STOP_START_TIME = 2.60;\nconst double HARD_TIME_LIMIT = 2.75;\n\ndouble elapsed_time() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t state = 1;\n    uint64_t next() {\n        uint64_t z = (state += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) {\n        if (l > r) swap(l, r);\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\nRNG rng;\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key& o) const {\n        return lo == o.lo && hi == o.hi;\n    }\n};\n\nstruct KeyHash {\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    size_t operator()(const Key& k) const {\n        return (size_t)(splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1));\n    }\n};\n\nstruct Proj {\n    ll s;\n    int idx;\n    bool operator<(const Proj& o) const {\n        if (s != o.s) return s < o.s;\n        return idx < o.idx;\n    }\n};\n\nstruct Line {\n    ll A, B, C;              // A*x + B*y = C\n    vector<Proj> ord;        // projections sorted by A*x+B*y\n};\n\nstruct LineOut {\n    ll A, B, C;\n};\n\nvector<LineOut> bestLines;\nint bestScore = -1;\nll bestValue = LLONG_MIN;\n\ninline bool getBit(const Key& k, int j) {\n    if (j < 64) return (k.lo >> j) & 1ULL;\n    return (k.hi >> (j - 64)) & 1ULL;\n}\n\ninline void flipBit(Key& k, int j) {\n    if (j < 64) k.lo ^= (1ULL << j);\n    else k.hi ^= (1ULL << (j - 64));\n}\n\nvector<Proj> computeOrder(ll A, ll B) {\n    vector<Proj> ord;\n    ord.reserve(N);\n    for (int i = 0; i < N; i++) {\n        ll s = A * (ll)Xs[i] + B * (ll)Ys[i];\n        ord.push_back({s, i});\n    }\n    sort(ord.begin(), ord.end());\n    return ord;\n}\n\nll thresholdAtRank(const vector<Proj>& ord, int rank) {\n    int n = (int)ord.size();\n    if (rank <= 0) return ord[0].s - 1;\n    if (rank >= n) return ord[n - 1].s + 1;\n\n    for (int d = 0; d <= n; d++) {\n        int b = rank - d;\n        if (0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n        b = rank + d;\n        if (d != 0 && 0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n    }\n    return (rank < n / 2 ? ord[0].s - 1 : ord[n - 1].s + 1);\n}\n\npair<ll,ll> primitive(ll A, ll B) {\n    if (A == 0 && B == 0) return {1, 0};\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) g = 1;\n    A /= g;\n    B /= g;\n    return {A, B};\n}\n\npair<ll,ll> normalFromAngle(long double theta) {\n    static const long double PI = acosl(-1.0L);\n    theta = fmodl(theta, PI);\n    if (theta < 0) theta += PI;\n\n    const long double S = 1000000.0L;\n    ll A = llround(cosl(theta) * S);\n    ll B = llround(sinl(theta) * S);\n    if (A == 0 && B == 0) A = 1;\n    return primitive(A, B);\n}\n\nlong long cellCountFormula(const vector<int>& c) {\n    long long cells = 1;\n    int sum = 0;\n    for (int x : c) sum += x;\n    cells += sum;\n    for (int i = 0; i < (int)c.size(); i++) {\n        for (int j = i + 1; j < (int)c.size(); j++) {\n            cells += 1LL * c[i] * c[j];\n        }\n    }\n    return cells;\n}\n\nvector<int> bestCounts(int G, int T) {\n    vector<int> best(G, 0), cur(G, 0);\n    long long bestCost = LLONG_MAX;\n\n    auto eval = [&]() {\n        int sum = 0, mn = 1e9, mx = -1;\n        for (int x : cur) {\n            sum += x;\n            mn = min(mn, x);\n            mx = max(mx, x);\n        }\n        if (sum > MAX_CUTS) return;\n        long long cells = cellCountFormula(cur);\n        long long diff = llabs(cells - T);\n        long long cost = diff * 100000LL + (cells < T ? 1000LL : 0LL)\n                       + (mx - mn) * 100LL + sum;\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = cur;\n        }\n    };\n\n    if (G == 2) {\n        for (int a = 0; a <= MAX_CUTS; a++) {\n            for (int b = 0; a + b <= MAX_CUTS; b++) {\n                cur[0] = a;\n                cur[1] = b;\n                eval();\n            }\n        }\n        return best;\n    }\n\n    long double denom = max(1, G * (G - 1));\n    int base = (int)round(sqrt((2.0L * T) / denom));\n    int R = (G == 4 ? 10 : 12);\n    int lo = max(0, base - R);\n    int hi = min(MAX_CUTS, base + R);\n\n    function<void(int,int)> dfs = [&](int pos, int sum) {\n        if (pos == G) {\n            eval();\n            return;\n        }\n        for (int v = lo; v <= hi; v++) {\n            if (sum + v <= MAX_CUTS) {\n                cur[pos] = v;\n                dfs(pos + 1, sum + v);\n            }\n        }\n    };\n    dfs(0, 0);\n\n    if (bestCost == LLONG_MAX) {\n        int v = min(MAX_CUTS / G, max(0, base));\n        fill(best.begin(), best.end(), v);\n    }\n    return best;\n}\n\nvector<Line> makeGroup(int G, const vector<int>& counts, long double baseAngle, int initMode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n\n    for (int g = 0; g < G; g++) {\n        auto [A, B] = normalFromAngle(baseAngle + PI * g / G);\n        vector<Proj> ord = computeOrder(A, B);\n        int m = counts[g];\n\n        vector<int> ranks;\n        ranks.reserve(m);\n\n        if (initMode == 0) {\n            for (int t = 1; t <= m; t++) {\n                ranks.push_back((int)((long long)t * N / (m + 1)));\n            }\n        } else if (initMode == 1) {\n            int low = N / 20;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            for (int t = 0; t < m; t++) ranks.push_back(rng.nextInt(low, high));\n            sort(ranks.begin(), ranks.end());\n        } else {\n            for (int t = 1; t <= m; t++) {\n                long double u = (long double)t + (rng.nextDouble() - 0.5L) * 0.9L;\n                int rank = (int)llround(u * N / (m + 1));\n                rank = max(0, min(N, rank));\n                ranks.push_back(rank);\n            }\n            sort(ranks.begin(), ranks.end());\n        }\n\n        for (int rank : ranks) {\n            Line L;\n            L.A = A;\n            L.B = B;\n            L.ord = ord;\n            L.C = thresholdAtRank(L.ord, rank);\n            res.push_back(std::move(L));\n        }\n    }\n\n    if ((int)res.size() > MAX_CUTS) res.resize(MAX_CUTS);\n    return res;\n}\n\nint kForCells(int T) {\n    for (int k = 0; k <= MAX_CUTS; k++) {\n        if (1LL + 1LL * k * (k + 1) / 2 >= T) return k;\n    }\n    return MAX_CUTS;\n}\n\nvector<Line> makeGeneral(int k, int mode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n    res.reserve(k);\n\n    long double base = (k > 0 ? rng.nextDouble() * PI / k : 0);\n\n    for (int i = 0; i < k; i++) {\n        long double theta;\n        if (mode == 0) {\n            theta = base + ((long double)i + 0.5L + (rng.nextDouble() - 0.5L) * 0.8L) * PI / k;\n        } else {\n            theta = rng.nextDouble() * PI;\n        }\n\n        auto [A, B] = normalFromAngle(theta);\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n\n        int low = N / 20;\n        int high = N - low;\n        if (low > high) {\n            low = 0;\n            high = N;\n        }\n        int rank = rng.nextInt(low, high);\n        L.C = thresholdAtRank(L.ord, rank);\n\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nstruct Config {\n    int k;\n    vector<Line> lines;\n    vector<Key> pat;\n    unordered_map<Key, int, KeyHash> mp;\n    int hist[11];\n    int overStraw = 0;\n\n    Config(vector<Line>&& ls) : k((int)ls.size()), lines(std::move(ls)), pat(N) {\n        memset(hist, 0, sizeof(hist));\n    }\n\n    inline void removeEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]--;\n        else if (c > 10) overStraw -= c;\n    }\n\n    inline void addEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]++;\n        else if (c > 10) overStraw += c;\n    }\n\n    void build() {\n        mp.clear();\n        mp.reserve(N * 4 + 100);\n        mp.max_load_factor(0.7);\n        memset(hist, 0, sizeof(hist));\n        overStraw = 0;\n\n        for (int i = 0; i < N; i++) {\n            Key key{0, 0};\n            for (int j = 0; j < k; j++) {\n                ll s = lines[j].A * (ll)Xs[i] + lines[j].B * (ll)Ys[i];\n                if (s > lines[j].C) {\n                    if (j < 64) key.lo |= (1ULL << j);\n                    else key.hi |= (1ULL << (j - 64));\n                }\n            }\n            pat[i] = key;\n            mp[key]++;\n        }\n\n        for (auto& kv : mp) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) hist[c]++;\n            else if (c > 10) overStraw += c;\n        }\n    }\n\n    void decKey(const Key& key) {\n        auto it = mp.find(key);\n        int old = it->second;\n        removeEffect(old);\n        int nw = old - 1;\n        addEffect(nw);\n        if (nw == 0) mp.erase(it);\n        else it->second = nw;\n    }\n\n    void incKey(const Key& key) {\n        auto it = mp.find(key);\n        if (it == mp.end()) {\n            addEffect(1);\n            mp.emplace(key, 1);\n        } else {\n            int old = it->second;\n            removeEffect(old);\n            int nw = old + 1;\n            addEffect(nw);\n            it->second = nw;\n        }\n    }\n\n    inline void flipPoint(int idx, int j) {\n        Key old = pat[idx];\n        Key nw = old;\n        flipBit(nw, j);\n        decKey(old);\n        incKey(nw);\n        pat[idx] = nw;\n    }\n\n    int score() const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], hist[d]);\n        return sc;\n    }\n\n    int surplus() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (hist[d] > targetA[d]) s += hist[d] - targetA[d];\n        }\n        return s;\n    }\n\n    ll value() const {\n        const ll SCORE_W = 1000000000000LL;\n        const ll SURPLUS_W = 1000000LL;\n        return (ll)score() * SCORE_W - (ll)surplus() * SURPLUS_W - overStraw;\n    }\n\n    int rankForC(int j) const {\n        const auto& ord = lines[j].ord;\n        int l = 0, r = N;\n        ll C = lines[j].C;\n        while (l < r) {\n            int m = (l + r) >> 1;\n            if (ord[m].s <= C) l = m + 1;\n            else r = m;\n        }\n        return l;\n    }\n\n    void sweepLine(int j) {\n        const auto& ord = lines[j].ord;\n\n        ll origVal = value();\n        int bestIdx = rankForC(j);\n        ll bestC = lines[j].C;\n        ll bestVal = origVal;\n\n        for (int i = 0; i < N; i++) {\n            if (!getBit(pat[i], j)) flipPoint(i, j);\n        }\n\n        ll valAll = value();\n        if (valAll > bestVal) {\n            bestVal = valAll;\n            bestIdx = 0;\n            bestC = ord[0].s - 1;\n        }\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = ord[idx].s;\n            while (idx < N && ord[idx].s == v) {\n                flipPoint(ord[idx].idx, j);\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = ord[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = value();\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestIdx = idx;\n                    bestC = candC;\n                }\n            }\n        }\n\n        // now all bits of line j are 0\n        for (int t = bestIdx; t < N; t++) {\n            flipPoint(ord[t].idx, j);\n        }\n        lines[j].C = bestC;\n    }\n\n    void optimize(int passes) {\n        if (k == 0) return;\n        vector<int> order(k);\n        iota(order.begin(), order.end(), 0);\n\n        for (int p = 0; p < passes; p++) {\n            for (int i = k - 1; i > 0; i--) {\n                int j = rng.nextInt(0, i);\n                swap(order[i], order[j]);\n            }\n\n            ll before = value();\n\n            for (int t = 0; t < k; t++) {\n                sweepLine(order[t]);\n                if ((t & 7) == 0 && elapsed_time() > HARD_TIME_LIMIT) return;\n            }\n\n            if (value() <= before) break;\n        }\n    }\n};\n\nvoid updateBest(const Config& cfg) {\n    int sc = cfg.score();\n    ll val = cfg.value();\n    if (sc > bestScore || (sc == bestScore && val > bestValue)) {\n        bestScore = sc;\n        bestValue = val;\n        bestLines.clear();\n        for (const auto& L : cfg.lines) {\n            bestLines.push_back({L.A, L.B, L.C});\n        }\n    }\n}\n\nvoid runCandidate(vector<Line> lines, int passes) {\n    if ((int)lines.size() > MAX_CUTS) lines.resize(MAX_CUTS);\n    if (elapsed_time() > STOP_START_TIME) return;\n\n    Config cfg(std::move(lines));\n    cfg.build();\n    cfg.optimize(passes);\n    updateBest(cfg);\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = 1;\n        y = 0;\n        return a;\n    }\n    ll x1, y1;\n    ll g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<ll,4> fallbackLine() {\n    return {1000000000LL, 1000000000LL, 999999999LL, 1000000000LL};\n}\n\narray<ll,4> endpoints(LineOut L) {\n    ll A = L.A, B = L.B, C = L.C;\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) return fallbackLine();\n    if (C % g != 0) return fallbackLine();\n    A /= g;\n    B /= g;\n    C /= g;\n\n    auto inside = [](ll v) {\n        return -1000000000LL <= v && v <= 1000000000LL;\n    };\n\n    if (B == 0) {\n        if (A == 0 || C % A != 0) return fallbackLine();\n        ll x = C / A;\n        if (!inside(x)) return fallbackLine();\n        return {x, 0, x, 1};\n    }\n    if (A == 0) {\n        if (B == 0 || C % B != 0) return fallbackLine();\n        ll y = C / B;\n        if (!inside(y)) return fallbackLine();\n        return {0, y, 1, y};\n    }\n\n    ll xg, yg;\n    extgcd(llabs(A), llabs(B), xg, yg);\n\n    __int128 x0 = (__int128)xg * (A >= 0 ? 1 : -1) * C;\n    __int128 y0 = (__int128)yg * (B >= 0 ? 1 : -1) * C;\n\n    ll dx = B;\n    ll dy = -A;\n\n    long double dot = (long double)x0 * (long double)dx + (long double)y0 * (long double)dy;\n    long double den = (long double)dx * dx + (long double)dy * dy;\n    ll t0 = llround(-dot / den);\n\n    __int128 bestNorm = -1;\n    __int128 bx = x0, by = y0;\n\n    for (ll dt = -6; dt <= 6; dt++) {\n        ll t = t0 + dt;\n        __int128 x = x0 + (__int128)dx * t;\n        __int128 y = y0 + (__int128)dy * t;\n        __int128 norm = x * x + y * y;\n        if (bestNorm < 0 || norm < bestNorm) {\n            bestNorm = norm;\n            bx = x;\n            by = y;\n        }\n    }\n\n    __int128 qx = bx + dx;\n    __int128 qy = by + dy;\n\n    if (bx < -1000000000LL || bx > 1000000000LL ||\n        by < -1000000000LL || by > 1000000000LL ||\n        qx < -1000000000LL || qx > 1000000000LL ||\n        qy < -1000000000LL || qy > 1000000000LL) {\n        return fallbackLine();\n    }\n\n    ll px = (ll)bx, py = (ll)by;\n    ll rx = (ll)qx, ry = (ll)qy;\n    if (px == rx && py == ry) return fallbackLine();\n    return {px, py, rx, ry};\n}\n\nLineOut canonical(LineOut L) {\n    ll g = std::gcd(llabs(L.A), llabs(L.B));\n    if (g > 0 && L.C % g == 0) {\n        L.A /= g;\n        L.B /= g;\n        L.C /= g;\n    }\n    if (L.A < 0 || (L.A == 0 && L.B < 0)) {\n        L.A = -L.A;\n        L.B = -L.B;\n        L.C = -L.C;\n    }\n    return L;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K_input;\n    MAX_CUTS = min(K_input, 100);\n\n    M_attendees = 0;\n    for (int d = 1; d <= 10; d++) {\n        cin >> targetA[d];\n        M_attendees += targetA[d];\n    }\n\n    Xs.resize(N);\n    Ys.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xs[i] >> Ys[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    auto mixSeed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed(N);\n    mixSeed(K_input);\n    for (int d = 1; d <= 10; d++) mixSeed(targetA[d]);\n    for (int i = 0; i < N; i++) {\n        mixSeed((uint64_t)(Xs[i] + 20000) * 40009ULL + (uint64_t)(Ys[i] + 20000));\n    }\n    rng.state = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    auto tryGroup = [&](int G, double factor, int initMode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * factor));\n        auto counts = bestCounts(G, T);\n        long double PI = acosl(-1.0L);\n        long double base = rng.nextDouble() * PI / G;\n        auto lines = makeGroup(G, counts, base, initMode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    auto tryGeneral = [&](double factor, int mode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * factor));\n        int k = kForCells(T);\n        auto lines = makeGeneral(k, mode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    // A few diversified initial attempts.\n    tryGroup(2, 1.25, 0, 3);\n    tryGroup(3, 1.25, 0, 3);\n    tryGroup(4, 1.25, 0, 3);\n    tryGeneral(1.30, 0, 3);\n\n    tryGroup(2, 1.45, 2, 2);\n    tryGroup(3, 1.45, 2, 2);\n    tryGeneral(1.10, 0, 2);\n    tryGroup(2, 1.05, 0, 2);\n    tryGeneral(1.50, 1, 2);\n    tryGroup(4, 1.45, 2, 2);\n\n    int iter = 0;\n    while (elapsed_time() < STOP_START_TIME) {\n        int typ = iter % 4;\n        double factor = 0.95 + 0.65 * rng.nextDouble();\n        int initMode = rng.nextInt(0, 2);\n        if (typ == 0) tryGroup(2, factor, initMode, 2);\n        else if (typ == 1) tryGroup(3, factor, initMode, 2);\n        else if (typ == 2) tryGeneral(factor, rng.nextInt(0, 1), 2);\n        else tryGroup(4, factor, initMode, 2);\n        iter++;\n    }\n\n    // Remove exactly duplicated geometric lines.\n    vector<LineOut> outputLines;\n    vector<LineOut> seen;\n    for (auto L : bestLines) {\n        LineOut C = canonical(L);\n        bool dup = false;\n        for (auto S : seen) {\n            if (S.A == C.A && S.B == C.B && S.C == C.C) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) {\n            seen.push_back(C);\n            outputLines.push_back(L);\n        }\n        if ((int)outputLines.size() == MAX_CUTS) break;\n    }\n\n    cout << outputLines.size() << '\\n';\n    for (auto L : outputLines) {\n        auto e = endpoints(L);\n        cout << e[0] << ' ' << e[1] << ' ' << e[2] << ' ' << e[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAXN = 61;\nconst int MAXC = MAXN * MAXN;\nconst int MAXTOP = 128;\n\nint N, M, C;\nint PX[MAXC], PY[MAXC];\nint WT[MAXC];\nint maxWeight = 0;\nunsigned char initDot[MAXC];\ndouble priorityVal[MAXC];\nlong long initialSum = 0;\n\nconst int DX[8] = {1, 0, -1, 0, 1, -1, -1, 1};\nconst int DY[8] = {0, 1, 0, -1, 1, 1, -1, -1};\n\n// E,N / N,W / W,S / S,E and NE,NW / NW,SW / SW,SE / SE,NE\nconst int PA[8] = {0, 1, 2, 3, 4, 5, 6, 7};\nconst int PB[8] = {1, 2, 3, 0, 5, 6, 7, 4};\n\ninline int pid(int x, int y) {\n    return x * N + y;\n}\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y < N;\n}\n\ninline uint64_t rangeMask(int l, int r) {\n    int len = r - l;\n    if (len <= 0) return 0ULL;\n    return ((1ULL << len) - 1ULL) << l;\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = splitmix64(seed);\n        if (x == 0) x = 88172645463325252ULL;\n    }\n    inline uint64_t next() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double nextSigned() {\n        return nextDouble() * 2.0 - 1.0;\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 Op {\n    int p1, p2, p3, p4;\n};\n\nstruct Candidate {\n    int p1, p2, p3, p4;\n    int lenSum;\n    int area;\n};\n\nstruct Node {\n    double key;\n    Candidate cand;\n};\n\ninline void heapSiftUp(Node h[], int i) {\n    while (i > 0) {\n        int p = (i - 1) >> 1;\n        if (h[p].key <= h[i].key) break;\n        swap(h[p], h[i]);\n        i = p;\n    }\n}\n\ninline void heapSiftDown(Node h[], int n, int i = 0) {\n    while (true) {\n        int l = i * 2 + 1;\n        int r = l + 1;\n        int m = i;\n        if (l < n && h[l].key < h[m].key) m = l;\n        if (r < n && h[r].key < h[m].key) m = r;\n        if (m == i) break;\n        swap(h[i], h[m]);\n        i = m;\n    }\n}\n\ninline void heapPushTop(Node h[], int& n, int K, const Node& nd) {\n    if (n < K) {\n        h[n] = nd;\n        heapSiftUp(h, n);\n        ++n;\n    } else if (nd.key > h[0].key) {\n        h[0] = nd;\n        heapSiftDown(h, n, 0);\n    }\n}\n\nstruct Params {\n    double perim;\n    double area;\n    double outward;\n    int topK;\n    double rankPower;\n    double noise;\n};\n\nstruct State {\n    unsigned char dot[MAXC];\n    int nearestDot[8][MAXC];\n\n    // Used elementary edge masks.\n    // H[y]: horizontal segment bit x: (x,y)-(x+1,y)\n    // V[x]: vertical segment bit y: (x,y)-(x,y+1)\n    // DP[x-y+N-1]: diagonal + segment bit x: (x,y)-(x+1,y+1)\n    // DM[x+y]: diagonal - segment bit x: (x,y)-(x+1,y-1)\n    uint64_t H[MAXN], V[MAXN], DPm[2 * MAXN], DMm[2 * MAXN];\n\n    vector<Op> ops;\n    long long sumW = 0;\n    bool dirtyNearest = true;\n\n    void reset() {\n        memcpy(dot, initDot, C * sizeof(unsigned char));\n        fill(H, H + MAXN, 0ULL);\n        fill(V, V + MAXN, 0ULL);\n        fill(DPm, DPm + 2 * MAXN, 0ULL);\n        fill(DMm, DMm + 2 * MAXN, 0ULL);\n        ops.clear();\n        sumW = initialSum;\n        dirtyNearest = true;\n    }\n\n    void buildNearest() {\n        for (int d = 0; d < 8; ++d) {\n            int dx = DX[d], dy = DY[d];\n            for (int sx = 0; sx < N; ++sx) {\n                for (int sy = 0; sy < N; ++sy) {\n                    int nx = sx + dx;\n                    int ny = sy + dy;\n                    if (inside(nx, ny)) continue;\n\n                    int cur = -1;\n                    int x = sx, y = sy;\n                    while (inside(x, y)) {\n                        int p = pid(x, y);\n                        nearestDot[d][p] = cur;\n                        if (dot[p]) cur = p;\n                        x -= dx;\n                        y -= dy;\n                    }\n                }\n            }\n        }\n        dirtyNearest = false;\n    }\n\n    void updateNearestAfterAdd(int p) {\n        for (int d = 0; d < 8; ++d) {\n            int x = PX[p] - DX[d];\n            int y = PY[p] - DY[d];\n            while (inside(x, y)) {\n                int q = pid(x, y);\n                nearestDot[d][q] = p;\n                if (dot[q]) break;\n                x -= DX[d];\n                y -= DY[d];\n            }\n        }\n    }\n\n    bool sideFree(int a, int b) const {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            uint64_t m = rangeMask(y1, y2);\n            return (V[x1] & m) == 0;\n        }\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            uint64_t m = rangeMask(x1, x2);\n            return (H[y1] & m) == 0;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        if (abs(dx) != abs(dy)) return false;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 - y1 + N - 1;\n            uint64_t m = rangeMask(x1, x2);\n            return (DPm[line] & m) == 0;\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 + y1;\n            uint64_t m = rangeMask(x1, x2);\n            return (DMm[line] & m) == 0;\n        }\n    }\n\n    void markSide(int a, int b) {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            V[x1] |= rangeMask(y1, y2);\n            return;\n        }\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            H[y1] |= rangeMask(x1, x2);\n            return;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 - y1 + N - 1;\n            DPm[line] |= rangeMask(x1, x2);\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 + y1;\n            DMm[line] |= rangeMask(x1, x2);\n        }\n    }\n\n    void applyOp(const Op& op, bool updateNearest) {\n        markSide(op.p1, op.p2);\n        markSide(op.p2, op.p3);\n        markSide(op.p3, op.p4);\n        markSide(op.p4, op.p1);\n\n        dot[op.p1] = 1;\n        sumW += WT[op.p1];\n        ops.push_back(op);\n\n        if (updateNearest && !dirtyNearest) {\n            updateNearestAfterAdd(op.p1);\n        } else {\n            dirtyNearest = true;\n        }\n    }\n\n    bool chooseCandidate(const Params& par, RNG& rng, Candidate& res) {\n        if (dirtyNearest) buildNearest();\n\n        int K = par.topK;\n        if (K < 1) K = 1;\n        if (K > MAXTOP) K = MAXTOP;\n\n        bool found = false;\n        double bestKey = -1e100;\n        int bestLen = INT_MAX;\n        Candidate bestCand{};\n\n        Node heap[MAXTOP];\n        int hsz = 0;\n\n        for (int p1 = 0; p1 < C; ++p1) {\n            if (dot[p1]) continue;\n\n            int x1 = PX[p1];\n            int y1 = PY[p1];\n\n            for (int t = 0; t < 8; ++t) {\n                int d1 = PA[t];\n                int d2 = PB[t];\n\n                int p2 = nearestDot[d1][p1];\n                if (p2 < 0) continue;\n\n                int p4 = nearestDot[d2][p1];\n                if (p4 < 0) continue;\n\n                int x3 = PX[p2] + PX[p4] - x1;\n                int y3 = PY[p2] + PY[p4] - y1;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n\n                int p3 = pid(x3, y3);\n                if (!dot[p3]) continue;\n\n                if (nearestDot[d2][p2] != p3) continue;\n                if (nearestDot[d1][p4] != p3) continue;\n\n                if (!sideFree(p1, p2)) continue;\n                if (!sideFree(p2, p3)) continue;\n                if (!sideFree(p3, p4)) continue;\n                if (!sideFree(p4, p1)) continue;\n\n                int len1 = max(abs(PX[p2] - x1), abs(PY[p2] - y1));\n                int len2 = max(abs(PX[p4] - x1), abs(PY[p4] - y1));\n                int lenSum = len1 + len2;\n                int area = len1 * len2;\n\n                double avgOther = (WT[p2] + WT[p3] + WT[p4]) / 3.0;\n                double key =\n                    priorityVal[p1]\n                    + par.outward * (WT[p1] - avgOther)\n                    - par.perim * lenSum\n                    - par.area * area;\n\n                Candidate cand{p1, p2, p3, p4, lenSum, area};\n\n                if (K == 1) {\n                    if (!found || key > bestKey + 1e-12 ||\n                        (fabs(key - bestKey) <= 1e-12 && lenSum < bestLen)) {\n                        found = true;\n                        bestKey = key;\n                        bestLen = lenSum;\n                        bestCand = cand;\n                    }\n                } else {\n                    Node nd{key, cand};\n                    heapPushTop(heap, hsz, K, nd);\n                }\n            }\n        }\n\n        if (K == 1) {\n            if (!found) return false;\n            res = bestCand;\n            return true;\n        } else {\n            if (hsz == 0) return false;\n\n            sort(heap, heap + hsz, [](const Node& a, const Node& b) {\n                return a.key > b.key;\n            });\n\n            int idx = 0;\n            if (hsz > 1) {\n                if (par.rankPower <= 0.0) {\n                    idx = rng.nextInt(hsz);\n                } else {\n                    double z = pow(rng.nextDouble(), par.rankPower);\n                    idx = (int)(z * hsz);\n                    if (idx >= hsz) idx = hsz - 1;\n                }\n            }\n\n            res = heap[idx].cand;\n            return true;\n        }\n    }\n};\n\nParams randomParam(RNG& rng) {\n    static const double perims[] = {\n        -1.0, -0.5, -0.2, 0.0, 0.3, 0.8, 1.5, 2.5, 4.0, 6.0, 9.0\n    };\n    static const double areas[] = {\n        -0.020, -0.005, 0.0, 0.0, 0.005, 0.015, 0.030, 0.060\n    };\n\n    Params p;\n    p.perim = perims[rng.nextInt((int)(sizeof(perims) / sizeof(perims[0])))]\n              + (rng.nextDouble() - 0.5) * 0.35;\n    p.area = areas[rng.nextInt((int)(sizeof(areas) / sizeof(areas[0])))];\n\n    p.outward = rng.nextDouble() * 1.5;\n    if (rng.nextInt(10) == 0) p.outward += rng.nextDouble() * 1.5;\n\n    int r = rng.nextInt(100);\n    if (r < 20) {\n        p.topK = 1;\n    } else if (r < 75) {\n        p.topK = 3 + rng.nextInt(25);\n    } else {\n        p.topK = 30 + rng.nextInt(90);\n    }\n    if (p.topK > MAXTOP) p.topK = MAXTOP;\n\n    if (p.topK == 1) {\n        p.rankPower = 1.0;\n    } else {\n        int q = rng.nextInt(100);\n        if (q < 20) p.rankPower = 1.0;                 // almost uniform in top-K\n        else if (q < 85) p.rankPower = 1.5 + rng.nextDouble() * 3.0; // biased to best\n        else p.rankPower = 0.5 + rng.nextDouble() * 0.5;             // exploratory\n    }\n\n    if (rng.nextInt(100) < 55) p.noise = rng.nextDouble() * 0.16;\n    else p.noise = rng.nextDouble() * 0.35;\n    if (rng.nextInt(100) < 5) p.noise = rng.nextDouble() * 0.60;\n\n    return p;\n}\n\nvoid preparePriority(const Params& par, RNG& rng) {\n    double amp = par.noise * maxWeight;\n    if (amp <= 1e-12) {\n        for (int i = 0; i < C; ++i) priorityVal[i] = WT[i];\n    } else {\n        for (int i = 0; i < C; ++i) {\n            priorityVal[i] = WT[i] + amp * rng.nextSigned();\n        }\n    }\n}\n\nvoid runGreedy(State& st, const Params& par, RNG& rng, const Timer& timer, double TL) {\n    Candidate cand;\n    while (timer.elapsed() < TL) {\n        if (!st.chooseCandidate(par, rng, cand)) break;\n        Op op{cand.p1, cand.p2, cand.p3, cand.p4};\n        st.applyOp(op, true);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    C = N * N;\n\n    fill(initDot, initDot + MAXC, 0);\n\n    int c = N / 2;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y < N; ++y) {\n            int p = pid(x, y);\n            PX[p] = x;\n            PY[p] = y;\n            int dx = x - c;\n            int dy = y - c;\n            WT[p] = dx * dx + dy * dy + 1;\n            maxWeight = max(maxWeight, WT[p]);\n        }\n    }\n\n    uint64_t seed = splitmix64(((uint64_t)N << 32) ^ (uint64_t)M);\n\n    for (int i = 0; i < M; ++i) {\n        int x, y;\n        cin >> x >> y;\n        int p = pid(x, y);\n        initDot[p] = 1;\n        seed ^= splitmix64(((uint64_t)(i + 1) << 40) ^ ((uint64_t)x << 20) ^ (uint64_t)y);\n    }\n\n    initialSum = 0;\n    for (int p = 0; p < C; ++p) {\n        if (initDot[p]) initialSum += WT[p];\n    }\n\n    RNG rng(seed);\n\n    vector<Params> presets = {\n        {0.0,  0.000, 0.0,  1, 1.0, 0.0},\n        {0.6,  0.000, 0.0,  1, 1.0, 0.0},\n        {1.4,  0.004, 0.4,  1, 1.0, 0.0},\n        {2.8,  0.015, 0.8,  1, 1.0, 0.0},\n        {-0.4, -0.004, 0.4,  8, 2.0, 0.0},\n        {0.5,  0.000, 1.0, 16, 1.7, 0.0},\n        {4.5,  0.050, 0.0, 24, 2.5, 0.0}\n    };\n\n    State st;\n    st.ops.reserve(C);\n\n    vector<Op> bestOps;\n    bestOps.reserve(C);\n    long long bestSum = initialSum;\n\n    Timer timer;\n    const double TL = 4.75;\n\n    int trial = 0;\n    while (timer.elapsed() < TL) {\n        Params par;\n        if (trial < (int)presets.size()) par = presets[trial];\n        else par = randomParam(rng);\n\n        bool usePrefix = false;\n        int cut = 0;\n\n        if (trial >= (int)presets.size() && !bestOps.empty() && rng.nextInt(100) < 70) {\n            usePrefix = true;\n            int K = (int)bestOps.size();\n\n            int mode = rng.nextInt(100);\n            if (mode < 55) {\n                int maxDrop = min(K, 50 + rng.nextInt(950));\n                int drop = 1 + rng.nextInt(maxDrop);\n                cut = K - drop;\n            } else if (mode < 85) {\n                cut = rng.nextInt(K + 1);\n            } else {\n                double u = rng.nextDouble();\n                cut = (int)(K * u * u);\n            }\n            if (cut < 0) cut = 0;\n            if (cut > K) cut = K;\n        }\n\n        preparePriority(par, rng);\n\n        st.reset();\n        if (usePrefix && cut > 0) {\n            for (int i = 0; i < cut; ++i) {\n                st.applyOp(bestOps[i], false);\n            }\n        }\n\n        runGreedy(st, par, rng, timer, TL);\n\n        if (st.sumW > bestSum) {\n            bestSum = st.sumW;\n            bestOps = st.ops;\n        }\n\n        ++trial;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (const auto& op : bestOps) {\n        cout << PX[op.p1] << ' ' << PY[op.p1] << ' '\n             << PX[op.p2] << ' ' << PY[op.p2] << ' '\n             << PX[op.p3] << ' ' << PY[op.p3] << ' '\n             << PX[op.p4] << ' ' << PY[op.p4] << '\\n';\n    }\n\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint flav[100];\nint totalCnt[4];\nint remAfter[100][4];\n\nint neighs[100][4], degs_[100];\nint rightCell[100], downCell[100];\nuint8_t manhDist[100][100];\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Board {\n    uint8_t a[100];\n    int n;\n\n    Board() { clear(); }\n\n    void clear() {\n        memset(a, 0, sizeof(a));\n        n = 0;\n    }\n\n    void placeRank(int rk, int fl) {\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) {\n                if (rk == 0) {\n                    a[i] = (uint8_t)fl;\n                    n++;\n                    return;\n                }\n                rk--;\n            }\n        }\n    }\n\n    void placeCell(int pos, int fl) {\n        a[pos] = (uint8_t)fl;\n        n++;\n    }\n\n    int getEmpties(int emp[]) const {\n        int m = 0;\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) emp[m++] = i;\n        }\n        return m;\n    }\n\n    void tilt(int dir) {\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; c++) {\n                int w = 0;\n                for (int r = 0; r < 10; r++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w++ * 10 + c] = v;\n                }\n                for (int r = w; r < 10; r++) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; c++) {\n                int w = 9;\n                for (int r = 9; r >= 0; r--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w-- * 10 + c] = v;\n                }\n                for (int r = w; r >= 0; r--) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; r++) {\n                int w = 0;\n                for (int c = 0; c < 10; c++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w++] = v;\n                }\n                for (int c = w; c < 10; c++) a[r * 10 + c] = 0;\n            }\n        } else { // R\n            for (int r = 0; r < 10; r++) {\n                int w = 9;\n                for (int c = 9; c >= 0; c--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w--] = v;\n                }\n                for (int c = w; c >= 0; c--) a[r * 10 + c] = 0;\n            }\n        }\n    }\n};\n\nstruct Layout {\n    uint8_t target[100];\n    uint8_t dist[4][100];\n};\n\nvector<Layout> layouts;\nunordered_set<string> seenLayouts;\n\nvoid initTables() {\n    for (int i = 0; i < 100; i++) {\n        degs_[i] = 0;\n        rightCell[i] = downCell[i] = -1;\n    }\n\n    for (int r = 0; r < 10; r++) {\n        for (int c = 0; c < 10; c++) {\n            int id = r * 10 + c;\n            if (r > 0) neighs[id][degs_[id]++] = (r - 1) * 10 + c;\n            if (r < 9) neighs[id][degs_[id]++] = (r + 1) * 10 + c;\n            if (c > 0) neighs[id][degs_[id]++] = r * 10 + c - 1;\n            if (c < 9) neighs[id][degs_[id]++] = r * 10 + c + 1;\n\n            if (c < 9) rightCell[id] = id + 1;\n            if (r < 9) downCell[id] = id + 10;\n        }\n    }\n\n    for (int i = 0; i < 100; i++) {\n        int r1 = i / 10, c1 = i % 10;\n        for (int j = 0; j < 100; j++) {\n            int r2 = j / 10, c2 = j % 10;\n            manhDist[i][j] = (uint8_t)(abs(r1 - r2) + abs(c1 - c2));\n        }\n    }\n}\n\nll finalScoreNum(const Board& b) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    ll res = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        res += 1LL * sz * sz;\n    }\n\n    return res;\n}\n\nll evalBoard(const Board& b, int step, const Layout& L) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    int maxComp[4] = {};\n    int sumSq = 0;\n    int comps = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        comps++;\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        sumSq += sz * sz;\n        maxComp[fl] = max(maxComp[fl], sz);\n    }\n\n    int adj = 0;\n    int distCost = 0;\n    int match = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int v = b.a[i];\n        if (!v) continue;\n\n        int r = rightCell[i];\n        if (r != -1 && b.a[r] == v) adj++;\n\n        int d = downCell[i];\n        if (d != -1 && b.a[d] == v) adj++;\n\n        distCost += L.dist[v][i];\n        if (L.target[i] == v) match++;\n    }\n\n    // Optimistic future-aware component potential:\n    // If all future candies of a flavor join its largest current component,\n    // contribution is sumSq + 2 * maxComponent * remaining + constant.\n    ll compPot = sumSq;\n    for (int f = 1; f <= 3; f++) {\n        compPot += 2LL * maxComp[f] * remAfter[step][f];\n    }\n\n    int future = 99 - step;\n\n    ll val = 0;\n    val += compPot * 1000LL;\n    val += adj * 200LL;\n    val -= comps * 50LL;\n    val += match * (30LL + future);\n    val -= distCost * (20LL + 3LL * future);\n\n    return val;\n}\n\nint greedyDir(const Board& b, int step, const Layout& L) {\n    int offset = ((step + 1) * 17 + flav[step] * 31) & 3;\n\n    int bestD = 0;\n    ll bestV = LLONG_MIN;\n\n    for (int k = 0; k < 4; k++) {\n        int d = (offset + k) & 3;\n        Board nb = b;\n        nb.tilt(d);\n        ll v = evalBoard(nb, step, L);\n        if (v > bestV) {\n            bestV = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nvoid computeLayoutDist(Layout& L) {\n    for (int f = 0; f < 4; f++) {\n        for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n    }\n\n    for (int f = 1; f <= 3; f++) {\n        vector<int> cells;\n        for (int i = 0; i < 100; i++) {\n            if (L.target[i] == f) cells.push_back(i);\n        }\n\n        if (cells.empty()) {\n            for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n            continue;\n        }\n\n        for (int i = 0; i < 100; i++) {\n            int best = 100;\n            for (int p : cells) {\n                best = min(best, (int)manhDist[i][p]);\n            }\n            L.dist[f][i] = (uint8_t)best;\n        }\n    }\n}\n\nvoid addLayout(const array<uint8_t, 100>& tar) {\n    string key;\n    key.resize(100);\n    for (int i = 0; i < 100; i++) key[i] = char('0' + tar[i]);\n\n    if (!seenLayouts.insert(key).second) return;\n\n    Layout L;\n    memset(&L, 0, sizeof(L));\n    for (int i = 0; i < 100; i++) L.target[i] = tar[i];\n    computeLayoutDist(L);\n    layouts.push_back(L);\n}\n\npair<int, int> transformCoord(int r, int c, int s) {\n    if (s == 0) return {r, c};\n    if (s == 1) return {r, 9 - c};\n    if (s == 2) return {9 - r, c};\n    if (s == 3) return {9 - r, 9 - c};\n    if (s == 4) return {c, r};\n    if (s == 5) return {c, 9 - r};\n    if (s == 6) return {9 - c, r};\n    return {9 - c, 9 - r};\n}\n\nstruct PQNode {\n    int dist;\n    int tie;\n    int f;\n    int pos;\n};\n\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        if (a.dist != b.dist) return a.dist > b.dist;\n        if (a.tie != b.tie) return a.tie > b.tie;\n        return a.f > b.f;\n    }\n};\n\nint tieValue(int pos, int f, int seed) {\n    return (pos * 37 + f * 101 + seed * 17) & 1023;\n}\n\narray<uint8_t, 100> makeCornerLayout(const int seeds[4]) {\n    array<uint8_t, 100> tar;\n    tar.fill(0);\n\n    int cap[4];\n    for (int f = 1; f <= 3; f++) cap[f] = totalCnt[f];\n\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq;\n\n    for (int f = 1; f <= 3; f++) {\n        if (cap[f] > 0) {\n            int p = seeds[f];\n            pq.push({0, tieValue(p, f, seeds[f]), f, p});\n        }\n    }\n\n    int assigned = 0;\n\n    while (assigned < 100 && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n\n        int f = cur.f;\n        int p = cur.pos;\n\n        if (cap[f] <= 0 || tar[p] != 0) continue;\n\n        tar[p] = (uint8_t)f;\n        cap[f]--;\n        assigned++;\n\n        if (cap[f] > 0) {\n            for (int k = 0; k < degs_[p]; k++) {\n                int to = neighs[p][k];\n                if (tar[to] == 0) {\n                    pq.push({cur.dist + 1, tieValue(to, f, seeds[f]), f, to});\n                }\n            }\n        }\n    }\n\n    // Fallback, rarely used.\n    if (assigned < 100) {\n        for (int p = 0; p < 100; p++) {\n            if (tar[p] != 0) continue;\n\n            int bestF = -1;\n            int bestCost = 1e9;\n\n            for (int f = 1; f <= 3; f++) {\n                if (cap[f] <= 0) continue;\n\n                int cost = manhDist[p][seeds[f]];\n                bool adj = false;\n                for (int k = 0; k < degs_[p]; k++) {\n                    if (tar[neighs[p][k]] == f) adj = true;\n                }\n                if (adj) cost -= 20;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestF = f;\n                }\n            }\n\n            if (bestF == -1) {\n                for (int f = 1; f <= 3; f++) {\n                    if (cap[f] > 0) {\n                        bestF = f;\n                        break;\n                    }\n                }\n            }\n\n            tar[p] = (uint8_t)bestF;\n            cap[bestF]--;\n            assigned++;\n        }\n    }\n\n    return tar;\n}\n\nvoid generateLayouts() {\n    layouts.clear();\n    seenLayouts.clear();\n    layouts.reserve(128);\n    seenLayouts.reserve(256);\n\n    // Neutral layout: target term disabled.\n    {\n        Layout neutral;\n        memset(&neutral, 0, sizeof(neutral));\n        layouts.push_back(neutral);\n        seenLayouts.insert(string(100, '0'));\n    }\n\n    // Snake/band layouts.\n    vector<int> basePath;\n    basePath.reserve(100);\n\n    for (int r = 0; r < 10; r++) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < 10; c++) basePath.push_back(r * 10 + c);\n        } else {\n            for (int c = 9; c >= 0; c--) basePath.push_back(r * 10 + c);\n        }\n    }\n\n    for (int sym = 0; sym < 8; sym++) {\n        vector<int> path;\n        path.reserve(100);\n        bool used[100] = {};\n        bool ok = true;\n\n        for (int id : basePath) {\n            int r = id / 10, c = id % 10;\n            auto [nr, nc] = transformCoord(r, c, sym);\n            int p = nr * 10 + nc;\n            if (used[p]) ok = false;\n            used[p] = true;\n            path.push_back(p);\n        }\n\n        if (!ok) continue;\n\n        array<int, 3> perm = {1, 2, 3};\n        do {\n            array<uint8_t, 100> tar;\n            tar.fill(0);\n\n            int idx = 0;\n            for (int k = 0; k < 3; k++) {\n                int f = perm[k];\n                for (int cnt = 0; cnt < totalCnt[f]; cnt++) {\n                    tar[path[idx++]] = (uint8_t)f;\n                }\n            }\n\n            addLayout(tar);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    // Three-corner growing layouts.\n    int corners[4] = {0, 9, 90, 99};\n    for (int a = 0; a < 4; a++) {\n        for (int b = 0; b < 4; b++) if (b != a) {\n            for (int c = 0; c < 4; c++) if (c != a && c != b) {\n                int seeds[4] = {};\n                seeds[1] = corners[a];\n                seeds[2] = corners[b];\n                seeds[3] = corners[c];\n\n                auto tar = makeCornerLayout(seeds);\n                addLayout(tar);\n            }\n        }\n    }\n}\n\nint chooseLayout() {\n    constexpr int K = 3;\n\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 100; i++) {\n        seed = seed * 1000003ULL + flav[i] * 97ULL + i;\n    }\n\n    RNG rng(seed);\n    uint8_t ranks[K][100];\n\n    for (int k = 0; k < K; k++) {\n        for (int s = 0; s < 100; s++) {\n            ranks[k][s] = (uint8_t)rng.nextInt(100 - s);\n        }\n    }\n\n    int bestIdx = 0;\n    ll bestScore = LLONG_MIN;\n\n    for (int li = 0; li < (int)layouts.size(); li++) {\n        ll total = 0;\n\n        for (int k = 0; k < K; k++) {\n            Board b;\n\n            for (int s = 0; s < 100; s++) {\n                b.placeRank(ranks[k][s], flav[s]);\n\n                if (s == 99) break;\n\n                int d = greedyDir(b, s, layouts[li]);\n                b.tilt(d);\n            }\n\n            total += finalScoreNum(b);\n        }\n\n        if (total > bestScore) {\n            bestScore = total;\n            bestIdx = li;\n        }\n    }\n\n    return bestIdx;\n}\n\ndouble exactValue(const Board& b, int step);\n\ndouble exactDirValue(const Board& b, int step, int dir) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    Board bb = b;\n    bb.tilt(dir);\n\n    int emp[100];\n    int m = bb.getEmpties(emp);\n\n    if (m == 0) return (double)finalScoreNum(bb);\n\n    double sum = 0.0;\n\n    for (int i = 0; i < m; i++) {\n        Board nb = bb;\n        nb.placeCell(emp[i], flav[step + 1]);\n        sum += exactValue(nb, step + 1);\n    }\n\n    return sum / m;\n}\n\ndouble exactValue(const Board& b, int step) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        best = max(best, exactDirValue(b, step, d));\n    }\n\n    return best;\n}\n\nint exactBestDir(const Board& b, int step) {\n    int bestD = 0;\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        double v = exactDirValue(b, step, d);\n        if (v > best) {\n            best = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nstruct BeamNode {\n    Board b;\n    ll val;\n};\n\nvoid addBeamCandidate(BeamNode next[], int& cnt, int BW, const Board& b, ll val) {\n    if (cnt < BW) {\n        next[cnt].b = b;\n        next[cnt].val = val;\n        cnt++;\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < BW; i++) {\n        if (next[i].val < next[worst].val) worst = i;\n    }\n\n    if (val > next[worst].val) {\n        next[worst].b = b;\n        next[worst].val = val;\n    }\n}\n\nll simulateBeam(const Board& start, int step, const uint8_t ranks[], const Layout& L, int BW) {\n    BeamNode beam[2], nxt[2];\n\n    int bc = 1;\n    beam[0].b = start;\n    beam[0].val = 0;\n\n    for (int s = step + 1; s < 100; s++) {\n        int nc = 0;\n        ll bestFinal = -1;\n\n        for (int i = 0; i < bc; i++) {\n            Board placed = beam[i].b;\n            placed.placeRank(ranks[s], flav[s]);\n\n            if (s == 99) {\n                bestFinal = max(bestFinal, finalScoreNum(placed));\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    Board nb = placed;\n                    nb.tilt(d);\n                    ll v = evalBoard(nb, s, L);\n                    addBeamCandidate(nxt, nc, BW, nb, v);\n                }\n            }\n        }\n\n        if (s == 99) return bestFinal;\n\n        bc = nc;\n        for (int i = 0; i < bc; i++) beam[i] = nxt[i];\n    }\n\n    return finalScoreNum(start);\n}\n\nint decideMove(const Board& b, int step, const Layout& L, RNG& rng) {\n    if (step >= 99) return 0;\n\n    int rem = 99 - step;\n    double el = elapsedSec();\n\n    // Exact expectimax for the last few moves.\n    if (rem <= 5 && el < 1.72) {\n        return exactBestDir(b, step);\n    }\n\n    if (el > 1.84) {\n        return greedyDir(b, step, L);\n    }\n\n    Board first[4];\n    for (int d = 0; d < 4; d++) {\n        first[d] = b;\n        first[d].tilt(d);\n    }\n\n    int BW = (rem <= 25 ? 2 : 1);\n    int work = (BW == 1 ? 520 : 360);\n    int R = max(4, min(60, work / max(1, rem)));\n\n    if (el > 1.70) R = max(2, R / 3);\n    else if (el > 1.50) R = max(3, R / 2);\n\n    ll scores[4] = {};\n    uint8_t ranks[100];\n\n    int done = 0;\n\n    for (int it = 0; it < R; it++) {\n        if (it > 0 && (it & 3) == 0 && elapsedSec() > 1.86) break;\n\n        for (int s = step + 1; s < 100; s++) {\n            ranks[s] = (uint8_t)rng.nextInt(100 - s);\n        }\n\n        for (int d = 0; d < 4; d++) {\n            scores[d] += simulateBeam(first[d], step, ranks, L, BW);\n        }\n\n        done++;\n    }\n\n    if (done == 0) {\n        return greedyDir(b, step, L);\n    }\n\n    int bestD = 0;\n    ll bestScore = LLONG_MIN;\n    ll bestHeur = LLONG_MIN;\n\n    for (int d = 0; d < 4; d++) {\n        ll h = evalBoard(first[d], step, L);\n\n        if (scores[d] > bestScore || (scores[d] == bestScore && h > bestHeur)) {\n            bestScore = scores[d];\n            bestHeur = h;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    initTables();\n\n    for (int i = 0; i < 100; i++) {\n        if (!(cin >> flav[i])) return 0;\n        totalCnt[flav[i]]++;\n    }\n\n    int suf[4] = {};\n    for (int i = 99; i >= 0; i--) {\n        for (int f = 1; f <= 3; f++) remAfter[i][f] = suf[f];\n        suf[flav[i]]++;\n    }\n\n    generateLayouts();\n    int layoutIdx = chooseLayout();\n    Layout layout = layouts[layoutIdx];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < 100; i++) {\n        seed ^= (uint64_t)(flav[i] + 1237 * i);\n        seed *= 0xbf58476d1ce4e5b9ULL;\n    }\n\n    RNG rng(seed ^ 0xdeadbeefcafebabeULL);\n\n    Board board;\n    const char dc[4] = {'F', 'B', 'L', 'R'};\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        board.placeRank(p - 1, flav[t]);\n\n        int dir;\n        if (t == 99) {\n            dir = 0;\n        } else {\n            dir = decideMove(board, t, layout, rng);\n        }\n\n        board.tilt(dir);\n\n        cout << dc[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nconst int MAXN = 100;\nusing Row = array<ull, 2>;\n\nint M;\ndouble EPS, QV;\n\nint Ncur, Bcur, Lcur, Fcur;\nint POSBIN[MAXN];\nint FIDX[10][10];\nvector<int> PAIRCNT;\n\ndouble PMF[MAXN][MAXN];\ndouble NEGLOGP[MAXN][MAXN];\ndouble edgePenalty = 0.0;\n\nstruct Candidate {\n    uint32_t mask;\n    array<unsigned char, MAXN> deg;\n    int sum;\n};\n\nstruct Codeword {\n    uint32_t mask;\n    array<unsigned char, MAXN> deg;\n    vector<Row> rows;\n    array<double, MAXN> mixNeg;\n    vector<int> blockCnt;\n};\n\nstruct QueryFeat {\n    array<int, MAXN> degSorted;\n    array<int, MAXN> hist;\n    vector<Row> rows;\n    vector<int> blockCnt;\n};\n\nstruct Config {\n    double alpha; // sorted degree NLL weight\n    double wb;    // block edge feature weight\n    double we;    // aligned edge hamming weight\n};\n\nstruct TrainResult {\n    Config cfg;\n    int err;\n    int samples;\n};\n\nvector<Codeword> codes;\nConfig bestCfg{0.5, 0.0, 0.0};\n\ninline int thresholdBit(uint32_t mask, int idx, int B, int N) {\n    int b = (long long)idx * B / N;\n    return (mask >> b) & 1u;\n}\n\ninline void setEdge(vector<Row>& rows, int i, int j) {\n    rows[i][j >> 6] |= 1ULL << (j & 63);\n    rows[j][i >> 6] |= 1ULL << (i & 63);\n}\n\ninline bool getEdge(const vector<Row>& rows, int i, int j) {\n    return (rows[i][j >> 6] >> (j & 63)) & 1ULL;\n}\n\ninline double rnd01(mt19937_64& rng) {\n    return (rng() >> 11) * (1.0 / 9007199254740992.0);\n}\n\nvoid thresholdDegrees(uint32_t mask, int B, int N, array<int, MAXN>& degOrig) {\n    int cnt = 0;\n    for (int i = N - 1; i >= 0; --i) {\n        int bit = thresholdBit(mask, i, B, N);\n        if (bit) degOrig[i] = i + cnt;\n        else degOrig[i] = cnt;\n        if (bit) cnt++;\n    }\n}\n\nvector<Candidate> buildPool(int N, int B) {\n    vector<Candidate> pool;\n    int total = 1 << B;\n    pool.reserve(total);\n\n    unordered_set<string> seen;\n    seen.reserve(total * 2);\n\n    for (uint32_t mask = 0; mask < (uint32_t)total; ++mask) {\n        array<int, MAXN> dorig{};\n        thresholdDegrees(mask, B, N, dorig);\n\n        Candidate c;\n        c.mask = mask;\n        c.deg.fill(0);\n        c.sum = 0;\n        for (int i = 0; i < N; ++i) {\n            c.deg[i] = (unsigned char)dorig[i];\n            c.sum += dorig[i];\n        }\n        sort(c.deg.begin(), c.deg.begin() + N);\n\n        string key;\n        key.resize(N);\n        for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n        if (seen.insert(key).second) {\n            pool.push_back(c);\n        }\n    }\n    return pool;\n}\n\ninline int dist2Deg(const array<unsigned char, MAXN>& a,\n                    const array<unsigned char, MAXN>& b,\n                    int N) {\n    int s = 0;\n    for (int i = 0; i < N; ++i) {\n        int d = (int)a[i] - (int)b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstruct Selection {\n    vector<int> idx;\n    int minD2;\n};\n\nSelection selectFarthest(const vector<Candidate>& pool, int N, int m, int improveIters) {\n    int P = (int)pool.size();\n    Selection res;\n    res.minD2 = 0;\n    if (P < m) return res;\n\n    vector<int> selected;\n    vector<int> minDist(P, INT_MAX);\n    vector<char> used(P, 0);\n\n    int start = 0;\n    for (int i = 1; i < P; ++i) {\n        if (pool[i].sum < pool[start].sum) start = i;\n    }\n\n    for (int it = 0; it < m; ++it) {\n        int id;\n        if (it == 0) {\n            id = start;\n        } else {\n            id = -1;\n            int best = -1;\n            for (int i = 0; i < P; ++i) {\n                if (!used[i] && minDist[i] > best) {\n                    best = minDist[i];\n                    id = i;\n                }\n            }\n        }\n\n        used[id] = 1;\n        selected.push_back(id);\n\n        for (int i = 0; i < P; ++i) {\n            if (!used[i]) {\n                int d = dist2Deg(pool[i].deg, pool[id].deg, N);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    for (int rep = 0; rep < improveIters; ++rep) {\n        vector<int> near(m, INT_MAX);\n        int curMin = INT_MAX;\n        int worstPos = -1;\n\n        for (int i = 0; i < m; ++i) {\n            for (int j = 0; j < m; ++j) if (i != j) {\n                int d = dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N);\n                near[i] = min(near[i], d);\n            }\n            if (near[i] < curMin) {\n                curMin = near[i];\n                worstPos = i;\n            }\n        }\n\n        int bestP = -1;\n        int bestMd = curMin;\n\n        for (int p = 0; p < P; ++p) if (!used[p]) {\n            int md = INT_MAX;\n            for (int i = 0; i < m; ++i) {\n                if (i == worstPos) continue;\n                int d = dist2Deg(pool[p].deg, pool[selected[i]].deg, N);\n                md = min(md, d);\n                if (md <= curMin) break;\n            }\n            if (md > bestMd) {\n                bestMd = md;\n                bestP = p;\n            }\n        }\n\n        if (bestP == -1) break;\n\n        used[selected[worstPos]] = 0;\n        selected[worstPos] = bestP;\n        used[bestP] = 1;\n    }\n\n    int md2 = INT_MAX;\n    for (int i = 0; i < m; ++i) {\n        for (int j = i + 1; j < m; ++j) {\n            md2 = min(md2, dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N));\n        }\n    }\n\n    res.idx = selected;\n    res.minD2 = md2;\n    return res;\n}\n\nvoid setupBlocks(int N) {\n    Lcur = min(10, N);\n    Fcur = 0;\n    for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) FIDX[i][j] = -1;\n\n    for (int a = 0; a < Lcur; ++a) {\n        for (int b = a; b < Lcur; ++b) {\n            FIDX[a][b] = FIDX[b][a] = Fcur++;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        POSBIN[i] = (long long)i * Lcur / N;\n        if (POSBIN[i] >= Lcur) POSBIN[i] = Lcur - 1;\n    }\n\n    PAIRCNT.assign(Fcur, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            int f = FIDX[POSBIN[i]][POSBIN[j]];\n            PAIRCNT[f]++;\n        }\n    }\n}\n\nvector<int> computeBlockCounts(const vector<Row>& rows) {\n    vector<int> cnt(Fcur, 0);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, i, j)) {\n                int f = FIDX[POSBIN[i]][POSBIN[j]];\n                cnt[f]++;\n            }\n        }\n    }\n    return cnt;\n}\n\nvector<double> binomDist(int n, double p) {\n    vector<double> d(n + 1, 0.0);\n    if (n == 0) {\n        d[0] = 1.0;\n        return d;\n    }\n    double q = 1.0 - p;\n    d[0] = pow(q, n);\n    for (int k = 0; k < n; ++k) {\n        if (q == 0.0) {\n            d[k + 1] = (k + 1 == n ? 1.0 : 0.0);\n        } else {\n            d[k + 1] = d[k] * (double)(n - k) / (double)(k + 1) * p / q;\n        }\n    }\n    return d;\n}\n\nvoid setupPMF(int N) {\n    vector<vector<double>> keep(N), flip(N);\n    for (int n = 0; n <= N - 1; ++n) {\n        keep[n] = binomDist(n, 1.0 - EPS);\n        flip[n] = binomDist(n, EPS);\n    }\n\n    for (int d = 0; d <= N - 1; ++d) {\n        for (int x = 0; x <= N - 1; ++x) PMF[d][x] = 0.0;\n\n        int absent = N - 1 - d;\n        for (int y = 0; y <= d; ++y) {\n            for (int z = 0; z <= absent; ++z) {\n                PMF[d][y + z] += keep[d][y] * flip[absent][z];\n            }\n        }\n\n        for (int x = 0; x <= N - 1; ++x) {\n            double p = max(PMF[d][x], 1e-300);\n            NEGLOGP[d][x] = -log(p);\n        }\n    }\n}\n\nCodeword buildCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = cand.mask;\n    c.deg = cand.deg;\n    c.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : c.rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> dorig{};\n    thresholdDegrees(c.mask, Bcur, Ncur, dorig);\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (dorig[a] != dorig[b]) return dorig[a] < dorig[b];\n        return a < b;\n    });\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            int u = ord[a], v = ord[b];\n            int later = max(u, v);\n            if (thresholdBit(c.mask, later, Bcur, Ncur)) {\n                setEdge(c.rows, a, b);\n            }\n        }\n    }\n\n    c.mixNeg.fill(0.0);\n    for (int x = 0; x < Ncur; ++x) {\n        double p = 0.0;\n        for (int i = 0; i < Ncur; ++i) {\n            p += PMF[c.deg[i]][x];\n        }\n        p /= Ncur;\n        c.mixNeg[x] = -log(max(p, 1e-300));\n    }\n\n    c.blockCnt = computeBlockCounts(c.rows);\n    return c;\n}\n\nQueryFeat makeFeatureFromRows(const vector<Row>& rowsIn, const array<int, MAXN>& deg) {\n    QueryFeat q;\n    q.hist.fill(0);\n    q.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : q.rows) r = {0ULL, 0ULL};\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < Ncur; ++i) {\n        q.degSorted[i] = deg[ord[i]];\n        q.hist[q.degSorted[i]]++;\n    }\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            if (getEdge(rowsIn, ord[a], ord[b])) {\n                setEdge(q.rows, a, b);\n            }\n        }\n    }\n\n    q.blockCnt = computeBlockCounts(q.rows);\n    return q;\n}\n\nQueryFeat featureFromString(const string& s) {\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    int pos = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (s[pos++] == '1') {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    return makeFeatureFromRows(rows, deg);\n}\n\nQueryFeat simulateQuery(int k, mt19937_64& rng) {\n    const Codeword& cw = codes[k];\n\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            int g = thresholdBit(cw.mask, j, Bcur, Ncur);\n            int h = g;\n            if (rnd01(rng) < EPS) h ^= 1;\n            if (h) {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    array<int, MAXN> perm{};\n    for (int i = 0; i < Ncur; ++i) perm[i] = i;\n    for (int i = Ncur - 1; i >= 1; --i) {\n        int r = rng() % (i + 1);\n        swap(perm[i], perm[r]);\n    }\n\n    vector<Row> shuf(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : shuf) r = {0ULL, 0ULL};\n    array<int, MAXN> deg2{};\n    deg2.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        deg2[i] = deg[perm[i]];\n    }\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, perm[i], perm[j])) {\n                setEdge(shuf, i, j);\n            }\n        }\n    }\n\n    return makeFeatureFromRows(shuf, deg2);\n}\n\nint edgeMismatch(const vector<Row>& A, const vector<Row>& B) {\n    int s = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        s += __builtin_popcountll(A[i][0] ^ B[i][0]);\n        if (Ncur > 64) s += __builtin_popcountll(A[i][1] ^ B[i][1]);\n    }\n    return s / 2;\n}\n\nstruct Components {\n    double sortedCost;\n    double mixCost;\n    double blockCost;\n    int edgeMis;\n};\n\nComponents computeComponents(const QueryFeat& q, const Codeword& c) {\n    Components comp{0.0, 0.0, 0.0, 0};\n\n    for (int i = 0; i < Ncur; ++i) {\n        comp.sortedCost += NEGLOGP[c.deg[i]][q.degSorted[i]];\n    }\n\n    for (int x = 0; x < Ncur; ++x) {\n        if (q.hist[x]) comp.mixCost += q.hist[x] * c.mixNeg[x];\n    }\n\n    for (int f = 0; f < Fcur; ++f) {\n        int pairs = PAIRCNT[f];\n        if (pairs <= 0) continue;\n        double mu = EPS * pairs + QV * c.blockCnt[f];\n        double var = pairs * EPS * (1.0 - EPS) + 1.0;\n        double diff = q.blockCnt[f] - mu;\n        comp.blockCost += diff * diff / (2.0 * var);\n    }\n\n    comp.edgeMis = edgeMismatch(q.rows, c.rows);\n    return comp;\n}\n\ninline double scoreWithConfig(const Components& comp, const Config& cfg) {\n    double degCost = cfg.alpha * comp.sortedCost + (1.0 - cfg.alpha) * comp.mixCost;\n    return degCost + cfg.wb * comp.blockCost + cfg.we * edgePenalty * comp.edgeMis;\n}\n\nvector<Config> buildConfigs() {\n    vector<Config> cfgs;\n    cfgs.push_back({0.5, 0.0, 0.0}); // conservative default\n\n    vector<double> alphas = {0.0, 0.25, 0.5, 0.75, 1.0};\n    vector<double> wbs = {0.0, 0.2, 0.5, 1.0, 2.0};\n    vector<double> wes = {0.0, 0.02, 0.05, 0.1, 0.2};\n\n    for (double a : alphas) {\n        for (double wb : wbs) {\n            for (double we : wes) {\n                cfgs.push_back({a, wb, we});\n            }\n        }\n    }\n    return cfgs;\n}\n\nTrainResult trainDecoder() {\n    vector<Config> cfgs = buildConfigs();\n    int C = cfgs.size();\n\n    int R = 3;\n    if (EPS > 0.25) R = 5;\n    else if (EPS > 0.12) R = 4;\n    if (M <= 20) R += 4;\n    else if (M <= 50) R += 1;\n\n    int samples = M * R;\n    vector<int> errs(C, 0);\n\n    mt19937_64 rng(1234567ULL + (uint64_t)M * 1009ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 9176ULL\n                   + (uint64_t)Ncur * 1000003ULL);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n\n            vector<double> best(C, 1e300);\n            vector<int> bestId(C, -1);\n\n            for (int k = 0; k < M; ++k) {\n                Components comp = computeComponents(q, codes[k]);\n                for (int ci = 0; ci < C; ++ci) {\n                    double sc = scoreWithConfig(comp, cfgs[ci]);\n                    if (sc < best[ci]) {\n                        best[ci] = sc;\n                        bestId[ci] = k;\n                    }\n                }\n            }\n\n            for (int ci = 0; ci < C; ++ci) {\n                if (bestId[ci] != trueId) errs[ci]++;\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int ci = 1; ci < C; ++ci) {\n        if (errs[ci] < errs[bestC]) bestC = ci;\n    }\n\n    return {cfgs[bestC], errs[bestC], samples};\n}\n\nint predict(const QueryFeat& q) {\n    double best = 1e300;\n    int ans = 0;\n\n    for (int k = 0; k < M; ++k) {\n        Components comp = computeComponents(q, codes[k]);\n        double sc = scoreWithConfig(comp, bestCfg);\n        if (sc < best) {\n            best = sc;\n            ans = k;\n        }\n    }\n    return ans;\n}\n\nstring graphString(uint32_t mask) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(thresholdBit(mask, j, Bcur, Ncur) ? '1' : '0');\n        }\n    }\n    return s;\n}\n\nint chooseN() {\n    int minN = 4;\n    while (minN < 100 && (1LL << (minN - 1)) < M) minN++;\n\n    double r = sqrt(EPS * (1.0 - EPS)) / QV;\n    int nest = (int)ceil(4.0 + 38.0 * r * sqrt(M / 100.0) + 0.03 * M);\n    nest = max(minN, min(100, nest));\n\n    int start, end;\n    if (EPS < 0.05) {\n        start = minN;\n        end = min(100, max(nest + 15, minN + 8));\n    } else {\n        start = max(minN, nest - 20);\n        end = min(100, nest + 25);\n        if (EPS > 0.34) end = 100;\n    }\n\n    vector<int> ns;\n    for (int n = start; n <= end;) {\n        ns.push_back(n);\n        if (n < 35) n++;\n        else if (n < 75) n += 2;\n        else n += 4;\n    }\n    ns.push_back(minN);\n    ns.push_back(nest);\n    ns.push_back(100);\n    sort(ns.begin(), ns.end());\n    ns.erase(unique(ns.begin(), ns.end()), ns.end());\n\n    double target = 3.25 + 0.12 * log((double)M);\n    if (EPS > 0.25) target += 0.15;\n    if (EPS < 0.03) target -= 0.75;\n    else if (EPS < 0.07) target -= 0.30;\n    if (M <= 20) target -= 0.15;\n    target = max(2.4, target);\n\n    for (int n : ns) {\n        if (n < minN || n > 100) continue;\n        int Bs = min(n, (n >= 80 ? 12 : 11));\n        vector<Candidate> pool = buildPool(n, Bs);\n        if ((int)pool.size() < M) continue;\n\n        Selection sel = selectFarthest(pool, n, M, 0);\n        if (sel.idx.empty()) continue;\n\n        double sigma = sqrt((n - 1) * EPS * (1.0 - EPS));\n        double z = QV * sqrt((double)sel.minD2) / (2.0 * sigma);\n        if (z >= target) return n;\n    }\n\n    return 100;\n}\n\nvoid buildThresholdSolution(int initialN) {\n    int chosenN = initialN;\n    int attempts = 0;\n\n    while (true) {\n        Ncur = chosenN;\n        Bcur = min(Ncur, (Ncur >= 70 ? 14 : (Ncur >= 35 ? 13 : 12)));\n\n        vector<Candidate> pool = buildPool(Ncur, Bcur);\n        if ((int)pool.size() < M) {\n            chosenN++;\n            continue;\n        }\n\n        Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n        setupBlocks(Ncur);\n        setupPMF(Ncur);\n        edgePenalty = log((1.0 - EPS) / EPS);\n\n        codes.clear();\n        codes.reserve(M);\n        for (int id : sel.idx) {\n            codes.push_back(buildCodeword(pool[id]));\n        }\n\n        TrainResult tr = trainDecoder();\n        bestCfg = tr.cfg;\n\n        int allowed;\n        if (EPS < 0.05) allowed = max(4, tr.samples / 50);\n        else allowed = max(3, tr.samples / 100);\n\n        if (tr.err > allowed && chosenN < 100 && attempts < 3) {\n            int inc = (chosenN < 50 ? 10 : 6);\n            if (EPS > 0.3) inc = max(inc, 8);\n            chosenN = min(100, chosenN + inc);\n            attempts++;\n            continue;\n        }\n\n        break;\n    }\n}\n\n// Exact solver for epsilon = 0\nstruct ExactSolver {\n    int n, T;\n    vector<string> reps;\n    vector<int> cmap;\n    vector<array<int, 15>> trans;\n\n    int pairPos[6][6];\n\n    void prepareTrans(int n_) {\n        n = n_;\n        T = n * (n - 1) / 2;\n        for (int i = 0; i < 6; ++i) for (int j = 0; j < 6; ++j) pairPos[i][j] = -1;\n\n        int p = 0;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                pairPos[i][j] = pairPos[j][i] = p++;\n            }\n        }\n\n        vector<int> perm(n);\n        iota(perm.begin(), perm.end(), 0);\n        trans.clear();\n\n        do {\n            array<int, 15> tr{};\n            int pos = 0;\n            for (int i = 0; i < n; ++i) {\n                for (int j = i + 1; j < n; ++j) {\n                    int a = perm[i], b = perm[j];\n                    tr[pos++] = pairPos[a][b];\n                }\n            }\n            trans.push_back(tr);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    int canonicalMask(int mask) const {\n        int best = INT_MAX;\n        for (const auto& tr : trans) {\n            int val = 0;\n            for (int i = 0; i < T; ++i) {\n                val = (val << 1) | ((mask >> tr[i]) & 1);\n            }\n            if (val < best) best = val;\n        }\n        return best;\n    }\n\n    string maskToString(int mask) const {\n        string s;\n        s.resize(T);\n        for (int i = 0; i < T; ++i) {\n            s[i] = ((mask >> i) & 1) ? '1' : '0';\n        }\n        return s;\n    }\n\n    int stringToMask(const string& s) const {\n        int mask = 0;\n        for (int i = 0; i < T; ++i) {\n            if (s[i] == '1') mask |= 1 << i;\n        }\n        return mask;\n    }\n\n    void generate(int M) {\n        for (int nn = 4; nn <= 6; ++nn) {\n            prepareTrans(nn);\n            reps.clear();\n            cmap.assign(1 << T, -1);\n\n            for (int mask = 0; mask < (1 << T); ++mask) {\n                int c = canonicalMask(mask);\n                if (cmap[c] == -1) {\n                    int id = (int)reps.size();\n                    cmap[c] = id;\n                    reps.push_back(maskToString(mask));\n                    if ((int)reps.size() == M) return;\n                }\n            }\n        }\n    }\n\n    int decode(const string& s) const {\n        int mask = stringToMask(s);\n        int c = canonicalMask(mask);\n        if (0 <= c && c < (int)cmap.size() && cmap[c] != -1) return cmap[c];\n        return 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> M >> EPS;\n    QV = 1.0 - 2.0 * EPS;\n\n    if (EPS < 1e-12) {\n        ExactSolver ex;\n        ex.generate(M);\n\n        cout << ex.n << '\\n';\n        for (int i = 0; i < M; ++i) {\n            cout << ex.reps[i] << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            cin >> H;\n            int ans = ex.decode(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n        return 0;\n    }\n\n    int initialN = chooseN();\n    buildThresholdSolution(initialN);\n\n    cout << Ncur << '\\n';\n    for (int i = 0; i < M; ++i) {\n        cout << graphString(codes[i].mask) << '\\n';\n    }\n    cout.flush();\n\n    for (int q = 0; q < 100; ++q) {\n        string H;\n        cin >> H;\n        QueryFeat feat = featureFromString(H);\n        int ans = predict(feat);\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#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() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    static constexpr int INF = 1100000000;\n    static constexpr int UNREACH = 1000000000;\n    static constexpr long long DISCONN_SCORE = 4000000000000000LL;\n\n    struct Edge {\n        int u, v, w;\n        int cell;\n        uint32_t key;\n    };\n    struct Arc {\n        int to, w, id;\n    };\n    struct ScoreRes {\n        long long total;\n        vector<long long> day;\n    };\n    struct State {\n        vector<int> assign;\n        vector<int> count;\n        vector<vector<int>> dayEdges;\n        vector<int> pos;\n        vector<int> inc;\n        vector<double> dayImp;\n        vector<int> cellCnt;\n        vector<int> cutCnt;\n        vector<long long> dayScore;\n        long long totalScore = 0;\n    };\n    struct Cand {\n        int type = 0; // 1: move, 2: swap\n        int e = -1, f = -1;\n        double cheap = 1e100;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Arc>> adj;\n    vector<int> xs, ys;\n    vector<int> origDist;\n    vector<long long> load;\n    vector<vector<int>> cutAdj;\n    vector<double> stretch;\n    vector<double> impNorm;\n    vector<int> target;\n    vector<int> optSources;\n\n    static constexpr int G = 16;\n    static constexpr int C = G * G;\n    vector<vector<int>> neighCells;\n    vector<unsigned char> nearCell;\n\n    RNG rng;\n    chrono::steady_clock::time_point startTime;\n    double localEndTime = 5.65;\n\n    vector<pair<int, int>> heapBuf;\n    vector<int> distBuf;\n    vector<int> bfsVis, bfsQ;\n    int bfsStamp = 1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static uint64_t mix64(uint64_t z) {\n        z += 0x9e3779b97f4a7c15ull;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n\n    uint32_t zOrder(int x, int y) const {\n        uint32_t r = 0;\n        for (int b = 0; b < 11; b++) {\n            r |= ((x >> b) & 1u) << (2 * b);\n            r |= ((y >> b) & 1u) << (2 * b + 1);\n        }\n        return r;\n    }\n\n    int edgeCellFromSum(int sx, int sy) const {\n        int cx = min(G - 1, (sx * G) / 2001);\n        int cy = min(G - 1, (sy * G) / 2001);\n        return cx * G + cy;\n    }\n\n    void setupCells() {\n        neighCells.assign(C, {});\n        nearCell.assign(C * C, 0);\n        for (int cx = 0; cx < G; cx++) {\n            for (int cy = 0; cy < G; cy++) {\n                int c = cx * G + cy;\n                for (int dx = -1; dx <= 1; dx++) {\n                    for (int dy = -1; dy <= 1; dy++) {\n                        int nx = cx + dx, ny = cy + dy;\n                        if (0 <= nx && nx < G && 0 <= ny && ny < G) {\n                            int nc = nx * G + ny;\n                            neighCells[c].push_back(nc);\n                            nearCell[c * C + nc] = 1;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    void readInput() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        adj.assign(N, {});\n        uint64_t seed = 123456789;\n\n        for (int i = 0; i < M; i++) {\n            int u, v, w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i].u = u;\n            edges[i].v = v;\n            edges[i].w = w;\n            edges[i].cell = 0;\n            edges[i].key = 0;\n            adj[u].push_back({v, w, i});\n            adj[v].push_back({u, w, i});\n            seed ^= mix64((uint64_t)(u + 1) * 1000003ull + (uint64_t)(v + 1) * 1009ull + w);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> xs[i] >> ys[i];\n            seed ^= mix64((uint64_t)(xs[i] + 1) * 10007ull + ys[i] + i * 97ull);\n        }\n        rng.x = seed ? seed : 88172645463325252ull;\n\n        setupCells();\n\n        for (int i = 0; i < M; i++) {\n            int u = edges[i].u, v = edges[i].v;\n            int sx = xs[u] + xs[v];\n            int sy = ys[u] + ys[v];\n            edges[i].cell = edgeCellFromSum(sx, sy);\n            int hx = min(2047, (sx * 2047) / 2000);\n            int hy = min(2047, (sy * 2047) / 2000);\n            edges[i].key = zOrder(hx, hy);\n        }\n\n        target.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) target[d]++;\n\n        distBuf.assign(N, INF);\n        bfsVis.assign(N, 0);\n        bfsQ.assign(N, 0);\n        heapBuf.reserve(max(10000, 4 * M + 2 * N));\n    }\n\n    void heapPush(int d, int v) {\n        pair<int, int> val = {d, v};\n        int i = (int)heapBuf.size();\n        heapBuf.push_back(val);\n        while (i > 0) {\n            int p = (i - 1) >> 1;\n            if (heapBuf[p].first <= val.first) break;\n            heapBuf[i] = heapBuf[p];\n            i = p;\n        }\n        heapBuf[i] = val;\n    }\n\n    pair<int, int> heapPop() {\n        pair<int, int> res = heapBuf[0];\n        pair<int, int> val = heapBuf.back();\n        heapBuf.pop_back();\n        if (!heapBuf.empty()) {\n            int i = 0;\n            int n = (int)heapBuf.size();\n            while (true) {\n                int l = i * 2 + 1;\n                if (l >= n) break;\n                int r = l + 1;\n                int c = l;\n                if (r < n && heapBuf[r].first < heapBuf[l].first) c = r;\n                if (heapBuf[c].first >= val.first) break;\n                heapBuf[i] = heapBuf[c];\n                i = c;\n            }\n            heapBuf[i] = val;\n        }\n        return res;\n    }\n\n    void dijkstraOriginalParent(\n        int src,\n        vector<int>& dist,\n        vector<int>& parV,\n        vector<int>& parE,\n        vector<int>& order\n    ) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        order.clear();\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            order.push_back(v);\n            for (const auto& a : adj[v]) {\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    parV[a.to] = v;\n                    parE[a.to] = a.id;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    void dijkstraDaySource(int src, int day, const vector<int>& assign, vector<int>& dist) {\n        fill(dist.begin(), dist.end(), INF);\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            for (const auto& a : adj[v]) {\n                if (assign[a.id] == day) continue;\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    int dijkstraBetweenSkipEdge(int src, int dst, int banned) {\n        fill(distBuf.begin(), distBuf.end(), INF);\n        heapBuf.clear();\n\n        distBuf[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != distBuf[v]) continue;\n            if (v == dst) return du;\n            for (const auto& a : adj[v]) {\n                if (a.id == banned) continue;\n                int nd = du + a.w;\n                if (nd < distBuf[a.to]) {\n                    distBuf[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n        return INF;\n    }\n\n    void computeOriginalAndLoad() {\n        origDist.assign(N * N, INF);\n        load.assign(M, 0);\n\n        vector<int> dist(N), parV(N), parE(N), order;\n        vector<int> sub(N);\n\n        for (int s = 0; s < N; s++) {\n            dijkstraOriginalParent(s, dist, parV, parE, order);\n            memcpy(&origDist[s * N], dist.data(), sizeof(int) * N);\n\n            fill(sub.begin(), sub.end(), 1);\n            for (int ii = (int)order.size() - 1; ii >= 0; ii--) {\n                int v = order[ii];\n                int e = parE[v];\n                if (e != -1) {\n                    load[e] += sub[v];\n                    sub[parV[v]] += sub[v];\n                }\n            }\n        }\n    }\n\n    void detectTwoEdgeCuts() {\n        cutAdj.assign(M, {});\n        vector<int> tin(N), low(N);\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), 0);\n            fill(low.begin(), low.end(), 0);\n            int timer = 0;\n\n            auto dfs = [&](auto&& self, int v, int pe) -> void {\n                tin[v] = low[v] = ++timer;\n                for (const auto& a : adj[v]) {\n                    if (a.id == banned || a.id == pe) continue;\n                    int to = a.to;\n                    if (!tin[to]) {\n                        self(self, to, a.id);\n                        low[v] = min(low[v], low[to]);\n                        if (low[to] > tin[v]) {\n                            int f = a.id;\n                            if (banned < f) {\n                                cutAdj[banned].push_back(f);\n                                cutAdj[f].push_back(banned);\n                            }\n                        }\n                    } else {\n                        low[v] = min(low[v], tin[to]);\n                    }\n                }\n            };\n\n            dfs(dfs, 0, -1);\n        }\n\n        for (auto& v : cutAdj) {\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n    }\n\n    void computeStretch() {\n        stretch.assign(M, 0.0);\n        const double deadline = 1.35;\n\n        for (int e = 0; e < M; e++) {\n            if (elapsed() > deadline) break;\n            int u = edges[e].u;\n            int v = edges[e].v;\n            int repl = dijkstraBetweenSkipEdge(u, v, e);\n            int base = origDist[u * N + v];\n            if (repl >= INF) {\n                stretch[e] = 5.0;\n            } else {\n                stretch[e] = max(0.0, (double)(repl - base) / max(1, base));\n                stretch[e] = min(stretch[e], 8.0);\n            }\n        }\n    }\n\n    void computeImportance() {\n        double sumLoad = 0.0;\n        for (auto x : load) sumLoad += (double)x;\n        double meanLoad = max(1.0, sumLoad / max(1, M));\n\n        double avgW = 0.0;\n        for (const auto& e : edges) avgW += e.w;\n        avgW /= max(1, M);\n\n        vector<double> raw(M);\n        double sumRaw = 0.0;\n\n        for (int e = 0; e < M; e++) {\n            double r = (double)load[e] + 0.05 * meanLoad + 1.0;\n            r *= 1.0 + 0.7 * min(5.0, stretch[e]);\n            r *= 1.0 + 0.03 * min(50, (int)cutAdj[e].size());\n            r *= 0.75 + 0.25 * sqrt(max(0.1, edges[e].w / avgW));\n            raw[e] = r;\n            sumRaw += r;\n        }\n\n        double meanRaw = max(1e-9, sumRaw / max(1, M));\n        impNorm.assign(M, 1.0);\n        for (int e = 0; e < M; e++) {\n            impNorm[e] = raw[e] / meanRaw;\n            impNorm[e] = min(60.0, max(0.03, impNorm[e]));\n        }\n    }\n\n    vector<int> selectSources(int P) {\n        P = min(P, N);\n        vector<pair<uint32_t, int>> ord;\n        ord.reserve(N);\n        for (int i = 0; i < N; i++) {\n            int hx = xs[i] * 2047 / 1000;\n            int hy = ys[i] * 2047 / 1000;\n            ord.push_back({zOrder(hx, hy), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        vector<int> res;\n        vector<char> used(N, 0);\n        for (int t = 0; t < P; t++) {\n            int idx = (int)(((long long)(2 * t + 1) * N) / (2 * P));\n            idx = min(idx, N - 1);\n            int v = ord[idx].second;\n            if (used[v]) {\n                for (int k = 0; k < N; k++) {\n                    int nv = ord[(idx + k) % N].second;\n                    if (!used[nv]) {\n                        v = nv;\n                        break;\n                    }\n                }\n            }\n            used[v] = 1;\n            res.push_back(v);\n        }\n        return res;\n    }\n\n    bool isConnectedSkip(const vector<int>& assign, int day, int extraSkip = -1) {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            fill(bfsVis.begin(), bfsVis.end(), 0);\n            bfsStamp = 1;\n        }\n\n        int head = 0, tail = 0;\n        bfsVis[0] = bfsStamp;\n        bfsQ[tail++] = 0;\n        int seen = 1;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            for (const auto& a : adj[v]) {\n                if (a.id == extraSkip) continue;\n                if (assign[a.id] == day) continue;\n                int to = a.to;\n                if (bfsVis[to] == bfsStamp) continue;\n                bfsVis[to] = bfsStamp;\n                bfsQ[tail++] = to;\n                seen++;\n            }\n        }\n        return seen == N;\n    }\n\n    long long computeDayScore(\n        const vector<int>& assign,\n        int day,\n        const vector<int>& sources,\n        int removedCount,\n        bool checkConn\n    ) {\n        if (removedCount == 0) return 0;\n        if (checkConn && !isConnectedSkip(assign, day, -1)) return DISCONN_SCORE;\n\n        long long sum = 0;\n        for (int s : sources) {\n            dijkstraDaySource(s, day, assign, distBuf);\n            int base = s * N;\n            for (int v = 0; v < N; v++) {\n                int d = distBuf[v];\n                int dd = (d >= INF ? UNREACH : d);\n                int diff = dd - origDist[base + v];\n                if (diff > 0) sum += diff;\n            }\n        }\n        return sum;\n    }\n\n    ScoreRes scoreAll(const vector<int>& assign, const vector<int>& sources) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n            cnt[assign[e]]++;\n        }\n\n        ScoreRes r;\n        r.total = 0;\n        r.day.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            r.day[d] = computeDayScore(assign, d, sources, cnt[d], true);\n            r.total += r.day[d];\n        }\n        return r;\n    }\n\n    void shuffleVec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int localCellCount(const vector<int>& cellCnt, int day, int cell) const {\n        int s = 0;\n        int base = day * C;\n        for (int nb : neighCells[cell]) s += cellCnt[base + nb];\n        return s;\n    }\n\n    vector<int> buildHilbertLike(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0 || variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                int ax = xs[edges[a].u] + xs[edges[a].v];\n                int bx = xs[edges[b].u] + xs[edges[b].v];\n                if (ax != bx) return ax < bx;\n                int ay = ys[edges[a].u] + ys[edges[a].v];\n                int by = ys[edges[b].u] + ys[edges[b].v];\n                return ay < by;\n            });\n        }\n\n        vector<int> assign(M, 0);\n        vector<int> perm(D);\n        for (int b = 0; b < M; b += D) {\n            iota(perm.begin(), perm.end(), 0);\n            if (variant == 0) {\n                rotate(perm.begin(), perm.begin() + ((b / D) % D), perm.end());\n            } else {\n                shuffleVec(perm);\n            }\n            for (int i = 0; i < D && b + i < M; i++) {\n                assign[order[b + i]] = perm[i];\n            }\n        }\n        return assign;\n    }\n\n    vector<int> buildRandomBalanced() {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffleVec(order);\n\n        vector<int> days;\n        days.reserve(M);\n        for (int d = 0; d < D; d++) {\n            for (int i = 0; i < target[d]; i++) days.push_back(d);\n        }\n        shuffleVec(days);\n\n        vector<int> assign(M);\n        for (int i = 0; i < M; i++) assign[order[i]] = days[i];\n        return assign;\n    }\n\n    vector<int> buildGreedy(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (impNorm[a] != impNorm[b]) return impNorm[a] > impNorm[b];\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (cutAdj[a].size() != cutAdj[b].size()) return cutAdj[a].size() > cutAdj[b].size();\n                return impNorm[a] > impNorm[b];\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 3) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            vector<double> key(M);\n            for (int e = 0; e < M; e++) key[e] = impNorm[e] * (0.6 + 0.8 * rng.nextDouble());\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        }\n\n        vector<int> assign(M, -1);\n        vector<int> count(D, 0);\n        vector<int> inc(N * D, 0);\n        vector<double> dayImp(D, 0.0);\n        vector<int> cellCnt(D * C, 0);\n        vector<int> cutCnt(M * D, 0);\n\n        for (int e : order) {\n            int u = edges[e].u, v = edges[e].v;\n            int cell = edges[e].cell;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(D);\n\n            for (int d = 0; d < D; d++) {\n                if (count[d] >= K) continue;\n\n                int adjCnt = inc[u * D + d] + inc[v * D + d];\n                int loc = localCellCount(cellCnt, d, cell);\n                int cut = cutCnt[e * D + d];\n\n                double over = max(0, count[d] + 1 - target[d]);\n                double cost = 100000000.0 * cut;\n                cost += 25.0 * adjCnt;\n                cost += 2.0 * loc;\n                cost += 4.0 * impNorm[e] * (dayImp[d] / max(1, target[d]));\n                if (count[d] >= target[d]) cost += 600.0 * over * over;\n                else cost += 0.1 * (double)count[d] / max(1, target[d]);\n                cost += 0.01 * rng.nextDouble();\n\n                cand.push_back({cost, d});\n            }\n\n            if (cand.empty()) {\n                // Should never happen because total capacity is sufficient.\n                int best = min_element(count.begin(), count.end()) - count.begin();\n                cand.push_back({0.0, best});\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int chosen = -1;\n            for (auto [cost, d] : cand) {\n                if (isConnectedSkip(assign, d, e)) {\n                    chosen = d;\n                    break;\n                }\n            }\n            if (chosen == -1) chosen = cand[0].second;\n\n            assign[e] = chosen;\n            count[chosen]++;\n            inc[u * D + chosen]++;\n            inc[v * D + chosen]++;\n            dayImp[chosen] += impNorm[e];\n            cellCnt[chosen * C + cell]++;\n            for (int g : cutAdj[e]) cutCnt[g * D + chosen]++;\n        }\n\n        return assign;\n    }\n\n    State buildState(const vector<int>& assign, const vector<int>& sources) {\n        State st;\n        st.assign = assign;\n        st.count.assign(D, 0);\n        st.dayEdges.assign(D, {});\n        st.pos.assign(M, -1);\n        st.inc.assign(N * D, 0);\n        st.dayImp.assign(D, 0.0);\n        st.cellCnt.assign(D * C, 0);\n        st.cutCnt.assign(M * D, 0);\n        st.dayScore.assign(D, 0);\n        st.totalScore = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            st.pos[e] = (int)st.dayEdges[d].size();\n            st.dayEdges[d].push_back(e);\n            st.count[d]++;\n            st.inc[edges[e].u * D + d]++;\n            st.inc[edges[e].v * D + d]++;\n            st.dayImp[d] += impNorm[e];\n            st.cellCnt[d * C + edges[e].cell]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            for (int g : cutAdj[e]) {\n                st.cutCnt[g * D + d]++;\n            }\n        }\n\n        for (int d = 0; d < D; d++) {\n            st.dayScore[d] = computeDayScore(st.assign, d, sources, st.count[d], true);\n            st.totalScore += st.dayScore[d];\n        }\n\n        return st;\n    }\n\n    bool isCutPair(int a, int b) const {\n        const auto& v = cutAdj[a];\n        return binary_search(v.begin(), v.end(), b);\n    }\n\n    int shareCount(int a, int b) const {\n        int c = 0;\n        if (edges[a].u == edges[b].u || edges[a].u == edges[b].v) c++;\n        if (edges[a].v == edges[b].u || edges[a].v == edges[b].v) c++;\n        return c;\n    }\n\n    double placeCost(const State& st, int e, int d, int removeY) {\n        bool inD = (st.assign[e] == d);\n        int u = edges[e].u, v = edges[e].v;\n        int adjCnt = st.inc[u * D + d] + st.inc[v * D + d];\n        if (inD) adjCnt -= 2;\n        if (removeY >= 0 && st.assign[removeY] == d) {\n            adjCnt -= shareCount(e, removeY);\n        }\n        adjCnt = max(0, adjCnt);\n\n        int cut = st.cutCnt[e * D + d];\n        if (removeY >= 0 && st.assign[removeY] == d && isCutPair(e, removeY)) cut--;\n        cut = max(0, cut);\n\n        int loc = localCellCount(st.cellCnt, d, edges[e].cell);\n        if (inD) loc--;\n        if (removeY >= 0 && st.assign[removeY] == d &&\n            nearCell[edges[e].cell * C + edges[removeY].cell]) {\n            loc--;\n        }\n        loc = max(0, loc);\n\n        double impSum = st.dayImp[d];\n        if (inD) impSum -= impNorm[e];\n        if (removeY >= 0 && st.assign[removeY] == d) impSum -= impNorm[removeY];\n        impSum = max(0.0, impSum);\n\n        double cost = 1000000.0 * cut;\n        cost += 10.0 * adjCnt;\n        cost += 1.5 * loc;\n        cost += 2.0 * impNorm[e] * (impSum / max(1, target[d]));\n        return cost;\n    }\n\n    double edgeBadness(const State& st, int e, int d) {\n        return placeCost(st, e, d, -1) + 0.5 * impNorm[e];\n    }\n\n    int randomNonemptyDay(const State& st, int exclude = -1) {\n        for (int t = 0; t < 50; t++) {\n            int d = rng.nextInt(D);\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        for (int d = 0; d < D; d++) {\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        return -1;\n    }\n\n    int argMaxDay(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int d = 0; d < D; d++) {\n            if (st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int argMinDay(const State& st, int exclude = -1, bool requireNonempty = true) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int d = 0; d < D; d++) {\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int tournamentHigh(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int i = 0; i < 5; i++) {\n            int d = randomNonemptyDay(st);\n            if (d == -1) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMaxDay(st);\n        return best;\n    }\n\n    int tournamentLow(const State& st, int exclude, bool requireNonempty) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int i = 0; i < 5; i++) {\n            int d = rng.nextInt(D);\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMinDay(st, exclude, requireNonempty);\n        return best;\n    }\n\n    int selectEdge(const State& st, int day, bool bad) {\n        const auto& v = st.dayEdges[day];\n        if (v.empty()) return -1;\n\n        int best = v[rng.nextInt((int)v.size())];\n        double bv = edgeBadness(st, best, day);\n\n        int samples = min(7, (int)v.size());\n        for (int i = 1; i < samples; i++) {\n            int e = v[rng.nextInt((int)v.size())];\n            double val = edgeBadness(st, e, day);\n            if ((bad && val > bv) || (!bad && val < bv)) {\n                bv = val;\n                best = e;\n            }\n        }\n        return best;\n    }\n\n    double cheapDeltaSwap(const State& st, int e, int f) {\n        int a = st.assign[e], b = st.assign[f];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1) + placeCost(st, f, b, -1);\n        double after = placeCost(st, e, b, f) + placeCost(st, f, a, e);\n        return after - before;\n    }\n\n    double cheapDeltaMove(const State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1);\n        double after = placeCost(st, e, b, -1);\n        return after - before;\n    }\n\n    Cand proposeSwap(const State& st) {\n        Cand best;\n        best.type = 2;\n\n        for (int t = 0; t < 14; t++) {\n            int a, b;\n            int mode = rng.nextInt(100);\n\n            if (mode < 45) {\n                a = argMaxDay(st);\n                b = argMinDay(st, a, true);\n            } else if (mode < 80) {\n                a = tournamentHigh(st);\n                b = tournamentLow(st, a, true);\n            } else {\n                a = randomNonemptyDay(st);\n                b = randomNonemptyDay(st, a);\n            }\n\n            if (a < 0 || b < 0 || a == b) continue;\n\n            int e = selectEdge(st, a, true);\n            int f = selectEdge(st, b, false);\n            if (e < 0 || f < 0) continue;\n\n            double cd = cheapDeltaSwap(st, e, f);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = f;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    Cand proposeMove(const State& st) {\n        Cand best;\n        best.type = 1;\n\n        int lowBound = max(0, M / D - 2);\n        int highBound = min(K, (M + D - 1) / D + 2);\n\n        for (int t = 0; t < 12; t++) {\n            int a = -1;\n            long long av = LLONG_MIN;\n\n            if (rng.nextInt(100) < 60) {\n                for (int d = 0; d < D; d++) {\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            } else {\n                for (int k = 0; k < 8; k++) {\n                    int d = rng.nextInt(D);\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            }\n\n            if (a < 0) continue;\n\n            int b = -1;\n            long long bv = LLONG_MAX;\n            for (int k = 0; k < 8; k++) {\n                int d = rng.nextInt(D);\n                if (d == a) continue;\n                if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                if (st.dayScore[d] < bv) {\n                    bv = st.dayScore[d];\n                    b = d;\n                }\n            }\n            if (b < 0) {\n                for (int d = 0; d < D; d++) {\n                    if (d == a) continue;\n                    if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                    if (st.dayScore[d] < bv) {\n                        bv = st.dayScore[d];\n                        b = d;\n                    }\n                }\n            }\n            if (b < 0) continue;\n\n            int e = selectEdge(st, a, true);\n            if (e < 0) continue;\n\n            double cd = cheapDeltaMove(st, e, b);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = b;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    bool acceptDelta(const State& st, long long delta, bool isMove) {\n        if (delta <= 0) return true;\n\n        double avg = max(1.0, st.totalScore / (double)max(1, D));\n        double prog = min(1.0, elapsed() / localEndTime);\n        double factor = isMove ? 0.004 : 0.008;\n        double T = avg * (factor * (1.0 - prog) + 0.00002);\n\n        if (T <= 1.0) return false;\n        if ((double)delta > T * 20.0) return false;\n        return rng.nextDouble() < exp(-(double)delta / T);\n    }\n\n    void applySwap(State& st, int e, int f, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e], pf = st.pos[f];\n        st.dayEdges[a][pe] = f;\n        st.dayEdges[b][pf] = e;\n        st.pos[f] = pe;\n        st.pos[e] = pf;\n\n        auto decEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]--;\n            st.inc[edges[x].v * D + d]--;\n            st.dayImp[d] -= impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]--;\n        };\n        auto incEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]++;\n            st.inc[edges[x].v * D + d]++;\n            st.dayImp[d] += impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]++;\n        };\n\n        decEdge(e, a); incEdge(e, b);\n        decEdge(f, b); incEdge(f, a);\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n        for (int g : cutAdj[f]) {\n            st.cutCnt[g * D + b]--;\n            st.cutCnt[g * D + a]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    void applyMove(State& st, int e, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e];\n        int last = st.dayEdges[a].back();\n        st.dayEdges[a][pe] = last;\n        st.pos[last] = pe;\n        st.dayEdges[a].pop_back();\n\n        st.pos[e] = (int)st.dayEdges[b].size();\n        st.dayEdges[b].push_back(e);\n\n        st.count[a]--;\n        st.count[b]++;\n\n        st.inc[edges[e].u * D + a]--;\n        st.inc[edges[e].v * D + a]--;\n        st.inc[edges[e].u * D + b]++;\n        st.inc[edges[e].v * D + b]++;\n\n        st.dayImp[a] -= impNorm[e];\n        st.dayImp[b] += impNorm[e];\n\n        st.cellCnt[a * C + edges[e].cell]--;\n        st.cellCnt[b * C + edges[e].cell]++;\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    bool trySwap(State& st, int e, int f) {\n        int a = st.assign[e];\n        int b = st.assign[f];\n        if (a == b) return false;\n\n        st.assign[e] = b;\n        st.assign[f] = a;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a], false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b], false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, false);\n\n        if (acc) {\n            applySwap(st, e, f, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            st.assign[f] = b;\n            return false;\n        }\n    }\n\n    bool tryMove(State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return false;\n        if (st.count[b] >= K) return false;\n\n        st.assign[e] = b;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a] - 1, false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b] + 1, false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, true);\n\n        if (acc) {\n            applyMove(st, e, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            return false;\n        }\n    }\n\n    void ensureLegal(vector<int>& assign) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) assign[e] = 0;\n            cnt[assign[e]]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            if (cnt[d] <= K) continue;\n            int b = -1;\n            for (int j = 0; j < D; j++) {\n                if (cnt[j] < K) {\n                    b = j;\n                    break;\n                }\n            }\n            if (b == -1) break;\n            cnt[d]--;\n            assign[e] = b;\n            cnt[b]++;\n        }\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        readInput();\n\n        computeOriginalAndLoad();\n        detectTwoEdgeCuts();\n        computeStretch();\n        computeImportance();\n\n        int P = 24;\n        if (D <= 10) P += 8;\n        else if (D <= 18) P += 4;\n        if (M <= 1200) P += 8;\n        else if (M <= 2000) P += 4;\n        if (N <= 700) P += 4;\n        P = min({P, N, 52});\n        optSources = selectSources(P);\n\n        vector<int> bestAssign;\n        long long bestScore = LLONG_MAX;\n\n        auto consider = [&](const vector<int>& assign) {\n            ScoreRes sc = scoreAll(assign, optSources);\n            if (sc.total < bestScore) {\n                bestScore = sc.total;\n                bestAssign = assign;\n            }\n        };\n\n        consider(buildHilbertLike(0));\n        consider(buildGreedy(0));\n\n        const double initDeadline = 2.25;\n        if (elapsed() < initDeadline) consider(buildGreedy(1));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(1));\n        if (elapsed() < initDeadline) consider(buildGreedy(2));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(2));\n        if (elapsed() < initDeadline) consider(buildGreedy(4));\n        if (elapsed() < initDeadline) consider(buildRandomBalanced());\n\n        if (bestAssign.empty()) bestAssign = buildRandomBalanced();\n\n        State st = buildState(bestAssign, optSources);\n        vector<int> bestLocal = st.assign;\n        long long bestLocalScore = st.totalScore;\n\n        localEndTime = 5.65;\n        while (elapsed() < localEndTime) {\n            Cand cand;\n            if (rng.nextInt(100) < 18) cand = proposeMove(st);\n            if (cand.type == 0) cand = proposeSwap(st);\n\n            bool accepted = false;\n            if (cand.type == 1) {\n                accepted = tryMove(st, cand.e, cand.f);\n            } else if (cand.type == 2) {\n                accepted = trySwap(st, cand.e, cand.f);\n            }\n\n            if (accepted && st.totalScore < bestLocalScore) {\n                bestLocalScore = st.totalScore;\n                bestLocal = st.assign;\n            }\n        }\n\n        ensureLegal(bestLocal);\n\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << bestLocal[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    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct I3 {\n        short x, y, z;\n    };\n    struct Rot {\n        int perm[3];\n        int sign[3];\n    };\n    struct AlignCand {\n        long long key;\n        int ori, tid, cnt, w;\n    };\n    struct AlignMinCmp {\n        bool operator()(const AlignCand& a, const AlignCand& b) const {\n            return a.key > b.key; // min-heap\n        }\n    };\n    struct CompCand {\n        bool valid = false;\n        double score = -1;\n        int size = 0;\n        int cov = 0;\n        int ori = 0;\n        int tx = 0, ty = 0, tz = 0;\n        vector<int> cells;\n    };\n    struct Box {\n        int x = 0, y = 0, z = 0;\n        int lx = 0, ly = 0, lz = 0;\n        int cov = -1;\n        int vol = 0;\n        bool valid = false;\n    };\n    struct BoxCand {\n        bool valid = false;\n        Box b0, b1;\n        int vol = 0;\n        int cov = 0;\n        double score = -1;\n    };\n\n    int D, D2, N;\n    int rangeT, offsetT, Tcnt;\n    array<vector<string>, 2> F, Rt;\n\n    array<vector<char>, 2> allowed, rem, covF, covR;\n    array<vector<int>, 2> ans;\n    array<vector<unsigned char>, 2> aw;\n\n    vector<int> xs, ys, zs;\n    vector<array<int, 6>> neigh;\n\n    vector<Rot> rots;\n    vector<vector<I3>> rotp;\n\n    int unF[2][15];\n    int unR[2][15];\n\n    int allowedCount[2] = {0, 0};\n    int minAllowed = 0;\n    int totalUncov = 0;\n\n    int label = 0;\n    int commonVol = 0;\n    int uniqueVol[2] = {0, 0};\n    double commonCost = 0.0;\n\n    vector<int> cnt, wcnt;\n    vector<int> mark, vis, qmap;\n    int markToken = 1, visToken = 1;\n    array<vector<int>, 2> tmpF, tmpR;\n    int pixToken = 1;\n\n    chrono::steady_clock::time_point startTime;\n\n    Solver(int D_, const array<vector<string>, 2>& F_, const array<vector<string>, 2>& Rt_)\n        : D(D_), F(F_), Rt(Rt_) {\n        D2 = D * D;\n        N = D * D * D;\n        rangeT = 3 * D - 2;\n        offsetT = D - 1;\n        Tcnt = rangeT * rangeT * rangeT;\n\n        memset(unF, 0, sizeof(unF));\n        memset(unR, 0, sizeof(unR));\n\n        for (int s = 0; s < 2; s++) {\n            allowed[s].assign(N, 0);\n            rem[s].assign(N, 0);\n            covF[s].assign(D2, 0);\n            covR[s].assign(D2, 0);\n            ans[s].assign(N, 0);\n            aw[s].assign(N, 0);\n            tmpF[s].assign(D2, 0);\n            tmpR[s].assign(D2, 0);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        zs.resize(N);\n        neigh.resize(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 v = id(x, y, z);\n                    xs[v] = x;\n                    ys[v] = y;\n                    zs[v] = z;\n                }\n            }\n        }\n\n        for (int v = 0; v < N; v++) {\n            int x = xs[v], y = ys[v], z = zs[v];\n            array<int, 6> nb;\n            nb.fill(-1);\n            if (x > 0) nb[0] = id(x - 1, y, z);\n            if (x + 1 < D) nb[1] = id(x + 1, y, z);\n            if (y > 0) nb[2] = id(x, y - 1, z);\n            if (y + 1 < D) nb[3] = id(x, y + 1, z);\n            if (z > 0) nb[4] = id(x, y, z - 1);\n            if (z + 1 < D) nb[5] = id(x, y, z + 1);\n            neigh[v] = nb;\n        }\n\n        for (int s = 0; s < 2; s++) {\n            for (int z = 0; z < D; z++) {\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1') {\n                        unF[s][z]++;\n                        totalUncov++;\n                    }\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1') {\n                        unR[s][z]++;\n                        totalUncov++;\n                    }\n                }\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                        if (F[s][z][x] == '1' && Rt[s][z][y] == '1') {\n                            int v = id(x, y, z);\n                            allowed[s][v] = 1;\n                            rem[s][v] = 1;\n                            allowedCount[s]++;\n                        }\n                    }\n                }\n            }\n        }\n\n        minAllowed = min(allowedCount[0], allowedCount[1]);\n\n        generateRotations();\n        rotp.assign(rots.size(), vector<I3>(N));\n        for (int ri = 0; ri < (int)rots.size(); ri++) {\n            for (int v = 0; v < N; v++) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) {\n                    q[a] = rots[ri].sign[a] * p[rots[ri].perm[a]];\n                }\n                rotp[ri][v] = I3{(short)q[0], (short)q[1], (short)q[2]};\n            }\n        }\n\n        cnt.assign(Tcnt, 0);\n        wcnt.assign(Tcnt, 0);\n        mark.assign(N, 0);\n        vis.assign(N, 0);\n        qmap.assign(N, -1);\n    }\n\n    inline int id(int x, int y, int z) const {\n        return (x * D + y) * D + z;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void generateRotations() {\n        array<int, 3> p = {0, 1, 2};\n        sort(p.begin(), p.end());\n        do {\n            int inv = 0;\n            for (int i = 0; i < 3; i++) {\n                for (int j = i + 1; j < 3; j++) {\n                    if (p[i] > p[j]) inv++;\n                }\n            }\n            int parity = (inv % 2 == 0 ? 1 : -1);\n            for (int sx : {-1, 1}) {\n                for (int sy : {-1, 1}) {\n                    for (int sz : {-1, 1}) {\n                        if (parity * sx * sy * sz == 1) {\n                            Rot r;\n                            r.perm[0] = p[0];\n                            r.perm[1] = p[1];\n                            r.perm[2] = p[2];\n                            r.sign[0] = sx;\n                            r.sign[1] = sy;\n                            r.sign[2] = sz;\n                            rots.push_back(r);\n                        }\n                    }\n                }\n            }\n        } while (next_permutation(p.begin(), p.end()));\n    }\n\n    inline int activeWeight(int s, int v) const {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int w = 0;\n        if (!covF[s][z * D + x]) w++;\n        if (!covR[s][z * D + y]) w++;\n        return w;\n    }\n\n    void coverCell(int s, int v) {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int fid = z * D + x;\n        int rid = z * D + y;\n\n        if (F[s][z][x] == '1' && !covF[s][fid]) {\n            covF[s][fid] = 1;\n            unF[s][z]--;\n            totalUncov--;\n        }\n        if (Rt[s][z][y] == '1' && !covR[s][rid]) {\n            covR[s][rid] = 1;\n            unR[s][z]--;\n            totalUncov--;\n        }\n    }\n\n    int calcLBAfter(int s, const int* nf, const int* nr) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) {\n            int a = unF[s][z] - nf[z];\n            int b = unR[s][z] - nr[z];\n            if (a < 0) a = 0;\n            if (b < 0) b = 0;\n            if (a > 0 && b > 0) res += max(a, b);\n            else res += a + b;\n        }\n        return res;\n    }\n\n    void decodeTid(int tid, int& tx, int& ty, int& tz) const {\n        tz = tid % rangeT;\n        tid /= rangeT;\n        ty = tid % rangeT;\n        tx = tid / rangeT;\n        tx -= offsetT;\n        ty -= offsetT;\n        tz -= offsetT;\n    }\n\n    void evalAlignment(int ori, int tid, const vector<int>& list0, CompCand& best) {\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        int inter = 0;\n\n        for (int p : list0) {\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            if (0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D) {\n                int q = id(qx, qy, qz);\n                if (rem[1][q]) {\n                    mark[p] = mt;\n                    qmap[p] = q;\n                    inter++;\n                }\n            }\n        }\n        if (inter == 0) return;\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(inter);\n        comp.reserve(inter);\n\n        for (int st : list0) {\n            if (mark[st] != mt || vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int remCap = minAllowed - (commonVol + sz);\n            int def = max(0, max(lb0, lb1) - remCap);\n\n            double score = (double)cov * sz;\n            score /= (1.0 + 0.03 * def);\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponent(int topK, double timeLimit) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if (list0.empty() || list1.empty()) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        priority_queue<AlignCand, vector<AlignCand>, AlignMinCmp> pq1, pq2;\n\n        auto consider = [&](auto& pq, const AlignCand& a) {\n            if ((int)pq.size() < topK) {\n                pq.push(a);\n            } else if (a.key > pq.top().key) {\n                pq.pop();\n                pq.push(a);\n            }\n        };\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int awp = aw[0][p];\n                for (int j = 0; j < n1; j++) {\n                    int tx = qx[j] - rp.x + offsetT;\n                    int ty = qy[j] - rp.y + offsetT;\n                    int tz = qz[j] - rp.z + offsetT;\n                    int tid = (tx * rangeT + ty) * rangeT + tz;\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            for (int tid = 0; tid < Tcnt; tid++) {\n                if (wcnt[tid] == 0) continue;\n                int c = cnt[tid];\n                int w = wcnt[tid];\n                consider(pq1, AlignCand{1LL * c * (w + 1), oi, tid, c, w});\n                consider(pq2, AlignCand{1LL * c * c, oi, tid, c, w});\n            }\n\n            if (elapsed() > timeLimit) break;\n        }\n\n        vector<AlignCand> aligns;\n        while (!pq1.empty()) {\n            aligns.push_back(pq1.top());\n            pq1.pop();\n        }\n        while (!pq2.empty()) {\n            aligns.push_back(pq2.top());\n            pq2.pop();\n        }\n\n        sort(aligns.begin(), aligns.end(), [](const AlignCand& a, const AlignCand& b) {\n            return a.key > b.key;\n        });\n\n        unordered_set<long long> seen;\n        seen.reserve(aligns.size() * 2 + 1);\n\n        int evalCnt = 0;\n        for (const auto& a : aligns) {\n            long long code = 1LL * a.ori * Tcnt + a.tid;\n            if (!seen.insert(code).second) continue;\n            evalAlignment(a.ori, a.tid, list0, best);\n            evalCnt++;\n            if (evalCnt >= topK) break;\n            if (elapsed() > timeLimit) break;\n        }\n\n        return best;\n    }\n\n    void placeCommonMapped(const CompCand& c) {\n        int lab = ++label;\n        int sz = (int)c.cells.size();\n\n        for (int p : c.cells) {\n            I3 rp = rotp[c.ori][p];\n            int qx = rp.x + c.tx;\n            int qy = rp.y + c.ty;\n            int qz = rp.z + c.tz;\n            int q = id(qx, qy, qz);\n\n            ans[0][p] = lab;\n            rem[0][p] = 0;\n            coverCell(0, p);\n\n            ans[1][q] = lab;\n            rem[1][q] = 0;\n            coverCell(1, q);\n        }\n\n        commonVol += sz;\n        commonCost += 1.0 / sz;\n    }\n\n    inline int p3id(int x, int y, int z) const {\n        int P = D + 1;\n        return (x * P + y) * P + z;\n    }\n\n    inline int p2id(int a, int b) const {\n        int P = D + 1;\n        return a * P + b;\n    }\n\n    int query3(const vector<int>& ps, int x0, int x1, int y0, int y1, int z0, int z1) const {\n        return ps[p3id(x1, y1, z1)]\n             - ps[p3id(x0, y1, z1)]\n             - ps[p3id(x1, y0, z1)]\n             - ps[p3id(x1, y1, z0)]\n             + ps[p3id(x0, y0, z1)]\n             + ps[p3id(x0, y1, z0)]\n             + ps[p3id(x1, y0, z0)]\n             - ps[p3id(x0, y0, z0)];\n    }\n\n    int query2(const vector<int>& ps, int a0, int a1, int b0, int b1) const {\n        return ps[p2id(a1, b1)]\n             - ps[p2id(a0, b1)]\n             - ps[p2id(a1, b0)]\n             + ps[p2id(a0, b0)];\n    }\n\n    void buildPrefix3(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P * P, 0);\n        for (int x = 1; x <= D; x++) {\n            for (int y = 1; y <= D; y++) {\n                for (int z = 1; z <= D; z++) {\n                    int val = rem[s][id(x - 1, y - 1, z - 1)] ? 1 : 0;\n                    ps[p3id(x, y, z)] =\n                        val\n                        + ps[p3id(x - 1, y, z)]\n                        + ps[p3id(x, y - 1, z)]\n                        + ps[p3id(x, y, z - 1)]\n                        - ps[p3id(x - 1, y - 1, z)]\n                        - ps[p3id(x - 1, y, z - 1)]\n                        - ps[p3id(x, y - 1, z - 1)]\n                        + ps[p3id(x - 1, y - 1, z - 1)];\n                }\n            }\n        }\n    }\n\n    void buildPrefix2F(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int x = 1; x <= D; x++) {\n                int val = (F[s][z - 1][x - 1] == '1' && !covF[s][(z - 1) * D + (x - 1)]) ? 1 : 0;\n                ps[p2id(z, x)] =\n                    val + ps[p2id(z - 1, x)] + ps[p2id(z, x - 1)] - ps[p2id(z - 1, x - 1)];\n            }\n        }\n    }\n\n    void buildPrefix2R(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int y = 1; y <= D; y++) {\n                int val = (Rt[s][z - 1][y - 1] == '1' && !covR[s][(z - 1) * D + (y - 1)]) ? 1 : 0;\n                ps[p2id(z, y)] =\n                    val + ps[p2id(z - 1, y)] + ps[p2id(z, y - 1)] - ps[p2id(z - 1, y - 1)];\n            }\n        }\n    }\n\n    int shapeKey(int a, int b, int c) const {\n        if (a > b) swap(a, b);\n        if (b > c) swap(b, c);\n        if (a > b) swap(a, b);\n        return (a * 15 + b) * 15 + c;\n    }\n\n    void enumerateBoxesSide(int s, vector<Box>& best, double timeLimit) {\n        vector<int> ps3, psF, psR;\n        buildPrefix3(s, ps3);\n        buildPrefix2F(s, psF);\n        buildPrefix2R(s, psR);\n\n        for (int x0 = 0; x0 < D; x0++) {\n            if (elapsed() > timeLimit) return;\n            for (int x1 = x0 + 1; x1 <= D; x1++) {\n                int lx = x1 - x0;\n                for (int y0 = 0; y0 < D; y0++) {\n                    for (int y1 = y0 + 1; y1 <= D; y1++) {\n                        int ly = y1 - y0;\n                        for (int z0 = 0; z0 < D; z0++) {\n                            for (int z1 = z0 + 1; z1 <= D; z1++) {\n                                int lz = z1 - z0;\n                                int vol = lx * ly * lz;\n                                if (vol < 2) continue;\n\n                                if (query3(ps3, x0, x1, y0, y1, z0, z1) != vol) continue;\n\n                                int cov =\n                                    query2(psF, z0, z1, x0, x1)\n                                    + query2(psR, z0, z1, y0, y1);\n\n                                int key = shapeKey(lx, ly, lz);\n                                if (!best[key].valid || cov > best[key].cov) {\n                                    Box b;\n                                    b.x = x0;\n                                    b.y = y0;\n                                    b.z = z0;\n                                    b.lx = lx;\n                                    b.ly = ly;\n                                    b.lz = lz;\n                                    b.cov = cov;\n                                    b.vol = vol;\n                                    b.valid = true;\n                                    best[key] = b;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    BoxCand findBestCuboid(double timeLimit) {\n        const int KEY = 15 * 15 * 15;\n        vector<Box> best0(KEY), best1(KEY);\n\n        enumerateBoxesSide(0, best0, timeLimit);\n        if (elapsed() > timeLimit) return BoxCand();\n        enumerateBoxesSide(1, best1, timeLimit);\n\n        BoxCand res;\n        for (int k = 0; k < KEY; k++) {\n            if (!best0[k].valid || !best1[k].valid) continue;\n            int cov = best0[k].cov + best1[k].cov;\n            if (cov <= 0) continue;\n            int vol = best0[k].vol;\n            double score = (double)cov * vol;\n            if (!res.valid || score > res.score || (abs(score - res.score) < 1e-9 && vol > res.vol)) {\n                res.valid = true;\n                res.b0 = best0[k];\n                res.b1 = best1[k];\n                res.vol = vol;\n                res.cov = cov;\n                res.score = score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBox(const Box& b0, const Box& b1) {\n        int lab = ++label;\n        int vol = b0.vol;\n\n        auto put = [&](int s, const Box& b) {\n            for (int x = b.x; x < b.x + b.lx; x++) {\n                for (int y = b.y; y < b.y + b.ly; y++) {\n                    for (int z = b.z; z < b.z + b.lz; z++) {\n                        int v = id(x, y, z);\n                        ans[s][v] = lab;\n                        rem[s][v] = 0;\n                        coverCell(s, v);\n                    }\n                }\n            }\n        };\n\n        put(0, b0);\n        put(1, b1);\n\n        commonVol += vol;\n        commonCost += 1.0 / vol;\n    }\n\n    int findBestCell(int s, bool needActive) const {\n        int best = -1;\n        int bestW = needActive ? 0 : 100;\n        for (int v = 0; v < N; v++) {\n            if (!rem[s][v]) continue;\n            int w = activeWeight(s, v);\n            if (needActive) {\n                if (w > bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            } else {\n                if (best == -1 || w < bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            }\n        }\n        return best;\n    }\n\n    void placeCommonUnit(int a, int b) {\n        int lab = ++label;\n        ans[0][a] = lab;\n        rem[0][a] = 0;\n        coverCell(0, a);\n\n        ans[1][b] = lab;\n        rem[1][b] = 0;\n        coverCell(1, b);\n\n        commonVol += 1;\n        commonCost += 1.0;\n    }\n\n    bool placeUniqueCell(int s, int v) {\n        if (v < 0 || !rem[s][v]) return false;\n        int lab = ++label;\n        ans[s][v] = lab;\n        rem[s][v] = 0;\n        coverCell(s, v);\n        uniqueVol[s]++;\n        return true;\n    }\n\n    void placeCommonUnits() {\n        while (totalUncov > 0) {\n            int a0 = findBestCell(0, true);\n            int a1 = findBestCell(1, true);\n\n            if (a0 == -1 && a1 == -1) break;\n\n            if (a0 != -1 && a1 != -1) {\n                placeCommonUnit(a0, a1);\n            } else if (a0 != -1) {\n                int b = findBestCell(1, false);\n                if (b == -1) break;\n                placeCommonUnit(a0, b);\n            } else {\n                int a = findBestCell(0, false);\n                if (a == -1) break;\n                placeCommonUnit(a, a1);\n            }\n        }\n    }\n\n    int sideUncovered(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += unF[s][z] + unR[s][z];\n        return res;\n    }\n\n    int chooseCell(int s, int z, int x, int y) const {\n        if (x >= 0 && y >= 0) {\n            int v = id(x, y, z);\n            if (rem[s][v]) return v;\n        }\n        if (x >= 0) {\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] == '1') {\n                    int v = id(x, yy, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        if (y >= 0) {\n            for (int xx = 0; xx < D; xx++) {\n                if (F[s][z][xx] == '1') {\n                    int v = id(xx, y, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        for (int xx = 0; xx < D; xx++) {\n            if (F[s][z][xx] != '1') continue;\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] != '1') continue;\n                int v = id(xx, yy, z);\n                if (rem[s][v]) return v;\n            }\n        }\n        return -1;\n    }\n\n    void fillUnique(int s) {\n        int guard = 0;\n        while (sideUncovered(s) > 0 && guard++ < 1000) {\n            bool progress = false;\n\n            for (int z = 0; z < D; z++) {\n                vector<int> X, Y;\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1' && !covF[s][z * D + x]) X.push_back(x);\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) Y.push_back(y);\n                }\n\n                if (X.empty() && Y.empty()) continue;\n\n                if (!X.empty() && !Y.empty()) {\n                    int m = max((int)X.size(), (int)Y.size());\n                    for (int k = 0; k < m; k++) {\n                        int x = (k < (int)X.size() ? X[k] : X[0]);\n                        int y = (k < (int)Y.size() ? Y[k] : Y[0]);\n                        int v = chooseCell(s, z, x, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else if (!X.empty()) {\n                    for (int x : X) {\n                        int v = chooseCell(s, z, x, -1);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else {\n                    for (int y : Y) {\n                        int v = chooseCell(s, z, -1, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                }\n            }\n\n            if (!progress) {\n                int v = findBestCell(s, true);\n                if (!placeUniqueCell(s, v)) break;\n            }\n        }\n    }\n\n    void finalRepair() {\n        for (int s = 0; s < 2; s++) {\n            int guard = 0;\n            while (sideUncovered(s) > 0 && guard++ < 1000) {\n                bool progress = false;\n                for (int z = 0; z < D; z++) {\n                    for (int x = 0; x < D; x++) {\n                        if (F[s][z][x] == '1' && !covF[s][z * D + x]) {\n                            int v = chooseCell(s, z, x, -1);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                    for (int y = 0; y < D; y++) {\n                        if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) {\n                            int v = chooseCell(s, z, -1, y);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                }\n                if (!progress) break;\n            }\n        }\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        // 1. Large arbitrary common connected components from rotational overlaps.\n        double compDeadline = 2.6;\n        for (int it = 0; it < 12 && totalUncov > 0 && elapsed() < compDeadline; it++) {\n            CompCand c = findBestComponent(90, compDeadline);\n            if (!c.valid || c.size < 3) break;\n            placeCommonMapped(c);\n        }\n\n        // 2. Greedy common cuboids.\n        for (int it = 0; it < 180 && totalUncov > 0 && elapsed() < 5.45; it++) {\n            BoxCand b = findBestCuboid(5.55);\n            if (!b.valid || b.vol < 2 || b.cov <= 0) break;\n            placeCommonBox(b.b0, b.b1);\n        }\n\n        // 3. Common unit cubes, then unique fallback.\n        placeCommonUnits();\n        fillUnique(0);\n        fillUnique(1);\n        finalRepair();\n    }\n\n    void print() const {\n        cout << label << '\\n';\n        for (int s = 0; s < 2; s++) {\n            for (int i = 0; i < N; i++) {\n                if (i) cout << ' ';\n                cout << ans[s][i];\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n\n    array<vector<string>, 2> F, R;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        R[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> R[i][z];\n    }\n\n    Solver solver(D, F, R);\n    solver.run();\n    solver.print();\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 105;\nstatic const int MAXM = 305;\nstatic const long long INFLL = (1LL << 62);\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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} gtimer;\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) {\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);\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 Edge {\n    int u, v;\n    long long w;\n};\n\nstruct RK {\n    unsigned short p;\n    int k;\n};\n\nstruct TreeResult {\n    long long cost = INFLL;\n    bitset<MAXM> mask;\n};\n\nstruct Solution {\n    vector<int> P;\n    TreeResult tree;\n    long long radCost = INFLL;\n    long long total = INFLL;\n};\n\nint N, M, K;\nvector<int> X, Y, RA, RB;\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj;\n\nvector<vector<int>> distSq;\nvector<vector<unsigned short>> ceilD;\nvector<RK> coverList[MAXN];\n\nlong long spDist[MAXN][MAXN];\nbitset<MAXM> pathE[MAXN][MAXN];\nbitset<MAXN> pathV[MAXN][MAXN];\n\nvector<int> edgeOrder;\nbitset<MAXM> globalMSTMask;\nbitset<MAXM> allEdgesMask;\n\nint ceil_sqrt_ll(long long v) {\n    int r = (int) sqrt((long double) v);\n    while (1LL * r * r < v) ++r;\n    while (r > 0 && 1LL * (r - 1) * (r - 1) >= v) --r;\n    return r;\n}\n\nlong long calcRadCost(const vector<int>& P) {\n    long long s = 0;\n    for (int p : P) s += 1LL * p * p;\n    return s;\n}\n\nint computeCovered(const vector<int>& P, vector<char>& covered) {\n    covered.assign(K, 0);\n    int rem = K;\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                if (rem == 0) return K;\n            }\n        }\n    }\n    return K - rem;\n}\n\nbool isFull(const vector<int>& P) {\n    vector<char> covered;\n    return computeCovered(P, covered) == K;\n}\n\nvector<int> makeOrder(const vector<int>& P, int mode, const vector<long long>* branch = nullptr) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            double p2 = 1.0 * P[i] * P[i];\n            double rd = (double) spDist[0][i];\n            if (mode == 0) sc = p2;\n            else if (mode == 1) sc = p2 + 0.7 * rd;\n            else if (mode == 2) sc = 0.2 * p2 + rd;\n            else {\n                long long b = (branch ? (*branch)[i] : 0LL);\n                sc = p2 + (double)b;\n            }\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvoid trimP(vector<int>& P, const vector<int>& order) {\n    vector<int> cnt(K, 0);\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            cnt[rk.k]++;\n        }\n    }\n\n    for (int i : order) {\n        if (P[i] <= 0) continue;\n        int old = P[i];\n        int need = 0;\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > old) break;\n            if (cnt[rk.k] == 1) need = max(need, (int)rk.p);\n        }\n        if (need < old) {\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > old) break;\n                if ((int)rk.p > need) cnt[rk.k]--;\n            }\n            P[i] = need;\n        }\n    }\n}\n\nTreeResult reduceMask(const bitset<MAXM>& mask, const vector<char>& terminal) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    DSU d(N);\n    bitset<MAXM> tree;\n    for (int eid : edgeOrder) {\n        if (mask.test(eid) && d.unite(edges[eid].u, edges[eid].v)) {\n            tree.set(eid);\n        }\n    }\n\n    vector<int> deg(N, 0);\n    vector<vector<int>> inc(N);\n    for (int e = 0; e < M; ++e) {\n        if (!tree.test(e)) continue;\n        int u = edges[e].u, v = edges[e].v;\n        deg[u]++;\n        deg[v]++;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n    }\n\n    queue<int> q;\n    for (int i = 0; i < N; ++i) {\n        if (!terminal[i] && deg[i] <= 1) q.push(i);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (terminal[v] || deg[v] != 1) continue;\n\n        int remEdge = -1;\n        for (int e : inc[v]) {\n            if (tree.test(e)) {\n                remEdge = e;\n                break;\n            }\n        }\n        if (remEdge == -1) {\n            deg[v] = 0;\n            continue;\n        }\n\n        int to = edges[remEdge].u ^ edges[remEdge].v ^ v;\n        tree.reset(remEdge);\n        deg[v]--;\n        deg[to]--;\n        if (!terminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    vector<char> vis(N, 0);\n    queue<int> qq;\n    vis[0] = 1;\n    qq.push(0);\n    while (!qq.empty()) {\n        int v = qq.front();\n        qq.pop();\n        for (auto [to, eid] : adj[v]) {\n            if (!tree.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            qq.push(to);\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (terminal[i] && !vis[i]) return res;\n    }\n\n    long long cost = 0;\n    for (int e = 0; e < M; ++e) {\n        if (tree.test(e)) cost += edges[e].w;\n    }\n    res.cost = cost;\n    res.mask = tree;\n    return res;\n}\n\nbitset<MAXM> buildMetricMSTMask(const vector<char>& terminal) {\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) terms.push_back(i);\n    }\n\n    int T = (int)terms.size();\n    bitset<MAXM> mask;\n    if (T <= 1) return mask;\n\n    vector<char> used(T, 0);\n    vector<long long> key(T, INFLL);\n    vector<int> parent(T, -1);\n    key[0] = 0;\n\n    for (int it = 0; it < T; ++it) {\n        int v = -1;\n        long long best = INFLL;\n        for (int i = 0; i < T; ++i) {\n            if (!used[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) {\n            mask |= pathE[terms[v]][terms[parent[v]]];\n        }\n\n        for (int u = 0; u < T; ++u) {\n            if (!used[u] && spDist[terms[v]][terms[u]] < key[u]) {\n                key[u] = spDist[terms[v]][terms[u]];\n                parent[u] = v;\n            }\n        }\n    }\n    return mask;\n}\n\nbitset<MAXM> buildSPTMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) mask |= pathE[0][i];\n    }\n    return mask;\n}\n\nbitset<MAXM> buildGreedyMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(0);\n\n    while (true) {\n        bool any = false;\n        for (int t = 1; t < N; ++t) {\n            if (terminal[t] && !treeV.test(t)) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n        for (int t = 1; t < N; ++t) {\n            if (!terminal[t] || treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult buildBestTree(const vector<int>& P) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    int termCnt = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminal[i] = 1;\n            termCnt++;\n        }\n    }\n    if (P[0] > 0 && !terminal[0]) {\n        terminal[0] = 1;\n        termCnt++;\n    }\n\n    TreeResult best;\n    best.cost = INFLL;\n    best.mask.reset();\n\n    if (termCnt <= 1) {\n        best.cost = 0;\n        return best;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    upd(buildMetricMSTMask(terminal));\n    upd(buildSPTMask(terminal));\n    upd(buildGreedyMask(terminal));\n    upd(globalMSTMask);\n    upd(allEdgesMask);\n\n    return best;\n}\n\nvector<char> getReachable(const bitset<MAXM>& mask) {\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] : adj[v]) {\n            if (!mask.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return vis;\n}\n\nvector<long long> computeBranch(const vector<int>& P, const TreeResult& tr) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terminal[i] = 1;\n    }\n\n    vector<long long> branch(N, 0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        vector<char> t2 = terminal;\n        t2[i] = 0;\n        t2[0] = 1;\n        TreeResult r = reduceMask(tr.mask, t2);\n        if (r.cost < INFLL / 2) {\n            branch[i] = max(0LL, tr.cost - r.cost);\n        }\n    }\n    return branch;\n}\n\nSolution evaluateSolution(const vector<int>& P) {\n    Solution s;\n    s.P = P;\n    if (!isFull(P)) {\n        s.total = INFLL;\n        return s;\n    }\n    s.radCost = calcRadCost(P);\n    s.tree = buildBestTree(P);\n    if (s.tree.cost >= INFLL / 2) {\n        s.total = INFLL;\n    } else {\n        s.total = s.radCost + s.tree.cost;\n    }\n    return s;\n}\n\nbool greedyRepair(\n    vector<int>& P,\n    const vector<char>& allowed,\n    double connWeight,\n    double exponent,\n    const vector<char>* freeVertices = nullptr,\n    double stopTime = 1e100\n) {\n    for (int i = 0; i < N; ++i) {\n        if (!allowed[i]) P[i] = 0;\n        P[i] = min(5000, max(0, P[i]));\n    }\n\n    vector<char> covered;\n    int cov = computeCovered(P, covered);\n    int rem = K - cov;\n    if (rem == 0) return true;\n\n    vector<long long> minConn(N);\n    for (int i = 0; i < N; ++i) minConn[i] = spDist[0][i];\n\n    for (int t = 0; t < N; ++t) {\n        if (P[t] > 0) {\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][t]);\n            }\n        }\n    }\n\n    vector<double> denom(K + 1, 1.0);\n    if (fabs(exponent - 1.0) < 1e-9) {\n        for (int i = 1; i <= K; ++i) denom[i] = (double)i;\n    } else {\n        for (int i = 1; i <= K; ++i) denom[i] = pow((double)i, exponent);\n    }\n\n    int iter = 0;\n    while (rem > 0) {\n        if ((iter & 7) == 0 && gtimer.elapsed() > stopTime) return false;\n        if (iter > 1000) {\n            // Safe fallback: cover one currently uncovered resident at a time.\n            for (int k = 0; k < K && rem > 0; ++k) {\n                if (covered[k]) continue;\n                int bestI = -1, bestP = 0;\n                double bestCost = 1e100;\n\n                for (int i = 0; i < N; ++i) {\n                    if (!allowed[i]) continue;\n                    int p = (int)ceilD[i][k];\n                    if (p > 5000) continue;\n                    int old = P[i];\n                    int np = max(old, p);\n                    double act = 0.0;\n                    if (old == 0 && connWeight != 0.0) {\n                        if (freeVertices && (*freeVertices)[i]) act = 0.0;\n                        else act = connWeight * (double)minConn[i];\n                    }\n                    double cost = (double)(1LL * np * np - 1LL * old * old) + act;\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestI = i;\n                        bestP = np;\n                    }\n                }\n\n                if (bestI == -1) return false;\n\n                int old = P[bestI];\n                P[bestI] = bestP;\n                if (old == 0) {\n                    for (int j = 0; j < N; ++j) {\n                        minConn[j] = min(minConn[j], spDist[j][bestI]);\n                    }\n                }\n\n                for (const auto& rk : coverList[bestI]) {\n                    if ((int)rk.p > bestP) break;\n                    if (!covered[rk.k]) {\n                        covered[rk.k] = 1;\n                        --rem;\n                    }\n                }\n\n                if (gtimer.elapsed() > stopTime) return false;\n            }\n            return rem == 0;\n        }\n\n        ++iter;\n\n        double bestScore = 1e100;\n        double bestAbsCost = 1e100;\n        int bestI = -1, bestP = -1, bestCnt = -1;\n\n        for (int i = 0; i < N; ++i) {\n            if (!allowed[i] || P[i] >= 5000 || coverList[i].empty()) continue;\n\n            int old = P[i];\n            double activation = 0.0;\n            if (old == 0 && connWeight != 0.0) {\n                if (freeVertices && (*freeVertices)[i]) activation = 0.0;\n                else activation = connWeight * (double)minConn[i];\n            }\n\n            int cnt = 0;\n            const auto& lst = coverList[i];\n            int idx = 0, sz = (int)lst.size();\n\n            while (idx < sz && (int)lst[idx].p <= old) idx++;\n\n            while (idx < sz) {\n                int p = (int)lst[idx].p;\n                int add = 0;\n                while (idx < sz && (int)lst[idx].p == p) {\n                    if (!covered[lst[idx].k]) add++;\n                    idx++;\n                }\n                if (add == 0) continue;\n\n                cnt += add;\n                double cost = (double)(1LL * p * p - 1LL * old * old) + activation;\n                double score = cost / denom[cnt];\n\n                if (score < bestScore - 1e-12 ||\n                    (fabs(score - bestScore) <= 1e-12 &&\n                     (cost < bestAbsCost || cnt > bestCnt))) {\n                    bestScore = score;\n                    bestAbsCost = cost;\n                    bestI = i;\n                    bestP = p;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestI == -1) return false;\n\n        int old = P[bestI];\n        P[bestI] = bestP;\n\n        int gained = 0;\n        for (const auto& rk : coverList[bestI]) {\n            if ((int)rk.p > bestP) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                gained++;\n            }\n        }\n\n        if (old == 0) {\n            for (int j = 0; j < N; ++j) {\n                minConn[j] = min(minConn[j], spDist[j][bestI]);\n            }\n        }\n\n        if (gained == 0) return false;\n    }\n\n    return true;\n}\n\nvoid computeShortestPaths() {\n    for (int s = 0; s < N; ++s) {\n        vector<long long> dist(N, INFLL);\n        vector<int> parNode(N, -1), parEdge(N, -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n\n        dist[s] = 0;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n\n            for (auto [to, eid] : adj[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parNode[to] = v;\n                    parEdge[to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        for (int t = 0; t < N; ++t) {\n            spDist[s][t] = dist[t];\n            pathE[s][t].reset();\n            pathV[s][t].reset();\n\n            if (dist[t] >= INFLL / 2) continue;\n\n            int cur = t;\n            pathV[s][t].set(cur);\n            while (cur != s) {\n                int e = parEdge[cur];\n                if (e < 0) break;\n                pathE[s][t].set(e);\n                cur = parNode[cur];\n                pathV[s][t].set(cur);\n            }\n        }\n    }\n}\n\nbitset<MAXM> buildGlobalMST() {\n    DSU d(N);\n    bitset<MAXM> m;\n    for (int eid : edgeOrder) {\n        if (d.unite(edges[eid].u, edges[eid].v)) {\n            m.set(eid);\n        }\n    }\n    return m;\n}\n\nvector<int> nearestSolution(double lambda) {\n    vector<int> P(N, 0);\n    for (int k = 0; k < K; ++k) {\n        double best = 1e100;\n        int bi = -1;\n        for (int i = 0; i < N; ++i) {\n            int p = (int)ceilD[i][k];\n            if (p > 5000) continue;\n            double val = (double)distSq[i][k] + lambda * (double)spDist[0][i];\n            if (val < best) {\n                best = val;\n                bi = i;\n            }\n        }\n\n        if (bi == -1) {\n            int bp = INT_MAX;\n            for (int i = 0; i < N; ++i) {\n                if ((int)ceilD[i][k] < bp) {\n                    bp = (int)ceilD[i][k];\n                    bi = i;\n                }\n            }\n        }\n\n        P[bi] = max(P[bi], (int)ceilD[bi][k]);\n    }\n    return P;\n}\n\nvoid considerCandidate(vector<int> P, vector<Solution>& sols, double stopTime) {\n    for (int& p : P) p = min(5000, max(0, p));\n\n    vector<char> allAllowed(N, 1);\n    if (!isFull(P)) {\n        greedyRepair(P, allAllowed, 0.6, 1.0, nullptr, stopTime);\n    }\n    if (!isFull(P)) return;\n\n    auto add = [&](const vector<int>& Q) {\n        Solution s = evaluateSolution(Q);\n        if (s.total < INFLL / 2) sols.push_back(s);\n    };\n\n    add(P);\n\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<int> q = P;\n        trimP(q, makeOrder(q, mode));\n        add(q);\n    }\n\n    vector<int> q = P;\n    trimP(q, makeOrder(q, 1));\n    trimP(q, makeOrder(q, 0));\n    add(q);\n}\n\nSolution localSearch(Solution cur, double deadline) {\n    vector<char> allAllowed(N, 1);\n\n    for (int pass = 0; pass < 6 && gtimer.elapsed() < deadline; ++pass) {\n        cur = evaluateSolution(cur.P);\n        bool improved = false;\n\n        // Strong reverse-delete using current branch costs.\n        if (gtimer.elapsed() < deadline) {\n            vector<long long> br = computeBranch(cur.P, cur.tree);\n            vector<int> p2 = cur.P;\n            trimP(p2, makeOrder(p2, 3, &br));\n            Solution ns = evaluateSolution(p2);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        // Re-optimize radii using only vertices already connected by the current tree.\n        if (gtimer.elapsed() < deadline) {\n            vector<char> avail = getReachable(cur.tree.mask);\n            double exps[2] = {1.0, 1.15};\n            for (double ex : exps) {\n                vector<int> p0(N, 0);\n                if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n                trimP(p0, makeOrder(p0, 0));\n                Solution ns = evaluateSolution(p0);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        vector<int> order = makeOrder(cur.P, 3, &br);\n\n        // Remove or shrink one expensive station, then repair.\n        int stationTried = 0;\n        int maxStations = (pass == 0 ? 50 : 30);\n\n        for (int id : order) {\n            if (cur.P[id] <= 0) continue;\n            if (gtimer.elapsed() > deadline) break;\n            if (stationTried++ >= maxStations) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            vector<int> uniqTargets;\n            for (int t : targets) {\n                if (t < 0 || t >= p) continue;\n                bool seen = false;\n                for (int u : uniqTargets) if (u == t) seen = true;\n                if (!seen) uniqTargets.push_back(t);\n            }\n\n            for (int np : uniqTargets) {\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                p2[id] = np;\n\n                double beta = (np == 0 ? 0.8 : 0.4);\n                if (!greedyRepair(p2, allAllowed, beta, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n        if (improved) continue;\n\n        // Destroy a whole subtree of the current cable tree.\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            struct CutCand {\n                long long score;\n                int e;\n                vector<int> terms;\n            };\n            vector<CutCand> cuts;\n\n            for (int e = 0; e < M; ++e) {\n                if (!cur.tree.mask.test(e)) continue;\n\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] : adj[v]) {\n                        if (eid == e || !cur.tree.mask.test(eid) || vis[to]) continue;\n                        vis[to] = 1;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> terms;\n                long long p2sum = 0;\n                for (int v = 0; v < N; ++v) {\n                    if (!vis[v] && cur.P[v] > 0) {\n                        terms.push_back(v);\n                        p2sum += 1LL * cur.P[v] * cur.P[v];\n                    }\n                }\n                if (terms.empty()) continue;\n\n                long long branchCost = edges[e].w;\n                for (int ee = 0; ee < M; ++ee) {\n                    if (ee == e || !cur.tree.mask.test(ee)) continue;\n                    int u = edges[ee].u, v = edges[ee].v;\n                    if (!vis[u] && !vis[v]) branchCost += edges[ee].w;\n                }\n\n                cuts.push_back({branchCost + p2sum, e, terms});\n            }\n\n            sort(cuts.begin(), cuts.end(), [](const CutCand& a, const CutCand& b) {\n                return a.score > b.score;\n            });\n\n            int tried = 0;\n            for (const auto& cc : cuts) {\n                if (tried++ >= 8) break;\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                for (int v : cc.terms) p2[v] = 0;\n\n                if (!greedyRepair(p2, allAllowed, 0.9, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        // Remove a pair among the most expensive terminals.\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            vector<int> top;\n            for (int id : order) {\n                if (cur.P[id] > 0) {\n                    top.push_back(id);\n                    if ((int)top.size() >= 8) break;\n                }\n            }\n\n            for (int a = 0; a < (int)top.size() && !improved; ++a) {\n                for (int b = a + 1; b < (int)top.size(); ++b) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> p2 = cur.P;\n                    p2[top[a]] = 0;\n                    p2[top[b]] = 0;\n\n                    if (!greedyRepair(p2, allAllowed, 0.85, 1.05, nullptr, deadline)) continue;\n\n                    trimP(p2, makeOrder(p2, 1));\n                    trimP(p2, makeOrder(p2, 0));\n\n                    Solution ns = evaluateSolution(p2);\n                    if (ns.total < cur.total) {\n                        cur = ns;\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gtimer.reset();\n\n    cin >> N >> M >> K;\n\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    adj.assign(N, {});\n    for (int j = 0; j < M; ++j) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n        adj[u].push_back({v, j});\n        adj[v].push_back({u, j});\n    }\n\n    RA.resize(K);\n    RB.resize(K);\n    for (int k = 0; k < K; ++k) cin >> RA[k] >> RB[k];\n\n    edgeOrder.resize(M);\n    iota(edgeOrder.begin(), edgeOrder.end(), 0);\n    sort(edgeOrder.begin(), edgeOrder.end(), [&](int a, int b) {\n        if (edges[a].w != edges[b].w) return edges[a].w < edges[b].w;\n        return a < b;\n    });\n\n    allEdgesMask.reset();\n    for (int e = 0; e < M; ++e) allEdgesMask.set(e);\n\n    computeShortestPaths();\n    globalMSTMask = buildGlobalMST();\n\n    distSq.assign(N, vector<int>(K));\n    ceilD.assign(N, vector<unsigned short>(K));\n\n    for (int i = 0; i < N; ++i) {\n        coverList[i].clear();\n        for (int k = 0; k < K; ++k) {\n            long long dx = (long long)X[i] - RA[k];\n            long long dy = (long long)Y[i] - RB[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            distSq[i][k] = (int)d2;\n            ceilD[i][k] = (unsigned short)p;\n            if (p <= 5000) coverList[i].push_back({(unsigned short)p, k});\n        }\n        sort(coverList[i].begin(), coverList[i].end(), [](const RK& a, const RK& b) {\n            if (a.p != b.p) return a.p < b.p;\n            return a.k < b.k;\n        });\n    }\n\n    vector<Solution> sols;\n    const double GEN_DEADLINE = 0.85;\n    const double LOCAL_DEADLINE = 1.90;\n\n    // Initial 1: nearest assignments with root-distance bias.\n    vector<double> lambdas = {0.0, 0.05, 0.2, 0.7, 1.5};\n    for (double l : lambdas) {\n        vector<int> P = nearestSolution(l);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    // Initial 2: reverse delete from all radius-5000 stations.\n    {\n        vector<int> P(N, 5000);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    // Initial 3: greedy set cover with several connection penalties.\n    vector<pair<double,double>> params = {\n        {0.0, 1.0}, {0.2, 1.0}, {0.5, 1.0}, {0.8, 1.0},\n        {1.2, 1.0}, {2.0, 1.0}, {0.3, 1.15}, {0.8, 1.15},\n        {1.5, 1.15}, {0.5, 0.9}\n    };\n\n    vector<char> allAllowed(N, 1);\n    for (auto [beta, ex] : params) {\n        if (gtimer.elapsed() > GEN_DEADLINE) break;\n        vector<int> P(N, 0);\n        if (greedyRepair(P, allAllowed, beta, ex, nullptr, GEN_DEADLINE)) {\n            considerCandidate(P, sols, GEN_DEADLINE);\n        }\n    }\n\n    // Emergency fallback.\n    if (sols.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        if (!isFull(P)) greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        sols.push_back(evaluateSolution(P));\n    }\n\n    sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b) {\n        return a.total < b.total;\n    });\n\n    vector<Solution> uniq;\n    for (const auto& s : sols) {\n        if (s.total >= INFLL / 2) continue;\n        bool dup = false;\n        for (const auto& u : uniq) {\n            if (u.P == s.P) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniq.push_back(s);\n        if ((int)uniq.size() >= 20) break;\n    }\n\n    if (uniq.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        uniq.push_back(evaluateSolution(P));\n    }\n\n    Solution best = uniq[0];\n\n    int optN = min(5, (int)uniq.size());\n    for (int i = 0; i < optN && gtimer.elapsed() < LOCAL_DEADLINE; ++i) {\n        Solution opt = localSearch(uniq[i], LOCAL_DEADLINE);\n        if (opt.total < best.total) best = opt;\n    }\n\n    // Final safe trim.\n    best = evaluateSolution(best.P);\n    if (gtimer.elapsed() < 1.95) {\n        vector<long long> br = computeBranch(best.P, best.tree);\n        vector<int> p2 = best.P;\n        trimP(p2, makeOrder(p2, 3, &br));\n        Solution ns = evaluateSolution(p2);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (!isFull(best.P)) {\n        greedyRepair(best.P, allAllowed, 0.0, 1.0);\n        best = evaluateSolution(best.P);\n    } else {\n        best = evaluateSolution(best.P);\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 e = 0; e < M; ++e) {\n        if (e) cout << ' ';\n        cout << (best.tree.mask.test(e) ? 1 : 0);\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 int M = N * (N + 1) / 2;\nstatic constexpr int INTERNAL = M - N; // rows 0..28\n\nint ID[N][N], Xc[M], Yc[M];\nvector<int> G[M], PAR[M], CH[M];\nvector<pair<int,int>> EDGES;\nvector<int> INCIDENT[M];\n\nbool validXY(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y <= x;\n}\n\nvoid precompute() {\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) ID[i][j] = -1;\n\n    int idx = 0;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            ID[x][y] = idx;\n            Xc[idx] = x;\n            Yc[idx] = y;\n            idx++;\n        }\n    }\n\n    int dx[6] = {0, 0, -1, -1, 1, 1};\n    int dy[6] = {-1, 1, -1, 0, 0, 1};\n\n    for (int p = 0; p < M; p++) {\n        int x = Xc[p], y = Yc[p];\n\n        for (int k = 0; k < 6; k++) {\n            int nx = x + dx[k], ny = y + dy[k];\n            if (validXY(nx, ny)) G[p].push_back(ID[nx][ny]);\n        }\n\n        if (x + 1 < N) {\n            CH[p].push_back(ID[x + 1][y]);\n            CH[p].push_back(ID[x + 1][y + 1]);\n        }\n        if (x > 0) {\n            if (y > 0) PAR[p].push_back(ID[x - 1][y - 1]);\n            if (y < x) PAR[p].push_back(ID[x - 1][y]);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int c : CH[p]) {\n            int ei = (int)EDGES.size();\n            EDGES.emplace_back(p, c);\n            INCIDENT[p].push_back(ei);\n            INCIDENT[c].push_back(ei);\n        }\n    }\n}\n\nstruct Work {\n    array<int, M> a;\n    array<int, M> pos;\n    vector<pair<int,int>> ops;\n\n    Work() {}\n\n    Work(const array<int, M>& init) {\n        a = init;\n        for (int i = 0; i < M; i++) pos[a[i]] = i;\n        ops.clear();\n    }\n};\n\ninline void doSwap(Work& w, int u, int v) {\n    int lu = w.a[u], lv = w.a[v];\n    swap(w.a[u], w.a[v]);\n    w.pos[lu] = v;\n    w.pos[lv] = u;\n    w.ops.emplace_back(u, v);\n}\n\nint countViol(const array<int, M>& a) {\n    int e = 0;\n    for (auto [p, c] : EDGES) {\n        if (a[p] > a[c]) e++;\n    }\n    return e;\n}\n\nint centerVal(int p) {\n    return abs(2 * Yc[p] - Xc[p]);\n}\n\nint chooseCand(const vector<int>& cand, int choice, const Work& w) {\n    int best = cand[0];\n    for (int q : cand) {\n        bool take = false;\n        if (choice == 0) {\n            if (w.a[q] > w.a[best]) take = true;\n        } else if (choice == 1) {\n            if (w.a[q] < w.a[best]) take = true;\n        } else if (choice == 2) {\n            if (Yc[q] < Yc[best]) take = true;\n        } else if (choice == 3) {\n            if (Yc[q] > Yc[best]) take = true;\n        } else {\n            int cq = centerVal(q), cb = centerVal(best);\n            if (cq < cb || (cq == cb && w.a[q] > w.a[best])) take = true;\n        }\n        if (take) best = q;\n    }\n    return best;\n}\n\n// Guaranteed finisher: for each internal cell, pull up the minimum in its descendant cone.\nbool appendCone(Work& w, int yOrder, int pathMode, int limit) {\n    if (countViol(w.a) == 0) return true;\n\n    for (int x = 0; x <= N - 2; x++) {\n        for (int yi = 0; yi <= x; yi++) {\n            int y = (yOrder == 0 ? yi : x - yi);\n\n            int best = ID[x][y];\n            int bv = w.a[best];\n\n            for (int r = x; r < N; r++) {\n                int c0 = y;\n                int c1 = y + (r - x);\n                for (int c = c0; c <= c1; c++) {\n                    int p = ID[r][c];\n                    if (w.a[p] < bv) {\n                        bv = w.a[p];\n                        best = p;\n                    }\n                }\n            }\n\n            int cur = best;\n            while (Xc[cur] > x) {\n                int cx = Xc[cur], cy = Yc[cur];\n                bool goLeft = false;\n\n                if (pathMode == 0) {\n                    // use up-left moves first\n                    goLeft = (cy > y);\n                } else if (pathMode == 1) {\n                    // use up-right moves first\n                    goLeft = !(cx - cy > x - y);\n                } else {\n                    // balanced\n                    int rem = cx - x;\n                    int needLeft = cy - y;\n                    if (needLeft <= 0) goLeft = false;\n                    else if (needLeft >= rem) goLeft = true;\n                    else goLeft = (needLeft * 2 >= rem);\n                }\n\n                int np = goLeft ? ID[cx - 1][cy - 1] : ID[cx - 1][cy];\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, cur, np);\n                cur = np;\n            }\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n    return countViol(w.a) == 0;\n}\n\n// Label-order sift.\nbool solveSift(const array<int, M>& init, int dir, int choice, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        // increasing labels: move upward while a parent is larger\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    } else {\n        // decreasing labels: move downward while a child is smaller\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool parentsFixed(int p, const vector<char>& fixed) {\n    for (int q : PAR[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nbool childrenFixed(int p, const vector<char>& fixed) {\n    for (int q : CH[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nint openInc(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (fixed[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openDec(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (fixed[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\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 Strat {\n    int w;\n    int row;\n    int center;\n    int open;\n    int randAmp;\n    uint64_t seed;\n};\n\n// Topological/reverse-topological BFS construction.\nbool solveBFS(const array<int, M>& init, int dir, const Strat& st, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<char> fixed(M, 0), avail(M, 0);\n\n    if (dir == 0) {\n        avail[ID[0][0]] = 1;\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openInc(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(v + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) {\n                doSwap(w, path[i], path[i + 1]);\n            }\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] < N - 1) internalFixed++;\n\n            for (int ch : CH[best]) {\n                if (!fixed[ch] && parentsFixed(ch, fixed)) avail[ch] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    } else {\n        for (int y = 0; y < N; y++) avail[ID[N - 1][y]] = 1;\n\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n            int step = M - 1 - v;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openDec(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) {\n                doSwap(w, path[i], path[i + 1]);\n            }\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] > 0) nonTopFixed++;\n\n            for (int pr : PAR[best]) {\n                if (!fixed[pr] && childrenFixed(pr, fixed)) avail[pr] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint localDelta(const Work& w, int p, int c) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[c]) add(e);\n\n    int before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        if (w.a[u] > w.a[v]) before++;\n\n        int au = (u == p ? w.a[c] : (u == c ? w.a[p] : w.a[u]));\n        int av = (v == p ? w.a[c] : (v == c ? w.a[p] : w.a[v]));\n        if (au > av) after++;\n    }\n\n    return before - after;\n}\n\nint chooseViolationEdge(const Work& w, int variant) {\n    long long bestKey = LLONG_MIN;\n    int best = -1;\n\n    for (int ei = 0; ei < (int)EDGES.size(); ei++) {\n        auto [p, c] = EDGES[ei];\n        if (w.a[p] <= w.a[c]) continue;\n\n        int diff = w.a[p] - w.a[c];\n        int delta = 0;\n        if (variant >= 6) delta = localDelta(w, p, c);\n\n        long long key = 0;\n        if (variant == 0) {\n            key = diff;\n        } else if (variant == 1) {\n            key = 1LL * (M - w.a[c]) * 1000 + diff;\n        } else if (variant == 2) {\n            key = 1LL * w.a[p] * 1000 + diff;\n        } else if (variant == 3) {\n            key = 1LL * (N - Xc[p]) * 100000 + diff;\n        } else if (variant == 4) {\n            key = 1LL * Xc[p] * 100000 + diff;\n        } else if (variant == 5) {\n            key = 1LL * diff * 1000 + (N - Xc[p]) * 20 + (M - w.a[c]);\n        } else if (variant == 6) {\n            key = 1LL * delta * 1000000 + 1LL * diff * 1000 + (M - w.a[c]);\n        } else if (variant == 7) {\n            key = 1LL * delta * 1000000 + 1LL * (N - Xc[p]) * 1000 + diff;\n        } else {\n            key = 1LL * delta * 1000000 + 1LL * Xc[p] * 1000 + diff;\n        }\n\n        if (key > bestKey) {\n            bestKey = key;\n            best = ei;\n        }\n    }\n\n    return best;\n}\n\nbool runLocalSteps(Work& w, int variant, int steps, int limit) {\n    for (int s = 0; s < steps; s++) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) return true;\n\n        if ((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n    return true;\n}\n\nbool solveLocal(const array<int, M>& init, int variant, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) {\n            out = move(w);\n            return true;\n        }\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool solveSweep(const array<int, M>& init, int xdir, int ydir, int choice, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        bool changed = false;\n\n        for (int xi = 0; xi < N - 1; xi++) {\n            int x = (xdir == 0 ? N - 2 - xi : xi);\n\n            for (int yi = 0; yi <= x; yi++) {\n                int y = (ydir == 0 ? yi : x - yi);\n                int cur = ID[x][y];\n\n                while (Xc[cur] < N - 1) {\n                    vector<int> cand;\n                    for (int q : CH[cur]) {\n                        if (w.a[cur] > w.a[q]) cand.push_back(q);\n                    }\n                    if (cand.empty()) break;\n\n                    int q = chooseCand(cand, choice, w);\n                    if ((int)w.ops.size() + 1 > limit) return false;\n\n                    doSwap(w, cur, q);\n                    cur = q;\n                    changed = true;\n                }\n            }\n        }\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n        if (!changed) break;\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    array<int, M> init;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            cin >> init[ID[x][y]];\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto timeOK = [&]() {\n        double t = chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n        return t < 1.85;\n    };\n\n    vector<pair<int,int>> bestOps;\n    int bestK = 10001;\n\n    auto consider = [&](Work&& w) {\n        int k = (int)w.ops.size();\n        if (k <= 10000 && k < bestK && countViol(w.a) == 0) {\n            bestK = k;\n            bestOps = move(w.ops);\n        }\n    };\n\n    auto limitNow = [&]() {\n        return min(10000, max(0, bestK - 1));\n    };\n\n    // Guaranteed candidates.\n    for (int yo = 0; yo < 2; yo++) {\n        for (int pm = 0; pm < 3; pm++) {\n            Work w(init);\n            if (appendCone(w, yo, pm, 10000)) consider(move(w));\n        }\n    }\n\n    // Label-order sifts.\n    for (int dir = 0; dir < 2 && timeOK() && bestK > 0; dir++) {\n        for (int ch = 0; ch < 5 && timeOK() && bestK > 0; ch++) {\n            Work w;\n            if (solveSift(init, dir, ch, limitNow(), w)) consider(move(w));\n        }\n    }\n\n    // Hybrid: a few local fixing swaps, then guaranteed finisher.\n    vector<int> prefVars = {0, 1, 6, 7};\n    vector<int> prefSteps = {100, 300, 600, 1000};\n\n    for (int var : prefVars) {\n        for (int stp : prefSteps) {\n            if (!timeOK() || bestK == 0) break;\n\n            Work pref(init);\n            if (!runLocalSteps(pref, var, stp, limitNow())) continue;\n\n            if (countViol(pref.a) == 0) {\n                consider(move(pref));\n                continue;\n            }\n\n            for (int yo = 0; yo < 2; yo++) {\n                for (int pm = 0; pm < 3; pm++) {\n                    if (!timeOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendCone(w, yo, pm, limitNow())) consider(move(w));\n                }\n            }\n        }\n    }\n\n    // BFS topological constructions.\n    vector<Strat> strats;\n    auto addStrat = [&](int w, int r, int c, int o, int ra = 0, uint64_t seed = 0) {\n        strats.push_back({w, r, c, o, ra, seed});\n    };\n\n    addStrat(1000, 0, 0, 0);\n    addStrat(1000, 1, 0, 0);\n    addStrat(1000, -1, 0, 0);\n    addStrat(1000, 0, 1, 0);\n    addStrat(1000, 0, -1, 0);\n    addStrat(1000, 0, 0, -10);\n    addStrat(200, 10, 0, 0);\n    addStrat(200, -10, 0, 0);\n    addStrat(200, 30, 0, 0);\n    addStrat(200, -30, 0, 0);\n    addStrat(200, 0, 10, 0);\n    addStrat(200, 0, -10, 0);\n    addStrat(200, 10, -5, -20);\n    addStrat(200, -10, 5, -20);\n    addStrat(100, 10, 0, -30);\n    addStrat(100, -10, 0, -30);\n    addStrat(1000, 0, 0, 0, 100, 1234567);\n    addStrat(1000, 0, 0, 0, 100, 9876543);\n    addStrat(1000, 0, 0, 0, 100, 5555555);\n    addStrat(1000, 0, 0, 0, 100, 3141592);\n\n    for (int dir = 0; dir < 2 && timeOK() && bestK > 0; dir++) {\n        for (const auto& st : strats) {\n            if (!timeOK() || bestK == 0) break;\n            Work w;\n            if (solveBFS(init, dir, st, limitNow(), w)) consider(move(w));\n        }\n    }\n\n    // Sweep heapification variants.\n    for (int xd = 0; xd < 2 && timeOK() && bestK > 0; xd++) {\n        for (int yd = 0; yd < 2 && timeOK() && bestK > 0; yd++) {\n            for (int ch = 0; ch < 4 && timeOK() && bestK > 0; ch++) {\n                Work w;\n                if (solveSweep(init, xd, yd, ch, limitNow(), w)) consider(move(w));\n            }\n        }\n    }\n\n    // Pure local violation swapping variants.\n    for (int var = 0; var < 9 && timeOK() && bestK > 0; var++) {\n        Work w;\n        if (solveLocal(init, var, limitNow(), w)) consider(move(w));\n    }\n\n    // Safety, should never be needed because cone is guaranteed.\n    if (bestK > 10000) {\n        Work w(init);\n        appendCone(w, 0, 0, 10000);\n        bestOps = move(w.ops);\n        bestK = (int)bestOps.size();\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto [u, v] : bestOps) {\n        cout << Xc[u] << ' ' << Yc[u] << ' ' << Xc[v] << ' ' << Yc[v] << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nint D, N, M;\nint rootR, rootC;\nbool obs[9][9];\nint gid[9][9];\n\nvector<pair<int,int>> posi;\nvector<vector<int>> adjList;\nvector<int> rootAdjCells;\nvector<char> isRootAdj;\n\nvector<uint64_t> adjLo, adjHi;\nvector<int> orderP, pIndex;\n\nvector<int> assignedLabel;\nvector<char> unseenLabel;\nint emptyCnt;\n\nstatic inline bool inside(int r, int c) {\n    return 0 <= r && r < D && 0 <= c && c < D;\n}\n\nstatic inline bool hasBit(uint64_t lo, uint64_t hi, int i) {\n    if (i < 64) return (lo >> i) & 1ULL;\n    return (hi >> (i - 64)) & 1ULL;\n}\n\nstatic inline void setBit(uint64_t &lo, uint64_t &hi, int i) {\n    if (i < 64) lo |= 1ULL << i;\n    else hi |= 1ULL << (i - 64);\n}\n\nstatic inline bool intersects(uint64_t aLo, uint64_t aHi, uint64_t bLo, uint64_t bHi) {\n    return ((aLo & bLo) | (aHi & bHi)) != 0;\n}\n\nstatic inline int countLessMask(uint64_t lo, uint64_t hi, int x) {\n    if (x <= 0) return 0;\n    if (x < 64) {\n        return __builtin_popcountll(lo & ((1ULL << x) - 1));\n    }\n    if (x == 64) return __builtin_popcountll(lo);\n    int h = x - 64;\n    uint64_t mask = (1ULL << h) - 1;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n}\n\n// Checks whether all current empty cells except a,b are reachable from entrance.\nbool connectedAvoid(int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (assignedLabel[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (assignedLabel[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validPlacementCandidates() {\n    vector<int> cand;\n    for (int c = 0; c < M; c++) {\n        if (assignedLabel[c] != -1) continue;\n        if (connectedAvoid(c, -1, emptyCnt - 1)) cand.push_back(c);\n    }\n\n    // Should never happen if the invariant is maintained.\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (assignedLabel[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nint countNextValidAfter(int c) {\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return 0;\n    if (rem == 1) return 1;\n\n    int cnt = 0;\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (connectedAvoid(c, e, rem - 1)) cnt++;\n    }\n    return cnt;\n}\n\nint invOfValues(const int *seq) {\n    int inv = 0;\n    for (int i = 0; i < M; i++) {\n        for (int j = i + 1; j < M; j++) {\n            if (seq[i] > seq[j]) inv++;\n        }\n    }\n    return inv;\n}\n\nint greedyCostLabels(const vector<int> &lab) {\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            bool acc = isRootAdj[i] || intersects(adjLo[i], adjHi[i], rlo, rhi);\n            if (acc && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) return 1000000000;\n\n        int x = lab[best];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nint sequenceCost(const vector<int> &seq, const vector<int> &lab) {\n    if ((int)seq.size() != M) return 1000000000;\n\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int x = lab[seq[step]];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nvector<int> greedySequenceMinLabel(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            bool acc = isRootAdj[i] || intersects(adjLo[i], adjHi[i], rlo, rhi);\n            if (acc && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) break;\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n    }\n\n    return seq;\n}\n\nvector<int> greedySequenceLookahead2(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestScore = INT_MAX;\n        int bestCostInc = INT_MAX;\n        int bestLab = INT_MAX;\n\n        for (int c = 0; c < M; c++) {\n            if (hasBit(rlo, rhi, c)) continue;\n            bool acc = isRootAdj[c] || intersects(adjLo[c], adjHi[c], rlo, rhi);\n            if (!acc) continue;\n\n            int x = lab[c];\n            int less = countLessMask(llo, lhi, x);\n            int inc1 = x - less;\n            int costInc = step - less;\n\n            uint64_t nrlo = rlo, nrhi = rhi;\n            uint64_t nllo = llo, nlhi = lhi;\n            setBit(nrlo, nrhi, c);\n            setBit(nllo, nlhi, x);\n\n            int inc2 = 0;\n            if (step + 1 < M) {\n                inc2 = INT_MAX / 4;\n                for (int d = 0; d < M; d++) {\n                    if (hasBit(nrlo, nrhi, d)) continue;\n                    bool acc2 = isRootAdj[d] || intersects(adjLo[d], adjHi[d], nrlo, nrhi);\n                    if (!acc2) continue;\n\n                    int y = lab[d];\n                    int less2 = countLessMask(nllo, nlhi, y);\n                    inc2 = min(inc2, y - less2);\n                }\n            }\n\n            int score = inc1 + inc2;\n\n            if (score < bestScore ||\n                (score == bestScore && costInc < bestCostInc) ||\n                (score == bestScore && costInc == bestCostInc && x < bestLab)) {\n                bestScore = score;\n                bestCostInc = costInc;\n                bestLab = x;\n                best = c;\n            }\n        }\n\n        if (best == -1) break;\n\n        int x = lab[best];\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return seq;\n}\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key &o) const {\n        return lo == o.lo && hi == o.hi;\n    }\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\nstruct KeyHash {\n    size_t operator()(const Key &k) const {\n        return splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1);\n    }\n};\n\nstruct Node {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nstruct Temp {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nvector<int> beamSearchRemoval(const vector<int> &lab, int upperBound) {\n    const int BEAM = 5000;\n\n    vector<Node> nodes;\n    nodes.reserve((M + 1) * BEAM + 1);\n    nodes.push_back(Node{0, 0, 0, 0, 0, 0, -1, -1});\n\n    vector<int> cur;\n    cur.push_back(0);\n\n    auto betterTemp = [](const Temp &a, const Temp &b) {\n        if (a.forced != b.forced) return a.forced < b.forced;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.lo != b.lo) return a.lo < b.lo;\n        return a.hi < b.hi;\n    };\n\n    for (int depth = 0; depth < M; depth++) {\n        vector<Temp> temps;\n        size_t reserveSize = min<size_t>((size_t)cur.size() * 32 + 100, 300000);\n        temps.reserve(reserveSize);\n\n        unordered_map<Key, int, KeyHash> mp;\n        mp.reserve(reserveSize * 2);\n\n        for (int idx : cur) {\n            const Node &s = nodes[idx];\n\n            for (int i = 0; i < M; i++) {\n                if (hasBit(s.lo, s.hi, i)) continue;\n\n                bool acc = isRootAdj[i] || intersects(adjLo[i], adjHi[i], s.lo, s.hi);\n                if (!acc) continue;\n\n                int x = lab[i];\n                int less = countLessMask(s.llo, s.lhi, x);\n\n                int cost2 = s.cost + (depth - less);\n                int forced2 = s.forced + (x - less);\n\n                if (forced2 > upperBound) continue;\n\n                uint64_t nlo = s.lo, nhi = s.hi;\n                uint64_t nllo = s.llo, nlhi = s.lhi;\n                setBit(nlo, nhi, i);\n                setBit(nllo, nlhi, x);\n\n                Temp t{nlo, nhi, nllo, nlhi, cost2, forced2, idx, i};\n                Key key{nlo, nhi};\n\n                auto it = mp.find(key);\n                if (it == mp.end()) {\n                    int id = (int)temps.size();\n                    temps.push_back(t);\n                    mp.emplace(key, id);\n                } else {\n                    int id = it->second;\n                    if (t.cost < temps[id].cost ||\n                        (t.cost == temps[id].cost && t.forced < temps[id].forced)) {\n                        temps[id] = t;\n                    }\n                }\n            }\n        }\n\n        if (temps.empty()) return {};\n\n        if ((int)temps.size() > BEAM) {\n            nth_element(temps.begin(), temps.begin() + BEAM, temps.end(), betterTemp);\n            temps.resize(BEAM);\n        }\n\n        vector<int> nxt;\n        nxt.reserve(temps.size());\n\n        for (const Temp &t : temps) {\n            int id = (int)nodes.size();\n            nodes.push_back(Node{t.lo, t.hi, t.llo, t.lhi, t.cost, t.forced, t.parent, t.cell});\n            nxt.push_back(id);\n        }\n\n        cur.swap(nxt);\n    }\n\n    int bestNode = -1;\n    int bestCost = INT_MAX;\n\n    for (int idx : cur) {\n        if (nodes[idx].cost < bestCost) {\n            bestCost = nodes[idx].cost;\n            bestNode = idx;\n        }\n    }\n\n    if (bestNode == -1) return {};\n\n    vector<int> seq;\n    while (bestNode != 0 && bestNode != -1) {\n        seq.push_back(nodes[bestNode].cell);\n        bestNode = nodes[bestNode].parent;\n    }\n\n    reverse(seq.begin(), seq.end());\n    if ((int)seq.size() != M) return {};\n    return seq;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D >> N;\n    rootR = 0;\n    rootC = (D - 1) / 2;\n\n    memset(obs, 0, sizeof(obs));\n    memset(gid, -1, sizeof(gid));\n\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = true;\n    }\n\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (r == rootR && c == rootC) continue;\n            if (obs[r][c]) continue;\n            gid[r][c] = (int)posi.size();\n            posi.push_back({r, c});\n        }\n    }\n\n    M = (int)posi.size();\n\n    adjList.assign(M, {});\n    isRootAdj.assign(M, 0);\n    adjLo.assign(M, 0);\n    adjHi.assign(M, 0);\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    for (int id = 0; id < M; id++) {\n        auto [r, c] = posi[id];\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n            if (!inside(nr, nc)) continue;\n\n            if (nr == rootR && nc == rootC) {\n                isRootAdj[id] = 1;\n            } else if (!obs[nr][nc]) {\n                int to = gid[nr][nc];\n                if (to >= 0) adjList[id].push_back(to);\n            }\n        }\n\n        if (isRootAdj[id]) rootAdjCells.push_back(id);\n    }\n\n    for (int i = 0; i < M; i++) {\n        for (int to : adjList[i]) {\n            if (to < 64) adjLo[i] |= 1ULL << to;\n            else adjHi[i] |= 1ULL << (to - 64);\n        }\n    }\n\n    // BFS order from entrance, prioritizing downward/central expansion.\n    int dist[9][9];\n    int disc[9][9];\n    for (int r = 0; r < 9; r++) {\n        for (int c = 0; c < 9; c++) {\n            dist[r][c] = 1e9;\n            disc[r][c] = 1e9;\n        }\n    }\n\n    int bfsDirs[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};\n    queue<pair<int,int>> q;\n    dist[rootR][rootC] = 0;\n    disc[rootR][rootC] = 0;\n    int dcnt = 1;\n    q.push({rootR, rootC});\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : bfsDirs) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != (int)1e9) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            disc[nr][nc] = dcnt++;\n            q.push({nr, nc});\n        }\n    }\n\n    orderP.resize(M);\n    iota(orderP.begin(), orderP.end(), 0);\n\n    sort(orderP.begin(), orderP.end(), [&](int a, int b) {\n        auto [ra, ca] = posi[a];\n        auto [rb, cb] = posi[b];\n        if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n        if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n        return a < b;\n    });\n\n    pIndex.assign(M, 0);\n    for (int i = 0; i < M; i++) pIndex[orderP[i]] = i;\n\n    assignedLabel.assign(M, -1);\n    unseenLabel.assign(M, 1);\n    emptyCnt = M;\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<int> cand = validPlacementCandidates();\n\n        vector<int> futureLabels;\n        futureLabels.reserve(emptyCnt - 1);\n\n        int rankLabel = 0;\n        for (int x = 0; x < M; x++) {\n            if (!unseenLabel[x]) continue;\n            if (x < t) rankLabel++;\n            if (x != t) futureLabels.push_back(x);\n        }\n\n        int bestCell = -1;\n        int bestHyp = INT_MAX;\n        int bestInv = INT_MAX;\n        int bestAbs = INT_MAX;\n        int bestNext = -1;\n        int bestPDiff = INT_MAX;\n\n        vector<int> lab(M);\n        int seqVals[85];\n\n        for (int c : cand) {\n            int ptr = 0;\n            int si = 0;\n\n            for (int cell : orderP) {\n                int v;\n                if (assignedLabel[cell] != -1) {\n                    v = assignedLabel[cell];\n                } else if (cell == c) {\n                    v = t;\n                } else {\n                    v = futureLabels[ptr++];\n                }\n\n                lab[cell] = v;\n                seqVals[si++] = v;\n            }\n\n            int fixedInv = invOfValues(seqVals);\n            int greedyInv = greedyCostLabels(lab);\n            int hyp = min(fixedInv, greedyInv);\n\n            int rankCell = 0;\n            for (int e = 0; e < M; e++) {\n                if (assignedLabel[e] == -1 && pIndex[e] < pIndex[c]) rankCell++;\n            }\n\n            int absDiff = abs(rankCell - rankLabel);\n            int nextValid = countNextValidAfter(c);\n            int pDiff = abs(pIndex[c] - t);\n\n            bool better = false;\n            if (hyp != bestHyp) better = hyp < bestHyp;\n            else if (fixedInv != bestInv) better = fixedInv < bestInv;\n            else if (absDiff != bestAbs) better = absDiff < bestAbs;\n            else if (nextValid != bestNext) better = nextValid > bestNext;\n            else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n\n            if (better) {\n                bestHyp = hyp;\n                bestInv = fixedInv;\n                bestAbs = absDiff;\n                bestNext = nextValid;\n                bestPDiff = pDiff;\n                bestCell = c;\n            }\n        }\n\n        if (bestCell == -1) bestCell = cand[0];\n\n        assignedLabel[bestCell] = t;\n        unseenLabel[t] = 0;\n        emptyCnt--;\n\n        cout << posi[bestCell].first << ' ' << posi[bestCell].second << endl;\n    }\n\n    vector<int> bestSeq = orderP;\n    int bestCost = sequenceCost(bestSeq, assignedLabel);\n\n    vector<int> gseq = greedySequenceMinLabel(assignedLabel);\n    int gcost = sequenceCost(gseq, assignedLabel);\n    if (gcost < bestCost) {\n        bestCost = gcost;\n        bestSeq = gseq;\n    }\n\n    vector<int> lseq = greedySequenceLookahead2(assignedLabel);\n    int lcost = sequenceCost(lseq, assignedLabel);\n    if (lcost < bestCost) {\n        bestCost = lcost;\n        bestSeq = lseq;\n    }\n\n    vector<int> bseq = beamSearchRemoval(assignedLabel, bestCost);\n    int bcost = sequenceCost(bseq, assignedLabel);\n    if (bcost < bestCost) {\n        bestSeq = bseq;\n        bestCost = bcost;\n    }\n\n    if ((int)bestSeq.size() != M) bestSeq = orderP;\n\n    for (int cell : bestSeq) {\n        cout << posi[cell].first << ' ' << posi[cell].second << '\\n';\n    }\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 50;\nstatic const int MAXV = MAXN * MAXN;\nstatic const int MAXC = 105;\n\nint N, M, V;\nbool REQ[MAXC][MAXC];\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\n\nint visArr[MAXV];\nint bfsQ[MAXV];\nint visStamp = 1;\n\ninline int newStamp() {\n    ++visStamp;\n    if (visStamp == INT_MAX) {\n        memset(visArr, 0, sizeof(visArr));\n        visStamp = 1;\n    }\n    return visStamp;\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 RNG {\n    uint64_t s;\n    RNG(uint64_t seed = 1) : s(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (s += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    template<class T>\n    void shuffle(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            swap(v[i], v[nextInt(i + 1)]);\n        }\n    }\n};\n\nstruct State {\n    array<unsigned char, MAXV> g;\n    int cnt[MAXC];\n    int edge[MAXC][MAXC];\n    int zeros;\n\n    void clear() {\n        g.fill(0);\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n        zeros = 0;\n    }\n\n    inline void addEdgeCnt(int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        edge[a][b] += d;\n        edge[b][a] += d;\n    }\n\n    void rebuild() {\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n\n        for (int p = 0; p < V; ++p) {\n            int a = g[p];\n            cnt[a]++;\n        }\n        zeros = cnt[0];\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int p = r * N + c;\n                int a = g[p];\n\n                if (r + 1 < N) addEdgeCnt(a, g[(r + 1) * N + c], 1);\n                if (c + 1 < N) addEdgeCnt(a, g[r * N + (c + 1)], 1);\n\n                if (r == 0) addEdgeCnt(0, a, 1);\n                if (r == N - 1) addEdgeCnt(0, a, 1);\n                if (c == 0) addEdgeCnt(0, a, 1);\n                if (c == N - 1) addEdgeCnt(0, a, 1);\n            }\n        }\n    }\n\n    inline bool hasZeroAdj(int p) const {\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return true;\n            int q = nr * N + nc;\n            if (g[q] == 0) return true;\n        }\n        return false;\n    }\n\n    bool connectedAfterRemove(int p, int col) const {\n        if (cnt[col] <= 1) return false;\n\n        int r = p / N, c = p % N;\n        int nb[4], k = 0;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (g[q] == col) nb[k++] = q;\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        bool reached[4] = {};\n        reached[0] = true;\n        int found = 1;\n\n        visArr[nb[0]] = stamp;\n        bfsQ[tail++] = nb[0];\n\n        while (head < tail && found < k) {\n            int v = bfsQ[head++];\n            int vr = v / N, vc = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = vr + DR[d], nc = vc + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n\n                visArr[q] = stamp;\n                for (int i = 1; i < k; ++i) {\n                    if (!reached[i] && q == nb[i]) {\n                        reached[i] = true;\n                        ++found;\n                        break;\n                    }\n                }\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return found == k;\n    }\n\n    bool tryChange(int p, int to) {\n        int from = g[p];\n        if (from == to) return false;\n        if (from == 0) return false;\n        if (to < 0 || to > M) return false;\n        if (cnt[from] <= 1) return false;\n\n        if (to == 0) {\n            if (!hasZeroAdj(p)) return false;\n        } else {\n            bool adjTarget = false;\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] == to) {\n                    adjTarget = true;\n                    break;\n                }\n            }\n            if (!adjTarget) return false;\n        }\n\n        int du[16], dv[16], dd[16], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            int nbcol = 0;\n            if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                nbcol = g[nr * N + nc];\n            }\n\n            addDelta(from, nbcol, -1);\n            addDelta(to, nbcol, +1);\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        if (!connectedAfterRemove(p, from)) return false;\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        cnt[from]--;\n        cnt[to]++;\n        if (to == 0) zeros++;\n        g[p] = (unsigned char)to;\n\n        return true;\n    }\n};\n\nvoid computeDist(const State& st, vector<int>& dist) {\n    const int INF = 1e9;\n    dist.assign(V, INF);\n\n    int head = 0, tail = 0;\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] == 0) {\n            dist[p] = 0;\n            bfsQ[tail++] = p;\n        }\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n            int p = r * N + c;\n            if (st.g[p] != 0 && dist[p] > 1) {\n                dist[p] = 1;\n                bfsQ[tail++] = p;\n            }\n        }\n    }\n\n    while (head < tail) {\n        int v = bfsQ[head++];\n        int r = v / N, c = v % N;\n        int nd = dist[v] + 1;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (dist[q] > nd) {\n                dist[q] = nd;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n}\n\nint greedyDelete(State& st, RNG& rng) {\n    vector<int> cand;\n    cand.reserve(V * 6);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0 && st.hasZeroAdj(p)) cand.push_back(p);\n    }\n\n    rng.shuffle(cand);\n\n    int deleted = 0;\n\n    for (size_t idx = 0; idx < cand.size(); ++idx) {\n        int p = cand[idx];\n        if (st.g[p] == 0) continue;\n        if (!st.hasZeroAdj(p)) continue;\n\n        if (st.tryChange(p, 0)) {\n            ++deleted;\n\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) cand.push_back(q);\n            }\n        }\n    }\n\n    return deleted;\n}\n\nstruct Params {\n    int orderMode;      // 0: near-to-far, 1: random, 2: far-to-near\n    int eqProb;         // probability to allow same-distance repaint\n    bool useLayer;\n    bool targetRandom;\n    bool preDelete;\n};\n\nParams getParams(int run) {\n    switch (run % 12) {\n        case 0: return {0,  0, false, false, true};\n        case 1: return {0,  0, true,  false, true};\n        case 2: return {0, 20, false, false, true};\n        case 3: return {1,  0, false, true,  true};\n        case 4: return {0, 30, true,  false, true};\n        case 5: return {1, 15, false, true,  true};\n        case 6: return {0, 50, false, true,  false};\n        case 7: return {0, 10, false, false, false};\n        case 8: return {2,  0, false, true,  true};\n        case 9: return {0, 10, true,  true,  false};\n        case 10:return {1, 40, true,  true,  true};\n        default:return {0,  0, true,  true,  false};\n    }\n}\n\nint recolorPass(State& st, const vector<int>& dist, RNG& rng, const Params& par) {\n    const int INF = 1e9;\n\n    int layer[MAXC];\n    for (int i = 0; i < MAXC; ++i) layer[i] = INF;\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a > 0) layer[a] = min(layer[a], dist[p]);\n    }\n\n    vector<int> order;\n    order.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) order.push_back(p);\n    }\n\n    rng.shuffle(order);\n\n    if (par.orderMode == 0) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 2) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n    }\n\n    struct Target {\n        int col;\n        int td;\n        int lay;\n        int rnd;\n    };\n\n    int changed = 0;\n\n    for (int p : order) {\n        int a = st.g[p];\n        if (a == 0) continue;\n        if (st.cnt[a] <= 1) continue;\n\n        int dp = dist[p];\n        int r = p / N, c = p % N;\n\n        Target ts[4];\n        int tn = 0;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int q = nr * N + nc;\n            int b = st.g[q];\n            if (b == 0 || b == a) continue;\n\n            int dq = dist[q];\n            bool ok = false;\n\n            if (dq < dp) {\n                ok = true;\n            } else if (par.eqProb > 0 && dq == dp && rng.nextInt(100) < par.eqProb) {\n                ok = true;\n            }\n\n            if (!ok) continue;\n            if (par.useLayer && layer[b] > layer[a]) continue;\n\n            int pos = -1;\n            for (int i = 0; i < tn; ++i) {\n                if (ts[i].col == b) {\n                    pos = i;\n                    break;\n                }\n            }\n\n            if (pos == -1) {\n                ts[tn++] = {b, dq, layer[b], (int)(rng.next() & 0x7fffffff)};\n            } else {\n                ts[pos].td = min(ts[pos].td, dq);\n            }\n        }\n\n        if (tn == 0) continue;\n\n        if (par.targetRandom) {\n            for (int i = tn - 1; i > 0; --i) {\n                swap(ts[i], ts[rng.nextInt(i + 1)]);\n            }\n        } else {\n            for (int i = 0; i < tn; ++i) {\n                for (int j = i + 1; j < tn; ++j) {\n                    bool better = false;\n                    if (ts[j].td != ts[i].td) {\n                        better = ts[j].td < ts[i].td;\n                    } else if (par.useLayer && ts[j].lay != ts[i].lay) {\n                        better = ts[j].lay < ts[i].lay;\n                    } else {\n                        better = ts[j].rnd < ts[i].rnd;\n                    }\n                    if (better) swap(ts[i], ts[j]);\n                }\n            }\n        }\n\n        for (int i = 0; i < tn; ++i) {\n            if (st.tryChange(p, ts[i].col)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid improve(State& st, State& best, RNG& rng, const Params& par, const Timer& timer, double limit) {\n    vector<int> dist;\n    int lastZeros = st.zeros;\n    int stagnant = 0;\n\n    for (int cycle = 0; cycle < 100; ++cycle) {\n        if (timer.elapsed() > limit) break;\n\n        int del = 0;\n\n        if (par.preDelete) {\n            del += greedyDelete(st, rng);\n            if (st.zeros > best.zeros) best = st;\n        }\n\n        computeDist(st, dist);\n        int rec = recolorPass(st, dist, rng, par);\n\n        del += greedyDelete(st, rng);\n        if (st.zeros > best.zeros) best = st;\n\n        if (st.zeros > lastZeros) {\n            lastZeros = st.zeros;\n            stagnant = 0;\n        } else {\n            ++stagnant;\n        }\n\n        if (del + rec == 0) break;\n\n        int maxStag = par.eqProb > 0 ? 6 : 5;\n        if (stagnant >= maxStag) break;\n    }\n}\n\nbool validateState(const State& st) {\n    static int cnt2[MAXC];\n    static int ed2[MAXC][MAXC];\n\n    memset(cnt2, 0, sizeof(cnt2));\n    memset(ed2, 0, sizeof(ed2));\n\n    auto add = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        ed2[a][b]++;\n        ed2[b][a]++;\n    };\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a < 0 || a > M) return false;\n        cnt2[a]++;\n    }\n\n    for (int c = 1; c <= M; ++c) {\n        if (cnt2[c] == 0) return false;\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n            int a = st.g[p];\n\n            if (r + 1 < N) add(a, st.g[(r + 1) * N + c]);\n            if (c + 1 < N) add(a, st.g[r * N + (c + 1)]);\n\n            if (r == 0) add(0, a);\n            if (r == N - 1) add(0, a);\n            if (c == 0) add(0, a);\n            if (c == N - 1) add(0, a);\n        }\n    }\n\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if ((ed2[i][j] > 0) != REQ[i][j]) return false;\n        }\n    }\n\n    for (int col = 1; col <= M; ++col) {\n        int start = -1;\n        for (int p = 0; p < V; ++p) {\n            if (st.g[p] == col) {\n                start = p;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        visArr[start] = stamp;\n        bfsQ[tail++] = start;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != cnt2[col]) return false;\n    }\n\n    if (cnt2[0] > 0) {\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (st.g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != cnt2[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    V = N * N;\n\n    State init;\n    init.clear();\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int x;\n            cin >> x;\n            init.g[i * N + j] = (unsigned char)x;\n\n            seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    init.rebuild();\n\n    memset(REQ, 0, sizeof(REQ));\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if (init.edge[i][j] > 0) {\n                REQ[i][j] = REQ[j][i] = true;\n            }\n        }\n    }\n\n    Timer timer;\n    const double SEARCH_LIMIT = 1.80;\n    const double POLISH_LIMIT = 1.88;\n\n    State best = init;\n\n    int run = 0;\n    while (timer.elapsed() < SEARCH_LIMIT) {\n        State st = (run >= 3 && run % 4 == 3) ? best : init;\n\n        uint64_t rseed =\n            seed\n            + 0x9e3779b97f4a7c15ULL * (uint64_t)(run + 1)\n            + 0xbf58476d1ce4e5b9ULL * (uint64_t)(best.zeros + 1);\n\n        RNG rng(rseed);\n        Params par = getParams(run);\n\n        improve(st, best, rng, par, timer, SEARCH_LIMIT);\n        ++run;\n    }\n\n    RNG finalRng(seed ^ 0xd1b54a32d192ed03ULL);\n    while (timer.elapsed() < POLISH_LIMIT) {\n        int d = greedyDelete(best, finalRng);\n        if (d == 0) break;\n    }\n\n    if (!validateState(best)) {\n        best = init;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (j) cout << ' ';\n            cout << (int)best.g[i * N + j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, D, Q;\nint qUsed = 0;\nmt19937_64 rng;\nvector<vector<char>> itemCmp;\n\nconstexpr int DP_SCALE_BASE = 500;\nconstexpr int DP_SUM_LIMIT = 80000;\n\nstruct Solution {\n    vector<int> assign;\n    vector<vector<int>> bins;\n    vector<double> load;\n    double obj = 1e100;\n};\n\nchar invCmp(char c) {\n    if (c == '>') return '<';\n    if (c == '<') return '>';\n    return c;\n}\n\nchar ask(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    if (!(cin >> s)) exit(0);\n    qUsed++;\n    return s[0];\n}\n\nchar compareItems(int a, int b) {\n    if (a == b) return '=';\n    if (itemCmp[a][b] != '?') return itemCmp[a][b];\n    if (qUsed >= Q) return '?';\n\n    vector<int> L{a}, R{b};\n    char c = ask(L, R);\n    itemCmp[a][b] = c;\n    itemCmp[b][a] = invCmp(c);\n    return c;\n}\n\ndouble norm_pdf(double x) {\n    static const double INV_SQRT_2PI = 1.0 / sqrt(2.0 * acos(-1.0));\n    if (abs(x) > 40) return 0.0;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble norm_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble truncatedNormalMean(double mu, double sd, double lo, double hi) {\n    if (sd < 1e-12) return clamp(mu, lo, hi);\n\n    double a = (lo - mu) / sd;\n    double b = (hi - mu) / sd;\n    double A = norm_cdf(a);\n    double B = norm_cdf(b);\n    double Z = B - A;\n\n    if (Z < 1e-14) {\n        if (mu < lo) return lo;\n        if (mu > hi) return hi;\n        return clamp(mu, lo, hi);\n    }\n\n    double mean = mu + sd * (norm_pdf(a) - norm_pdf(b)) / Z;\n    return clamp(mean, lo, hi);\n}\n\nvector<double> estimateWeights(const vector<double>& score, int qRand) {\n    vector<double> est(N, 1.0);\n    if (qRand <= 0) return est;\n\n    const double PI = acos(-1.0);\n    const double c = sqrt(2.0 / PI);\n\n    int K = N / 2;\n    double pNonZero = 2.0 * K / N;\n    double lambda = 2.0 * K / (N - 1.0);\n    double ce = c * sqrt(lambda);\n\n    double sigmaZ = sqrt(pNonZero * N) / (ce * sqrt((double)qRand));\n\n    // Prior: Exp(1), truncated at b=N/D, then normalized to mean 1.\n    double cap = (double)N / D;\n    double e = exp(-cap);\n    double Z = 1.0 - e;\n    double meanX = (1.0 - (cap + 1.0) * e) / Z;\n    double secondX = (2.0 - (cap * cap + 2.0 * cap + 2.0) * e) / Z;\n    double varX = max(1e-12, secondX - meanX * meanX);\n    double cv = sqrt(varX) / meanX;\n    double rMax = cap / meanX;\n\n    double tau = max(1e-6, cv * sigmaZ);\n    double rate = meanX;\n\n    for (int i = 0; i < N; i++) {\n        double zObs = score[i] * sqrt((double)N) / (ce * qRand);\n        double obsR = 1.0 + cv * zObs;\n\n        // Posterior with exponential prior:\n        // exp(-rate*r) * Normal(obsR | r, tau^2)\n        double mu = obsR - rate * tau * tau;\n        est[i] = truncatedNormalMean(mu, tau, 0.0, rMax);\n        est[i] = max(est[i], 1e-6);\n    }\n\n    return est;\n}\n\ndouble calcObjLoad(const vector<double>& load, double target) {\n    double res = 0.0;\n    for (double x : load) {\n        double d = x - target;\n        res += d * d;\n    }\n    return res;\n}\n\ndouble totalWeight(const vector<double>& w) {\n    return accumulate(w.begin(), w.end(), 0.0);\n}\n\nSolution buildSolution(const vector<int>& assign, const vector<double>& w) {\n    Solution sol;\n    sol.assign = assign;\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    for (int i = 0; i < N; i++) {\n        int b = sol.assign[i];\n        sol.bins[b].push_back(i);\n        sol.load[b] += w[i];\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nvoid eraseItem(vector<int>& v, int x) {\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (v[i] == x) {\n            v[i] = v.back();\n            v.pop_back();\n            return;\n        }\n    }\n}\n\nvoid moveItemSol(Solution& sol, int item, int from, int to, const vector<double>& w) {\n    eraseItem(sol.bins[from], item);\n    sol.bins[to].push_back(item);\n    sol.assign[item] = to;\n    sol.load[from] -= w[item];\n    sol.load[to] += w[item];\n}\n\nvoid swapItemsSol(Solution& sol, int x, int y, int bx, int by, const vector<double>& w) {\n    for (int& v : sol.bins[bx]) {\n        if (v == x) {\n            v = y;\n            break;\n        }\n    }\n    for (int& v : sol.bins[by]) {\n        if (v == y) {\n            v = x;\n            break;\n        }\n    }\n\n    sol.assign[x] = by;\n    sol.assign[y] = bx;\n\n    sol.load[bx] += w[y] - w[x];\n    sol.load[by] += w[x] - w[y];\n}\n\nvoid localImprove(Solution& sol, const vector<double>& w, double target) {\n    for (int iter = 0; iter < 2000; iter++) {\n        double bestDelta = -1e-12;\n        int bestType = 0;\n        int bestI = -1, bestJ = -1;\n        int bestA = -1, bestB = -1;\n\n        // Single-item move\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            if ((int)sol.bins[a].size() <= 1) continue;\n\n            for (int b = 0; b < D; b++) {\n                if (a == b) continue;\n\n                double oldVal =\n                    pow(sol.load[a] - target, 2) +\n                    pow(sol.load[b] - target, 2);\n\n                double newVal =\n                    pow(sol.load[a] - w[i] - target, 2) +\n                    pow(sol.load[b] + w[i] - target, 2);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        // Swap\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            for (int j = i + 1; j < N; j++) {\n                int b = sol.assign[j];\n                if (a == b) continue;\n\n                double oldVal =\n                    pow(sol.load[a] - target, 2) +\n                    pow(sol.load[b] - target, 2);\n\n                double newVal =\n                    pow(sol.load[a] - w[i] + w[j] - target, 2) +\n                    pow(sol.load[b] - w[j] + w[i] - target, 2);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestI = i;\n                    bestJ = j;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        if (bestType == 0) break;\n\n        if (bestType == 1) {\n            moveItemSol(sol, bestI, bestA, bestB, w);\n        } else {\n            swapItemsSol(sol, bestI, bestJ, bestA, bestB, w);\n        }\n\n        sol.obj += bestDelta;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nbool pairBalanceDP(Solution& sol, int a, int b, const vector<double>& w, double target) {\n    vector<int> items = sol.bins[a];\n    for (int x : sol.bins[b]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 1) return false;\n\n    double pairSum = sol.load[a] + sol.load[b];\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(w[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1);\n    vector<int> parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    int bestS = -1;\n    int bestDiff = INT_MAX;\n    for (int s = 0; s <= total; s++) {\n        if (!dp[s]) continue;\n        int diff = abs(total - 2 * s);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestS = s;\n        }\n    }\n\n    if (bestS < 0) return false;\n\n    vector<char> inA(M, 0);\n    int cur = bestS;\n    while (cur > 0) {\n        int idx = parItem[cur];\n        if (idx < 0) return false;\n        inA[idx] = 1;\n        cur = parPrev[cur];\n    }\n\n    int cntA = 0;\n    double loadA = 0.0;\n    for (int i = 0; i < M; i++) {\n        if (inA[i]) {\n            cntA++;\n            loadA += w[items[i]];\n        }\n    }\n\n    if (cntA == 0 || cntA == M) return false;\n\n    double loadB = pairSum - loadA;\n\n    // Keep orientation closer to the previous one.\n    double keepCost = abs(loadA - sol.load[a]) + abs(loadB - sol.load[b]);\n    double flipCost = abs(loadB - sol.load[a]) + abs(loadA - sol.load[b]);\n    if (flipCost < keepCost) {\n        for (char& x : inA) x ^= 1;\n        swap(loadA, loadB);\n        cntA = M - cntA;\n    }\n\n    double oldPair =\n        pow(sol.load[a] - target, 2) +\n        pow(sol.load[b] - target, 2);\n\n    double newPair =\n        pow(loadA - target, 2) +\n        pow(loadB - target, 2);\n\n    if (newPair >= oldPair - 1e-12) return false;\n\n    sol.bins[a].clear();\n    sol.bins[b].clear();\n    sol.load[a] = 0.0;\n    sol.load[b] = 0.0;\n\n    for (int i = 0; i < M; i++) {\n        int item = items[i];\n        if (inA[i]) {\n            sol.assign[item] = a;\n            sol.bins[a].push_back(item);\n            sol.load[a] += w[item];\n        } else {\n            sol.assign[item] = b;\n            sol.bins[b].push_back(item);\n            sol.load[b] += w[item];\n        }\n    }\n\n    sol.obj += newPair - oldPair;\n    return true;\n}\n\nvoid improveSolution(Solution& sol, const vector<double>& w, int sweeps) {\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n\n    localImprove(sol, w, target);\n\n    for (int sw = 0; sw < sweeps; sw++) {\n        double before = sol.obj;\n        vector<tuple<double, int, int>> pairs;\n\n        for (int a = 0; a < D; a++) {\n            for (int b = a + 1; b < D; b++) {\n                pairs.emplace_back(abs(sol.load[a] - sol.load[b]), a, b);\n            }\n        }\n\n        sort(pairs.rbegin(), pairs.rend());\n\n        bool changed = false;\n        for (auto [_, a, b] : pairs) {\n            changed |= pairBalanceDP(sol, a, b, w, target);\n        }\n\n        localImprove(sol, w, target);\n\n        if (!changed || sol.obj >= before - 1e-12) break;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nSolution makeGreedyOrder(const vector<int>& order, const vector<double>& w) {\n    Solution sol;\n    sol.assign.assign(N, -1);\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    vector<int> cnt(D, 0);\n\n    for (int item : order) {\n        int best = 0;\n        for (int b = 1; b < D; b++) {\n            if (sol.load[b] < sol.load[best] - 1e-12 ||\n                (abs(sol.load[b] - sol.load[best]) <= 1e-12 && cnt[b] < cnt[best])) {\n                best = b;\n            }\n        }\n\n        sol.assign[item] = best;\n        sol.bins[best].push_back(item);\n        sol.load[best] += w[item];\n        cnt[best]++;\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nSolution makeSnake(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        int block = i / D;\n        int pos = i % D;\n        int b = (block % 2 == 0) ? pos : (D - 1 - pos);\n        assign[order[i]] = b;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution makeRoundRobin(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        assign[order[i]] = i % D;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution partitionEstimated(const vector<double>& w) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return w[a] > w[b];\n    });\n\n    Solution best;\n    auto consider = [&](Solution sol) {\n        improveSolution(sol, w, 2);\n        if (sol.obj < best.obj) best = sol;\n    };\n\n    consider(makeGreedyOrder(order, w));\n    consider(makeSnake(order, w));\n    consider(makeRoundRobin(order, w));\n\n    normal_distribution<double> nd(0.0, 0.35);\n\n    for (int rep = 0; rep < 3; rep++) {\n        vector<pair<double, int>> keys;\n        keys.reserve(N);\n\n        for (int i = 0; i < N; i++) {\n            double key = log(max(1e-9, w[i])) + nd(rng);\n            keys.emplace_back(-key, i);\n        }\n\n        sort(keys.begin(), keys.end());\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto [_, id] : keys) ord.push_back(id);\n\n        consider(makeGreedyOrder(ord, w));\n    }\n\n    improveSolution(best, w, 2);\n    return best;\n}\n\nvector<int> withoutItem(const vector<int>& v, int x) {\n    vector<int> res;\n    res.reserve(v.size());\n    for (int y : v) {\n        if (y != x) res.push_back(y);\n    }\n    return res;\n}\n\nint minMaxCost() {\n    int pairs = D / 2;\n    int sz = pairs + (D % 2);\n    return pairs + max(0, sz - 1) + max(0, sz - 1);\n}\n\nbool findActualMinMax(const vector<vector<int>>& bins, int& mn, int& mx) {\n    vector<int> winners, losers;\n\n    for (int i = 0; i + 1 < D; i += 2) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[i], bins[i + 1]);\n        if (c == '>') {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        } else if (c == '<') {\n            winners.push_back(i + 1);\n            losers.push_back(i);\n        } else {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        }\n    }\n\n    if (D % 2 == 1) {\n        winners.push_back(D - 1);\n        losers.push_back(D - 1);\n    }\n\n    mx = winners[0];\n    for (int i = 1; i < (int)winners.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[winners[i]], bins[mx]);\n        if (c == '>') mx = winners[i];\n    }\n\n    mn = losers[0];\n    for (int i = 1; i < (int)losers.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[losers[i]], bins[mn]);\n        if (c == '<') mn = losers[i];\n    }\n\n    return true;\n}\n\nint actualRefine(Solution& sol, const vector<double>& est) {\n    int successes = 0;\n\n    while (qUsed < Q) {\n        int cost = minMaxCost();\n        if (Q - qUsed < cost + 1) break;\n\n        int mn = -1, mx = -1;\n        if (!findActualMinMax(sol.bins, mn, mx)) break;\n\n        int H = mx;\n        int L = mn;\n        if (H == L) break;\n\n        bool success = false;\n\n        // Try moving a small item from the actual heaviest bin to the actual lightest bin.\n        if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n            vector<int> items = sol.bins[H];\n            sort(items.begin(), items.end(), [&](int a, int b) {\n                return est[a] < est[b];\n            });\n\n            int rem = Q - qUsed;\n            int moveLimit = min((int)items.size(), min(6, max(1, rem / 3)));\n            if (rem <= 3) moveLimit = min((int)items.size(), rem);\n\n            int bestMove = -1;\n            int tried = 0;\n\n            for (int x : items) {\n                if (tried >= moveLimit || qUsed >= Q) break;\n\n                vector<int> left = withoutItem(sol.bins[H], x);\n                if (left.empty()) break;\n\n                char c = ask(left, sol.bins[L]);\n                tried++;\n\n                if (c == '>') {\n                    bestMove = x;\n                } else if (bestMove != -1) {\n                    break;\n                }\n            }\n\n            if (bestMove != -1) {\n                moveItemSol(sol, bestMove, H, L, est);\n                success = true;\n            }\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        // Try swaps that are provably improving.\n        if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n            vector<tuple<double, int, int>> cand;\n\n            for (int x : sol.bins[H]) {\n                for (int y : sol.bins[L]) {\n                    double diff = est[x] - est[y];\n                    double key = (diff >= 0.0) ? diff : (2.0 + (-diff));\n                    cand.emplace_back(key, x, y);\n                }\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int tried = 0;\n            for (auto [_, x, y] : cand) {\n                if (tried >= 20 || qUsed >= Q) break;\n                tried++;\n\n                char xy = compareItems(x, y);\n                if (xy == '?') break;\n                if (xy != '>') continue;\n\n                // If L consists only of y, then H\\{x} has positive weight,\n                // so the condition H\\{x} > L\\{y}=0 is automatically true.\n                if ((int)sol.bins[L].size() == 1) {\n                    swapItemsSol(sol, x, y, H, L, est);\n                    success = true;\n                    break;\n                }\n\n                vector<int> left = withoutItem(sol.bins[H], x);\n                vector<int> right = withoutItem(sol.bins[L], y);\n\n                if (left.empty()) continue;\n                if (right.empty()) {\n                    swapItemsSol(sol, x, y, H, L, est);\n                    success = true;\n                    break;\n                }\n\n                if (qUsed >= Q) break;\n\n                char c = ask(left, right);\n                if (c == '>') {\n                    swapItemsSol(sol, x, y, H, L, est);\n                    success = true;\n                    break;\n                }\n            }\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        break;\n    }\n\n    return successes;\n}\n\nvoid randomBalancedQueries(int cnt, vector<double>& score) {\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n\n    int K = N / 2;\n\n    for (int q = 0; q < cnt && qUsed < Q; q++) {\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L, R;\n        L.reserve(K);\n        R.reserve(K);\n\n        for (int i = 0; i < K; i++) L.push_back(perm[i]);\n        for (int i = 0; i < K; i++) R.push_back(perm[K + i]);\n\n        char c = ask(L, R);\n        int y = 0;\n        if (c == '>') y = 1;\n        else if (c == '<') y = -1;\n\n        if (y != 0) {\n            for (int x : L) score[x] += y;\n            for (int x : R) score[x] -= y;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)N * 1000003ULL;\n    seed ^= (uint64_t)D * 10007ULL;\n    seed ^= (uint64_t)Q * 998244353ULL;\n    rng.seed(seed);\n\n    itemCmp.assign(N, vector<char>(N, '?'));\n    for (int i = 0; i < N; i++) itemCmp[i][i] = '=';\n\n    vector<double> score(N, 0.0);\n\n    int qRefine = min(Q / 5, 2 * N);\n    int qRandom = Q - qRefine;\n\n    randomBalancedQueries(qRandom, score);\n\n    vector<double> est = estimateWeights(score, qRandom);\n\n    Solution sol = partitionEstimated(est);\n\n    actualRefine(sol, est);\n\n    // Remaining queries are consumed safely.\n    while (qUsed < Q) {\n        vector<int> L{0}, R{1};\n        ask(L, R);\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << sol.assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MMAX = 10;\nstatic const int INF = 1000000000;\n\nint nG, mG;\nusing StackArray = array<vector<int>, MMAX>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (double)(next() >> 11) * (1.0 / (double)(1ULL << 53));\n    }\n};\n\nstruct Params {\n    int mode = 2;          // 0: whole, 1: individual, 2: clean-run, 3: enum-scored\n    int badMode = 0;       // clean-run fallback: 0 clean, 1 whole, 2 single, 3 enum\n    int goodMode = 0;      // 0 longest good suffix, 1 maximal clean if good, 2 always maximal clean\n    int thresholdMode = 0; // 0 stack minimum, 1 stack top\n    int destMode = 0;\n\n    double noise = 0.0;\n\n    // enum scoring parameters\n    double lenW = 0.06;\n    double dirtyW = 1.5;\n    double badW = 3.0;\n    double amountW = 0.05;\n    double slackW = 0.02;\n    double heightW = 0.0;\n    double gW = 0.05;\n\n    int initA = -1, initB = -1;\n};\n\nstruct Result {\n    vector<pair<int,int>> ops;\n    int cost = INF;\n    bool ok = false;\n};\n\nstruct Stats {\n    int len = 0;\n    int maxv = -1;\n    int minv = INF;\n    int internalBad = 0;\n};\n\nResult invalidResult() {\n    return Result{{}, INF, false};\n}\n\npair<int,int> findBox(const StackArray& st, int v) {\n    for (int i = 0; i < mG; 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\nint minStackValue(const StackArray& st, int s) {\n    if (st[s].empty()) return INF;\n    int mn = INF;\n    for (int x : st[s]) mn = min(mn, x);\n    return mn;\n}\n\nint thresholdValue(const StackArray& st, int s, int mode) {\n    if (st[s].empty()) return INF;\n    if (mode == 1) return st[s].back();\n    return minStackValue(st, s);\n}\n\nint aboveMinCountOne(const vector<int>& a) {\n    if (a.empty()) return 0;\n    int mn = INF, pos = -1;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i] < mn) {\n            mn = a[i];\n            pos = i;\n        }\n    }\n    return (int)a.size() - pos - 1;\n}\n\nStats blockStats(const vector<int>& a, int cut) {\n    Stats s;\n    s.len = (int)a.size() - cut;\n    for (int i = cut; i < (int)a.size(); i++) {\n        s.maxv = max(s.maxv, a[i]);\n        s.minv = min(s.minv, a[i]);\n        if (i + 1 < (int)a.size() && a[i] < a[i + 1]) s.internalBad++;\n    }\n    return s;\n}\n\nint countGreaterThan(const vector<int>& a, int cut, int g) {\n    int c = 0;\n    for (int i = cut; i < (int)a.size(); i++) {\n        if (a[i] > g) c++;\n    }\n    return c;\n}\n\nint topCleanStart(const vector<int>& a, int targetPos) {\n    int c = (int)a.size() - 1;\n    while (c - 1 > targetPos && a[c - 1] > a[c]) c--;\n    return c;\n}\n\nbool existsGoodDest(const StackArray& st, int src, const Stats& bs, const Params& p) {\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int g = thresholdValue(st, d, p.thresholdMode);\n        if (bs.maxv < g) return true;\n    }\n    return false;\n}\n\nint chooseDest(const StackArray& st, int src, int cut, const Params& p, XorShift& rng) {\n    Stats bs = blockStats(st[src], cut);\n    int bestDst = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        int g = thresholdValue(st, d, p.thresholdMode);\n        double normG = (g >= INF / 2 ? 1000.0 : (double)g);\n        bool good = (bs.maxv < g);\n        int badCnt = countGreaterThan(st[src], cut, g);\n        int h = (int)st[d].size();\n        int aboveMin = aboveMinCountOne(st[d]);\n\n        double score = 0.0;\n        if (p.destMode == 0) {\n            if (good) {\n                score = normG * 10.0 + h * 0.01;\n            } else {\n                score = 100000.0 - normG * 10.0 + badCnt * 100.0 + h * 0.01;\n            }\n        } else if (p.destMode == 1) {\n            if (good) {\n                score = normG * 10.0 - h * 0.05;\n            } else {\n                score = 100000.0 - normG * 10.0 - aboveMin * 5.0 + h * 0.01;\n            }\n        } else if (p.destMode == 2) {\n            if (good) {\n                score = (g >= INF / 2 ? 0.0 : normG * 10.0) + h * 0.02;\n            } else {\n                score = 100000.0 + badCnt * 1000.0 - normG * 20.0 - aboveMin * 5.0;\n            }\n        } else {\n            if (good) {\n                score = (normG - bs.maxv) * 10.0 + h * 0.1;\n            } else {\n                score = 100000.0 + badCnt * 500.0\n                      + max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g)) * 5.0\n                      - normG * 10.0 + h * 0.1;\n            }\n        }\n\n        if (p.noise > 0.0) {\n            score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestDst = d;\n        }\n    }\n\n    if (bestDst == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return bestDst;\n}\n\nbool applyMove(StackArray& st, vector<pair<int,int>>& ops, int& cost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    int label = st[src][cut];\n\n    ops.push_back({label, dst + 1});\n    cost += len + 1;\n\n    if (cost >= cutoff) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    if ((int)ops.size() > 5000) return false;\n    return true;\n}\n\nstruct Choice {\n    int cut = -1;\n    int dst = -1;\n};\n\nChoice chooseEnumMove(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    int blockers = h - pos - 1;\n\n    vector<int> cuts;\n    auto addCut = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    addCut(h - 1);\n    addCut(pos + 1);\n    int c0 = topCleanStart(a, pos);\n    addCut(c0);\n\n    for (int c = c0; c < h; c++) addCut(c);\n\n    int cur = h - 1;\n    int added = 0;\n    while (cur > pos && added < 12) {\n        int r = cur;\n        while (r - 1 > pos && a[r - 1] > a[r]) r--;\n        addCut(r);\n        cur = r - 1;\n        added++;\n    }\n\n    if (blockers <= 25) {\n        for (int c = pos + 1; c < h; c++) addCut(c);\n    } else {\n        for (int t = 1; t <= 10; t++) {\n            int c = pos + 1 + (int)((long long)(blockers - 1) * t / 11);\n            addCut(c);\n        }\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    Choice best;\n    double bestScore = 1e100;\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(a, cut);\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            int g = thresholdValue(st, d, p.thresholdMode);\n            int badCnt = countGreaterThan(a, cut, g);\n            double normG = (g >= INF / 2 ? 250.0 : (double)g);\n\n            double score = 1.0 - p.lenW * bs.len + p.dirtyW * bs.internalBad;\n\n            if (badCnt == 0) {\n                score += p.slackW * (normG - bs.maxv);\n                score += p.heightW * (int)st[d].size();\n            } else {\n                score += p.badW * badCnt;\n                score += p.amountW * max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g));\n                score -= p.gW * normG;\n                score += p.heightW * (int)st[d].size();\n            }\n\n            if (p.noise > 0.0) {\n                score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best.cut = cut;\n                best.dst = d;\n            }\n        }\n    }\n\n    if (best.cut == -1) {\n        best.cut = h - 1;\n        best.dst = (src == 0 ? 1 : 0);\n    }\n    return best;\n}\n\nResult simulateGreedy(const StackArray& init, Params p, uint64_t seed, int cutoff) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n    XorShift rng(seed);\n\n    if (p.initA >= 0 && p.initA < mG && p.initB >= 0 && p.initB < mG &&\n        p.initA != p.initB && !st[p.initA].empty()) {\n        if (!applyMove(st, ops, cost, p.initA, 0, p.initB, cutoff)) {\n            return invalidResult();\n        }\n    }\n\n    for (int v = 1; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            if (p.mode == 3) {\n                Choice ch = chooseEnumMove(st, src, pos, p, rng);\n                if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                    return invalidResult();\n                }\n                continue;\n            }\n\n            int cut = -1;\n\n            if (p.mode == 0) { // move all above target\n                cut = pos + 1;\n            } else if (p.mode == 1) { // one box\n                cut = h - 1;\n            } else { // clean-run strategy\n                int c0 = topCleanStart(st[src], pos);\n                bool selected = false;\n\n                if (p.goodMode == 0) {\n                    for (int c = c0; c < h; c++) {\n                        Stats bs = blockStats(st[src], c);\n                        if (existsGoodDest(st, src, bs, p)) {\n                            cut = c;\n                            selected = true;\n                            break;\n                        }\n                    }\n                } else if (p.goodMode == 1) {\n                    Stats bs = blockStats(st[src], c0);\n                    if (existsGoodDest(st, src, bs, p)) {\n                        cut = c0;\n                        selected = true;\n                    }\n                } else {\n                    cut = c0;\n                    selected = true;\n                }\n\n                if (!selected) {\n                    if (p.badMode == 3) {\n                        Choice ch = chooseEnumMove(st, src, pos, p, rng);\n                        if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                            return invalidResult();\n                        }\n                        continue;\n                    } else if (p.badMode == 0) {\n                        cut = c0;\n                    } else if (p.badMode == 1) {\n                        cut = pos + 1;\n                    } else {\n                        cut = h - 1;\n                    }\n                }\n            }\n\n            int dst = chooseDest(st, src, cut, p, rng);\n            if (!applyMove(st, ops, cost, src, cut, dst, cutoff)) {\n                return invalidResult();\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    for (int i = 0; i < mG; i++) {\n        if (!st[i].empty()) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint stateBadCount(const StackArray& st) {\n    int cnt = 0;\n    for (int i = 0; i < mG; i++) {\n        int mn = INF;\n        for (int x : st[i]) {\n            if (x > mn) cnt++;\n            mn = min(mn, x);\n        }\n    }\n    return cnt;\n}\n\nint aboveMinTotal(const StackArray& st) {\n    int s = 0;\n    for (int i = 0; i < mG; i++) s += aboveMinCountOne(st[i]);\n    return s;\n}\n\ndouble beamEval(const StackArray& st, int cost, double alpha) {\n    return cost + alpha * stateBadCount(st) + 0.30 * alpha * aboveMinTotal(st);\n}\n\nstruct BeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateBeamWhole(const StackArray& init, int W, double alpha, int cutoff) {\n    BeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(6000);\n    first.eval = beamEval(first.st, first.cost, alpha);\n\n    vector<BeamState> beam;\n    beam.push_back(first);\n\n    for (int v = 1; v <= nG; v++) {\n        vector<BeamState> cand;\n        cand.reserve(beam.size() * mG);\n\n        for (const auto& bs : beam) {\n            if (bs.cost >= cutoff) continue;\n\n            auto [src, pos] = findBox(bs.st, v);\n            if (src < 0) continue;\n\n            int h = (int)bs.st[src].size();\n\n            if (pos == h - 1) {\n                BeamState ns = bs;\n                ns.ops.push_back({v, 0});\n                ns.st[src].pop_back();\n                if ((int)ns.ops.size() > 5000) continue;\n                ns.eval = beamEval(ns.st, ns.cost, alpha);\n                cand.push_back(std::move(ns));\n            } else {\n                int cut = pos + 1;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n\n                    BeamState ns = bs;\n                    if (!applyMove(ns.st, ns.ops, ns.cost, src, cut, d, cutoff)) continue;\n\n                    if (ns.st[src].empty() || ns.st[src].back() != v) continue;\n                    ns.ops.push_back({v, 0});\n                    ns.st[src].pop_back();\n                    if ((int)ns.ops.size() > 5000) continue;\n\n                    ns.eval = beamEval(ns.st, ns.cost, alpha);\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const BeamState& a, const BeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)cand.size() > W) cand.resize(W);\n        beam = std::move(cand);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nint validateCost(const StackArray& init, const vector<pair<int,int>>& ops) {\n    if ((int)ops.size() > 5000) return -1;\n\n    StackArray st = init;\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (auto [v, to] : ops) {\n        if (v < 1 || v > nG) return -1;\n\n        if (to == 0) {\n            if (v != nextRemove) return -1;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!st[s].empty() && st[s].back() == v) {\n                    st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return -1;\n            int dst = to - 1;\n\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)st[s].size(); j++) {\n                    if (st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n            if (src == -1) return -1;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n\n            if (src != dst) {\n                st[dst].insert(st[dst].end(), st[src].begin() + pos, st[src].end());\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return -1;\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return -1;\n    return cost;\n}\n\nParams randomParams(XorShift& rng) {\n    Params p;\n\n    int r = rng.nextInt(100);\n    if (r < 12) p.mode = 0;\n    else if (r < 30) p.mode = 1;\n    else if (r < 82) p.mode = 2;\n    else p.mode = 3;\n\n    p.badMode = rng.nextInt(4);\n    p.goodMode = rng.nextInt(3);\n    p.thresholdMode = (rng.nextInt(100) < 85 ? 0 : 1);\n    p.destMode = rng.nextInt(4);\n\n    p.noise = rng.nextDouble() * 4.0;\n\n    p.lenW = 0.02 + rng.nextDouble() * 0.18;\n    p.dirtyW = 0.5 + rng.nextDouble() * 4.0;\n    p.badW = 1.0 + rng.nextDouble() * 6.0;\n    p.amountW = rng.nextDouble() * 0.25;\n    p.slackW = rng.nextDouble() * 0.08;\n    p.heightW = (rng.nextDouble() - 0.5) * 0.06;\n    p.gW = rng.nextDouble() * 0.20;\n\n    if (mG >= 2 && rng.nextInt(100) < 12) {\n        p.initA = rng.nextInt(mG);\n        p.initB = rng.nextInt(mG - 1);\n        if (p.initB >= p.initA) p.initB++;\n    }\n\n    return p;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> nG >> mG;\n\n    StackArray init;\n    for (int i = 0; i < mG; i++) {\n        init[i].reserve(nG);\n        for (int j = 0; j < nG / mG; j++) {\n            int x;\n            cin >> x;\n            init[i].push_back(x);\n        }\n    }\n\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < mG; i++) {\n        for (int x : init[i]) {\n            seed = seed * 1000003ULL + (uint64_t)x + 97ULL;\n        }\n    }\n    XorShift master(seed);\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto timeUp = [&]() -> bool {\n        return elapsed() > 1.80;\n    };\n\n    Result best;\n\n    auto consider = [&](Result r) {\n        if (!r.ok) return;\n        if ((int)r.ops.size() > 5000) return;\n        if (best.ok && r.cost >= best.cost) return;\n\n        int vc = validateCost(init, r.ops);\n        if (vc < 0 || vc != r.cost) return;\n\n        best = std::move(r);\n    };\n\n    // Guaranteed valid fallback.\n    {\n        Params p;\n        p.mode = 0;\n        p.thresholdMode = 0;\n        p.destMode = 0;\n        consider(simulateGreedy(init, p, master.next(), INF));\n    }\n\n    auto runParam = [&](Params p) {\n        if (timeUp()) return;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    // Deterministic variants.\n    for (int th = 0; th <= 1; th++) {\n        for (int dm = 0; dm < 4; dm++) {\n            Params p;\n\n            p = Params();\n            p.mode = 0;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            p = Params();\n            p.mode = 1;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            for (int bad = 0; bad <= 2; bad++) {\n                for (int good = 0; good <= 2; good++) {\n                    p = Params();\n                    p.mode = 2;\n                    p.badMode = bad;\n                    p.goodMode = good;\n                    p.thresholdMode = th;\n                    p.destMode = dm;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Some scored-enumeration presets.\n    for (int th = 0; th <= 1; th++) {\n        for (double lw : {0.03, 0.07, 0.13}) {\n            for (double dw : {0.8, 1.8, 3.0}) {\n                Params p;\n                p.mode = 3;\n                p.thresholdMode = th;\n                p.lenW = lw;\n                p.dirtyW = dw;\n                p.badW = 3.0;\n                p.gW = 0.08;\n                p.slackW = 0.02;\n                runParam(p);\n            }\n        }\n    }\n\n    // Beam search for whole-suffix moves.\n    for (double alpha : {0.0, 1.0, 2.0, 4.0, 6.0}) {\n        if (timeUp()) break;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateBeamWhole(init, 80, alpha, cutoff));\n    }\n\n    // Try one initial stack merge for some clean-run variants.\n    if (!timeUp()) {\n        for (int bad = 0; bad <= 1 && !timeUp(); bad++) {\n            for (int a = 0; a < mG && !timeUp(); a++) {\n                for (int b = 0; b < mG && !timeUp(); b++) {\n                    if (a == b) continue;\n                    Params p;\n                    p.mode = 2;\n                    p.goodMode = 0;\n                    p.badMode = bad;\n                    p.thresholdMode = 0;\n                    p.destMode = 0;\n                    p.initA = a;\n                    p.initB = b;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Random multi-start until time limit.\n    while (!timeUp()) {\n        Params p = randomParams(master);\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    }\n\n    // Final safety.\n    if (!best.ok || validateCost(init, best.ops) < 0) {\n        Params p;\n        p.mode = 0;\n        p.thresholdMode = 0;\n        p.destMode = 0;\n        best = simulateGreedy(init, p, seed, INF);\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIMIT_LEN = 100000;\nstatic const unsigned short INF_DIST = 30000;\n\nint N, V;\nvector<string> hwall, vwall;\nvector<int> dirtv;\n\nstruct Edge {\n    int to;\n    char ch;\n};\nvector<vector<Edge>> adjg;\nvector<unsigned short> distAll;\nvector<int> dist0;\n\ninline int D(int a, int b) {\n    return distAll[a * V + b];\n}\n\ninline char moveChar(int from, int to) {\n    int diff = to - from;\n    if (diff == 1) return 'R';\n    if (diff == -1) return 'L';\n    if (diff == N) return 'D';\n    return 'U';\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 RouteBuilder {\n    int cur = 0;\n    int t = 0;\n    vector<int> seq;\n    string moves;\n    vector<int> last;\n    vector<char> seen;\n    int unseen = 0;\n\n    RouteBuilder() {}\n\n    void init() {\n        cur = 0;\n        t = 0;\n        seq.clear();\n        moves.clear();\n        last.assign(V, 0);\n        seen.assign(V, 0);\n        seen[0] = 1;\n        unseen = V - 1;\n    }\n\n    void addMove(int nb) {\n        moves.push_back(moveChar(cur, nb));\n        cur = nb;\n        ++t;\n        seq.push_back(nb);\n        last[nb] = t;\n        if (!seen[nb]) {\n            seen[nb] = 1;\n            --unseen;\n        }\n    }\n};\n\nvoid computeAllPairsDistances() {\n    distAll.assign(V * V, INF_DIST);\n    vector<int> q(V);\n    for (int s = 0; s < V; ++s) {\n        unsigned short* ds = &distAll[s * V];\n        int head = 0, tail = 0;\n        ds[s] = 0;\n        q[tail++] = s;\n        while (head < tail) {\n            int x = q[head++];\n            unsigned short nd = ds[x] + 1;\n            for (auto &e : adjg[x]) {\n                if (ds[e.to] == INF_DIST) {\n                    ds[e.to] = nd;\n                    q[tail++] = e.to;\n                }\n            }\n        }\n    }\n    dist0.assign(V, 0);\n    for (int i = 0; i < V; ++i) dist0[i] = D(i, 0);\n}\n\nint chooseNextOnShortestPath(const RouteBuilder& b, int target, bool preferUnseen) {\n    int cur = b.cur;\n    int cd = D(target, cur);\n    int best = -1;\n    long double bestVal = -1e100;\n\n    for (const auto& e : adjg[cur]) {\n        int nb = e.to;\n        if (D(target, nb) + 1 != cd) continue;\n\n        long long age = (long long)b.t + 1 - b.last[nb];\n        long double val = (long double)dirtv[nb] * age * age;\n\n        if (preferUnseen && !b.seen[nb]) val += 1e30L;\n\n        // Stable tie breaker.\n        val += (long double)(nb % 17) * 1e-9L;\n\n        if (val > bestVal) {\n            bestVal = val;\n            best = nb;\n        }\n    }\n\n    if (best == -1) {\n        for (const auto& e : adjg[cur]) {\n            if (D(target, e.to) + 1 == cd) return e.to;\n        }\n    }\n    return best;\n}\n\nvoid appendPath(RouteBuilder& b, int target, bool preferUnseen) {\n    while (b.cur != target) {\n        int nb = chooseNextOnShortestPath(b, target, preferUnseen);\n        b.addMove(nb);\n    }\n}\n\nlong double evaluateSeq(const vector<int>& seq, int L) {\n    if (L <= 0 || L > LIMIT_LEN) return 1e100L;\n    if ((int)seq.size() < L) return 1e100L;\n    if (seq[L - 1] != 0) return 1e100L;\n\n    vector<int> first(V, -1), prev(V, -1);\n    vector<long long> gapSum(V, 0);\n\n    for (int t = 1; t <= L; ++t) {\n        int id = seq[t - 1];\n        if (first[id] == -1) {\n            first[id] = t;\n        } else {\n            long long g = t - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = t;\n    }\n\n    long double total = 0;\n    for (int id = 0; id < V; ++id) {\n        if (first[id] == -1) return 1e100L;\n        long long g = (long long)L - prev[id] + first[id];\n        gapSum[id] += g * (g - 1) / 2;\n        total += (long double)gapSum[id] * dirtv[id];\n    }\n    return total / L;\n}\n\nvector<int> rowOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        } else {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int j = 0; j < N; ++j) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        } else {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nRouteBuilder makeRouteByOrder(const vector<int>& ord) {\n    RouteBuilder b;\n    b.init();\n    for (int id : ord) {\n        if (!b.seen[id]) appendPath(b, id, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeNearestCover(int variant) {\n    RouteBuilder b;\n    b.init();\n\n    while (b.unseen > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n            int r = D(b.cur, id);\n\n            int degUnseen = 0;\n            if (variant == 1) {\n                for (auto &e : adjg[id]) if (!b.seen[e.to]) ++degUnseen;\n            }\n\n            double key = (double)r * 1000000.0;\n            if (variant == 0) {\n                key -= dirtv[id];\n            } else if (variant == 1) {\n                key += degUnseen * 1000.0 - dirtv[id] * 0.01;\n            } else {\n                int x = id / N, y = id % N;\n                key += (x + y) * 0.001 - dirtv[id] * 0.001;\n            }\n\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best == -1) break;\n        appendPath(b, best, true);\n        if (b.t + D(b.cur, 0) > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeDFSRoute(const string& dirOrder, bool highFirst) {\n    RouteBuilder b;\n    b.init();\n\n    vector<int> rankDir(256, 0);\n    for (int i = 0; i < 4; ++i) rankDir[(int)dirOrder[i]] = i;\n\n    vector<char> vis(V, 0);\n\n    function<void(int)> dfs = [&](int u) {\n        vis[u] = 1;\n        vector<Edge> es = adjg[u];\n        sort(es.begin(), es.end(), [&](const Edge& a, const Edge& c) {\n            if (highFirst && dirtv[a.to] != dirtv[c.to]) return dirtv[a.to] > dirtv[c.to];\n            return rankDir[(int)a.ch] < rankDir[(int)c.ch];\n        });\n\n        for (auto &e : es) {\n            if (!vis[e.to]) {\n                b.addMove(e.to);\n                dfs(e.to);\n                b.addMove(u);\n            }\n        }\n    };\n\n    dfs(0);\n    return b;\n}\n\nvector<int> firstVisitOrder(const RouteBuilder& b) {\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n    ord.push_back(0);\n    used[0] = 1;\n    for (int id : b.seq) {\n        if (!used[id]) {\n            used[id] = 1;\n            ord.push_back(id);\n        }\n    }\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) ord.push_back(id);\n    }\n    return ord;\n}\n\nlong long phaseLength(const vector<int>& ord, const vector<double>& weight, double scale, long long cap) {\n    vector<int> cnt(V);\n    int M = 1;\n    for (int id = 0; id < V; ++id) {\n        int c = max(1, (int)(scale * weight[id] + 0.5));\n        cnt[id] = c;\n        M = max(M, c);\n    }\n\n    vector<int> acc(V, 0);\n    long long len = 0;\n    int cur = 0;\n\n    for (int p = 0; p < M; ++p) {\n        if ((p & 1) == 0) {\n            for (int k = 0; k < V; ++k) {\n                int id = ord[k];\n                acc[id] += cnt[id];\n                if (acc[id] >= M) {\n                    acc[id] -= M;\n                    len += D(cur, id);\n                    cur = id;\n                    if (len > cap) return len;\n                }\n            }\n        } else {\n            for (int k = V - 1; k >= 0; --k) {\n                int id = ord[k];\n                acc[id] += cnt[id];\n                if (acc[id] >= M) {\n                    acc[id] -= M;\n                    len += D(cur, id);\n                    cur = id;\n                    if (len > cap) return len;\n                }\n            }\n        }\n    }\n\n    len += D(cur, 0);\n    return len;\n}\n\nRouteBuilder buildPhaseRoute(const vector<int>& ord, const vector<double>& weight, double scale) {\n    vector<int> cnt(V);\n    int M = 1;\n    for (int id = 0; id < V; ++id) {\n        int c = max(1, (int)(scale * weight[id] + 0.5));\n        cnt[id] = c;\n        M = max(M, c);\n    }\n\n    RouteBuilder b;\n    b.init();\n\n    vector<int> acc(V, 0);\n\n    for (int p = 0; p < M; ++p) {\n        if ((p & 1) == 0) {\n            for (int k = 0; k < V; ++k) {\n                int id = ord[k];\n                acc[id] += cnt[id];\n                if (acc[id] >= M) {\n                    acc[id] -= M;\n                    appendPath(b, id, true);\n                }\n            }\n        } else {\n            for (int k = V - 1; k >= 0; --k) {\n                int id = ord[k];\n                acc[id] += cnt[id];\n                if (acc[id] >= M) {\n                    acc[id] -= M;\n                    appendPath(b, id, true);\n                }\n            }\n        }\n    }\n\n    appendPath(b, 0, true);\n    return b;\n}\n\ndouble findPhaseScale(const vector<int>& ord, const vector<double>& weight) {\n    double lo = 0.0, hi = 1.0;\n\n    while (hi < 2048.0 && phaseLength(ord, weight, hi, LIMIT_LEN + 1) <= LIMIT_LEN) {\n        lo = hi;\n        hi *= 2.0;\n    }\n\n    for (int it = 0; it < 14; ++it) {\n        double mid = (lo + hi) * 0.5;\n        if (phaseLength(ord, weight, mid, LIMIT_LEN + 1) <= LIMIT_LEN) lo = mid;\n        else hi = mid;\n    }\n\n    return lo;\n}\n\nRouteBuilder buildGreedyRoute(const RouteBuilder& prefix, double offset, int minTargetDist,\n                              int maxLen, const Timer& timer, double timeLimit) {\n    RouteBuilder b = prefix;\n    vector<double> denom(V + 1);\n    for (int r = 0; r <= V; ++r) denom[r] = r + offset;\n\n    auto selectTarget = [&](int md) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (b.t + r + dist0[id] > maxLen) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / denom[r];\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n        return best;\n    };\n\n    int iter = 0;\n    while (true) {\n        int reserve = D(b.cur, 0);\n        if (b.t + reserve >= maxLen) break;\n\n        if ((iter++ & 127) == 0 && timer.elapsed() > timeLimit) break;\n\n        int target = selectTarget(minTargetDist);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1);\n        if (target == -1) break;\n\n        appendPath(b, target, false);\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n    return b;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n\n    cin >> N;\n    V = N * N;\n\n    hwall.resize(N - 1);\n    for (int i = 0; i < N - 1; ++i) cin >> hwall[i];\n\n    vwall.resize(N);\n    for (int i = 0; i < N; ++i) cin >> vwall[i];\n\n    dirtv.assign(V, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> dirtv[i * N + j];\n        }\n    }\n\n    adjg.assign(V, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = i * N + j;\n            if (i + 1 < N && hwall[i][j] == '0') {\n                int to = (i + 1) * N + j;\n                adjg[id].push_back({to, 'D'});\n                adjg[to].push_back({id, 'U'});\n            }\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int to = i * N + (j + 1);\n                adjg[id].push_back({to, 'R'});\n                adjg[to].push_back({id, 'L'});\n            }\n        }\n    }\n\n    computeAllPairsDistances();\n\n    long double bestScore = 1e100L;\n    string bestMoves;\n    RouteBuilder bestShort;\n\n    auto consider = [&](const RouteBuilder& b, int L = -1) {\n        if (L < 0) L = b.t;\n        long double sc = evaluateSeq(b.seq, L);\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestMoves = b.moves.substr(0, L);\n        }\n    };\n\n    auto considerShort = [&](const RouteBuilder& b) {\n        if (b.t <= LIMIT_LEN && b.cur == 0 && b.unseen == 0) {\n            long double sc = evaluateSeq(b.seq, b.t);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = b.moves;\n            }\n            long double scShort = sc;\n            long double scBestShort = bestShort.t ? evaluateSeq(bestShort.seq, bestShort.t) : 1e100L;\n            if (scShort < scBestShort) bestShort = b;\n        }\n    };\n\n    // Always-valid base candidates.\n    vector<RouteBuilder> shortCandidates;\n    shortCandidates.push_back(makeDFSRoute(\"RDLU\", false));\n    shortCandidates.push_back(makeDFSRoute(\"DRUL\", false));\n    shortCandidates.push_back(makeDFSRoute(\"RDLU\", true));\n    shortCandidates.push_back(makeRouteByOrder(rowOrder()));\n    shortCandidates.push_back(makeRouteByOrder(colOrder()));\n    shortCandidates.push_back(makeNearestCover(0));\n    shortCandidates.push_back(makeNearestCover(1));\n\n    for (auto &b : shortCandidates) considerShort(b);\n\n    if (bestShort.t == 0) {\n        bestShort = shortCandidates[0];\n        consider(bestShort);\n    }\n\n    // Orders for phase patrol.\n    vector<vector<int>> orders;\n    orders.push_back(firstVisitOrder(bestShort));\n    orders.push_back(rowOrder());\n    orders.push_back(colOrder());\n\n    // Remove duplicate orders roughly by first few elements.\n    vector<vector<int>> uniqueOrders;\n    for (auto &ord : orders) {\n        bool dup = false;\n        for (auto &u : uniqueOrders) {\n            if (ord == u) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniqueOrders.push_back(ord);\n    }\n\n    // Weighted phase candidates: frequency approximately proportional to d^exp.\n    vector<double> expsMain = {0.50, 0.60, 0.42};\n\n    int orderIndex = 0;\n    for (auto &ord : uniqueOrders) {\n        vector<double> exps = (orderIndex == 0 ? expsMain : vector<double>{0.50});\n        ++orderIndex;\n\n        for (double ep : exps) {\n            if (timer.elapsed() > 1.35) break;\n\n            vector<double> weight(V);\n            for (int id = 0; id < V; ++id) weight[id] = pow((double)dirtv[id], ep);\n\n            double scale = findPhaseScale(ord, weight);\n            vector<double> scales = {scale, scale * 0.85, scale * 0.65, scale * 1.08};\n\n            for (double sca : scales) {\n                if (sca < 0.0) continue;\n                long long len = phaseLength(ord, weight, sca, LIMIT_LEN + 1);\n                if (len <= LIMIT_LEN) {\n                    RouteBuilder b = buildPhaseRoute(ord, weight, sca);\n                    if (b.t <= LIMIT_LEN && b.cur == 0) {\n                        consider(b);\n                    }\n                }\n            }\n        }\n    }\n\n    // Online greedy patrol candidate, time permitting.\n    if (timer.elapsed() < 1.55) {\n        RouteBuilder g = buildGreedyRoute(bestShort, 20.0, 1, LIMIT_LEN, timer, 1.82);\n        if (g.t <= LIMIT_LEN && g.cur == 0) {\n            consider(g);\n\n            // Also test some closed prefixes; sometimes a shorter cycle is better.\n            int lastAdded = bestShort.t;\n            for (int t = bestShort.t; t <= g.t; ++t) {\n                if (g.seq[t - 1] == 0 && t - lastAdded >= 10000) {\n                    consider(g, t);\n                    lastAdded = t;\n                }\n            }\n        }\n    }\n\n    if (timer.elapsed() < 1.82) {\n        RouteBuilder g = buildGreedyRoute(bestShort, 60.0, 3, LIMIT_LEN, timer, 1.90);\n        if (g.t <= LIMIT_LEN && g.cur == 0) consider(g);\n    }\n\n    // Final fallback, should not be needed.\n    if (bestMoves.empty()) bestMoves = shortCandidates[0].moves;\n\n    cout << bestMoves << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x = 88172645463325252ull;\n    uint32_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n    double nextDouble() {\n        return (next() >> 8) * (1.0 / 16777216.0);\n    }\n};\n\nstruct Solver {\n    int N, M;\n    int si, sj, startId;\n    vector<string> grid;\n    vector<string> words;\n    vector<array<int, 5>> wch;\n\n    vector<int> letterPos[26];\n    unsigned char distCell[225][225];\n\n    vector<int> lastChar;\n    vector<unsigned char> overlap;\n\n    vector<int> initOff;\n    vector<unsigned short> initData;\n    vector<int> startMinCost, startMin10, startAvg10;\n\n    vector<int> edgeOff;\n    vector<unsigned short> edgeData;\n    vector<int> edgeMin10, edgeAvg10;\n\n    int maxOcc = 0;\n\n    struct Mode {\n        vector<int> edge;\n        vector<int> start;\n    };\n    vector<Mode> modes;\n\n    struct Move {\n        int type; // 0 relocate, 1 swap, 2 reverse\n        int a, b;\n        long long delta;\n    };\n\n    struct Candidate {\n        int cost;\n        vector<int> order;\n    };\n\n    Timer timer;\n    XorShift rng;\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    unordered_map<int, int> targetMap;\n    int pow4 = 456976; // 26^4\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        startId = si * N + sj;\n\n        grid.resize(N);\n        for (int c = 0; c < 26; c++) letterPos[c].clear();\n\n        for (int i = 0; i < N; i++) {\n            cin >> grid[i];\n            for (int j = 0; j < N; j++) {\n                int c = grid[i][j] - 'A';\n                letterPos[c].push_back(i * N + j);\n            }\n        }\n\n        words.resize(M);\n        wch.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) wch[i][k] = words[i][k] - 'A';\n        }\n    }\n\n    int encodeWord(const string& s) const {\n        int code = 0;\n        for (char ch : s) code = code * 26 + (ch - 'A');\n        return code;\n    }\n\n    int calcOverlap(int a, int b) const {\n        for (int k = 4; k >= 1; k--) {\n            bool ok = true;\n            for (int p = 0; p < k; p++) {\n                if (words[a][5 - k + p] != words[b][p]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    void precompute() {\n        int V = N * N;\n        for (int a = 0; a < V; a++) {\n            int ai = a / N, aj = a % N;\n            for (int b = 0; b < V; b++) {\n                int bi = b / N, bj = b % N;\n                distCell[a][b] = (unsigned char)(abs(ai - bi) + abs(aj - bj));\n            }\n        }\n\n        maxOcc = 0;\n        for (int c = 0; c < 26; c++) {\n            maxOcc = max(maxOcc, (int)letterPos[c].size());\n        }\n\n        lastChar.assign(M, 0);\n        for (int i = 0; i < M; i++) lastChar[i] = wch[i][4];\n\n        overlap.assign(M * M, 0);\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                overlap[i * M + j] = (unsigned char)calcOverlap(i, j);\n            }\n        }\n\n        targetMap.clear();\n        targetMap.reserve(512);\n        for (int i = 0; i < M; i++) targetMap[encodeWord(words[i])] = i;\n\n        long long sumOccLast = 0;\n        for (int i = 0; i < M; i++) {\n            sumOccLast += (int)letterPos[lastChar[i]].size();\n        }\n\n        // Initial word DP vectors.\n        initOff.assign(M, 0);\n        startMinCost.assign(M, 0);\n        startMin10.assign(M, 0);\n        startAvg10.assign(M, 0);\n        initData.clear();\n        initData.reserve((size_t)sumOccLast);\n\n        vector<int> cur(maxOcc), nxt(maxOcc);\n        const int INF = 1e9;\n\n        for (int i = 0; i < M; i++) {\n            int c0 = wch[i][0];\n            int cnt = (int)letterPos[c0].size();\n\n            for (int p = 0; p < cnt; p++) {\n                cur[p] = (int)distCell[startId][letterPos[c0][p]] + 1;\n            }\n\n            int prevC = c0;\n            int prevCnt = cnt;\n            for (int h = 1; h < 5; h++) {\n                int nc = wch[i][h];\n                int nextCnt = (int)letterPos[nc].size();\n\n                for (int q = 0; q < nextCnt; q++) {\n                    int best = INF;\n                    int qid = letterPos[nc][q];\n                    for (int p = 0; p < prevCnt; p++) {\n                        int v = cur[p] + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                        if (v < best) best = v;\n                    }\n                    nxt[q] = best;\n                }\n\n                for (int q = 0; q < nextCnt; q++) cur[q] = nxt[q];\n                prevC = nc;\n                prevCnt = nextCnt;\n            }\n\n            initOff[i] = (int)initData.size();\n            int mn = INF;\n            long long sum = 0;\n            for (int p = 0; p < prevCnt; p++) {\n                mn = min(mn, cur[p]);\n                sum += cur[p];\n                initData.push_back((unsigned short)cur[p]);\n            }\n            startMinCost[i] = mn;\n            startMin10[i] = 10 * mn;\n            startAvg10[i] = (int)((10 * sum + prevCnt / 2) / prevCnt);\n        }\n\n        // Pair transition matrices.\n        edgeOff.assign(M * M, 0);\n        edgeAvg10.assign(M * M, 0);\n        edgeMin10.assign(M * M, 0);\n        edgeData.clear();\n\n        long long totalMat = sumOccLast * sumOccLast;\n        if (totalMat < 100000000LL) edgeData.reserve((size_t)totalMat);\n\n        vector<int> mat(maxOcc * maxOcc), mat2(maxOcc * maxOcc);\n\n        for (int i = 0; i < M; i++) {\n            int cStart = lastChar[i];\n            int rows = (int)letterPos[cStart].size();\n\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int k = overlap[idx];\n\n                int prevC = cStart;\n                int prevCnt = rows;\n\n                fill(mat.begin(), mat.begin() + rows * prevCnt, INF);\n                for (int r = 0; r < rows; r++) mat[r * prevCnt + r] = 0;\n\n                for (int h = k; h < 5; h++) {\n                    int nc = wch[j][h];\n                    int nextCnt = (int)letterPos[nc].size();\n\n                    for (int r = 0; r < rows; r++) {\n                        int baseIdx = r * prevCnt;\n                        int outIdx = r * nextCnt;\n                        for (int q = 0; q < nextCnt; q++) {\n                            int best = INF;\n                            int qid = letterPos[nc][q];\n                            for (int p = 0; p < prevCnt; p++) {\n                                int v = mat[baseIdx + p]\n                                      + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                                if (v < best) best = v;\n                            }\n                            mat2[outIdx + q] = best;\n                        }\n                    }\n\n                    mat.swap(mat2);\n                    prevC = nc;\n                    prevCnt = nextCnt;\n                }\n\n                int cols = (int)letterPos[lastChar[j]].size();\n                edgeOff[idx] = (int)edgeData.size();\n                edgeData.resize(edgeData.size() + rows * cols);\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                int off = edgeOff[idx];\n\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    for (int q = 0; q < cols; q++) {\n                        int v = mat[r * cols + q];\n                        edgeData[off + r * cols + q] = (unsigned short)v;\n                        rowMin = min(rowMin, v);\n                        globalMin = min(globalMin, v);\n                    }\n                    sumRowMin += rowMin;\n                }\n\n                edgeMin10[idx] = 10 * globalMin;\n                edgeAvg10[idx] = (int)((10 * sumRowMin + rows / 2) / rows);\n            }\n        }\n    }\n\n    void buildModes() {\n        modes.clear();\n        modes.resize(4);\n\n        for (auto& mo : modes) {\n            mo.edge.assign(M * M, 0);\n            mo.start.assign(M, 0);\n        }\n\n        for (int i = 0; i < M; i++) {\n            modes[0].start[i] = startAvg10[i];\n            modes[1].start[i] = startMin10[i];\n            modes[2].start[i] = startAvg10[i];\n            modes[3].start[i] = startAvg10[i];\n        }\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int len = 5 - (int)overlap[idx];\n\n                modes[0].edge[idx] = edgeAvg10[idx];\n                modes[1].edge[idx] = edgeMin10[idx];\n                modes[2].edge[idx] = len * 1000 + edgeAvg10[idx];\n                modes[3].edge[idx] = len * 10000 + edgeAvg10[idx];\n            }\n        }\n    }\n\n    inline long long arc(const Mode& mode, int u, int v) const {\n        if (u < 0 && v < 0) return 0;\n        if (u < 0) return mode.start[v];\n        if (v < 0) return 0;\n        return mode.edge[u * M + v];\n    }\n\n    int exactCost(const vector<int>& ord) const {\n        if (ord.empty()) return 0;\n\n        const int INF = 1e9;\n        int dp[225], ndp[225];\n\n        int first = ord[0];\n        int cnt = (int)letterPos[lastChar[first]].size();\n        int off0 = initOff[first];\n\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off0 + i];\n\n        for (int idx = 1; idx < (int)ord.size(); idx++) {\n            int a = ord[idx - 1];\n            int b = ord[idx];\n\n            int rows = (int)letterPos[lastChar[a]].size();\n            int cols = (int)letterPos[lastChar[b]].size();\n\n            fill(ndp, ndp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[a * M + b]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)mr[c];\n                    if (v < ndp[c]) ndp[c] = v;\n                }\n            }\n\n            for (int c = 0; c < cols; c++) dp[c] = ndp[c];\n        }\n\n        int last = ord.back();\n        int lastCnt = (int)letterPos[lastChar[last]].size();\n        int ans = INF;\n        for (int i = 0; i < lastCnt; i++) ans = min(ans, dp[i]);\n        return ans;\n    }\n\n    vector<int> hungarian(const vector<vector<int>>& a) const {\n        int n = (int)a.size();\n        const long long INF = (1LL << 60);\n\n        vector<long long> u(n + 1), v(n + 1);\n        vector<int> p(n + 1), way(n + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<long long> minv(n + 1, INF);\n            vector<char> used(n + 1, false);\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0];\n                int j1 = 0;\n                long long delta = INF;\n\n                for (int j = 1; j <= n; j++) {\n                    if (used[j]) continue;\n                    long long cur = (long long)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\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\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);\n        for (int j = 1; j <= n; j++) ans[p[j] - 1] = j - 1;\n        return ans;\n    }\n\n    vector<int> patchAssignment(const vector<int>& succ, const Mode& mode) const {\n        int D = M;\n        int n = M + 1;\n\n        vector<char> visited(n, false);\n        vector<int> path;\n\n        int cur = succ[D];\n        visited[D] = true;\n        while (cur != D && !visited[cur]) {\n            visited[cur] = true;\n            path.push_back(cur);\n            cur = succ[cur];\n        }\n\n        vector<vector<int>> cycles;\n        for (int i = 0; i < M; i++) {\n            if (visited[i]) continue;\n\n            vector<int> cyc;\n            cur = i;\n            while (!visited[cur]) {\n                visited[cur] = true;\n                cyc.push_back(cur);\n                cur = succ[cur];\n            }\n            if (!cyc.empty()) cycles.push_back(cyc);\n        }\n\n        auto costArc = [&](int u, int v) -> long long {\n            if (u == D && v == D) return 0;\n            if (u == D) return mode.start[v];\n            if (v == D) return 0;\n            return mode.edge[u * M + v];\n        };\n\n        while (!cycles.empty()) {\n            long long bestDelta = (1LL << 60);\n            int bestC = -1, bestE = -1, bestBreak = -1;\n\n            for (int ci = 0; ci < (int)cycles.size(); ci++) {\n                const auto& C = cycles[ci];\n                int k = (int)C.size();\n\n                for (int e = 0; e <= (int)path.size(); e++) {\n                    int u = (e == 0 ? D : path[e - 1]);\n                    int v = (e == (int)path.size() ? D : path[e]);\n                    long long oldCost = costArc(u, v);\n\n                    for (int bidx = 0; bidx < k; bidx++) {\n                        int a = C[bidx];\n                        int b = C[(bidx + 1) % k];\n\n                        long long delta = costArc(u, b) + costArc(a, v)\n                                        - oldCost - costArc(a, b);\n\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestC = ci;\n                            bestE = e;\n                            bestBreak = bidx;\n                        }\n                    }\n                }\n            }\n\n            const auto& C = cycles[bestC];\n            int k = (int)C.size();\n            vector<int> seg;\n            seg.reserve(k);\n            for (int t = 0; t < k; t++) {\n                seg.push_back(C[(bestBreak + 1 + t) % k]);\n            }\n\n            path.insert(path.begin() + bestE, seg.begin(), seg.end());\n            cycles.erase(cycles.begin() + bestC);\n        }\n\n        return path;\n    }\n\n    vector<int> hungarianPatch(const Mode& mode) const {\n        int n = M + 1;\n        int D = M;\n        const int INF = 100000000;\n\n        vector<vector<int>> cost(n, vector<int>(n, INF));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                cost[i][j] = (i == j ? INF : mode.edge[i * M + j]);\n            }\n            cost[i][D] = 0;\n        }\n\n        for (int j = 0; j < M; j++) cost[D][j] = mode.start[j];\n        cost[D][D] = INF;\n\n        vector<int> assign = hungarian(cost);\n        return patchAssignment(assign, mode);\n    }\n\n    vector<int> cheapestInsertion(const Mode& mode) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestDelta = (1LL << 60);\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> nearestNeighborBest(const Mode& mode) const {\n        vector<int> bestPath;\n        long long bestScore = (1LL << 60);\n\n        for (int s = 0; s < M; s++) {\n            vector<char> used(M, false);\n            vector<int> path;\n            path.reserve(M);\n\n            path.push_back(s);\n            used[s] = true;\n\n            long long score = mode.start[s];\n            int last = s;\n\n            for (int step = 1; step < M; step++) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (used[j]) continue;\n                    int c = mode.edge[last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                path.push_back(bestJ);\n                used[bestJ] = true;\n                score += bestC;\n                last = bestJ;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestPath = path;\n            }\n        }\n\n        return bestPath;\n    }\n\n    struct DSU {\n        vector<int> p;\n        DSU(int n = 0) { init(n); }\n        void init(int n) {\n            p.resize(n);\n            iota(p.begin(), p.end(), 0);\n        }\n        int find(int x) {\n            return p[x] == x ? x : p[x] = find(p[x]);\n        }\n        bool unite(int a, int b) {\n            a = find(a);\n            b = find(b);\n            if (a == b) return false;\n            p[b] = a;\n            return true;\n        }\n    };\n\n    vector<int> greedyPathCover(const Mode& mode, bool overlapKey) const {\n        struct E {\n            int u, v, ov, cost;\n        };\n\n        vector<E> es;\n        es.reserve(M * (M - 1));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                es.push_back({i, j, (int)overlap[i * M + j], mode.edge[i * M + j]});\n            }\n        }\n\n        if (overlapKey) {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                if (a.ov != b.ov) return a.ov > b.ov;\n                return a.cost < b.cost;\n            });\n        } else {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                return a.cost < b.cost;\n            });\n        }\n\n        vector<int> out(M, -1), in(M, -1);\n        DSU dsu(M);\n        int added = 0;\n\n        for (const auto& e : es) {\n            if (out[e.u] != -1 || in[e.v] != -1) continue;\n            if (dsu.find(e.u) == dsu.find(e.v)) continue;\n\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n\n            added++;\n            if (added == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) {\n            if (in[i] == -1) {\n                head = i;\n                break;\n            }\n        }\n\n        vector<int> path;\n        while (head != -1) {\n            path.push_back(head);\n            head = out[head];\n        }\n\n        if ((int)path.size() != M) {\n            path.resize(M);\n            iota(path.begin(), path.end(), 0);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedy(int startWord) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = (int)letterPos[lastChar[curWord]].size();\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            int bestScore = INF;\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = (int)letterPos[lastChar[j]].size();\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                if (minv < bestScore) {\n                    bestScore = minv;\n                    bestJ = j;\n                }\n            }\n\n            int cols = (int)letterPos[lastChar[bestJ]].size();\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    long long relocateDelta(const vector<int>& ord, int i, int p, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (p == i) return 0;\n\n        int x = ord[i];\n\n        int L = (i > 0 ? ord[i - 1] : -1);\n        int R = (i + 1 < n ? ord[i + 1] : -1);\n\n        long long rem = arc(mode, L, R) - arc(mode, L, x) - arc(mode, x, R);\n\n        auto getRemoved = [&](int idx) -> int {\n            return ord[idx < i ? idx : idx + 1];\n        };\n\n        int left = (p > 0 ? getRemoved(p - 1) : -1);\n        int right = (p < n - 1 ? getRemoved(p) : -1);\n\n        long long ins = arc(mode, left, x) + arc(mode, x, right) - arc(mode, left, right);\n        return rem + ins;\n    }\n\n    long long swapDelta(const vector<int>& ord, int i, int j, const Mode& mode) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int n = (int)ord.size();\n        vector<int> ks;\n        int arr[4] = {i - 1, i, j - 1, j};\n\n        for (int t = 0; t < 4; t++) {\n            int k = arr[t];\n            if (k < -1 || k > n - 1) continue;\n            if (find(ks.begin(), ks.end(), k) == ks.end()) ks.push_back(k);\n        }\n\n        auto nodeNew = [&](int idx) -> int {\n            if (idx == i) return ord[j];\n            if (idx == j) return ord[i];\n            return ord[idx];\n        };\n\n        auto edgeOld = [&](int k) -> long long {\n            if (k == -1) return mode.start[ord[0]];\n            if (k >= n - 1) return 0;\n            return mode.edge[ord[k] * M + ord[k + 1]];\n        };\n\n        auto edgeNew = [&](int k) -> long long {\n            if (k == -1) return mode.start[nodeNew(0)];\n            if (k >= n - 1) return 0;\n            return mode.edge[nodeNew(k) * M + nodeNew(k + 1)];\n        };\n\n        long long oldSum = 0, newSum = 0;\n        for (int k : ks) {\n            oldSum += edgeOld(k);\n            newSum += edgeNew(k);\n        }\n        return newSum - oldSum;\n    }\n\n    long long reverseDeltaSlow(const vector<int>& ord, int l, int r, const Mode& mode) const {\n        int n = (int)ord.size();\n        long long oldCost = 0, newCost = 0;\n\n        if (l == 0) {\n            oldCost += mode.start[ord[l]];\n            newCost += mode.start[ord[r]];\n        } else {\n            oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n            newCost += mode.edge[ord[l - 1] * M + ord[r]];\n        }\n\n        if (r + 1 < n) {\n            oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n            newCost += mode.edge[ord[l] * M + ord[r + 1]];\n        }\n\n        for (int k = l; k < r; k++) {\n            oldCost += mode.edge[ord[k] * M + ord[k + 1]];\n            newCost += mode.edge[ord[k + 1] * M + ord[k]];\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyMove(vector<int>& ord, const Move& mv) const {\n        if (mv.type == 0) {\n            int x = ord[mv.a];\n            ord.erase(ord.begin() + mv.a);\n            ord.insert(ord.begin() + mv.b, x);\n        } else if (mv.type == 1) {\n            swap(ord[mv.a], ord[mv.b]);\n        } else {\n            reverse(ord.begin() + mv.a, ord.begin() + mv.b + 1);\n        }\n    }\n\n    void improveAdditive(vector<int>& ord, const Mode& mode, int maxIter = 60) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if ((iter & 3) == 0 && timer.elapsed() > 1.45) break;\n\n            long long bestDelta = 0;\n            Move bestMove{-1, 0, 0, 0};\n\n            // relocate\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {0, i, p, d};\n                    }\n                }\n            }\n\n            // swap\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {1, i, j, d};\n                    }\n                }\n            }\n\n            // reverse\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    long long d = newCost - oldCost;\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {2, l, r, d};\n                    }\n                }\n            }\n\n            if (bestDelta < 0) {\n                applyMove(ord, bestMove);\n            } else {\n                break;\n            }\n        }\n    }\n\n    Candidate exactRefine(vector<int> ord, double deadline, int rounds, int K) {\n        int cur = exactCost(ord);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestOrder = ord;\n        }\n\n        const Mode& mode = modes[0];\n        int n = (int)ord.size();\n\n        for (int round = 0; round < rounds; round++) {\n            if (timer.elapsed() > deadline) break;\n\n            vector<Move> moves;\n            moves.reserve(n * n * 2);\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    moves.push_back({0, i, p, d});\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    moves.push_back({1, i, j, d});\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    moves.push_back({2, l, r, newCost - oldCost});\n                }\n            }\n\n            sort(moves.begin(), moves.end(), [](const Move& a, const Move& b) {\n                return a.delta < b.delta;\n            });\n\n            int bestLocal = cur;\n            Move bestMv{-1, 0, 0, 0};\n            int lim = min(K, (int)moves.size());\n\n            for (int i = 0; i < lim; i++) {\n                if ((i & 31) == 0 && timer.elapsed() > deadline) break;\n\n                vector<int> cand = ord;\n                applyMove(cand, moves[i]);\n                int nc = exactCost(cand);\n\n                if (nc < bestLocal) {\n                    bestLocal = nc;\n                    bestMv = moves[i];\n                }\n            }\n\n            if (bestMv.type != -1) {\n                applyMove(ord, bestMv);\n                cur = bestLocal;\n\n                if (cur < bestCost) {\n                    bestCost = cur;\n                    bestOrder = ord;\n                }\n            } else {\n                break;\n            }\n        }\n\n        return {cur, ord};\n    }\n\n    void simulatedAnnealing(double deadline) {\n        if (timer.elapsed() > deadline) return;\n\n        vector<int> curOrd = bestOrder;\n        int curCost = bestCost;\n        const Mode& mode = modes[0];\n\n        double st = timer.elapsed();\n        int n = (int)curOrd.size();\n        if (n <= 1) return;\n\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            Move mv{-1, 0, 0, 0};\n\n            int typ = rng.nextInt(100);\n            if (typ < 45) {\n                int i = rng.nextInt(n);\n                int p = rng.nextInt(n);\n                if (p == i) continue;\n                long long d = relocateDelta(curOrd, i, p, mode);\n                mv = {0, i, p, d};\n            } else if (typ < 75) {\n                int i = rng.nextInt(n);\n                int j = rng.nextInt(n);\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                long long d = swapDelta(curOrd, i, j, mode);\n                mv = {1, i, j, d};\n            } else {\n                int l = rng.nextInt(n);\n                int r = rng.nextInt(n);\n                if (l == r) continue;\n                if (l > r) swap(l, r);\n                long long d = reverseDeltaSlow(curOrd, l, r, mode);\n                mv = {2, l, r, d};\n            }\n\n            if (mv.delta > 3000) continue;\n            if (mv.delta > 800 && rng.nextInt(100) < 95) continue;\n\n            vector<int> cand = curOrd;\n            applyMove(cand, mv);\n            int nc = exactCost(cand);\n\n            int diff = nc - curCost;\n            double progress = (timer.elapsed() - st) / max(1e-9, deadline - st);\n            double temp = 20.0 * pow(0.05, progress) + 0.5;\n\n            if (diff <= 0 || rng.nextDouble() < exp(-diff / temp)) {\n                curOrd.swap(cand);\n                curCost = nc;\n\n                if (curCost < bestCost) {\n                    bestCost = curCost;\n                    bestOrder = curOrd;\n                }\n            }\n\n            iter++;\n            if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    string buildString(const vector<int>& ord) const {\n        if (ord.empty()) return \"\";\n\n        string s = words[ord[0]];\n        for (int i = 1; i < (int)ord.size(); i++) {\n            int a = ord[i - 1];\n            int b = ord[i];\n            int k = overlap[a * M + b];\n            s += words[b].substr(k);\n        }\n        return s;\n    }\n\n    bool containsAll(const string& s) const {\n        if ((int)s.size() < 5) return false;\n\n        vector<char> seen(M, false);\n        int got = 0;\n\n        int code = 0;\n        for (int i = 0; i < 5; i++) code = code * 26 + (s[i] - 'A');\n\n        auto mark = [&](int cd) {\n            auto it = targetMap.find(cd);\n            if (it != targetMap.end()) {\n                int id = it->second;\n                if (!seen[id]) {\n                    seen[id] = true;\n                    got++;\n                }\n            }\n        };\n\n        mark(code);\n\n        for (int i = 5; i < (int)s.size(); i++) {\n            code = (code % pow4) * 26 + (s[i] - 'A');\n            mark(code);\n        }\n\n        return got == M;\n    }\n\n    void tryRemoveRedundant(double deadline) {\n        bool improved = true;\n\n        while (improved && timer.elapsed() < deadline) {\n            improved = false;\n\n            for (int p = 0; p < (int)bestOrder.size(); p++) {\n                if (timer.elapsed() > deadline) break;\n                if ((int)bestOrder.size() <= 1) break;\n\n                vector<int> cand = bestOrder;\n                cand.erase(cand.begin() + p);\n\n                string s = buildString(cand);\n                if (!containsAll(s)) continue;\n\n                int c = exactCost(cand);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestOrder = cand;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    void outputStringPath(const string& s) const {\n        int L = (int)s.size();\n        const int INF = 1e9;\n\n        vector<vector<int>> pred(L);\n        vector<int> dpPrev, dpCur;\n\n        for (int idx = 0; idx < L; idx++) {\n            int c = s[idx] - 'A';\n            int cnt = (int)letterPos[c].size();\n\n            dpCur.assign(cnt, INF);\n            pred[idx].assign(cnt, -1);\n\n            if (idx == 0) {\n                for (int q = 0; q < cnt; q++) {\n                    int id = letterPos[c][q];\n                    dpCur[q] = (int)distCell[startId][id] + 1;\n                }\n            } else {\n                int pc = s[idx - 1] - 'A';\n                int pcnt = (int)letterPos[pc].size();\n\n                for (int q = 0; q < cnt; q++) {\n                    int qid = letterPos[c][q];\n                    int best = INF;\n                    int bestP = -1;\n\n                    for (int p = 0; p < pcnt; p++) {\n                        int pid = letterPos[pc][p];\n                        int v = dpPrev[p] + (int)distCell[pid][qid] + 1;\n                        if (v < best) {\n                            best = v;\n                            bestP = p;\n                        }\n                    }\n\n                    dpCur[q] = best;\n                    pred[idx][q] = bestP;\n                }\n            }\n\n            dpPrev.swap(dpCur);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < dpPrev[bestIdx]) bestIdx = i;\n        }\n\n        vector<int> outIds(L);\n        for (int idx = L - 1; idx >= 0; idx--) {\n            int c = s[idx] - 'A';\n            outIds[idx] = letterPos[c][bestIdx];\n            bestIdx = pred[idx][bestIdx];\n        }\n\n        for (int id : outIds) {\n            cout << id / N << ' ' << id % N << '\\n';\n        }\n    }\n\n    void solve() {\n        timer.reset();\n\n        precompute();\n        buildModes();\n\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = exactCost(bestOrder);\n\n        vector<Candidate> candidates;\n\n        auto consider = [&](const vector<int>& ord) {\n            int c = exactCost(ord);\n            candidates.push_back({c, ord});\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = ord;\n            }\n        };\n\n        consider(bestOrder);\n\n        for (int mi = 0; mi < (int)modes.size(); mi++) {\n            if (timer.elapsed() > 1.25) break;\n\n            {\n                vector<int> ord = hungarianPatch(modes[mi]);\n                improveAdditive(ord, modes[mi], 50);\n                consider(ord);\n            }\n            {\n                vector<int> ord = cheapestInsertion(modes[mi]);\n                improveAdditive(ord, modes[mi], 50);\n                consider(ord);\n            }\n            {\n                vector<int> ord = nearestNeighborBest(modes[mi]);\n                improveAdditive(ord, modes[mi], 50);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes[0], false);\n            improveAdditive(ord, modes[0], 50);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes.back(), true);\n            improveAdditive(ord, modes.back(), 50);\n            consider(ord);\n        }\n\n        // Coordinate-aware greedy starts.\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return startMinCost[a] < startMinCost[b];\n        });\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<int> starts;\n        for (int i = 0; i < min(M, 10); i++) starts.push_back(ids[i]);\n        for (int i = 0; i < min((int)candidates.size(), 8); i++) {\n            if (!candidates[i].order.empty()) starts.push_back(candidates[i].order[0]);\n        }\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        int greedyRuns = 0;\n        for (int stWord : starts) {\n            if (greedyRuns >= 14 || timer.elapsed() > 1.45) break;\n\n            vector<int> ord = coordinateGreedy(stWord);\n            consider(ord);\n\n            improveAdditive(ord, modes[0], 30);\n            consider(ord);\n\n            greedyRuns++;\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<vector<int>> refineList;\n        for (const auto& cand : candidates) {\n            bool dup = false;\n            for (const auto& v : refineList) {\n                if (v == cand.order) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) refineList.push_back(cand.order);\n            if ((int)refineList.size() >= 4) break;\n        }\n\n        for (auto& ord : refineList) {\n            if (timer.elapsed() > 1.75) break;\n            Candidate r = exactRefine(ord, 1.75, 5, 350);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.78) {\n            Candidate r = exactRefine(bestOrder, 1.78, 4, 500);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        simulatedAnnealing(1.84);\n        tryRemoveRedundant(1.88);\n\n        string finalS = buildString(bestOrder);\n        if (!containsAll(finalS) || (int)finalS.size() > 5000) {\n            bestOrder.resize(M);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n            finalS = buildString(bestOrder);\n        }\n\n        outputStringPath(finalS);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXC = 400;\nstatic constexpr double EXACT_W = 1e7;\nstatic constexpr double BAN_W = 1e8;\n\nstruct Placement {\n    int di, dj;\n    vector<int> cells;\n    bitset<MAXC> bits;\n};\n\nstruct Field {\n    int area = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> placements;\n    vector<uint16_t> contrib; // flattened: placement * Q + q\n};\n\nstruct Observation {\n    vector<int> cells;\n    int k;\n    int y;\n};\n\nstruct State {\n    bool valid = false;\n    vector<int> pos;\n    vector<int> pred;\n    vector<int> cnt;\n    double score = -1e300;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n    int totalArea = 0;\n    int Q = 0;\n    int stride = 0;\n\n    vector<Field> fields;\n    vector<Observation> obs;\n\n    vector<double> scoreFlat;\n    vector<double> tHat, invVarT;\n\n    vector<unsigned char> drilled;\n    vector<int> drillVal;\n    vector<int> drilledCells;\n    int drilledCount = 0;\n\n    vector<vector<unsigned char>> bannedEqMasks;\n    vector<vector<unsigned char>> subsetMasks;\n\n    int opCount = 0;\n    int maxInitialQueries = 0;\n\n    mt19937 rng{123456789};\n\n    chrono::steady_clock::time_point startTime;\n\n    double elapsedMs() const {\n        return chrono::duration<double, std::milli>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    }\n\n    double normalCDF(double x) {\n        return 0.5 * erfc(-x / sqrt(2.0));\n    }\n\n    void readInput() {\n        cin >> N >> M >> eps;\n        C = N * N;\n        alpha = 1.0 - 2.0 * eps;\n        fields.resize(M);\n\n        for (int m = 0; m < M; m++) {\n            int d;\n            cin >> d;\n            fields[m].area = d;\n            fields[m].rel.resize(d);\n            int mx_i = 0, mx_j = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[m].rel[t] = {i, j};\n                mx_i = max(mx_i, i);\n                mx_j = max(mx_j, j);\n            }\n            fields[m].h = mx_i + 1;\n            fields[m].w = mx_j + 1;\n            totalArea += d;\n        }\n\n        generatePlacements();\n\n        drilled.assign(C, 0);\n        drillVal.assign(C, 0);\n    }\n\n    void generatePlacements() {\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            for (int di = 0; di + f.h <= N; di++) {\n                for (int dj = 0; dj + f.w <= N; dj++) {\n                    Placement p;\n                    p.di = di;\n                    p.dj = dj;\n                    p.bits.reset();\n                    for (auto [ri, rj] : f.rel) {\n                        int c = (di + ri) * N + (dj + rj);\n                        p.cells.push_back(c);\n                        p.bits.set(c);\n                    }\n                    f.placements.push_back(std::move(p));\n                }\n            }\n        }\n    }\n\n    void maybeAskDiv(vector<int> cells) {\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        if ((int)cells.size() < 2) return;\n        if ((int)obs.size() >= maxInitialQueries) return;\n\n        cout << \"q \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int y;\n        if (!(cin >> y)) exit(0);\n        if (y < 0) exit(0);\n\n        opCount++;\n        obs.push_back({cells, (int)cells.size(), y});\n    }\n\n    void askInitialQueries() {\n        maxInitialQueries = max(0, C - 10);\n\n        // Rows\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            maybeAskDiv(cells);\n        }\n\n        // Columns\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            maybeAskDiv(cells);\n        }\n\n        // Coarse blocks\n        int B = max(3, (N + 4) / 5);\n        for (int r = 0; r < N; r += B) {\n            for (int c = 0; c < N; c += B) {\n                vector<int> cells;\n                for (int i = r; i < min(N, r + B); i++) {\n                    for (int j = c; j < min(N, c + B); j++) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                maybeAskDiv(cells);\n            }\n        }\n\n        // Shifted full blocks\n        int off = B / 2;\n        if (off > 0) {\n            for (int r = off; r + B <= N; r += B) {\n                for (int c = off; c + B <= N; c += B) {\n                    vector<int> cells;\n                    for (int i = r; i < r + B; i++) {\n                        for (int j = c; j < c + B; j++) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        }\n\n        // Modulo patterns\n        auto addModQueries = [&](int mod) {\n            for (int a = 0; a < mod; a++) {\n                for (int b = 0; b < mod; b++) {\n                    vector<int> cells;\n                    for (int i = 0; i < N; i++) {\n                        for (int j = 0; j < N; j++) {\n                            if (i % mod == a && j % mod == b) {\n                                cells.push_back(i * N + j);\n                            }\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        };\n        addModQueries(2);\n        if (N >= 13) addModQueries(3);\n\n        // Random masks\n        int R = (N <= 12 ? N : 2 * N);\n        for (int r = 0; r < R; r++) {\n            vector<int> cells;\n            for (int attempt = 0; attempt < 100; attempt++) {\n                cells.clear();\n                for (int c = 0; c < C; c++) {\n                    if ((int)(rng() % 10000) < 2500) cells.push_back(c);\n                }\n                if ((int)cells.size() >= 2) break;\n            }\n            if ((int)cells.size() < 2) {\n                cells = {0, C - 1};\n            }\n            maybeAskDiv(cells);\n        }\n    }\n\n    int drillCell(int c) {\n        if (drilled[c]) return drillVal[c];\n\n        cout << \"q 1 \" << c / N << ' ' << c % N << '\\n';\n        cout.flush();\n\n        int v;\n        if (!(cin >> v)) exit(0);\n        if (v < 0) exit(0);\n\n        opCount++;\n        drilled[c] = 1;\n        drillVal[c] = v;\n        drilledCount++;\n        drilledCells.push_back(c);\n        return v;\n    }\n\n    bool submitAnswer(vector<unsigned char> mask) {\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        vector<int> cells;\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) cells.push_back(c);\n        }\n\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int res;\n        if (!(cin >> res)) exit(0);\n        opCount++;\n\n        if (res == 1) exit(0);\n        if (res < 0) exit(0);\n        return false;\n    }\n\n    bool canFallback() const {\n        return opCount + (C - drilledCount) + 1 <= 2 * C;\n    }\n\n    bool canWrongGuessAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    void fallback() {\n        for (int c = 0; c < C; c++) {\n            if (!drilled[c]) drillCell(c);\n        }\n\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (drillVal[c] > 0) mask[c] = 1;\n        }\n\n        submitAnswer(mask);\n        exit(0);\n    }\n\n    void buildContrib() {\n        Q = (int)obs.size();\n        vector<vector<int>> obsOfCell(C);\n\n        for (int q = 0; q < Q; q++) {\n            for (int c : obs[q].cells) obsOfCell[c].push_back(q);\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            int P = (int)f.placements.size();\n            f.contrib.assign(P * Q, 0);\n\n            for (int p = 0; p < P; p++) {\n                uint16_t *arr = Q ? &f.contrib[p * Q] : nullptr;\n                for (int c : f.placements[p].cells) {\n                    for (int q : obsOfCell[c]) {\n                        arr[q]++;\n                    }\n                }\n            }\n        }\n    }\n\n    void buildScoreTables() {\n        stride = totalArea + 1;\n        scoreFlat.assign(Q * stride, 0.0);\n        tHat.assign(Q, 0.0);\n        invVarT.assign(Q, 1.0);\n\n        for (int q = 0; q < Q; q++) {\n            int k = obs[q].k;\n            int y = obs[q].y;\n\n            double sigma = sqrt(k * eps * (1.0 - eps));\n            double varT = k * eps * (1.0 - eps) / (alpha * alpha)\n                        + 0.25 / (alpha * alpha);\n            invVarT[q] = 1.0 / max(1e-9, varT);\n\n            double th = (y - eps * k) / alpha;\n            th = min<double>(totalArea, max<double>(0.0, th));\n            tHat[q] = th;\n\n            for (int t = 0; t <= totalArea; t++) {\n                double mu = eps * k + alpha * t;\n                double prob;\n\n                if (y == 0) {\n                    prob = normalCDF((0.5 - mu) / sigma);\n                } else {\n                    double lo = (y - 0.5 - mu) / sigma;\n                    double hi = (y + 0.5 - mu) / sigma;\n                    prob = normalCDF(hi) - normalCDF(lo);\n                }\n\n                if (!(prob > 1e-300)) prob = 1e-300;\n                scoreFlat[q * stride + t] = log(prob);\n            }\n        }\n    }\n\n    void addToState(State &s, int m, int p, int sign) {\n        if (Q) {\n            const uint16_t *arr = &fields[m].contrib[p * Q];\n            for (int q = 0; q < Q; q++) s.pred[q] += sign * (int)arr[q];\n        }\n\n        for (int c : fields[m].placements[p].cells) {\n            s.cnt[c] += sign;\n        }\n    }\n\n    double computeExactScore(const vector<int> &cnt) const {\n        long long sq = 0;\n        for (int c : drilledCells) {\n            int diff = cnt[c] - drillVal[c];\n            sq += 1LL * diff * diff;\n        }\n        return -EXACT_W * (double)sq;\n    }\n\n    double computeBanPenalty(const vector<int> &cnt) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = cnt[c] > 0;\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (cnt[c] > 0 && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeBanPenaltyBits(const bitset<MAXC> &uni) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = uni.test(c);\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (uni.test(c) && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeScore(const State &s) const {\n        double sc = 0.0;\n\n        for (int q = 0; q < Q; q++) {\n            sc += scoreFlat[q * stride + s.pred[q]];\n        }\n\n        sc += computeExactScore(s.cnt);\n        sc += computeBanPenalty(s.cnt);\n        return sc;\n    }\n\n    State buildState(const vector<int> &pos) {\n        State s;\n        s.valid = true;\n        s.pos = pos;\n        s.pred.assign(Q, 0);\n        s.cnt.assign(C, 0);\n\n        for (int m = 0; m < M; m++) {\n            addToState(s, m, s.pos[m], +1);\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    bool placementCoversKnownZero(int m, int p) const {\n        for (int c : fields[m].placements[p].cells) {\n            if (drilled[c] && drillVal[c] == 0) return true;\n        }\n        return false;\n    }\n\n    int randomPlacement(int m) {\n        int P = (int)fields[m].placements.size();\n\n        for (int t = 0; t < 50; t++) {\n            int p = (int)(rng() % P);\n            if (!placementCoversKnownZero(m, p)) return p;\n        }\n\n        vector<int> valid;\n        for (int p = 0; p < P; p++) {\n            if (!placementCoversKnownZero(m, p)) valid.push_back(p);\n        }\n\n        if (!valid.empty()) {\n            return valid[(int)(rng() % valid.size())];\n        }\n        return (int)(rng() % P);\n    }\n\n    State makeRandomState() {\n        vector<int> pos(M);\n        for (int m = 0; m < M; m++) {\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makePerturbedState(const State &base, int changes) {\n        vector<int> pos = base.pos;\n        for (int t = 0; t < changes; t++) {\n            int m = (int)(rng() % M);\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makeGreedyState() {\n        vector<int> pos(M, -1);\n        vector<int> pred(Q, 0);\n        vector<int> cnt(C, 0);\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].area > fields[b].area;\n        });\n\n        int placedArea = 0;\n\n        for (int m : order) {\n            int P = (int)fields[m].placements.size();\n            int newArea = placedArea + fields[m].area;\n\n            double bestVal = 1e300;\n            int bestP = 0;\n\n            for (int p = 0; p < P; p++) {\n                double val = 0.0;\n                const uint16_t *arr = Q ? &fields[m].contrib[p * Q] : nullptr;\n\n                for (int q = 0; q < Q; q++) {\n                    double target = tHat[q] * (double)newArea / (double)totalArea;\n                    double diff = (double)(pred[q] + arr[q]) - target;\n                    val += diff * diff * invVarT[q];\n                }\n\n                for (int c : fields[m].placements[p].cells) {\n                    if (drilled[c]) {\n                        if (drillVal[c] == 0) val += 1e9;\n                        if (cnt[c] + 1 > drillVal[c]) val += 1e9;\n                    }\n                }\n\n                if (val < bestVal - 1e-9 ||\n                    (fabs(val - bestVal) <= 1e-9 && (rng() & 1))) {\n                    bestVal = val;\n                    bestP = p;\n                }\n            }\n\n            pos[m] = bestP;\n            if (Q) {\n                const uint16_t *arr = &fields[m].contrib[bestP * Q];\n                for (int q = 0; q < Q; q++) pred[q] += arr[q];\n            }\n            for (int c : fields[m].placements[bestP].cells) cnt[c]++;\n            placedArea = newArea;\n        }\n\n        return buildState(pos);\n    }\n\n    State optimizeExactSmall() {\n        State invalid;\n\n        if (M == 2) {\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n\n            double bestSc = -1e300;\n            vector<int> bestPos(2, 0);\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    double sc = 0.0;\n                    for (int q = 0; q < Q; q++) {\n                        int t = a0[q] + a1[q];\n                        sc += scoreFlat[q * stride + t];\n                    }\n\n                    if (drilledCount > 0) {\n                        long long sq = 0;\n                        for (int c : drilledCells) {\n                            int cnt = (b0.test(c) ? 1 : 0) + (b1.test(c) ? 1 : 0);\n                            int diff = cnt - drillVal[c];\n                            sq += 1LL * diff * diff;\n                        }\n                        sc -= EXACT_W * (double)sq;\n                    }\n\n                    if (hasBan) {\n                        bitset<MAXC> uni = b0 | b1;\n                        sc += computeBanPenaltyBits(uni);\n                    }\n\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestPos[0] = p0;\n                        bestPos[1] = p1;\n                    }\n                }\n            }\n\n            return buildState(bestPos);\n        }\n\n        if (M == 3) {\n            long long prod = 1;\n            for (int m = 0; m < 3; m++) {\n                prod *= (long long)fields[m].placements.size();\n            }\n            if (prod > 250000) return invalid;\n\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n            int P2 = (int)fields[2].placements.size();\n\n            double bestSc = -1e300;\n            vector<int> bestPos(3, 0);\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            vector<int> pred01(Q);\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    for (int q = 0; q < Q; q++) pred01[q] = a0[q] + a1[q];\n\n                    bitset<MAXC> bits01;\n                    if (hasBan) bits01 = b0 | b1;\n\n                    for (int p2 = 0; p2 < P2; p2++) {\n                        const uint16_t *a2 = Q ? &fields[2].contrib[p2 * Q] : nullptr;\n                        const auto &b2 = fields[2].placements[p2].bits;\n\n                        double sc = 0.0;\n                        for (int q = 0; q < Q; q++) {\n                            int t = pred01[q] + a2[q];\n                            sc += scoreFlat[q * stride + t];\n                        }\n\n                        if (drilledCount > 0) {\n                            long long sq = 0;\n                            for (int c : drilledCells) {\n                                int cnt = (b0.test(c) ? 1 : 0)\n                                        + (b1.test(c) ? 1 : 0)\n                                        + (b2.test(c) ? 1 : 0);\n                                int diff = cnt - drillVal[c];\n                                sq += 1LL * diff * diff;\n                            }\n                            sc -= EXACT_W * (double)sq;\n                        }\n\n                        if (hasBan) {\n                            bitset<MAXC> uni = bits01 | b2;\n                            sc += computeBanPenaltyBits(uni);\n                        }\n\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bestPos[0] = p0;\n                            bestPos[1] = p1;\n                            bestPos[2] = p2;\n                        }\n                    }\n                }\n            }\n\n            return buildState(bestPos);\n        }\n\n        return invalid;\n    }\n\n    State coordinateDescent(State s, int sweeps, double deadlineMs) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            shuffle(order.begin(), order.end(), rng);\n            bool changed = false;\n\n            for (int m : order) {\n                if (elapsedMs() > deadlineMs) {\n                    s.score = computeScore(s);\n                    return s;\n                }\n\n                int oldP = s.pos[m];\n                addToState(s, m, oldP, -1);\n\n                double baseExact = computeExactScore(s.cnt);\n\n                vector<int> baseDiff(bannedEqMasks.size(), 0);\n                vector<int> baseOut(subsetMasks.size(), 0);\n\n                for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                    const auto &mask = bannedEqMasks[f];\n                    int diff = 0;\n                    for (int c = 0; c < C; c++) {\n                        bool cov = s.cnt[c] > 0;\n                        if (cov != (bool)mask[c]) diff++;\n                    }\n                    baseDiff[f] = diff;\n                }\n\n                for (size_t f = 0; f < subsetMasks.size(); f++) {\n                    const auto &mask = subsetMasks[f];\n                    int out = 0;\n                    for (int c = 0; c < C; c++) {\n                        if (s.cnt[c] > 0 && !mask[c]) out++;\n                    }\n                    baseOut[f] = out;\n                }\n\n                int P = (int)fields[m].placements.size();\n                int bestP = oldP;\n                double bestSc = -1e300;\n\n                for (int p = 0; p < P; p++) {\n                    const auto &pl = fields[m].placements[p];\n                    double total = baseExact;\n\n                    if (Q) {\n                        const uint16_t *arr = &fields[m].contrib[p * Q];\n                        for (int q = 0; q < Q; q++) {\n                            int t = s.pred[q] + arr[q];\n                            total += scoreFlat[q * stride + t];\n                        }\n                    }\n\n                    if (drilledCount > 0) {\n                        for (int c : pl.cells) {\n                            if (drilled[c]) {\n                                int diff = s.cnt[c] - drillVal[c];\n                                total += -EXACT_W *\n                                    (double)((diff + 1) * (diff + 1) - diff * diff);\n                            }\n                        }\n                    }\n\n                    for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                        int diff = baseDiff[f];\n                        const auto &mask = bannedEqMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0) {\n                                if (mask[c]) diff--;\n                                else diff++;\n                            }\n                        }\n\n                        if (diff == 0) total -= BAN_W;\n                    }\n\n                    for (size_t f = 0; f < subsetMasks.size(); f++) {\n                        int out = baseOut[f];\n                        const auto &mask = subsetMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0 && !mask[c]) out++;\n                        }\n\n                        if (out == 0) total -= BAN_W;\n                    }\n\n                    if (total > bestSc + 1e-9 ||\n                        (fabs(total - bestSc) <= 1e-9 && (rng() & 1))) {\n                        bestSc = total;\n                        bestP = p;\n                    }\n                }\n\n                addToState(s, m, bestP, +1);\n                s.pos[m] = bestP;\n                s.score = bestSc;\n                if (bestP != oldP) changed = true;\n            }\n\n            if (!changed) break;\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    State optimize(const State *prev, bool first) {\n        State exact = optimizeExactSmall();\n        if (exact.valid) return exact;\n\n        double now = elapsedMs();\n        double req = first ? 1200.0 : 450.0;\n        double deadline = min(2450.0, now + req);\n        if (deadline < now + 30.0) deadline = now + 30.0;\n\n        int maxRestarts;\n        if (first) {\n            if (M <= 4) maxRestarts = 80;\n            else if (M <= 10) maxRestarts = 50;\n            else maxRestarts = 35;\n        } else {\n            if (M <= 4) maxRestarts = 40;\n            else if (M <= 10) maxRestarts = 25;\n            else maxRestarts = 18;\n        }\n\n        int sweeps = first ? 7 : 5;\n\n        State best;\n\n        for (int r = 0; r < maxRestarts && elapsedMs() < deadline; r++) {\n            State s;\n\n            if (r == 0 && prev && prev->valid) {\n                s = buildState(prev->pos);\n            } else if ((r == 0 && (!prev || !prev->valid)) ||\n                       (r == 1 && prev && prev->valid)) {\n                s = makeGreedyState();\n            } else if (prev && prev->valid && r < 6) {\n                int changes = 1 + (r % max(1, M / 2));\n                s = makePerturbedState(*prev, changes);\n            } else {\n                s = makeRandomState();\n            }\n\n            s = coordinateDescent(s, sweeps, deadline);\n\n            if (!best.valid || s.score > best.score) {\n                best = std::move(s);\n            }\n        }\n\n        if (!best.valid) {\n            if (prev && prev->valid) best = buildState(prev->pos);\n            else best = makeGreedyState();\n        }\n\n        return best;\n    }\n\n    int countExactMismatch(const State &s) const {\n        int mism = 0;\n        for (int c : drilledCells) {\n            if (s.cnt[c] != drillVal[c]) mism++;\n        }\n        return mism;\n    }\n\n    vector<unsigned char> unionMask(const State &s) const {\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) mask[c] = 1;\n        }\n        return mask;\n    }\n\n    bool allVerifiedPositive(const vector<unsigned char> &mask) const {\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) {\n                if (!drilled[c]) return false;\n                if (drillVal[c] <= 0) return false;\n            }\n        }\n        return true;\n    }\n\n    bool sameMask(const vector<unsigned char> &a,\n                  const vector<unsigned char> &b) const {\n        return a == b;\n    }\n\n    bool isBannedEq(const vector<unsigned char> &mask) const {\n        for (const auto &x : bannedEqMasks) {\n            if (sameMask(x, mask)) return true;\n        }\n        return false;\n    }\n\n    void addBannedEq(const vector<unsigned char> &mask) {\n        if (!isBannedEq(mask)) bannedEqMasks.push_back(mask);\n    }\n\n    void addSubsetMask(const vector<unsigned char> &mask) {\n        for (const auto &x : subsetMasks) {\n            if (sameMask(x, mask)) return;\n        }\n        subsetMasks.push_back(mask);\n    }\n\n    int boundaryScore(int c, const vector<unsigned char> &mask) const {\n        int i = c / N;\n        int j = c % N;\n        int score = 0;\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                score++;\n            } else {\n                int nc = ni * N + nj;\n                if (!mask[nc]) score++;\n            }\n        }\n\n        return score;\n    }\n\n    vector<int> cellsToDrillInUnion(const vector<unsigned char> &U) {\n        vector<pair<int,int>> order;\n\n        for (int c = 0; c < C; c++) {\n            if (U[c] && !drilled[c]) {\n                int key = boundaryScore(c, U) * 1000000 + (int)(rng() % 1000000);\n                order.push_back({-key, c});\n            }\n        }\n\n        sort(order.begin(), order.end());\n\n        vector<int> res;\n        for (auto [_, c] : order) res.push_back(c);\n        return res;\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        askInitialQueries();\n        buildContrib();\n        buildScoreTables();\n\n        State best = optimize(nullptr, true);\n\n        int maxUnverifiedGuesses = (N >= 15 ? 3 : 2);\n        int unverifiedUsed = 0;\n        int mismatchRetries = 0;\n\n        while (true) {\n            if (!canFallback()) {\n                fallback();\n            }\n\n            if (elapsedMs() > 2600.0) {\n                fallback();\n            }\n\n            if (drilledCount == C) {\n                fallback();\n            }\n\n            int mism = countExactMismatch(best);\n            if (mism > 0) {\n                if (mismatchRetries < 3 && elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    mismatchRetries++;\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n            mismatchRetries = 0;\n\n            vector<unsigned char> U = unionMask(best);\n            vector<unsigned char> A = U;\n            for (int c = 0; c < C; c++) {\n                if (drilled[c] && drillVal[c] > 0) A[c] = 1;\n            }\n\n            bool verified = allVerifiedPositive(A);\n\n            if (verified && isBannedEq(A)) {\n                addSubsetMask(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            // A few cheap speculative guesses before paying drilling cost.\n            if (!verified &&\n                unverifiedUsed < maxUnverifiedGuesses &&\n                canWrongGuessAndFallback() &&\n                !isBannedEq(A)) {\n                submitAnswer(A);\n                addBannedEq(A);\n                unverifiedUsed++;\n                best = optimize(&best, false);\n                continue;\n            }\n\n            if (!verified) {\n                vector<int> todo = cellsToDrillInUnion(U);\n\n                if (todo.empty()) {\n                    if (elapsedMs() < 2400.0) {\n                        best = optimize(&best, false);\n                        continue;\n                    } else {\n                        fallback();\n                    }\n                }\n\n                bool contradiction = false;\n\n                for (int c : todo) {\n                    if (!canFallback()) fallback();\n\n                    int v = drillCell(c);\n                    if (v != best.cnt[c]) {\n                        contradiction = true;\n                        break;\n                    }\n                }\n\n                if (contradiction) {\n                    best = optimize(&best, false);\n                    continue;\n                } else {\n                    continue;\n                }\n            } else {\n                if (!canWrongGuessAndFallback()) {\n                    fallback();\n                }\n\n                submitAnswer(A);\n\n                // If all cells in A were confirmed positive and the answer is wrong,\n                // then the true union has at least one additional outside cell.\n                addSubsetMask(A);\n                addBannedEq(A);\n\n                best = optimize(&best, false);\n                continue;\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int W = 1000;\nstatic const int AREA = W * W;\nstatic const unsigned short INF = 30000;\nenum { VERT = 0, HOR = 1 };\nenum { POLICY_STATIC_ABS = 0, POLICY_STATIC_RATIO = 1, POLICY_PREV = 2 };\n\nstruct Rect {\n    int y0, x0, y1, x1;\n};\n\nint D, N;\nvector<vector<int>> A;\nvector<int> globalMaxDemand;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nint clamp_int(int v, int lo, int hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\n/* ---------- exact evaluator ---------- */\n\nstruct Bound {\n    array<vector<pair<int,int>>, W + 1> H, V;\n    void clear() {\n        for (int i = 0; i <= W; i++) {\n            H[i].clear();\n            V[i].clear();\n        }\n    }\n};\n\nvoid merge_intervals(vector<pair<int,int>>& v) {\n    if (v.empty()) return;\n    sort(v.begin(), v.end());\n    int m = 0;\n    for (auto p : v) {\n        if (m == 0 || p.first > v[m-1].second) {\n            v[m++] = p;\n        } else {\n            v[m-1].second = max(v[m-1].second, p.second);\n        }\n    }\n    v.resize(m);\n}\n\nvoid build_bound(const vector<Rect>& rs, Bound& b) {\n    b.clear();\n    for (const auto& r : rs) {\n        if (r.y0 > 0 && r.y0 < W) b.H[r.y0].push_back({r.x0, r.x1});\n        if (r.y1 > 0 && r.y1 < W) b.H[r.y1].push_back({r.x0, r.x1});\n        if (r.x0 > 0 && r.x0 < W) b.V[r.x0].push_back({r.y0, r.y1});\n        if (r.x1 > 0 && r.x1 < W) b.V[r.x1].push_back({r.y0, r.y1});\n    }\n    for (int i = 1; i < W; i++) {\n        merge_intervals(b.H[i]);\n        merge_intervals(b.V[i]);\n    }\n}\n\nlong long symdiff_line(const vector<pair<int,int>>& a, const vector<pair<int,int>>& b) {\n    long long la = 0, lb = 0, inter = 0;\n    for (auto [l, r] : a) la += r - l;\n    for (auto [l, r] : b) lb += r - l;\n\n    int i = 0, j = 0;\n    while (i < (int)a.size() && j < (int)b.size()) {\n        int l = max(a[i].first, b[j].first);\n        int r = min(a[i].second, b[j].second);\n        if (l < r) inter += r - l;\n        if (a[i].second < b[j].second) i++;\n        else j++;\n    }\n    return la + lb - 2 * inter;\n}\n\nlong long diff_bound(const Bound& a, const Bound& b) {\n    long long res = 0;\n    for (int i = 1; i < W; i++) {\n        res += symdiff_line(a.H[i], b.H[i]);\n        res += symdiff_line(a.V[i], b.V[i]);\n    }\n    return res;\n}\n\nlong long transition_cost(const vector<Rect>& x, const vector<Rect>& y) {\n    Bound bx, by;\n    build_bound(x, bx);\n    build_bound(y, by);\n    return diff_bound(bx, by);\n}\n\nlong long shortage_day(const vector<Rect>& rs, int d) {\n    long long res = 0;\n    for (int k = 0; k < N; k++) {\n        long long area = 1LL * (rs[k].y1 - rs[k].y0) * (rs[k].x1 - rs[k].x0);\n        if (area < A[d][k]) res += 100LL * (A[d][k] - area);\n    }\n    return res;\n}\n\nlong long evaluate_solution(const vector<vector<Rect>>& sol, long long limit = LLONG_MAX) {\n    long long total = 0;\n    Bound prev, cur;\n    for (int d = 0; d < D; d++) {\n        total += shortage_day(sol[d], d);\n        if (total > limit) return total;\n        build_bound(sol[d], cur);\n        if (d > 0) {\n            total += diff_bound(prev, cur);\n            if (total > limit) return total;\n        }\n        swap(prev, cur);\n    }\n    return total;\n}\n\n/* ---------- slicing tree ---------- */\n\nstruct Node {\n    int l = 0, r = 0;\n    int left = -1, right = -1;\n    int orient = VERT;\n    double ratio = 0.5;     // left/top base-area ratio\n    int target = 1;         // relative cut in base layout\n    int targetCoord = -1;   // global cut coordinate in base layout\n\n    bool leaf() const { return left == -1; }\n};\n\nstruct Tree {\n    vector<Node> nodes;\n    int root = 0;\n    vector<int> order; // postorder\n};\n\nvoid build_order(Tree& t) {\n    t.order.clear();\n    function<void(int)> dfs = [&](int v) {\n        if (!t.nodes[v].leaf()) {\n            dfs(t.nodes[v].left);\n            dfs(t.nodes[v].right);\n        }\n        t.order.push_back(v);\n    };\n    dfs(t.root);\n}\n\nint choose_split(int l, int r, int mode, const vector<double>& pref) {\n    if (r - l <= 1) return l + 1;\n    if (mode == 1) return (l + r) / 2; // count-balanced\n\n    double total = pref[r] - pref[l];\n    int best = l + 1;\n    double bestScore = 1e100;\n\n    for (int m = l + 1; m <= r - 1; m++) {\n        double af = (pref[m] - pref[l]) / total;\n        double cf = double(m - l) / double(r - l);\n        double score;\n        if (mode == 0) { // area-balanced\n            score = fabs(af - 0.5);\n        } else { // hybrid\n            score = fabs(af - 0.5) + 0.35 * fabs(cf - 0.5);\n        }\n        if (score < bestScore) {\n            bestScore = score;\n            best = m;\n        }\n    }\n    return best;\n}\n\nTree build_aspect_tree(const vector<int>& base, int splitMode, int orientMode) {\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    Tree t;\n    function<int(int,int,int,int,int)> rec = [&](int l, int r, int h, int w, int depth) -> int {\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].l = l;\n        t.nodes[idx].r = r;\n\n        if (r - l == 1) return idx;\n\n        int orient;\n        if (orientMode == 0) orient = (w >= h ? VERT : HOR);\n        else if (orientMode == 1) orient = (depth % 2 == 0 ? VERT : HOR);\n        else orient = (depth % 2 == 0 ? HOR : VERT);\n\n        int m = choose_split(l, r, splitMode, pref);\n        double sL = pref[m] - pref[l];\n        double sT = pref[r] - pref[l];\n        double ratio = sL / sT;\n\n        t.nodes[idx].orient = orient;\n        t.nodes[idx].ratio = ratio;\n\n        int hL = h, hR = h, wL = w, wR = w;\n        if (orient == VERT) {\n            int c = (w >= 2 ? clamp_int((int)llround(w * ratio), 1, w - 1) : 1);\n            wL = max(1, c);\n            wR = max(1, w - c);\n        } else {\n            int c = (h >= 2 ? clamp_int((int)llround(h * ratio), 1, h - 1) : 1);\n            hL = max(1, c);\n            hR = max(1, h - c);\n        }\n\n        int li = rec(l, m, hL, wL, depth + 1);\n        int ri = rec(m, r, hR, wR, depth + 1);\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        return idx;\n    };\n\n    t.root = rec(0, N, W, W, 0);\n    build_order(t);\n    return t;\n}\n\nint build_fixed_rec(Tree& t, int l, int r, int orient, int splitMode, const vector<double>& pref) {\n    int idx = (int)t.nodes.size();\n    t.nodes.push_back(Node());\n    t.nodes[idx].l = l;\n    t.nodes[idx].r = r;\n    t.nodes[idx].orient = orient;\n\n    if (r - l == 1) return idx;\n\n    int m = choose_split(l, r, splitMode, pref);\n    double sL = pref[m] - pref[l];\n    double sT = pref[r] - pref[l];\n    t.nodes[idx].ratio = sL / sT;\n\n    int li = build_fixed_rec(t, l, m, orient, splitMode, pref);\n    int ri = build_fixed_rec(t, m, r, orient, splitMode, pref);\n    t.nodes[idx].left = li;\n    t.nodes[idx].right = ri;\n    return idx;\n}\n\nTree build_shelf_tree(const vector<int>& base, int R, int groupMode, int itemSplitMode) {\n    R = clamp_int(R, 1, N);\n\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> groups;\n    int prev = 0;\n    for (int g = 0; g < R; g++) {\n        int en;\n        if (g == R - 1) {\n            en = N;\n        } else {\n            int minEnd = prev + 1;\n            int maxEnd = N - (R - g - 1);\n            if (groupMode == 0) {\n                double target = pref[N] * double(g + 1) / double(R);\n                en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            } else {\n                en = (int)llround(double(N) * double(g + 1) / double(R));\n            }\n            en = clamp_int(en, minEnd, maxEnd);\n        }\n        groups.push_back({prev, en});\n        prev = en;\n    }\n\n    Tree t;\n    vector<int> rowRoot;\n    vector<double> rowPref(R + 1, 0);\n\n    for (int i = 0; i < R; i++) {\n        auto [l, r] = groups[i];\n        rowRoot.push_back(build_fixed_rec(t, l, r, VERT, itemSplitMode, pref));\n        rowPref[i+1] = rowPref[i] + (pref[r] - pref[l]);\n    }\n\n    function<int(int,int)> combine = [&](int lo, int hi) -> int {\n        if (hi - lo == 1) return rowRoot[lo];\n\n        int mid = lo + 1;\n        double total = rowPref[hi] - rowPref[lo];\n        double best = 1e100;\n        for (int m = lo + 1; m <= hi - 1; m++) {\n            double d = fabs((rowPref[m] - rowPref[lo]) - total * 0.5);\n            if (d < best) {\n                best = d;\n                mid = m;\n            }\n        }\n\n        int li = combine(lo, mid);\n        int ri = combine(mid, hi);\n\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        t.nodes[idx].l = t.nodes[li].l;\n        t.nodes[idx].r = t.nodes[ri].r;\n        t.nodes[idx].orient = HOR;\n        t.nodes[idx].ratio = (rowPref[mid] - rowPref[lo]) / (rowPref[hi] - rowPref[lo]);\n        return idx;\n    };\n\n    t.root = combine(0, R);\n    build_order(t);\n    return t;\n}\n\n/* ---------- DP for slicing tree ---------- */\n\nstruct DPComputer {\n    const Tree* tr;\n    bool freeOrient;\n    vector<array<unsigned short, W + 1>> dp; // min width for height h\n    vector<array<unsigned short, W + 1>> mh; // min height for width w\n\n    DPComputer(const Tree& t, bool f) : tr(&t), freeOrient(f) {\n        dp.resize(t.nodes.size());\n        mh.resize(t.nodes.size());\n    }\n\n    void compute_mh_from_dp(int idx) {\n        auto& P = dp[idx];\n        auto& M = mh[idx];\n        for (int i = 0; i <= W; i++) M[i] = INF;\n\n        int prev = W + 1;\n        for (int h = 1; h <= W; h++) {\n            int v = P[h];\n            if (v <= W && v < prev) {\n                for (int w = v; w < prev; w++) M[w] = h;\n                prev = v;\n            }\n        }\n    }\n\n    void horizontal_merge(int L, int R, array<unsigned short, W + 1>& out) {\n        for (int i = 0; i <= W; i++) out[i] = INF;\n        int prev = W + 1;\n        for (int w = 1; w <= W; w++) {\n            int hL = mh[L][w], hR = mh[R][w];\n            int req = (hL >= INF || hR >= INF ? INF : hL + hR);\n            if (req <= W && req < prev) {\n                for (int h = req; h < prev; h++) out[h] = w;\n                prev = req;\n            }\n        }\n    }\n\n    void compute(const vector<int>& demand) {\n        for (int idx : tr->order) {\n            const Node& nd = tr->nodes[idx];\n            auto& P = dp[idx];\n            auto& M = mh[idx];\n\n            if (nd.leaf()) {\n                long long a = demand[nd.l];\n                P[0] = M[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    long long v = (a + h - 1) / h;\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                for (int w = 1; w <= W; w++) {\n                    long long v = (a + w - 1) / w;\n                    M[w] = (v <= W ? (unsigned short)v : INF);\n                }\n                continue;\n            }\n\n            int L = nd.left, R = nd.right;\n\n            if (!freeOrient && nd.orient == VERT) {\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                compute_mh_from_dp(idx);\n            } else if (!freeOrient && nd.orient == HOR) {\n                horizontal_merge(L, R, P);\n                compute_mh_from_dp(idx);\n            } else {\n                array<unsigned short, W + 1> HP;\n                horizontal_merge(L, R, HP);\n\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    if (v > W) v = INF;\n                    P[h] = (unsigned short)min(v, (int)HP[h]);\n                }\n                compute_mh_from_dp(idx);\n            }\n        }\n    }\n};\n\n/* ---------- target assignment and reconstruction ---------- */\n\nbool assign_targets_dp_rec(Tree& t, int idx, int y, int x, int h, int w, const DPComputer& comp) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return true;\n\n    int L = nd.left, R = nd.right;\n\n    if (nd.orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(w * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        nd.target = c;\n        nd.targetCoord = x + c;\n        return assign_targets_dp_rec(t, L, y, x, h, c, comp) &&\n               assign_targets_dp_rec(t, R, y, x + c, h, w - c, comp);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(h * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        nd.target = c;\n        nd.targetCoord = y + c;\n        return assign_targets_dp_rec(t, L, y, x, c, w, comp) &&\n               assign_targets_dp_rec(t, R, y + c, x, h - c, w, comp);\n    }\n}\n\nvoid assign_targets_ratio_rec(Tree& t, int idx, int y, int x, int h, int w) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return;\n\n    if (nd.orient == VERT) {\n        int c = (w >= 2 ? clamp_int((int)llround(w * nd.ratio), 1, w - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = x + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, h, max(1, c));\n        assign_targets_ratio_rec(t, nd.right, y, x + c, h, max(1, w - c));\n    } else {\n        int c = (h >= 2 ? clamp_int((int)llround(h * nd.ratio), 1, h - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = y + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, max(1, c), w);\n        assign_targets_ratio_rec(t, nd.right, y + c, x, max(1, h - c), w);\n    }\n}\n\nvoid assign_targets(Tree& t, const vector<int>& demand) {\n    for (auto& nd : t.nodes) {\n        nd.target = 1;\n        nd.targetCoord = -1;\n    }\n\n    DPComputer comp(t, false);\n    comp.compute(demand);\n\n    bool ok = (comp.dp[t.root][W] <= W);\n    if (ok) ok = assign_targets_dp_rec(t, t.root, 0, 0, W, W, comp);\n\n    if (!ok) assign_targets_ratio_rec(t, t.root, 0, 0, W, W);\n}\n\nbool feasible_vert(const DPComputer& comp, int L, int R, int h, int w) {\n    if (w < 2) return false;\n    int a = comp.dp[L][h], b = comp.dp[R][h];\n    return a < INF && b < INF && a + b <= w;\n}\n\nbool feasible_hor(const DPComputer& comp, int L, int R, int h, int w) {\n    if (h < 2) return false;\n    int a = comp.mh[L][w], b = comp.mh[R][w];\n    return a < INF && b < INF && a + b <= h;\n}\n\nint target_size_for(\n    const Tree& t,\n    int idx,\n    int orient,\n    int dim,\n    int originCoord,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (policy == POLICY_PREV && prevOrient[idx] == orient && prevCoord[idx] >= 0) {\n        return prevCoord[idx] - originCoord;\n    }\n\n    if (policy == POLICY_STATIC_RATIO || orient != nd.orient || nd.targetCoord < 0) {\n        return (int)llround(dim * nd.ratio);\n    }\n\n    return nd.targetCoord - originCoord;\n}\n\nbool reconstruct_rec(\n    const Tree& t,\n    int idx,\n    int y,\n    int x,\n    int h,\n    int w,\n    const DPComputer& comp,\n    vector<Rect>& rects,\n    bool freeOrient,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord,\n    vector<int>& curOrient,\n    vector<int>& curCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (nd.leaf()) {\n        if (h <= 0 || w <= 0) return false;\n        rects[nd.l] = {y, x, y + h, x + w};\n        return true;\n    }\n\n    int L = nd.left, R = nd.right;\n    bool canV = feasible_vert(comp, L, R, h, w);\n    bool canH = feasible_hor(comp, L, R, h, w);\n\n    int orient = nd.orient;\n    if (freeOrient) {\n        int po = (policy == POLICY_PREV ? prevOrient[idx] : -1);\n        if (po == VERT && canV) orient = VERT;\n        else if (po == HOR && canH) orient = HOR;\n        else if (nd.orient == VERT && canV) orient = VERT;\n        else if (nd.orient == HOR && canH) orient = HOR;\n        else if (canV) orient = VERT;\n        else if (canH) orient = HOR;\n        else return false;\n    } else {\n        if (orient == VERT && !canV) return false;\n        if (orient == HOR && !canH) return false;\n    }\n\n    if (orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, VERT, w, x, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        curOrient[idx] = VERT;\n        curCoord[idx] = x + c;\n\n        return reconstruct_rec(t, L, y, x, h, c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y, x + c, h, w - c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, HOR, h, y, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        curOrient[idx] = HOR;\n        curCoord[idx] = y + c;\n\n        return reconstruct_rec(t, L, y, x, c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y + c, x, h - c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    }\n}\n\nbool make_solution(const Tree& t, bool freeOrient, int policy, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n\n    DPComputer comp(t, freeOrient);\n    int M = (int)t.nodes.size();\n\n    vector<int> prevOrient(M, -1), prevCoord(M, -1);\n    for (int i = 0; i < M; i++) {\n        if (!t.nodes[i].leaf()) {\n            prevOrient[i] = t.nodes[i].orient;\n            prevCoord[i] = t.nodes[i].targetCoord;\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        comp.compute(A[d]);\n        if (comp.dp[t.root][W] > W) return false;\n\n        vector<int> curOrient(M, -1), curCoord(M, -1);\n        bool ok = reconstruct_rec(\n            t, t.root, 0, 0, W, W, comp, sol[d],\n            freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord\n        );\n        if (!ok) return false;\n\n        if (policy == POLICY_PREV) {\n            prevOrient.swap(curOrient);\n            prevCoord.swap(curCoord);\n        }\n    }\n    return true;\n}\n\nbool make_static_solution(const Tree& t, const vector<int>& demand, bool freeOrient, vector<vector<Rect>>& sol) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][W] > W) return false;\n\n    vector<Rect> one(N);\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    bool ok = reconstruct_rec(\n        t, t.root, 0, 0, W, W, comp, one,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n    if (!ok) return false;\n\n    sol.assign(D, one);\n    return true;\n}\n\n/* ---------- candidates and postprocessing ---------- */\n\nvector<int> scale_to_limit(const vector<int>& v) {\n    long long s = 0;\n    for (int x : v) s += x;\n    if (s <= AREA) return v;\n\n    vector<int> r(N);\n    double f = double(AREA) / double(s);\n    long long sr = 0;\n    for (int i = 0; i < N; i++) {\n        r[i] = max(1, (int)floor(v[i] * f));\n        sr += r[i];\n    }\n\n    while (sr > AREA) {\n        int id = -1;\n        for (int i = 0; i < N; i++) {\n            if (r[i] > 1 && (id == -1 || r[i] > r[id])) id = i;\n        }\n        if (id == -1) break;\n        r[id]--;\n        sr--;\n    }\n    return r;\n}\n\nvector<vector<Rect>> make_fallback() {\n    vector<vector<Rect>> sol(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; d++) {\n        vector<int> h(N, 1);\n        int rem = W - N;\n\n        auto gain = [&](int k) -> int {\n            long long covered = 1LL * h[k] * W;\n            if (covered >= A[d][k]) return 0;\n            return (int)min<long long>(W, A[d][k] - covered);\n        };\n\n        priority_queue<pair<int,int>> pq;\n        for (int k = 0; k < N; k++) pq.push({gain(k), k});\n\n        while (rem > 0 && !pq.empty()) {\n            auto [g, k] = pq.top();\n            pq.pop();\n            int cg = gain(k);\n            if (cg != g) {\n                pq.push({cg, k});\n                continue;\n            }\n            if (cg <= 0) break;\n            h[k]++;\n            rem--;\n            pq.push({gain(k), k});\n        }\n\n        h[N-1] += rem;\n\n        int y = 0;\n        for (int k = 0; k < N; k++) {\n            sol[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    return sol;\n}\n\nvector<vector<Rect>> bestSol;\nlong long bestScore = LLONG_MAX;\n\nvoid consider_solution(const vector<vector<Rect>>& sol) {\n    long long sc = evaluate_solution(sol, bestScore);\n    if (sc < bestScore) {\n        bestScore = sc;\n        bestSol = sol;\n    }\n}\n\nconst double TL_CAND = 2.65;\nconst double TL_POST = 2.85;\n\nvoid process_tree(Tree t, const vector<int>& base, int level) {\n    if (elapsed_sec() > TL_CAND || bestScore == 0) return;\n\n    vector<int> target = scale_to_limit(base);\n    assign_targets(t, target);\n\n    vector<vector<Rect>> sol;\n\n    if (elapsed_sec() < TL_CAND && make_static_solution(t, target, false, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, globalMaxDemand, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_PREV, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 1 && elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_STATIC_ABS, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, target, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_solution(t, true, POLICY_PREV, sol)) {\n        consider_solution(sol);\n    }\n}\n\nvoid try_all_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto orig = bestSol;\n    for (int t = 0; t < D && elapsed_sec() < TL_POST; t++) {\n        vector<vector<Rect>> sol(D, orig[t]);\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n}\n\nvoid smooth_by_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto sol = bestSol;\n    long long curScore = evaluate_solution(sol);\n\n    auto local_cost = [&](int d, const vector<Rect>& cand) -> long long {\n        long long c = shortage_day(cand, d);\n        if (d > 0) c += transition_cost(sol[d-1], cand);\n        if (d + 1 < D) c += transition_cost(cand, sol[d+1]);\n        return c;\n    };\n\n    for (int pass = 0; pass < 5 && elapsed_sec() < TL_POST; pass++) {\n        bool improved = false;\n\n        for (int d = 0; d < D && elapsed_sec() < TL_POST; d++) {\n            long long old = local_cost(d, sol[d]);\n\n            if (d > 0) {\n                long long nw = local_cost(d, sol[d-1]);\n                if (nw < old) {\n                    sol[d] = sol[d-1];\n                    curScore += nw - old;\n                    old = nw;\n                    improved = true;\n                }\n            }\n\n            if (d + 1 < D) {\n                long long nw = local_cost(d, sol[d+1]);\n                if (nw < old) {\n                    sol[d] = sol[d+1];\n                    curScore += nw - old;\n                    old = nw;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    curScore = evaluate_solution(sol);\n    if (curScore < bestScore) {\n        bestScore = curScore;\n        bestSol = sol;\n    }\n}\n\n/* ---------- main ---------- */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int inputW;\n    cin >> inputW >> 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    globalMaxDemand.assign(N, 1);\n    vector<int> meanDemand(N, 1), medDemand(N, 1), p75Demand(N, 1), p90Demand(N, 1);\n\n    for (int k = 0; k < N; k++) {\n        long long s = 0;\n        vector<int> vals;\n        for (int d = 0; d < D; d++) {\n            s += A[d][k];\n            vals.push_back(A[d][k]);\n            globalMaxDemand[k] = max(globalMaxDemand[k], A[d][k]);\n        }\n        sort(vals.begin(), vals.end());\n        meanDemand[k] = max(1, (int)(s / D));\n        medDemand[k] = vals[D / 2];\n        p75Demand[k] = vals[min(D - 1, (int)llround(0.75 * (D - 1)))];\n        p90Demand[k] = vals[min(D - 1, (int)llround(0.90 * (D - 1)))];\n    }\n\n    bestSol = make_fallback();\n    bestScore = evaluate_solution(bestSol);\n\n    vector<vector<int>> bases;\n    bases.push_back(globalMaxDemand);\n    bases.push_back(p90Demand);\n    bases.push_back(p75Demand);\n    bases.push_back(meanDemand);\n    bases.push_back(medDemand);\n\n    // Aspect/squarified slicing trees\n    vector<pair<int,int>> combos = {\n        {0, 0}, // area split, aspect orientation\n        {2, 0}, // hybrid split, aspect orientation\n        {1, 0}, // count split, aspect orientation\n        {0, 1}, // alternating V/H\n        {0, 2}  // alternating H/V\n    };\n\n    for (int bi = 0; bi < (int)bases.size(); bi++) {\n        for (int ci = 0; ci < (int)combos.size(); ci++) {\n            if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n\n            int splitMode = combos[ci].first;\n            int orientMode = combos[ci].second;\n            Tree t = build_aspect_tree(bases[bi], splitMode, orientMode);\n\n            int level = 1;\n            if (ci == 0 && bi <= 3) level = 2;\n            process_tree(t, bases[bi], level);\n        }\n        if (bestScore == 0) break;\n    }\n\n    // Shelf-like candidates\n    vector<int> Rs;\n    auto addR = [&](int r) {\n        r = clamp_int(r, 1, N);\n        if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n    };\n\n    int sq = max(1, (int)llround(sqrt((double)N)));\n    addR(sq);\n    addR(sq + 1);\n    addR(sq - 1);\n    addR(N / 4);\n    addR(N / 3);\n    addR(N / 2);\n    addR(2 * sq);\n    addR(5);\n    addR(8);\n    addR(10);\n    addR(15);\n    addR(20);\n    addR(N);\n    addR(1);\n\n    vector<int> shelfBaseIds = {0, 1, 3, 2};\n    for (int bi : shelfBaseIds) {\n        for (int groupMode = 0; groupMode <= 1; groupMode++) {\n            for (int r : Rs) {\n                if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n                Tree t = build_shelf_tree(bases[bi], r, groupMode, 0);\n                int level = (groupMode == 0 ? 1 : 0);\n                process_tree(t, bases[bi], level);\n            }\n            if (bestScore == 0) break;\n        }\n        if (bestScore == 0) break;\n    }\n\n    try_all_copy();\n    smooth_by_copy();\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            const Rect& r = bestSol[d][k];\n            cout << r.y0 << ' ' << r.x0 << ' ' << r.y1 << ' ' << r.x1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int BN = 9;\nstatic const int AP = 7;\nstatic const int KMAX = 81;\nstatic const int MOD = 998244353;\n\nint N, M, K;\narray<int, KMAX> initBoard;\nlong long initScore = 0;\nint stampVal[20][9];\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\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} timer;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n} rng(123456789);\n\nstruct Action {\n    int m, p, q;\n    int idx[9];\n    int val[9];\n};\n\nvector<Action> actions;\narray<array<int, 9>, 49> anchorCells;\nvector<int> cellCovers[81];\n\nstruct Option {\n    unsigned char cnt;\n    unsigned char s1, s2;\n    int val[9];\n};\n\nvector<Option> options;\n\ninline long long evalAdd(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applyAdd(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applySub(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\nstruct Solution {\n    array<int, KMAX> board;\n    array<int, KMAX> slot;\n    long long score;\n};\n\nvoid precompute() {\n    actions.reserve(49 * M);\n\n    for (int p = 0; p < AP; p++) {\n        for (int q = 0; q < AP; q++) {\n            int aid = p * AP + q;\n            int t = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    anchorCells[aid][t++] = (p + di) * BN + (q + dj);\n                }\n            }\n        }\n    }\n\n    for (int aid = 0; aid < 49; aid++) {\n        int p = aid / AP;\n        int q = aid % AP;\n        for (int m = 0; m < M; m++) {\n            Action a;\n            a.m = m;\n            a.p = p;\n            a.q = q;\n            for (int k = 0; k < 9; k++) {\n                a.idx[k] = anchorCells[aid][k];\n                a.val[k] = stampVal[m][k];\n            }\n            actions.push_back(a);\n        }\n    }\n\n    for (int r = 0; r < BN; r++) {\n        for (int c = 0; c < BN; c++) {\n            int cell = r * BN + c;\n            for (int p = max(0, r - 2); p <= min(AP - 1, r); p++) {\n                for (int q = max(0, c - 2); q <= min(AP - 1, c); q++) {\n                    cellCovers[cell].push_back(p * AP + q);\n                }\n            }\n        }\n    }\n\n    Option none{};\n    none.cnt = 0;\n    none.s1 = none.s2 = 0;\n    for (int k = 0; k < 9; k++) none.val[k] = 0;\n    options.push_back(none);\n\n    for (int m = 0; m < M; m++) {\n        Option op{};\n        op.cnt = 1;\n        op.s1 = m;\n        op.s2 = 0;\n        for (int k = 0; k < 9; k++) op.val[k] = stampVal[m][k];\n        options.push_back(op);\n    }\n\n    for (int a = 0; a < M; a++) {\n        for (int b = a; b < M; b++) {\n            Option op{};\n            op.cnt = 2;\n            op.s1 = a;\n            op.s2 = b;\n            for (int k = 0; k < 9; k++) {\n                int v = stampVal[a][k] + stampVal[b][k];\n                if (v >= MOD) v -= MOD;\n                op.val[k] = v;\n            }\n            options.push_back(op);\n        }\n    }\n}\n\nvoid rebuild(Solution& sol) {\n    sol.board = initBoard;\n    sol.score = initScore;\n    for (int i = 0; i < K; i++) {\n        if (sol.slot[i] >= 0) {\n            sol.score += applyAdd(sol.board, sol.slot[i]);\n        }\n    }\n}\n\nSolution makeSolutionFromOps(const vector<int>& ops) {\n    Solution sol;\n    sol.slot.fill(-1);\n    int L = min((int)ops.size(), K);\n    for (int i = 0; i < L; i++) sol.slot[i] = ops[i];\n    rebuild(sol);\n    return sol;\n}\n\nSolution greedySolution() {\n    Solution sol;\n    sol.board = initBoard;\n    sol.slot.fill(-1);\n    sol.score = initScore;\n\n    for (int step = 0; step < K; step++) {\n        long long bestDelta = 0;\n        int best = -1;\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long d = evalAdd(sol.board, aid);\n            if (d > bestDelta) {\n                bestDelta = d;\n                best = aid;\n            }\n        }\n        if (best == -1) break;\n        sol.slot[step] = best;\n        sol.score += applyAdd(sol.board, best);\n    }\n\n    return sol;\n}\n\nvoid coordinateDescent(Solution& sol, int maxSweeps, double timeLimit) {\n    array<int, KMAX> ord;\n    for (int i = 0; i < K; i++) ord[i] = i;\n\n    for (int sweep = 0; sweep < maxSweeps; sweep++) {\n        if (timer.elapsed() > timeLimit) break;\n\n        for (int i = K - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int oi = 0; oi < K; oi++) {\n            int pos = ord[oi];\n            int old = sol.slot[pos];\n            long long oldScore = sol.score;\n\n            if (old >= 0) {\n                sol.score += applySub(sol.board, old);\n            }\n            long long base = sol.score;\n\n            int best = old;\n            long long bestScore = oldScore;\n\n            if (base > bestScore) {\n                bestScore = base;\n                best = -1;\n            }\n\n            for (int aid = 0; aid < (int)actions.size(); aid++) {\n                long long cand = base + evalAdd(sol.board, aid);\n                if (cand > bestScore) {\n                    bestScore = cand;\n                    best = aid;\n                }\n            }\n\n            sol.score = base;\n            if (best >= 0) {\n                sol.score += applyAdd(sol.board, best);\n            }\n            sol.slot[pos] = best;\n\n            if (sol.score > oldScore) improved = true;\n        }\n\n        if (!improved) break;\n    }\n}\n\nbool optimizePair(Solution& sol, int i, int j, int topC) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n    long long base = sol.score;\n\n    vector<pair<long long, int>> all;\n    all.reserve(actions.size());\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        all.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    auto cmpPair = [](const pair<long long, int>& a, const pair<long long, int>& b) {\n        return a.first > b.first;\n    };\n\n    if ((int)all.size() > topC) {\n        nth_element(all.begin(), all.begin() + topC, all.end(), cmpPair);\n        all.resize(topC);\n    }\n\n    vector<pair<long long, int>> firsts = all;\n    firsts.push_back({base, -1});\n\n    for (int t = 0; t < 5; t++) {\n        int aid = rng.nextInt((int)actions.size());\n        firsts.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    long long bestScore = oldScore;\n    int best1 = old1;\n    int best2 = old2;\n\n    for (auto [dummyScore, f] : firsts) {\n        long long d1 = 0;\n        if (f >= 0) d1 = applyAdd(sol.board, f);\n        long long sc1 = base + d1;\n\n        long long localBest = sc1;\n        int gbest = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long cand = sc1 + evalAdd(sol.board, aid);\n            if (cand > localBest) {\n                localBest = cand;\n                gbest = aid;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best1 = f;\n            best2 = gbest;\n        }\n\n        if (f >= 0) applySub(sol.board, f);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        sol.slot[i] = best1;\n        sol.slot[j] = best2;\n        if (best1 >= 0) sol.score += applyAdd(sol.board, best1);\n        if (best2 >= 0) sol.score += applyAdd(sol.board, best2);\n        return true;\n    } else {\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n        return false;\n    }\n}\n\nvoid pairSearch(Solution& sol, double timeLimit) {\n    int attempts = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        int i, j;\n\n        if ((attempts & 7) == 0) {\n            vector<int> none;\n            for (int t = 0; t < K; t++) {\n                if (sol.slot[t] == -1) none.push_back(t);\n            }\n\n            if ((int)none.size() >= 2) {\n                int a = rng.nextInt((int)none.size());\n                int b = rng.nextInt((int)none.size() - 1);\n                if (b >= a) b++;\n                i = none[a];\n                j = none[b];\n            } else {\n                i = rng.nextInt(K);\n                do {\n                    j = rng.nextInt(K);\n                } while (j == i);\n            }\n        } else {\n            i = rng.nextInt(K);\n            do {\n                j = rng.nextInt(K);\n            } while (j == i);\n        }\n\n        attempts++;\n\n        if (optimizePair(sol, i, j, 22)) {\n            coordinateDescent(sol, 4, timeLimit);\n        }\n    }\n}\n\nlong long orderCost(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    int cnt[49] = {};\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        cnt[br]++;\n    }\n\n    int maxc = 0;\n    int sumsq = 0;\n    int zero = 0;\n    for (int i = 0; i < 49; i++) {\n        maxc = max(maxc, cnt[i]);\n        sumsq += cnt[i] * cnt[i];\n        if (cnt[i] == 0) zero++;\n    }\n\n    return (long long)maxc * 1000000LL + (long long)sumsq * 1000LL + zero;\n}\n\nvector<int> findBalancedOrder() {\n    vector<int> base(49);\n    iota(base.begin(), base.end(), 0);\n\n    vector<int> best = base;\n    long long bestCost = orderCost(best);\n\n    const int REPS = 10;\n    const int ITERS = 1300;\n\n    for (int rep = 0; rep < REPS; rep++) {\n        vector<int> perm = base;\n        for (int i = 48; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(perm[i], perm[j]);\n        }\n\n        long long cur = orderCost(perm);\n\n        for (int it = 0; it < ITERS; it++) {\n            int a = rng.nextInt(49);\n            int b = rng.nextInt(49);\n            if (a == b) continue;\n\n            swap(perm[a], perm[b]);\n            long long nc = orderCost(perm);\n\n            if (nc <= cur) {\n                cur = nc;\n            } else {\n                swap(perm[a], perm[b]);\n            }\n        }\n\n        if (cur < bestCost) {\n            bestCost = cur;\n            best = perm;\n        }\n    }\n\n    return best;\n}\n\nvector<vector<int>> computeFinalCells(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    vector<vector<int>> finalCells(49);\n\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            if (rank[aid] > br) br = rank[aid];\n        }\n        finalCells[br].push_back(cell);\n    }\n\n    return finalCells;\n}\n\nstruct BeamState {\n    array<int, KMAX> cell;\n    long long fin;\n    long long total;\n    long long key;\n    int parent;\n    short opt;\n    unsigned char used;\n};\n\nvector<int> beamSearch(const vector<int>& order, int perWidth) {\n    vector<vector<int>> finalCells = computeFinalCells(order);\n\n    vector<vector<BeamState>> layers;\n    layers.reserve(50);\n\n    BeamState init{};\n    init.cell = initBoard;\n    init.fin = 0;\n    init.total = initScore;\n    init.key = initScore;\n    init.parent = -1;\n    init.opt = -1;\n    init.used = 0;\n\n    layers.push_back(vector<BeamState>{init});\n\n    vector<vector<BeamState>> buckets(K + 1);\n    int reserveEach = perWidth * (int)options.size() + 8;\n    for (auto& b : buckets) b.reserve(reserveEach);\n\n    auto cmpState = [](const BeamState& a, const BeamState& b) {\n        if (a.key != b.key) return a.key > b.key;\n        if (a.fin != b.fin) return a.fin > b.fin;\n        return a.total > b.total;\n    };\n\n    for (int step = 0; step < 49; step++) {\n        for (auto& b : buckets) b.clear();\n\n        const vector<BeamState>& cur = layers.back();\n        int aid = order[step];\n        const auto& cells = anchorCells[aid];\n        const vector<int>& fins = finalCells[step];\n\n        for (int si = 0; si < (int)cur.size(); si++) {\n            const BeamState& st = cur[si];\n\n            for (int oid = 0; oid < (int)options.size(); oid++) {\n                const Option& op = options[oid];\n                int nu = (int)st.used + (int)op.cnt;\n                if (nu > K) continue;\n\n                BeamState ns;\n                ns.cell = st.cell;\n                ns.fin = st.fin;\n                ns.total = st.total;\n                ns.parent = si;\n                ns.opt = (short)oid;\n                ns.used = (unsigned char)nu;\n\n                if (op.cnt) {\n                    for (int k = 0; k < 9; k++) {\n                        int v = op.val[k];\n                        if (v == 0) continue;\n                        int idx = cells[k];\n                        int old = ns.cell[idx];\n                        int nv = old + v;\n                        if (nv >= MOD) nv -= MOD;\n                        ns.cell[idx] = nv;\n                        ns.total += (long long)nv - old;\n                    }\n                }\n\n                for (int idx : fins) {\n                    ns.fin += ns.cell[idx];\n                }\n\n                ns.key = ns.fin * 10 + (ns.total - ns.fin);\n                buckets[nu].push_back(std::move(ns));\n            }\n        }\n\n        vector<BeamState> next;\n        next.reserve((K + 1) * perWidth);\n\n        for (int u = 0; u <= K; u++) {\n            auto& v = buckets[u];\n            if ((int)v.size() > perWidth) {\n                nth_element(v.begin(), v.begin() + perWidth, v.end(), cmpState);\n                v.resize(perWidth);\n            }\n            for (auto& s : v) next.push_back(std::move(s));\n        }\n\n        layers.push_back(std::move(next));\n    }\n\n    const vector<BeamState>& last = layers.back();\n    int bestIdx = 0;\n    for (int i = 1; i < (int)last.size(); i++) {\n        if (last[i].fin > last[bestIdx].fin) bestIdx = i;\n    }\n\n    vector<int> optAt(49);\n    int idx = bestIdx;\n    for (int step = 48; step >= 0; step--) {\n        const BeamState& st = layers[step + 1][idx];\n        optAt[step] = st.opt;\n        idx = st.parent;\n    }\n\n    vector<int> ops;\n    ops.reserve(K);\n\n    for (int step = 0; step < 49; step++) {\n        int aid = order[step];\n        const Option& op = options[optAt[step]];\n\n        if (op.cnt >= 1) ops.push_back(aid * M + (int)op.s1);\n        if (op.cnt >= 2) ops.push_back(aid * M + (int)op.s2);\n    }\n\n    if ((int)ops.size() > K) ops.resize(K);\n    return ops;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> K;\n\n    for (int i = 0; i < BN; i++) {\n        for (int j = 0; j < BN; j++) {\n            int x;\n            cin >> x;\n            initBoard[i * BN + j] = x;\n            initScore += x;\n        }\n    }\n\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                cin >> stampVal[m][i * 3 + j];\n            }\n        }\n    }\n\n    timer.reset();\n\n    precompute();\n\n    Solution best = greedySolution();\n    coordinateDescent(best, 25, 1.86);\n\n    vector<int> order = findBalancedOrder();\n\n    if (timer.elapsed() < 1.20) {\n        vector<int> ops = beamSearch(order, 6);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 18, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    vector<int> revOrder = order;\n    reverse(revOrder.begin(), revOrder.end());\n\n    if (timer.elapsed() < 1.45) {\n        vector<int> ops = beamSearch(revOrder, 4);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 14, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    pairSearch(best, 1.86);\n\n    vector<int> out;\n    for (int i = 0; i < K; i++) {\n        if (best.slot[i] >= 0) out.push_back(best.slot[i]);\n    }\n\n    cout << out.size() << '\\n';\n    for (int id : out) {\n        const Action& a = actions[id];\n        cout << a.m << ' ' << a.p << ' ' << a.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 TOT = 25;\nstatic constexpr int BASE = 6;\nstatic constexpr int PBASE = 7776; // 6^5\nstatic constexpr int TOTAL_STATES = PBASE * PBASE;\nstatic constexpr int INF = 1e9;\n\nint A[N][N];\nint srcOf[TOT], idxOf[TOT];\nint pow6_[N + 1];\n\nuint8_t dig[PBASE][N];\nuint8_t sumCode[PBASE];\nuint8_t exhCode[PBASE];\n\nvector<signed char> memoBlock;\n\ninline int manhattan(int r1, int c1, int r2, int c2) {\n    return abs(r1 - r2) + abs(c1 - c2);\n}\n\nstruct TransCode {\n    int npcode, nqcode, code, k;\n};\n\n// Transition in the abstract sorting model.\n// q[d] is the next required item of output row d.\n// If it is hidden in an input queue, all preceding items become buffered.\nbool makeTransCodes(int pcode, int qcode, int d, TransCode &tr) {\n    int qd = dig[qcode][d];\n    if (qd >= N) return false;\n\n    int x = N * d + qd;\n    int s = srcOf[x];\n    int idx = idxOf[x];\n    int ps = dig[pcode][s];\n\n    int nq = qcode + pow6_[d];\n    int np = pcode;\n    int k = 0;\n\n    if (idx < ps) {\n        // already removed from input, so it must be in buffer\n        k = 0;\n    } else {\n        // Need to buffer idx - ps containers before x.\n        k = idx - ps;\n        int buffer = (int)sumCode[pcode] - (int)sumCode[qcode];\n        int capacity = 15 + (int)exhCode[pcode]; // cols 1..3 + exhausted receiving gates\n        if (buffer + k > capacity) return false;\n        np = pcode + (idx + 1 - ps) * pow6_[s];\n    }\n\n    tr = {np, nq, np * PBASE + nq, k};\n    return true;\n}\n\n// Minimum additional number of containers that must be buffered.\n// INF means impossible under our storage model.\nint dfsBlock(int code) {\n    signed char m = memoBlock[code];\n    if (m != -1) {\n        if (m >= 100) return INF;\n        return (int)m;\n    }\n\n    int pcode = code / PBASE;\n    int qcode = code % PBASE;\n\n    if (sumCode[qcode] == TOT) {\n        memoBlock[code] = 0;\n        return 0;\n    }\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(pcode, qcode, d, tr)) continue;\n        int sub = dfsBlock(tr.code);\n        if (sub >= INF) continue;\n        best = min(best, tr.k + sub);\n    }\n\n    memoBlock[code] = (best >= INF ? 100 : (signed char)best);\n    return best;\n}\n\nstruct State {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    void init() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) occ[i][j] = -1;\n        }\n        for (int i = 0; i < N; i++) occ[i][0] = A[i][0];\n        r = c = 0;\n        act.clear();\n        eval = 0;\n    }\n\n    int code() const {\n        return pcode * PBASE + qcode;\n    }\n\n    int delivered() const {\n        return sumCode[qcode];\n    }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveTo(int tr, int tc) {\n        while (r < tr) add('D');\n        while (r > tr) add('U');\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    pair<int, int> chooseStorage(int b, int srcRow, double storageW) const {\n        int bd = b / N;\n        double best = 1e100;\n        int bestTie = INF;\n        pair<int, int> res = {-1, -1};\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) { // col 4 is dispatch gate, not storage\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue; // non-exhausted receiving gate reserved\n\n                int ds = abs(srcRow - rr) + cc; // from (srcRow,0)\n                int dg = abs(bd - rr) + abs((N - 1) - cc); // to its dispatch gate\n                double sc = 2.0 * ds + storageW * dg;\n\n                int tie = dg * 10 + ((N - 1) - cc);\n                if (sc + 1e-9 < best || (fabs(sc - best) <= 1e-9 && tie < bestTie)) {\n                    best = sc;\n                    bestTie = tie;\n                    res = {rr, cc};\n                }\n            }\n        }\n        return res;\n    }\n\n    bool executeTarget(int d, double storageW) {\n        if (q[d] >= N) return false;\n\n        int x = N * d + q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        // Target is already buffered.\n        if (idx < p[s]) {\n            int rr = lr[x], cc = lc[x];\n            if (rr < 0 || occ[rr][cc] != x) return false;\n\n            moveTo(rr, cc);\n            add('P');\n            occ[rr][cc] = -1;\n            lr[x] = lc[x] = -1;\n\n            moveTo(d, N - 1);\n            add('Q');\n            incQ(d);\n            return true;\n        }\n\n        // Buffer preceding containers in the source queue.\n        while (p[s] < idx) {\n            if (p[s] >= N) return false;\n            int b = A[s][p[s]];\n            if (occ[s][0] != b) return false;\n\n            moveTo(s, 0);\n            add('P');\n            occ[s][0] = -1;\n            incP(s);\n            if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n            auto cell = chooseStorage(b, s, storageW);\n            if (cell.first < 0) return false;\n\n            moveTo(cell.first, cell.second);\n            add('Q');\n            occ[cell.first][cell.second] = b;\n            lr[b] = cell.first;\n            lc[b] = cell.second;\n        }\n\n        // Dispatch target.\n        if (p[s] >= N || A[s][p[s]] != x || occ[s][0] != x) return false;\n\n        moveTo(s, 0);\n        add('P');\n        occ[s][0] = -1;\n        incP(s);\n        if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n        moveTo(d, N - 1);\n        add('Q');\n        incQ(d);\n        return true;\n    }\n};\n\nint nearestHeuristic(const State &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct PlanResult {\n    bool ok = false;\n    string act;\n};\n\nPlanResult buildBeam(double storageW, int width, int hcoef) {\n    State init;\n    init.init();\n\n    vector<State> beam;\n    beam.push_back(init);\n\n    auto comp = [](const State &a, const State &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.act.size() < b.act.size();\n    };\n\n    for (int step = 0; step < TOT; step++) {\n        vector<State> cand;\n        cand.reserve(beam.size() * N);\n\n        for (const State &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                State ns = st;\n                if (!ns.executeTarget(d, storageW)) continue;\n                if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n\n                int near = nearestHeuristic(ns);\n                ns.eval = (int)ns.act.size() + hcoef * remAfter + near;\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return {false, \"\"};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    string best;\n    int bestLen = INF;\n    for (const State &st : beam) {\n        if (st.delivered() == TOT && (int)st.act.size() < bestLen) {\n            bestLen = (int)st.act.size();\n            best = st.act;\n        }\n    }\n\n    if (best.empty()) return {false, \"\"};\n    return {true, best};\n}\n\n// Correct dispatch gate, but not necessarily sorted. Used as safety / sometimes score fallback.\nstring buildDirectPlan() {\n    State st;\n    st.init();\n\n    for (int s = 0; s < N; s++) {\n        while (st.p[s] < N) {\n            int x = A[s][st.p[s]];\n            int d = x / N;\n\n            st.moveTo(s, 0);\n            st.add('P');\n            st.occ[s][0] = -1;\n            st.incP(s);\n            if (st.p[s] < N) st.occ[s][0] = A[s][st.p[s]];\n\n            st.moveTo(d, N - 1);\n            st.add('Q');\n        }\n    }\n\n    return st.act;\n}\n\nint directInversions() {\n    vector<int> seq[N];\n    int inv = 0;\n\n    for (int s = 0; s < N; s++) {\n        for (int k = 0; k < N; k++) {\n            int x = A[s][k];\n            int d = x / N;\n            for (int y : seq[d]) {\n                if (y > x) inv++;\n            }\n            seq[d].push_back(x);\n        }\n    }\n\n    return inv;\n}\n\nvoid initTables() {\n    pow6_[0] = 1;\n    for (int i = 0; i < N; i++) pow6_[i + 1] = pow6_[i] * BASE;\n\n    for (int code = 0; code < PBASE; code++) {\n        int tmp = code;\n        int sm = 0, ex = 0;\n        for (int i = 0; i < N; i++) {\n            int v = tmp % BASE;\n            tmp /= BASE;\n            dig[code][i] = (uint8_t)v;\n            sm += v;\n            if (v == N) ex++;\n        }\n        sumCode[code] = (uint8_t)sm;\n        exhCode[code] = (uint8_t)ex;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initTables();\n\n    int Nin;\n    cin >> Nin;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> A[i][j];\n            srcOf[A[i][j]] = i;\n            idxOf[A[i][j]] = j;\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsedMs = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    };\n\n    memoBlock.assign(TOTAL_STATES, -1);\n\n    string sortedAct;\n\n    int opt = dfsBlock(0);\n    if (opt < INF) {\n        // First, a very fast greedy beam, guaranteeing a sorted plan if execution succeeds.\n        PlanResult first = buildBeam(1.0, 1, 8);\n        if (first.ok) sortedAct = first.act;\n\n        vector<double> weights = {0.0, 0.25, 0.6, 1.0, 1.8, 3.5, 7.0};\n        vector<int> hcoefs = {0, 6, 12};\n        int width = 300;\n\n        bool stop = false;\n        for (int h : hcoefs) {\n            if (stop) break;\n            for (double w : weights) {\n                if (elapsedMs() > 2800) {\n                    stop = true;\n                    break;\n                }\n                PlanResult pr = buildBeam(w, width, h);\n                if (pr.ok && (sortedAct.empty() || pr.act.size() < sortedAct.size())) {\n                    sortedAct = pr.act;\n                }\n            }\n        }\n    }\n\n    string directAct = buildDirectPlan();\n    int inv = directInversions();\n    long long directScore = (long long)directAct.size() + 100LL * inv;\n\n    string answer;\n    if (!sortedAct.empty()) answer = sortedAct;\n    else answer = directAct;\n\n    long long sortedScore = sortedAct.empty() ? (long long)4e18 : (long long)sortedAct.size();\n    if (directScore < sortedScore) answer = directAct;\n\n    if (answer.empty() || answer.size() > 10000) {\n        answer = directAct;\n    }\n    if (answer.empty()) answer = \".\";\n\n    int L = (int)answer.size();\n\n    cout << answer << '\\n';\n    for (int i = 1; i < N; i++) {\n        string s(L, '.');\n        s[0] = 'B'; // bomb small cranes on the first turn\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 20;\nstatic const int V = N * N;\nstatic const long long INFLL = (1LL << 60);\nstatic const int INF = 1e9;\n\nint H[V];\nint DIST[V][V];\nlong long BASE_COST = 0;\n\nint cell_id(int r, int c) {\n    return r * N + c;\n}\n\nstruct Solution {\n    vector<string> ops;\n    long long cost = 0;\n    long long load = 0;\n    int pos = 0;\n    bool valid = true;\n\n    void moveOne(char ch) {\n        ops.emplace_back(1, ch);\n        cost += 100 + load;\n\n        int r = pos / N;\n        int c = pos % N;\n        if (ch == 'U') --r;\n        if (ch == 'D') ++r;\n        if (ch == 'L') --c;\n        if (ch == 'R') ++c;\n        if (r < 0 || r >= N || c < 0 || c >= N) valid = false;\n        pos = cell_id(r, c);\n    }\n\n    void moveTo(int target) {\n        int tr = target / N;\n        int tc = target % N;\n        while (pos / N < tr) moveOne('D');\n        while (pos / N > tr) moveOne('U');\n        while (pos % N < tc) moveOne('R');\n        while (pos % N > tc) moveOne('L');\n    }\n\n    void addLoad(int d) {\n        if (d <= 0) return;\n        ops.push_back(string(\"+\") + to_string(d));\n        cost += d;\n        load += d;\n    }\n\n    void addUnload(int d) {\n        if (d <= 0) return;\n        if (load < d) valid = false;\n        ops.push_back(string(\"-\") + to_string(d));\n        cost += d;\n        load -= d;\n    }\n};\n\narray<int, V> nearestDist(const vector<int>& rem, bool positive, bool& has) {\n    array<int, V> dist;\n    dist.fill(INF);\n    queue<int> q;\n    has = false;\n\n    for (int i = 0; i < V; ++i) {\n        if ((positive && rem[i] > 0) || (!positive && rem[i] < 0)) {\n            dist[i] = 0;\n            q.push(i);\n            has = true;\n        }\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        int r = v / N;\n        int c = v % N;\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];\n            int nc = c + dc[k];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int to = cell_id(nr, nc);\n            if (dist[to] > dist[v] + 1) {\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n    }\n    return dist;\n}\n\nint selectSource(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearNeg,\n    int mode,\n    int maxAmount\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] <= 0) continue;\n        if (maxAmount >= 0 && rem[i] > maxAmount) continue;\n\n        int d = DIST[cur][i];\n        int nd = nearNeg[i] >= INF ? 0 : nearNeg[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * rem[i];\n        } else if (mode == 1) {\n            score = 10000LL * d - 200LL * rem[i];\n        } else {\n            score = 8000LL * d + 3000LL * nd - 50LL * rem[i];\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nint selectDemand(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearPos,\n    bool hasPos,\n    long long load,\n    int mode\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] >= 0) continue;\n\n        int demand = -rem[i];\n        int del = (int)min<long long>(load, demand);\n        if (del <= 0) continue;\n\n        int d = DIST[cur][i];\n        int future = 0;\n        if (load == del && hasPos && nearPos[i] < INF) future = nearPos[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * del + 1000LL * future;\n        } else if (mode == 1) {\n            score = 1000LL * d * (100 + load) / (del + 10) + 500LL * future;\n        } else {\n            score = 10000LL * d - 200LL * del + 1000LL * future;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nSolution makeGreedySolution(int maxLoad, int ratioNum, int ratioDen, int sourceMode, int demandMode) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 10000; ++iter) {\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            sol.moveTo(p);\n            int a = rem[p];\n            sol.addLoad(a);\n            rem[p] = 0;\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (maxLoad > 0 && hasPos) {\n                int maxAmount = maxLoad - (int)sol.load;\n                if (maxAmount > 0) {\n                    p = selectSource(sol.pos, rem, nearNeg, sourceMode, maxAmount);\n                    if (p >= 0) {\n                        int nearestDemand = nearNeg[sol.pos];\n                        int dp = DIST[sol.pos][p];\n\n                        if (nearestDemand > 0 &&\n                            1LL * dp * ratioDen <= 1LL * nearestDemand * ratioNum) {\n                            takePos = true;\n                        }\n                    }\n                }\n            }\n\n            if (takePos) {\n                sol.moveTo(p);\n                int a = rem[p];\n                sol.addLoad(a);\n                rem[p] = 0;\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                sol.moveTo(q);\n                int x = (int)min<long long>(sol.load, -rem[q]);\n                sol.addUnload(x);\n                rem[q] += x;\n            }\n        }\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev;\n        long long cap, cost;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow(int n_) : n(n_), g(n_) {}\n\n    int addEdge(int fr, int to, long long cap, long long cost) {\n        Edge f{to, (int)g[to].size(), cap, cost};\n        Edge r{fr, (int)g[fr].size(), 0, -cost};\n        g[fr].push_back(f);\n        g[to].push_back(r);\n        return (int)g[fr].size() - 1;\n    }\n\n    pair<long long, long long> minCostFlow(int s, int t, long long maxf) {\n        long long flow = 0;\n        long long cost = 0;\n        vector<long long> pot(n, 0), dist(n);\n        vector<int> pv(n), pe(n);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INFLL);\n            dist[s] = 0;\n\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n                if (dist[v] != d) continue;\n\n                for (int i = 0; i < (int)g[v].size(); ++i) {\n                    Edge& e = g[v][i];\n                    if (e.cap <= 0) continue;\n                    long long nd = d + e.cost + pot[v] - pot[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INFLL) break;\n\n            for (int v = 0; v < n; ++v) {\n                if (dist[v] < INFLL) pot[v] += dist[v];\n            }\n\n            long long add = maxf - flow;\n            for (int v = t; v != s; v = pv[v]) {\n                add = min(add, g[pv[v]][pe[v]].cap);\n            }\n\n            for (int v = t; v != s; v = pv[v]) {\n                Edge& e = g[pv[v]][pe[v]];\n                e.cap -= add;\n                g[v][e.rev].cap += add;\n                cost += add * e.cost;\n            }\n\n            flow += add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nstruct Flow {\n    int s, t, amount;\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\nvector<Flow> computeMinCostFlows(int variant) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n            total += H[i];\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n    if (total == 0) return {};\n\n    int SRC = 0;\n    int posBase = 1;\n    int negBase = 1 + P;\n    int SNK = 1 + P + Q;\n    int nodes = SNK + 1;\n\n    MinCostFlow mf(nodes);\n\n    for (int i = 0; i < P; ++i) {\n        mf.addEdge(SRC, posBase + i, posAmt[i], 0);\n    }\n    for (int j = 0; j < Q; ++j) {\n        mf.addEdge(negBase + j, SNK, negAmt[j], 0);\n    }\n\n    struct Ref {\n        int node, edgeIndex, pi, qi;\n    };\n    vector<Ref> refs;\n\n    const long long CAP = 1e9;\n    const long long W = 100000000LL;\n\n    for (int i = 0; i < P; ++i) {\n        for (int j = 0; j < Q; ++j) {\n            long long tie = 0;\n            if (variant != 0) {\n                uint64_t seed = ((uint64_t)variant << 48) ^ ((uint64_t)posCells[i] << 24) ^ (uint64_t)negCells[j];\n                tie = splitmix64(seed) % 1000;\n            }\n\n            long long c = 1LL * DIST[posCells[i]][negCells[j]] * W + tie;\n            int idx = mf.addEdge(posBase + i, negBase + j, CAP, c);\n            refs.push_back({posBase + i, idx, i, j});\n        }\n    }\n\n    mf.minCostFlow(SRC, SNK, total);\n\n    vector<Flow> flows;\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            flows.push_back({posCells[ref.pi], negCells[ref.qi], (int)used});\n        }\n    }\n\n    return flows;\n}\n\nvector<int> optimizeOrder(const vector<int>& starts, const vector<int>& ends) {\n    int m = (int)starts.size();\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    vector<int> startLink(m);\n    vector<vector<int>> link(m, vector<int>(m));\n\n    for (int i = 0; i < m; ++i) {\n        startLink[i] = DIST[0][starts[i]];\n    }\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < m; ++j) {\n            link[i][j] = DIST[ends[i]][starts[j]];\n        }\n    }\n\n    auto L = [&](int prev, int cur) -> int {\n        if (prev < 0) return startLink[cur];\n        return link[prev][cur];\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n\n    for (int cnt = 0; cnt < m; ++cnt) {\n        int bestG = -1, bestPos = 0;\n        int bestInc = INF;\n\n        for (int g = 0; g < m; ++g) {\n            if (used[g]) continue;\n\n            for (int p = 0; p <= (int)order.size(); ++p) {\n                int prev = (p == 0 ? -1 : order[p - 1]);\n                int nxt = (p == (int)order.size() ? -2 : order[p]);\n\n                int inc = L(prev, g);\n                if (nxt != -2) inc += L(g, nxt) - L(prev, nxt);\n\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestG = g;\n                    bestPos = p;\n                }\n            }\n        }\n\n        order.insert(order.begin() + bestPos, bestG);\n        used[bestG] = true;\n    }\n\n    for (int pass = 0; pass < 30; ++pass) {\n        int bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        // Relocate\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prev = (i == 0 ? -1 : order[i - 1]);\n            int nxt = (i + 1 == m ? -2 : order[i + 1]);\n\n            int oldRemove = L(prev, x);\n            if (nxt != -2) oldRemove += L(x, nxt);\n\n            int newRemove = 0;\n            if (nxt != -2) newRemove += L(prev, nxt);\n\n            int removeDelta = newRemove - oldRemove;\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n                if (p == 0) before = -1;\n                else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n                if (p == m - 1) after = -2;\n                else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int oldInsert = 0;\n                if (after != -2) oldInsert += L(before, after);\n\n                int newInsert = L(before, x);\n                if (after != -2) newInsert += L(x, after);\n\n                int delta = removeDelta + newInsert - oldInsert;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        // 2-opt reverse\n        for (int l = 0; l + 1 < m; ++l) {\n            int oldInternal = 0;\n            int newInternal = 0;\n            int prev = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += L(order[r - 1], order[r]);\n                newInternal += L(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                int oldCost = L(prev, order[l]) + oldInternal;\n                if (after != -2) oldCost += L(order[r], after);\n\n                int newCost = L(prev, order[r]) + newInternal;\n                if (after != -2) newCost += L(order[l], after);\n\n                int delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else if (bestType == 2) {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nstruct SourceGroup {\n    int source = -1;\n    int total = 0;\n    int end = -1;\n    vector<int> dest, amt, order;\n    long long internalCost = 0;\n};\n\nvoid computeSourceOrder(SourceGroup& g, int target) {\n    int k = (int)g.dest.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            dp[idx(mask, j)] = 1LL * DIST[g.source][g.dest[j]] * (100 + total);\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = total - sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.dest[last]][g.dest[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)];\n            if (target >= 0) c += 100LL * DIST[g.dest[last]][target];\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = g.source;\n        int load = total;\n\n        for (int left = k; left > 0; --left) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n                long long score = 1LL * DIST[cur][g.dest[j]] * (100 + load);\n                if (left == 1 && target >= 0) {\n                    score += 100LL * DIST[g.dest[j]][target];\n                }\n                score -= 5LL * g.amt[j];\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.dest[bj];\n            load -= g.amt[bj];\n        }\n    }\n\n    g.end = g.dest[g.order.back()];\n\n    long long c = 0;\n    int cur = g.source;\n    int load = total;\n    for (int idx2 : g.order) {\n        c += 1LL * DIST[cur][g.dest[idx2]] * (100 + load);\n        load -= g.amt[idx2];\n        cur = g.dest[idx2];\n    }\n    g.internalCost = c;\n}\n\nvector<SourceGroup> buildSourceGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n    for (auto& f : flows) {\n        mp[f.s].push_back({f.t, f.amount});\n    }\n\n    vector<SourceGroup> groups;\n    for (int s = 0; s < V; ++s) {\n        if (mp[s].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [t, a] : mp[s]) comb[t] += a;\n\n        SourceGroup g;\n        g.source = s;\n\n        for (auto [t, a] : comb) {\n            g.dest.push_back(t);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeSourceOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeSourceGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildSourceGroups(flows);\n    int m = (int)groups.size();\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].source;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n            computeSourceOrder(groups[gi], target);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].source;\n            ends[i] = groups[i].end;\n        }\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n        computeSourceOrder(groups[gi], target);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        sol.moveTo(g.source);\n        sol.addLoad(g.total);\n\n        for (int idx : g.order) {\n            sol.moveTo(g.dest[idx]);\n            sol.addUnload(g.amt[idx]);\n        }\n    }\n\n    return sol;\n}\n\nSolution makePairSolution(const vector<Flow>& flows) {\n    Solution sol;\n    int m = (int)flows.size();\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n    for (int i = 0; i < m; ++i) {\n        starts[i] = flows[i].s;\n        ends[i] = flows[i].t;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int idx : order) {\n        const auto& f = flows[idx];\n        sol.moveTo(f.s);\n        sol.addLoad(f.amount);\n        sol.moveTo(f.t);\n        sol.addUnload(f.amount);\n    }\n\n    return sol;\n}\n\nstruct DemandGroup {\n    int demand = -1;\n    int total = 0;\n    int start = -1;\n    int end = -1;\n    vector<int> src, amt, order;\n};\n\nvoid computeDemandOrder(DemandGroup& g, int prevCell) {\n    int k = (int)g.src.size();\n    g.order.clear();\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            long long entry = 0;\n            if (prevCell >= 0) entry = 100LL * DIST[prevCell][g.src[j]];\n            dp[idx(mask, j)] = entry;\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.src[last]][g.src[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)] + 1LL * DIST[g.src[last]][g.demand] * (100 + total);\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = -1;\n        int load = 0;\n\n        for (int step = 0; step < k; ++step) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score;\n                if (step == 0) {\n                    score = 0;\n                    if (prevCell >= 0) score += 100LL * DIST[prevCell][g.src[j]];\n                    score -= 50LL * DIST[g.src[j]][g.demand];\n                } else {\n                    score = 1LL * DIST[cur][g.src[j]] * (100 + load)\n                          + 10LL * DIST[g.src[j]][g.demand];\n                }\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.src[bj];\n            load += g.amt[bj];\n        }\n    }\n\n    g.start = g.src[g.order.front()];\n    g.end = g.demand;\n}\n\nvector<DemandGroup> buildDemandGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n    for (auto& f : flows) {\n        mp[f.t].push_back({f.s, f.amount});\n    }\n\n    vector<DemandGroup> groups;\n    for (int t = 0; t < V; ++t) {\n        if (mp[t].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [s, a] : mp[t]) comb[s] += a;\n\n        DemandGroup g;\n        g.demand = t;\n\n        for (auto [s, a] : comb) {\n            g.src.push_back(s);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeDemandOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeDemandGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildDemandGroups(flows);\n    int m = (int)groups.size();\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].start;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n            computeDemandOrder(groups[gi], prev);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].start;\n            ends[i] = groups[i].end;\n        }\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n        computeDemandOrder(groups[gi], prev);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        bool first = true;\n        for (int idx : g.order) {\n            sol.moveTo(g.src[idx]);\n            sol.addLoad(g.amt[idx]);\n            first = false;\n        }\n\n        sol.moveTo(g.demand);\n        sol.addUnload(g.total);\n    }\n\n    return sol;\n}\n\npair<int, int> transformCoord(int r, int c, int type) {\n    if (type == 0) return {r, c};\n    if (type == 1) return {c, N - 1 - r};\n    if (type == 2) return {N - 1 - r, N - 1 - c};\n    if (type == 3) return {N - 1 - c, r};\n    if (type == 4) return {r, N - 1 - c};\n    if (type == 5) return {N - 1 - r, c};\n    if (type == 6) return {c, r};\n    return {N - 1 - c, N - 1 - r};\n}\n\nSolution makeCycleSolution() {\n    vector<pair<int, int>> base;\n\n    for (int i = 0; i < N; ++i) base.push_back({i, 0});\n\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) base.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) base.push_back({i, j});\n        }\n    }\n\n    for (int j = N - 1; j >= 1; --j) base.push_back({0, j});\n\n    long long bestCost = INFLL;\n    vector<int> bestCycle;\n    int bestStart = -1;\n\n    for (int type = 0; type < 8; ++type) {\n        vector<int> cyc;\n        cyc.reserve(V);\n\n        for (auto [r, c] : base) {\n            auto [nr, nc] = transformCoord(r, c, type);\n            cyc.push_back(cell_id(nr, nc));\n        }\n\n        for (int rev = 0; rev < 2; ++rev) {\n            if (rev) reverse(cyc.begin(), cyc.end());\n\n            for (int s = 0; s < V; ++s) {\n                long long load = 0;\n                long long cost = BASE_COST + 100LL * DIST[0][cyc[s]];\n                bool ok = true;\n\n                for (int k = 0; k < V; ++k) {\n                    int id = cyc[(s + k) % V];\n                    load += H[id];\n                    if (load < 0) {\n                        ok = false;\n                        break;\n                    }\n                    if (k + 1 < V) {\n                        int nxt = cyc[(s + k + 1) % V];\n                        cost += 1LL * DIST[id][nxt] * (100 + load);\n                    }\n                }\n\n                if (ok && cost < bestCost) {\n                    bestCost = cost;\n                    bestCycle = cyc;\n                    bestStart = s;\n                }\n            }\n\n            if (rev) reverse(cyc.begin(), cyc.end());\n        }\n    }\n\n    Solution sol;\n    if (bestStart < 0) {\n        sol.valid = false;\n        return sol;\n    }\n\n    sol.moveTo(bestCycle[bestStart]);\n\n    for (int k = 0; k < V; ++k) {\n        int id = bestCycle[(bestStart + k) % V];\n\n        if (H[id] > 0) sol.addLoad(H[id]);\n        else if (H[id] < 0) sol.addUnload(-H[id]);\n\n        if (k + 1 < V) {\n            int nxt = bestCycle[(bestStart + k + 1) % V];\n            sol.moveTo(nxt);\n        }\n    }\n\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int inputN;\n    cin >> inputN;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> H[cell_id(i, j)];\n        }\n    }\n\n    for (int a = 0; a < V; ++a) {\n        int ar = a / N;\n        int ac = a % N;\n        for (int b = 0; b < V; ++b) {\n            int br = b / N;\n            int bc = b % N;\n            DIST[a][b] = abs(ar - br) + abs(ac - bc);\n        }\n    }\n\n    for (int i = 0; i < V; ++i) BASE_COST += abs(H[i]);\n\n    if (BASE_COST == 0) {\n        return 0;\n    }\n\n    Solution best;\n    best.cost = INFLL;\n    best.valid = false;\n\n    auto consider = [&](Solution&& sol) {\n        if (!sol.valid) return;\n        if (sol.load != 0) return;\n        if (sol.ops.size() > 100000) return;\n        if (!best.valid || sol.cost < best.cost) {\n            best = std::move(sol);\n        }\n    };\n\n    // Greedy candidates\n    vector<int> maxLoads = {0, 120, 250, 500};\n    vector<pair<int, int>> ratios = {{1, 1}, {3, 2}, {2, 1}};\n    vector<int> sourceModes = {0, 2};\n    vector<int> demandModes = {0, 1, 2};\n\n    for (int ml : maxLoads) {\n        for (auto [rn, rd] : ratios) {\n            if (ml == 0 && !(rn == 1 && rd == 1)) continue;\n\n            for (int sm : sourceModes) {\n                for (int dm : demandModes) {\n                    consider(makeGreedySolution(ml, rn, rd, sm, dm));\n                }\n            }\n        }\n    }\n\n    // Min-cost-flow based candidates\n    for (int variant = 0; variant < 3; ++variant) {\n        vector<Flow> flows = computeMinCostFlows(variant);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // Hamiltonian fallback / candidate\n    consider(makeCycleSolution());\n\n    for (const string& s : best.ops) {\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, T;\n    int S;              // seed count = 2N(N-1)\n    int G;              // grid cells = N^2\n\n    vector<vector<int>> X;\n    vector<int> initMax;\n\n    vector<vector<int>> neigh;      // slot neighbors; outside slots have none\n    vector<int> degSlot;\n    vector<pair<int,int>> gridEdges;\n    vector<int> posOrder;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, int T_, const vector<vector<int>>& X_)\n        : N(N_), M(M_), T(T_), X(X_), rng(1234567) {\n        S = 2 * N * (N - 1);\n        G = N * N;\n\n        initMax.assign(M, 1);\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n            initMax[l] = max(1, mx);\n        }\n\n        build_grid_info();\n    }\n\n    void build_grid_info() {\n        neigh.assign(S, {});\n        degSlot.assign(S, 0);\n        gridEdges.clear();\n\n        auto id = [&](int i, int j) { return i * N + j; };\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = id(i, j);\n                if (j + 1 < N) {\n                    int q = id(i, j + 1);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    gridEdges.push_back({p, q});\n                }\n                if (i + 1 < N) {\n                    int q = id(i + 1, j);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    gridEdges.push_back({p, q});\n                }\n            }\n        }\n\n        for (int p = 0; p < S; p++) degSlot[p] = (int)neigh[p].size();\n\n        posOrder.resize(G);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        // high degree positions first, then closer to center\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            if (degSlot[a] != degSlot[b]) return degSlot[a] > degSlot[b];\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n            double ca = (ai - (N - 1) / 2.0) * (ai - (N - 1) / 2.0)\n                      + (aj - (N - 1) / 2.0) * (aj - (N - 1) / 2.0);\n            double cb = (bi - (N - 1) / 2.0) * (bi - (N - 1) / 2.0)\n                      + (bj - (N - 1) / 2.0) * (bj - (N - 1) / 2.0);\n            return ca < cb;\n        });\n    }\n\n    double objective(\n        const vector<int>& slotSeed,\n        const vector<vector<double>>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) {\n        double ret = 0.0;\n        for (int p = 0; p < G; p++) {\n            ret += nodeCoef * degSlot[p] * nodeW[slotSeed[p]];\n        }\n        for (auto [p, q] : gridEdges) {\n            ret += pairW[slotSeed[p]][slotSeed[q]];\n        }\n        return ret;\n    }\n\n    double swap_delta(\n        const vector<int>& slotSeed,\n        int p,\n        int q,\n        const vector<vector<double>>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) {\n        if (p == q) return 0.0;\n\n        int a = slotSeed[p];\n        int b = slotSeed[q];\n\n        double delta = 0.0;\n\n        delta += nodeCoef * degSlot[p] * (nodeW[b] - nodeW[a]);\n        delta += nodeCoef * degSlot[q] * (nodeW[a] - nodeW[b]);\n\n        for (int r : neigh[p]) {\n            if (r == q) continue;\n            int c = slotSeed[r];\n            delta += pairW[b][c] - pairW[a][c];\n        }\n        for (int r : neigh[q]) {\n            if (r == p) continue;\n            int c = slotSeed[r];\n            delta += pairW[a][c] - pairW[b][c];\n        }\n\n        return delta;\n    }\n\n    double local_search(\n        vector<int>& slotSeed,\n        const vector<vector<double>>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) {\n        double cur = objective(slotSeed, pairW, nodeW, nodeCoef);\n\n        for (int iter = 0; iter < 500; iter++) {\n            double bestD = 1e-9;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < S; p++) {\n                for (int q = p + 1; q < S; q++) {\n                    if (degSlot[p] == 0 && degSlot[q] == 0) continue;\n\n                    double d = swap_delta(slotSeed, p, q, pairW, nodeW, nodeCoef);\n                    if (d > bestD) {\n                        bestD = d;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur += bestD;\n        }\n\n        return cur;\n    }\n\n    vector<int> make_sorted_initial(const vector<double>& key, bool shuffleGrid = false) {\n        vector<int> seeds(S);\n        iota(seeds.begin(), seeds.end(), 0);\n        sort(seeds.begin(), seeds.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> slotSeed(S, -1);\n\n        for (int k = 0; k < G; k++) {\n            slotSeed[posOrder[k]] = seeds[k];\n        }\n        for (int k = G; k < S; k++) {\n            slotSeed[k] = seeds[k];\n        }\n\n        if (shuffleGrid) {\n            vector<int> placed;\n            for (int p = 0; p < G; p++) placed.push_back(slotSeed[p]);\n            shuffle(placed.begin(), placed.end(), rng);\n            for (int p = 0; p < G; p++) slotSeed[p] = placed[p];\n        }\n\n        return slotSeed;\n    }\n\n    vector<int> make_greedy_initial(\n        const vector<vector<double>>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        double noiseAmp\n    ) {\n        vector<int> slotSeed(S, -1);\n        vector<char> used(S, 0);\n\n        uniform_real_distribution<double> dist(-noiseAmp, noiseAmp);\n\n        for (int p : posOrder) {\n            int best = -1;\n            double bestScore = -1e100;\n\n            for (int s = 0; s < S; s++) {\n                if (used[s]) continue;\n\n                double sc = nodeCoef * degSlot[p] * nodeW[s];\n\n                for (int r : neigh[p]) {\n                    if (r < G && slotSeed[r] != -1) {\n                        sc += pairW[s][slotSeed[r]];\n                    }\n                }\n\n                if (noiseAmp > 0) sc += dist(rng);\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = s;\n                }\n            }\n\n            slotSeed[p] = best;\n            used[best] = 1;\n        }\n\n        int out = G;\n        for (int s = 0; s < S; s++) {\n            if (!used[s]) slotSeed[out++] = s;\n        }\n\n        return slotSeed;\n    }\n\n    vector<vector<int>> solve_turn(int turn) {\n        vector<int> val(S, 0);\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) val[i] += X[i][l];\n        }\n\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n\n        // Node score: value + bonus for currently rare/elite coordinates.\n        vector<double> rankBonus(S, 0.0);\n        static const double rb[6] = {130.0, 75.0, 45.0, 25.0, 14.0, 8.0};\n\n        for (int l = 0; l < M; l++) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                return X[a][l] > X[b][l];\n            });\n\n            for (int r = 0; r < min(6, S); r++) {\n                int id = ids[r];\n                double frac = (double)X[id][l] / initMax[l];\n                rankBonus[id] += rb[r] * frac;\n            }\n        }\n\n        double quadCoef = 0.95 - 0.45 * prog;\n        vector<double> nodeW(S, 0.0);\n        for (int i = 0; i < S; i++) {\n            double quad = 0.0;\n            for (int l = 0; l < M; l++) {\n                quad += (double)X[i][l] * X[i][l] / initMax[l];\n            }\n            nodeW[i] = val[i] + quadCoef * quad + rankBonus[i];\n        }\n\n        // Pair score:\n        // risk-sensitive certainty equivalent of one crossover child.\n        // Smaller tau means more optimistic / upper-tail oriented.\n        double tau = 50.0 - 20.0 * prog;       // 50 -> 30\n        double potMix = 0.06 + 0.17 * prog;    // small direct max-potential bonus\n\n        vector<vector<double>> pairW(S, vector<double>(S, 0.0));\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                double ce = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = X[i][l], b = X[j][l];\n                    int mx = max(a, b);\n                    int mn = min(a, b);\n                    pot += mx;\n\n                    double diff = mx - mn;\n                    // mx + tau * log((1 + exp(-diff/tau)) / 2)\n                    double term = mx + tau * log(0.5 * (1.0 + exp(-diff / tau)));\n                    ce += term;\n                }\n\n                double w = (1.0 - potMix) * ce + potMix * pot;\n                pairW[i][j] = pairW[j][i] = w;\n            }\n        }\n\n        double nodeCoef = 0.28 - 0.10 * prog;  // early: preserve good genes, late: edge-focused\n\n        vector<vector<int>> candidates;\n\n        // Deterministic starts.\n        candidates.push_back(make_sorted_initial(nodeW, false));\n        candidates.push_back(make_sorted_initial(nodeW, true));\n\n        vector<double> valKey(S);\n        for (int i = 0; i < S; i++) valKey[i] = val[i];\n        candidates.push_back(make_sorted_initial(valKey, false));\n\n        candidates.push_back(make_greedy_initial(pairW, nodeW, nodeCoef, 0.0));\n\n        // Randomized starts.\n        uniform_real_distribution<double> noise(-1.0, 1.0);\n        for (int st = 0; st < 7; st++) {\n            double amp = 70.0 + 35.0 * st;\n            vector<double> key = nodeW;\n            for (int i = 0; i < S; i++) key[i] += amp * noise(rng);\n\n            bool shuf = (st % 2 == 1);\n            candidates.push_back(make_sorted_initial(key, shuf));\n        }\n\n        for (int st = 0; st < 3; st++) {\n            candidates.push_back(make_greedy_initial(pairW, nodeW, nodeCoef, 30.0 + 40.0 * st));\n        }\n\n        double bestObj = -1e100;\n        vector<int> bestSlotSeed;\n\n        for (auto cand : candidates) {\n            double obj = local_search(cand, pairW, nodeW, nodeCoef);\n            if (obj > bestObj) {\n                bestObj = obj;\n                bestSlotSeed = cand;\n            }\n        }\n\n        vector<vector<int>> A(N, vector<int>(N));\n        for (int p = 0; p < G; p++) {\n            A[p / N][p % N] = bestSlotSeed[p];\n        }\n\n        return A;\n    }\n\n    void update_X(const vector<vector<int>>& nx) {\n        X = nx;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n\n    int S = 2 * N * (N - 1);\n    vector<vector<int>> X(S, vector<int>(M));\n\n    for (int i = 0; i < S; i++) {\n        for (int l = 0; l < M; l++) cin >> X[i][l];\n    }\n\n    Solver solver(N, M, T, X);\n\n    for (int t = 0; t < T; t++) {\n        auto A = solver.solve_turn(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << A[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        vector<vector<int>> nx(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                if (!(cin >> nx[i][l])) return 0;\n            }\n        }\n        solver.update_X(nx);\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int DX[4] = {0, 1, 0, -1}; // R,D,L,U as edge directions\nstatic const int DY[4] = {1, 0, -1, 0};\n\nstruct Assignment {\n    int f;      // vertex / finger id\n    int dir;    // desired direction\n    int cell;   // reserved cell id\n};\n\nstruct Estimate {\n    int cnt = 0;\n    int maxrot = 0;\n};\n\nstruct Choice {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct NextMove {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nstruct PlanResult {\n    vector<int> lengths;\n    int initX = 0, initY = 0;\n    vector<string> ops;\n    long long score = (1LL << 60);\n    bool complete = false;\n    bool valid = false;\n    int remT = 0;\n};\n\nclass Planner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    vector<int> outLen;      // size k, for output\n    vector<int> len;         // 1-indexed by vertex id\n    vector<int> dir;         // current absolute direction of each leaf\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    Planner(int N_, int V_,\n            const vector<unsigned char>& src0,\n            const vector<unsigned char>& tgt0,\n            const vector<int>& lengths,\n            int scoreMode_,\n            int strategy_)\n        : N(N_), Vp(V_), k(V_ - 1), C(N_ * N_),\n          outLen(lengths),\n          len(V_, 0), dir(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 1; i <= k; i++) len[i] = lengths[i - 1];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else runDynamic();\n\n        PlanResult res;\n        res.lengths = outLen;\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int f, int d) const {\n        int x = rootX + DX[d] * len[f];\n        int y = rootY + DY[d] * len[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        return cellAt(rx, ry, f, dir[f]);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    Estimate estimateAtRoot(int x, int y, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int r = rotDist(dir[f], d);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) {\n            return (travel + 0.3) / cnt + 0.002 * dist;\n        } else {\n            return travel - 1.5 * (cnt - 1) + 0.01 * dist;\n        }\n    }\n\n    Choice findBestRoot(int mode) {\n        Choice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, mode);\n                if (e.cnt == 0) continue;\n\n                int dist = abs(rx - x) + abs(ry - y);\n                int travel = max(dist, max(e.maxrot, 1));\n                double sc = rootScore(travel, e.cnt, dist);\n\n                if (!best.exists ||\n                    sc < best.score - 1e-12 ||\n                    (abs(sc - best.score) < 1e-12 &&\n                     (e.cnt > best.cnt ||\n                      (e.cnt == best.cnt && travel < best.travel)))) {\n                    best.exists = true;\n                    best.x = x;\n                    best.y = y;\n                    best.score = sc;\n                    best.cnt = e.cnt;\n                    best.travel = travel;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        if (remSrc == 0) {\n            rx = ry = 0;\n            return;\n        }\n\n        int bestCnt = -1;\n        int bestRot = 100;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, PICK);\n                int center = abs(x - N / 2) + abs(y - N / 2);\n\n                if (e.cnt > bestCnt ||\n                    (e.cnt == bestCnt && e.maxrot < bestRot) ||\n                    (e.cnt == bestCnt && e.maxrot == bestRot && center < bestCenter)) {\n                    bestCnt = e.cnt;\n                    bestRot = e.maxrot;\n                    bestCenter = center;\n                    rx = x;\n                    ry = y;\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int mode) {\n        struct Edge {\n            int cellIdx;\n            int dir;\n            int rot;\n        };\n\n        vector<int> fingers;\n        vector<vector<Edge>> edges;\n        vector<int> cells;\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                edges[li].push_back({tmpIndex[cid], d, rotDist(dir[f], d)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const Edge& a, const Edge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> order(L);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return edges[a].size() < edges[b].size();\n        });\n\n        vector<int> matchCell(R, -1), matchDir(R, -1);\n        vector<unsigned char> seen(R);\n\n        function<bool(int)> dfs = [&](int li) -> bool {\n            for (const Edge& e : edges[li]) {\n                if (seen[e.cellIdx]) continue;\n                seen[e.cellIdx] = 1;\n\n                if (matchCell[e.cellIdx] == -1 || dfs(matchCell[e.cellIdx])) {\n                    matchCell[e.cellIdx] = li;\n                    matchDir[e.cellIdx] = e.dir;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int li : order) {\n            if (edges[li].empty()) continue;\n            fill(seen.begin(), seen.end(), 0);\n            dfs(li);\n        }\n\n        vector<Assignment> assigns;\n        for (int ci = 0; ci < R; ci++) {\n            if (matchCell[ci] == -1) continue;\n            int li = matchCell[ci];\n            assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n        }\n\n        sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n            return a.f < b.f;\n        });\n\n        return assigns;\n    }\n\n    NextMove fallbackNext(int mode) {\n        NextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 1; f <= k; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int d = 0; d < 4; d++) {\n                    int tx = cx - DX[d] * len[f];\n                    int ty = cy - DY[d] * len[f];\n                    if (!inside(tx, ty)) continue;\n\n                    int md = abs(rx - tx) + abs(ry - ty);\n                    int travel = max(md, max(rotDist(dir[f], d), 1));\n                    double sc = travel;\n\n                    if (!best.exists || sc < best.score) {\n                        best.exists = true;\n                        best.x = tx;\n                        best.y = ty;\n                        best.score = sc;\n                        best.assigns = {Assignment{f, d, cid}};\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    NextMove makeNext(int mode, const Choice& ch) {\n        NextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    NextMove chooseNext(int mode) {\n        return makeNext(mode, findBestRoot(mode));\n    }\n\n    int potentialForRoot(int nx, int ny,\n                         const vector<unsigned char>& selected,\n                         const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        int cnt = 0;\n\n        static const int DELTA[3] = {0, 1, 3}; // stay, R, L\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(nx, ny, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                mark[cid] = st;\n                cnt++;\n                break;\n            }\n        }\n\n        return cnt;\n    }\n\n    char chooseMoveChar(int tx, int ty,\n                        const vector<unsigned char>& selected,\n                        const vector<unsigned char>& reserved) {\n        vector<pair<char, pair<int, int>>> cand;\n\n        if (rx < tx) cand.push_back({'D', {rx + 1, ry}});\n        if (rx > tx) cand.push_back({'U', {rx - 1, ry}});\n        if (ry < ty) cand.push_back({'R', {rx, ry + 1}});\n        if (ry > ty) cand.push_back({'L', {rx, ry - 1}});\n\n        if (cand.empty()) return '.';\n        if (cand.size() == 1) return cand[0].first;\n\n        int bestPot = -1;\n        char bestChar = cand[0].first;\n        int bestDimRemain = -1;\n\n        for (auto& c : cand) {\n            int pot = potentialForRoot(c.second.first, c.second.second, selected, reserved);\n            bool vertical = (c.first == 'U' || c.first == 'D');\n            int dimRemain = vertical ? abs(tx - rx) : abs(ty - ry);\n\n            if (pot > bestPot || (pot == bestPot && dimRemain > bestDimRemain)) {\n                bestPot = pot;\n                bestChar = c.first;\n                bestDimRemain = dimRemain;\n            }\n        }\n\n        return bestChar;\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenDir = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(rx, ry, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenDir = nd;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                dir[f] = chosenDir;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 1; f <= k; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetDir(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxrot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetDir[a.f] = a.dir;\n            reserved[a.cell] = 1;\n            maxrot = max(maxrot, rotDist(dir[a.f], a.dir));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max(md, max(maxrot, 1));\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty, selected, reserved);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (dir[f] != targetDir[f]) {\n                    char rc = rotateStep(dir[f], targetDir[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (dir[a.f] != a.dir) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                NextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                NextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < k / 2 && remSrc > 0) ds += 0.5; // slight capacity bias\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) {\n                mode = PICK;\n            } else {\n                mode = DROP;\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\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\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    int C = N * N;\n    vector<unsigned char> src(C, 0), tgt(C, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            if (s[i][j] == '1' && t[i][j] == '0') src[id] = 1;\n            if (s[i][j] == '0' && t[i][j] == '1') tgt[id] = 1;\n        }\n    }\n\n    int k = V - 1;\n    int maxSafeLen = max(1, N / 2);\n\n    vector<vector<int>> lengthSets;\n\n    auto addSet = [&](vector<int> a) {\n        for (auto& b : lengthSets) {\n            if (a == b) return;\n        }\n        lengthSets.push_back(a);\n    };\n\n    auto cycleSet = [&](int L) {\n        L = max(1, min({L, k, maxSafeLen}));\n        vector<int> a(k);\n        for (int i = 0; i < k; i++) a[i] = 1 + (i % L);\n        return a;\n    };\n\n    addSet(cycleSet(maxSafeLen));\n    addSet(cycleSet(max(1, N / 3)));\n    addSet(cycleSet(6));\n    addSet(cycleSet(4));\n\n    vector<int> all1(k, 1);\n    addSet(all1);\n\n    vector<tuple<int, int, int>> params; // length-set id, score mode, strategy\n\n    for (int i = 0; i < (int)lengthSets.size(); i++) params.emplace_back(i, 0, 0);\n    for (int i = 0; i < (int)lengthSets.size(); i++) params.emplace_back(i, 1, 0);\n    for (int i = 0; i < min(3, (int)lengthSets.size()); i++) params.emplace_back(i, 0, 1);\n\n    auto startTime = chrono::steady_clock::now();\n\n    PlanResult best;\n\n    int tried = 0;\n    for (auto [li, sm, st] : params) {\n        if (tried > 0) {\n            auto now = chrono::steady_clock::now();\n            long long ms = chrono::duration_cast<chrono::milliseconds>(now - startTime).count();\n            if (ms > 2750) break;\n        }\n\n        Planner planner(N, V, src, tgt, lengthSets[li], sm, st);\n        PlanResult res = planner.run();\n\n        if (res.valid &&\n            (res.score < best.score ||\n             (res.score == best.score && res.ops.size() < best.ops.size()))) {\n            best = std::move(res);\n        }\n\n        tried++;\n    }\n\n    // Extremely defensive fallback: legal empty output.\n    if (!best.valid) {\n        best.valid = true;\n        best.lengths = lengthSets[0];\n        best.initX = 0;\n        best.initY = 0;\n        best.ops.clear();\n    }\n\n    cout << V << '\\n';\n    for (int i = 1; i < V; i++) {\n        cout << 0 << ' ' << best.lengths[i - 1] << '\\n';\n    }\n    cout << best.initX << ' ' << best.initY << '\\n';\n\n    for (const string& op : best.ops) {\n        cout << op << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing ll = long long;\nusing uchar = unsigned char;\n\nconstexpr int CMAX = 100000;\nconstexpr int MAXLEN = 400000;\nconstexpr int MAXV = 1000;\n\nstruct Fish {\n    int x, y, w;\n};\n\nstruct Candidate {\n    int approx;\n    vector<pair<int,int>> poly;\n};\n\nvector<Fish> fishes;\nvector<Candidate> candidates;\nvector<pair<int,int>> bestPoly;\nint bestApprox = -1;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nvector<pair<int,int>> square_poly() {\n    return {{0,0}, {CMAX,0}, {CMAX,CMAX}, {0,CMAX}};\n}\n\nvoid record_candidate(const vector<pair<int,int>>& poly, int approx) {\n    if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return;\n    if (approx < 0) return;\n    if (approx == 0 && bestApprox >= 0) return;\n\n    if (approx > bestApprox) {\n        bestApprox = approx;\n        bestPoly = poly;\n    }\n    candidates.push_back({approx, poly});\n\n    if (candidates.size() > 120) {\n        nth_element(candidates.begin(), candidates.begin() + 80, candidates.end(),\n                    [](const Candidate& a, const Candidate& b) {\n                        return a.approx > b.approx;\n                    });\n        candidates.resize(80);\n    }\n}\n\nbool inside_or_on(const vector<pair<int,int>>& poly, int px, int py) {\n    bool inside = false;\n    int m = (int)poly.size();\n\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n\n        if (x1 == x2) {\n            if (px == x1 && min(y1, y2) <= py && py <= max(y1, y2)) return true;\n            int yl = min(y1, y2), yh = max(y1, y2);\n            if (yl <= py && py < yh && x1 > px) inside = !inside;\n        } else {\n            if (py == y1 && min(x1, x2) <= px && px <= max(x1, x2)) return true;\n        }\n    }\n    return inside;\n}\n\nint exact_score(const vector<pair<int,int>>& poly) {\n    int s = 0;\n    for (const auto& f : fishes) {\n        if (inside_or_on(poly, f.x, f.y)) s += f.w;\n    }\n    return s;\n}\n\nstruct GridSolver {\n    int D, G, maxEdges, ncell;\n    vector<int> w;\n\n    struct Comp {\n        vector<int> cells;\n        int score = 0;\n    };\n\n    struct Eval {\n        int score;\n        int len;\n    };\n\n    GridSolver(int d) : D(d), G(CMAX / d), maxEdges(MAXLEN / d), ncell(G * G), w(ncell, 0) {\n        for (const auto& f : fishes) {\n            int x = f.x / D;\n            int y = f.y / D;\n            if (x >= G) x = G - 1;\n            if (y >= G) y = G - 1;\n            w[idx(x, y)] += f.w;\n        }\n    }\n\n    inline int idx(int x, int y) const {\n        return y * G + x;\n    }\n\n    inline bool in_grid(int x, int y) const {\n        return 0 <= x && x < G && 0 <= y && y < G;\n    }\n\n    int mask_score(const vector<uchar>& mask) const {\n        int s = 0;\n        for (int i = 0; i < ncell; i++) if (mask[i]) s += w[i];\n        return s;\n    }\n\n    int selected_neighbor_count(const vector<uchar>& mask, int x, int y) const {\n        int c = 0;\n        if (x > 0 && mask[idx(x - 1, y)]) c++;\n        if (x + 1 < G && mask[idx(x + 1, y)]) c++;\n        if (y > 0 && mask[idx(x, y - 1)]) c++;\n        if (y + 1 < G && mask[idx(x, y + 1)]) c++;\n        return c;\n    }\n\n    int selected_neighbor_count_id(const vector<uchar>& mask, int v) const {\n        int x = v % G, y = v / G;\n        return selected_neighbor_count(mask, x, y);\n    }\n\n    int boundary_edges(const vector<uchar>& mask) const {\n        int p = 0;\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n                if (x == 0 || !mask[idx(x - 1, y)]) p++;\n                if (x + 1 == G || !mask[idx(x + 1, y)]) p++;\n                if (y == 0 || !mask[idx(x, y - 1)]) p++;\n                if (y + 1 == G || !mask[idx(x, y + 1)]) p++;\n            }\n        }\n        return p;\n    }\n\n    void fix_diagonal(vector<uchar>& mask) const {\n        for (int it = 0; it < 30; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < G; y++) {\n                for (int x = 0; x + 1 < G; x++) {\n                    int a = idx(x, y);\n                    int b = idx(x + 1, y);\n                    int c = idx(x, y + 1);\n                    int d = idx(x + 1, y + 1);\n\n                    bool A = mask[a], B = mask[b], C = mask[c], DD = mask[d];\n\n                    if (A && DD && !B && !C) {\n                        int choose = (w[b] >= w[c] ? b : c);\n                        mask[choose] = 1;\n                        changed = true;\n                    } else if (B && C && !A && !DD) {\n                        int choose = (w[a] >= w[d] ? a : d);\n                        mask[choose] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void fill_holes(vector<uchar>& mask) const {\n        vector<uchar> out(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto push = [&](int x, int y) {\n            int id = idx(x, y);\n            if (!mask[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < G; x++) {\n            push(x, 0);\n            push(x, G - 1);\n        }\n        for (int y = 0; y < G; y++) {\n            push(0, y);\n            push(G - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % G, y = v / G;\n            const int dx[4] = {1, -1, 0, 0};\n            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 (!in_grid(nx, ny)) continue;\n                int ni = idx(nx, ny);\n                if (!mask[ni] && !out[ni]) {\n                    out[ni] = 1;\n                    q.push_back(ni);\n                }\n            }\n        }\n\n        for (int i = 0; i < ncell; i++) {\n            if (!mask[i] && !out[i]) mask[i] = 1;\n        }\n    }\n\n    vector<Comp> find_components(const vector<uchar>& mask, vector<int>* compIdOut = nullptr) const {\n        vector<int> compId(ncell, -1);\n        vector<Comp> comps;\n        vector<int> q;\n        q.reserve(ncell);\n\n        for (int s = 0; s < ncell; s++) {\n            if (!mask[s] || compId[s] != -1) continue;\n\n            int cid = (int)comps.size();\n            comps.push_back(Comp{});\n            compId[s] = cid;\n            q.clear();\n            q.push_back(s);\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                comps[cid].cells.push_back(v);\n                comps[cid].score += w[v];\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n                    int ni = idx(nx, ny);\n                    if (mask[ni] && compId[ni] == -1) {\n                        compId[ni] = cid;\n                        q.push_back(ni);\n                    }\n                }\n            }\n        }\n\n        if (compIdOut) *compIdOut = move(compId);\n        return comps;\n    }\n\n    void trim_leaves(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        vector<uchar> inq(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto maybe_push = [&](int id) {\n            if (!mask[id] || w[id] > 0 || inq[id]) return;\n            if (selected_neighbor_count_id(mask, id) <= 1) {\n                inq[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < ncell; i++) maybe_push(i);\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            inq[v] = 0;\n            if (!mask[v] || w[v] > 0) continue;\n            if (sel <= 1) continue;\n\n            int k = selected_neighbor_count_id(mask, v);\n            if (k <= 1) {\n                mask[v] = 0;\n                sel--;\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (in_grid(nx, ny)) maybe_push(idx(nx, ny));\n                }\n            }\n        }\n    }\n\n    void add_positive_boundary(vector<uchar>& mask) const {\n        int P = boundary_edges(mask);\n\n        for (int it = 0; it < 4; it++) {\n            bool changed = false;\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool extract_polygon(const vector<uchar>& mask, vector<pair<int,int>>& poly) const {\n        int V = (G + 1) * (G + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (G + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n        };\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n\n                if (y == 0 || !mask[idx(x, y - 1)]) set_edge(x, y, x + 1, y);\n                if (x + 1 == G || !mask[idx(x + 1, y)]) set_edge(x + 1, y, x + 1, y + 1);\n                if (y + 1 == G || !mask[idx(x, y + 1)]) set_edge(x + 1, y + 1, x, y + 1);\n                if (x == 0 || !mask[idx(x - 1, y)]) set_edge(x, y + 1, x, y);\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (1LL * edges * D > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n        int cur = start;\n\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int px = pv % (G + 1), py = pv / (G + 1);\n            int cx = cv % (G + 1), cy = cv / (G + 1);\n            int nx = nv % (G + 1), ny = nv / (G + 1);\n\n            int dx1 = cx - px, dy1 = cy - py;\n            int dx2 = nx - cx, dy2 = ny - cy;\n\n            if (dx1 == dx2 && dy1 == dy2) continue;\n\n            poly.push_back({cx * D, cy * D});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    void finalize_candidate(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.90) return;\n\n        bool any = false;\n        for (uchar v : mask) {\n            if (v) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        trim_leaves(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        add_positive_boundary(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n        if (sc == 0 && bestApprox >= 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc);\n    }\n\n    Eval eval_l_path(int src, int dst, bool xFirst,\n                     const vector<uchar>& cur,\n                     int targetCid,\n                     const vector<int>& compId) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        int score = 0, len = 0;\n\n        auto visit = [&](int x, int y) {\n            int id = idx(x, y);\n            len++;\n            if (!cur[id] && compId[id] != targetCid) score += w[id];\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, ty);\n                }\n            }\n        }\n\n        return {score, len};\n    }\n\n    vector<int> build_l_path(int src, int dst, bool xFirst) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        vector<int> res;\n        res.reserve(abs(tx - sx) + abs(ty - sy) + 1);\n\n        auto add = [&](int x, int y) {\n            res.push_back(idx(x, y));\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, ty);\n                }\n            }\n        }\n\n        return res;\n    }\n\n    void greedy_connect(const vector<Comp>& comps,\n                        const vector<int>& compId,\n                        const vector<int>& ids,\n                        int maxAdd,\n                        int compLimit) const {\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> cur(ncell, 0);\n        vector<int> curCells;\n        curCells.reserve(ncell / 4);\n\n        auto add_cell = [&](int cell) {\n            if (!cur[cell]) {\n                cur[cell] = 1;\n                curCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            for (int cell : comps[cid].cells) add_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0])) addedConsidered++;\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c == 1 || c == 2 || c == 3 || c == 5 || c == 8 ||\n                   c == 13 || c == 21 || c == 34;\n        };\n\n        finalize_candidate(cur);\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : curCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                bool xFirst = true;\n                int gain = 0;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1) continue;\n                int src = root[bestCell];\n                if (src < 0) continue;\n\n                Eval e1 = eval_l_path(src, bestCell, true, cur, cid, compId);\n                Eval e2 = eval_l_path(src, bestCell, false, cur, cid, compId);\n\n                bool xf = true;\n                Eval e = e1;\n                if (e2.score > e1.score || (e2.score == e1.score && e2.len < e1.len)) {\n                    e = e2;\n                    xf = false;\n                }\n\n                int gain = comps[cid].score + e.score;\n                if (gain <= 0) continue;\n\n                double metric = (double)gain / (e.len + 5.0) + 0.03 * gain;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = src;\n                    best.dst = bestCell;\n                    best.xFirst = xf;\n                    best.gain = gain;\n                    best.len = e.len;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path = build_l_path(best.src, best.dst, best.xFirst);\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cell : path) add_cell(cell);\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            if (snapshot(addedConsidered)) finalize_candidate(cur);\n\n            if (iter % 3 == 0 && boundary_edges(cur) > maxEdges * 3 / 2) break;\n        }\n\n        finalize_candidate(cur);\n    }\n\n    void process_mask(vector<uchar> mask, int maxAdd, int compLimit) const {\n        if (elapsed_sec() > 1.82) return;\n\n        bool any = false;\n        for (uchar v : mask) {\n            if (v) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        vector<int> compId;\n        vector<Comp> comps = find_components(mask, &compId);\n        if (comps.empty()) return;\n\n        vector<int> ids;\n        for (int i = 0; i < (int)comps.size(); i++) {\n            if (comps[i].score > 0) ids.push_back(i);\n        }\n        if (ids.empty()) return;\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return comps[a].score > comps[b].score;\n        });\n\n        int alone = min(3, (int)ids.size());\n        for (int k = 0; k < alone; k++) {\n            vector<uchar> cur(ncell, 0);\n            for (int cell : comps[ids[k]].cells) cur[cell] = 1;\n            finalize_candidate(cur);\n        }\n\n        if ((int)ids.size() >= 2) {\n            greedy_connect(comps, compId, ids, maxAdd, compLimit);\n        }\n    }\n\n    void run_best_rectangle() const {\n        if (elapsed_sec() > 1.80) return;\n\n        int best = INT_MIN;\n        int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0;\n\n        vector<int> col(G, 0);\n        for (int x1 = 0; x1 < G; x1++) {\n            fill(col.begin(), col.end(), 0);\n\n            for (int x2 = x1; x2 < G; x2++) {\n                for (int y = 0; y < G; y++) col[y] += w[idx(x2, y)];\n\n                int cur = 0, st = 0;\n                for (int y = 0; y < G; y++) {\n                    if (y == 0 || cur <= 0) {\n                        cur = col[y];\n                        st = y;\n                    } else {\n                        cur += col[y];\n                    }\n\n                    if (cur > best) {\n                        best = cur;\n                        bx1 = x1;\n                        bx2 = x2;\n                        by1 = st;\n                        by2 = y;\n                    }\n                }\n            }\n        }\n\n        if (best <= 0) return;\n\n        vector<uchar> mask(ncell, 0);\n        for (int y = by1; y <= by2; y++) {\n            for (int x = bx1; x <= bx2; x++) {\n                mask[idx(x, y)] = 1;\n            }\n        }\n        finalize_candidate(mask);\n    }\n\n    vector<double> gaussian_blur(double sigma) const {\n        int r = max(1, (int)ceil(3.0 * sigma));\n        vector<double> ker(2 * r + 1);\n        double sum = 0.0;\n\n        for (int d = -r; d <= r; d++) {\n            double v = exp(-(double)d * d / (2.0 * sigma * sigma));\n            ker[d + r] = v;\n            sum += v;\n        }\n        for (double& v : ker) v /= sum;\n\n        vector<double> src(ncell), tmp(ncell), out(ncell);\n        for (int i = 0; i < ncell; i++) src[i] = (double)w[i];\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int nx = x + d;\n                    if (0 <= nx && nx < G) s += src[idx(nx, y)] * ker[d + r];\n                }\n                tmp[idx(x, y)] = s;\n            }\n        }\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int ny = y + d;\n                    if (0 <= ny && ny < G) s += tmp[idx(x, ny)] * ker[d + r];\n                }\n                out[idx(x, y)] = s;\n            }\n        }\n\n        return out;\n    }\n\n    void run_smoothing(const vector<double>& sigmas,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime) const {\n        vector<double> ratios = {-0.05, -0.02, 0.0, 0.02, 0.05, 0.10, 0.18, 0.30};\n\n        for (double sigma : sigmas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<double> blur = gaussian_blur(sigma);\n            double mx = *max_element(blur.begin(), blur.end());\n            if (mx <= 1e-12) continue;\n\n            for (double r : ratios) {\n                if (elapsed_sec() > stopTime) return;\n\n                double th = mx * r;\n                vector<uchar> mask(ncell, 0);\n                int cnt = 0;\n\n                for (int i = 0; i < ncell; i++) {\n                    if (blur[i] > th) {\n                        mask[i] = 1;\n                        cnt++;\n                    }\n                }\n\n                if (cnt == 0 || cnt == ncell) continue;\n                process_mask(move(mask), maxAdd, compLimit);\n            }\n        }\n    }\n\n    void run_weight_thresholds(const vector<int>& thresholds,\n                               int maxAdd,\n                               int compLimit,\n                               double stopTime) const {\n        for (int th : thresholds) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask(ncell, 0);\n            int cnt = 0;\n            for (int i = 0; i < ncell; i++) {\n                if (w[i] >= th) {\n                    mask[i] = 1;\n                    cnt++;\n                }\n            }\n            if (cnt == 0) continue;\n            process_mask(move(mask), maxAdd, compLimit);\n        }\n    }\n\n    vector<uchar> graph_cut_mask(int lam, int scale) const {\n        int S = ncell;\n        int T = ncell + 1;\n        atcoder::mf_graph<ll> g(ncell + 2);\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int v = idx(x, y);\n                ll profit = (ll)w[v] * scale;\n\n                if (profit > 0) g.add_edge(S, v, profit);\n                else if (profit < 0) g.add_edge(v, T, -profit);\n\n                int bs = 0;\n                if (x == 0) bs++;\n                if (x + 1 == G) bs++;\n                if (y == 0) bs++;\n                if (y + 1 == G) bs++;\n                if (bs) g.add_edge(v, T, (ll)lam * bs);\n\n                if (x + 1 < G) {\n                    int u = idx(x + 1, y);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n                if (y + 1 < G) {\n                    int u = idx(x, y + 1);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n            }\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n\n        vector<uchar> mask(ncell, 0);\n        for (int i = 0; i < ncell; i++) mask[i] = cut[i] ? 1 : 0;\n        return mask;\n    }\n\n    void run_graph_cut(const vector<int>& lambdas,\n                       int scale,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime) const {\n        for (int lam : lambdas) {\n            if (elapsed_sec() > stopTime) return;\n            vector<uchar> mask = graph_cut_mask(lam, scale);\n            process_mask(move(mask), maxAdd, compLimit);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int N;\n    cin >> N;\n\n    fishes.reserve(2 * N);\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n        int w = (i < N ? 1 : -1);\n        fishes.push_back({x, y, w});\n    }\n\n    bestApprox = -1;\n    record_candidate(square_poly(), 0);\n\n    GridSolver g500(500);\n    g500.run_best_rectangle();\n    g500.run_weight_thresholds(vector<int>{1, 2, 3}, 30, 120, 0.55);\n    g500.run_smoothing(vector<double>{2.0, 3.5, 5.5, 8.0, 12.0}, 18, 90, 1.00);\n\n    if (elapsed_sec() < 1.25) {\n        g500.run_graph_cut(vector<int>{10, 16, 25, 40, 70, 120}, 100, 22, 100, 1.38);\n    }\n\n    if (elapsed_sec() < 1.65) {\n        GridSolver g400(400);\n        g400.run_best_rectangle();\n        g400.run_smoothing(vector<double>{2.5, 4.0, 6.5, 10.0, 14.0}, 14, 80, 1.72);\n    }\n\n    vector<pair<int,int>> output = bestPoly.empty() ? square_poly() : bestPoly;\n\n    if (bestApprox >= 0) candidates.push_back({bestApprox, bestPoly});\n\n    if (elapsed_sec() < 1.82) {\n        sort(candidates.begin(), candidates.end(),\n             [](const Candidate& a, const Candidate& b) {\n                 return a.approx > b.approx;\n             });\n\n        int bestExact = 0;\n        vector<pair<int,int>> exactBest = square_poly();\n\n        int limit = min((int)candidates.size(), 10);\n        bool evaluated = false;\n\n        for (int i = 0; i < limit; i++) {\n            if (elapsed_sec() > 1.94) break;\n\n            int sc = exact_score(candidates[i].poly);\n            evaluated = true;\n\n            if (sc > bestExact) {\n                bestExact = sc;\n                exactBest = candidates[i].poly;\n            }\n        }\n\n        if (evaluated) output = exactBest;\n    }\n\n    cout << output.size() << '\\n';\n    for (auto [x, y] : output) {\n        cout << x << ' ' << y << '\\n';\n    }\n\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectD {\n    double w, h;\n};\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    double estScore = 1e100;\n    double baseW = 0, baseH = 0;\n    uint64_t hash = 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};\n\nstatic constexpr double TRUE_U = 100000.0;\nstatic constexpr double TRUE_L_MIN = 10000.0;\nstatic constexpr double TRUE_L_MAX = 50000.0;\nstatic constexpr double INF = 1e100;\n\nint N, T;\ndouble SIGMA;\nvector<double> sumWObs, sumHObs;\nvector<int> cntWObs, cntHObs;\n\nmt19937_64 rng(123456789);\n\ndouble normal_pdf(double x) {\n    static const double INV_SQRT_2PI = 0.39894228040143267794;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble normal_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble clamp_double(double x, double lo, double hi) {\n    return max(lo, min(hi, x));\n}\n\ndouble truncated_normal_mean(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    double a = (L - obsMean) / sd;\n    double b = (U - obsMean) / sd;\n    double Z = normal_cdf(b) - normal_cdf(a);\n    if (Z < 1e-12) return clamp_double(obsMean, L, U);\n    double m = obsMean + sd * (normal_pdf(a) - normal_pdf(b)) / Z;\n    return clamp_double(m, L, U);\n}\n\ndouble sample_truncated_normal(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    normal_distribution<double> nd(obsMean, sd);\n    for (int t = 0; t < 200; t++) {\n        double x = nd(rng);\n        if (L <= x && x <= U) return x;\n    }\n    return clamp_double(obsMean, L, U);\n}\n\ndouble estimate_L_from_current_observations() {\n    vector<double> vals;\n    vector<double> noiseVars;\n    vals.reserve(2 * N);\n    noiseVars.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        vals.push_back(sumWObs[i] / cntWObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntWObs[i]);\n        vals.push_back(sumHObs[i] / cntHObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntHObs[i]);\n    }\n\n    double mean = accumulate(vals.begin(), vals.end(), 0.0) / vals.size();\n    double L1 = 2.0 * mean - TRUE_U;\n\n    double var = 0.0;\n    for (double x : vals) var += (x - mean) * (x - mean);\n    var /= vals.size();\n\n    double avgNoise = accumulate(noiseVars.begin(), noiseVars.end(), 0.0) / noiseVars.size();\n    double trueVar = max(0.0, var - avgNoise);\n    double L2 = TRUE_U - sqrt(max(0.0, 12.0 * trueVar));\n\n    double L = 0.72 * L1 + 0.28 * L2;\n    return clamp_double(L, TRUE_L_MIN, TRUE_L_MAX);\n}\n\nvector<RectD> posterior_mean_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = truncated_normal_mean(mw, sw, L, TRUE_U);\n        res[i].h = truncated_normal_mean(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> posterior_sample_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = sample_truncated_normal(mw, sw, L, TRUE_U);\n        res[i].h = sample_truncated_normal(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nstatic inline bool overlap_interval(double l1, double r1, double l2, double r2) {\n    return max(l1, l2) < min(r1, r2) - 1e-9;\n}\n\npair<double, double> simulate_ops(const vector<Op>& ops, const vector<RectD>& rects) {\n    vector<double> x(N, 0), y(N, 0), w(N, 0), h(N, 0);\n    vector<int> placed;\n    placed.reserve(ops.size());\n\n    double W = 0, H = 0;\n\n    for (const Op& op : ops) {\n        int p = op.p;\n        double rw = op.r ? rects[p].h : rects[p].w;\n        double rh = op.r ? rects[p].w : rects[p].h;\n\n        double nx = 0, ny = 0;\n        if (op.d == 'U') {\n            nx = (op.b == -1 ? 0.0 : x[op.b] + w[op.b]);\n            ny = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(nx, nx + rw, x[q], x[q] + w[q])) {\n                    ny = max(ny, y[q] + h[q]);\n                }\n            }\n        } else {\n            ny = (op.b == -1 ? 0.0 : y[op.b] + h[op.b]);\n            nx = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(ny, ny + rh, y[q], y[q] + h[q])) {\n                    nx = max(nx, x[q] + w[q]);\n                }\n            }\n        }\n\n        x[p] = nx;\n        y[p] = ny;\n        w[p] = rw;\n        h[p] = rh;\n        placed.push_back(p);\n        W = max(W, nx + rw);\n        H = max(H, ny + rh);\n    }\n    return {W, H};\n}\n\nuint64_t splitmix64_u(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\nuint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (const Op& op : ops) {\n        uint64_t v = (uint64_t)(op.p + 1);\n        v = v * 1315423911ULL + (uint64_t)(op.r + 3);\n        v = v * 1315423911ULL + (uint64_t)(op.d == 'L' ? 7 : 11);\n        v = v * 1315423911ULL + (uint64_t)(op.b + 2);\n        h ^= splitmix64_u(v + h);\n    }\n    return h;\n}\n\nvoid add_candidate(vector<Candidate>& pool,\n                   unordered_set<uint64_t>& seen,\n                   const vector<Op>& ops,\n                   const vector<RectD>& baseRects) {\n    if ((int)ops.size() != N) return;\n\n    uint64_t hv = hash_ops(ops);\n    if (seen.find(hv) != seen.end()) return;\n    seen.insert(hv);\n\n    auto [W, H] = simulate_ops(ops, baseRects);\n    if (!isfinite(W) || !isfinite(H)) return;\n\n    Candidate c;\n    c.ops = ops;\n    c.baseW = W;\n    c.baseH = H;\n    c.estScore = W + H;\n    c.hash = hv;\n    pool.push_back(std::move(c));\n}\n\nstruct ShelfResult {\n    bool ok = false;\n    vector<Op> ops;\n};\n\n// mode 0: vertical columns using U\n// mode 1: horizontal rows using L\nShelfResult make_shelf_layout(const vector<RectD>& planRects, int mode, double cap) {\n    vector<array<double, 2>> cross(N), len(N);\n\n    for (int i = 0; i < N; i++) {\n        double w = planRects[i].w;\n        double h = planRects[i].h;\n        if (mode == 0) {\n            cross[i][0] = w; len[i][0] = h;\n            cross[i][1] = h; len[i][1] = w;\n        } else {\n            cross[i][0] = h; len[i][0] = w;\n            cross[i][1] = w; len[i][1] = h;\n        }\n    }\n\n    vector<double> vals;\n    vals.reserve(2 * N);\n    for (int i = 0; i < N; i++) {\n        vals.push_back(cross[i][0]);\n        vals.push_back(cross[i][1]);\n    }\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end(), [](double a, double b) {\n        return fabs(a - b) <= 1e-7 * max(1.0, max(fabs(a), fabs(b)));\n    }), vals.end());\n\n    int C = vals.size();\n\n    vector<vector<double>> pref(C, vector<double>(N + 1, 0.0));\n    for (int m = 0; m < C; m++) {\n        double M = vals[m];\n        for (int i = 0; i < N; i++) {\n            double bestLen = INF;\n            if (cross[i][0] <= M + 1e-7) bestLen = min(bestLen, len[i][0]);\n            if (cross[i][1] <= M + 1e-7) bestLen = min(bestLen, len[i][1]);\n            if (bestLen >= INF / 2 || pref[m][i] >= INF / 2) pref[m][i + 1] = INF;\n            else pref[m][i + 1] = min(INF, pref[m][i] + bestLen);\n        }\n    }\n\n    auto get_cost_idx = [&](int l, int r) -> int {\n        int lo = 0, hi = C;\n        while (lo < hi) {\n            int mid = (lo + hi) >> 1;\n            double s = pref[mid][r] - pref[mid][l];\n            if (s <= cap + 1e-7) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo == C) return -1;\n        return lo;\n    };\n\n    vector<double> dp(N + 1, INF);\n    vector<int> prv(N + 1, -1), prvM(N + 1, -1);\n    dp[0] = 0.0;\n\n    for (int r = 1; r <= N; r++) {\n        for (int l = 0; l < r; l++) {\n            if (dp[l] >= INF / 2) continue;\n            int mi = get_cost_idx(l, r);\n            if (mi < 0) continue;\n            double ndp = dp[l] + vals[mi];\n            if (ndp < dp[r]) {\n                dp[r] = ndp;\n                prv[r] = l;\n                prvM[r] = mi;\n            }\n        }\n    }\n\n    if (prv[N] < 0) return {};\n\n    vector<pair<int, int>> segs;\n    for (int r = N; r > 0; r = prv[r]) {\n        segs.push_back({prv[r], r});\n    }\n    reverse(segs.begin(), segs.end());\n\n    vector<int> orient(N, 0);\n    vector<int> anchorOfSeg(segs.size(), -1);\n\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        int mi = get_cost_idx(l, r);\n        double M = vals[mi];\n\n        int anchor = l;\n        double bestCross = -1.0;\n\n        for (int i = l; i < r; i++) {\n            int chosen = 0;\n            double bestLen = INF, bestCr = INF;\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (cross[i][rr] <= M + 1e-7) {\n                    if (len[i][rr] < bestLen - 1e-7 ||\n                        (fabs(len[i][rr] - bestLen) <= 1e-7 && cross[i][rr] < bestCr)) {\n                        bestLen = len[i][rr];\n                        bestCr = cross[i][rr];\n                        chosen = rr;\n                    }\n                }\n            }\n            orient[i] = chosen;\n\n            double cr = cross[i][chosen];\n            if (cr > bestCross) {\n                bestCross = cr;\n                anchor = i;\n            }\n        }\n        anchorOfSeg[si] = anchor;\n    }\n\n    vector<Op> ops;\n    ops.reserve(N);\n\n    int boundaryRef = -1;\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        for (int i = l; i < r; i++) {\n            Op op;\n            op.p = i;\n            op.r = orient[i];\n            op.d = (mode == 0 ? 'U' : 'L');\n            op.b = boundaryRef;\n            ops.push_back(op);\n        }\n        boundaryRef = anchorOfSeg[si];\n    }\n\n    ShelfResult res;\n    res.ok = true;\n    res.ops = std::move(ops);\n    return res;\n}\n\nvector<double> make_caps(const vector<RectD>& rects, int mode, int cnt) {\n    double area = 0.0;\n    double minCap = 0.0;\n    for (int i = 0; i < N; i++) {\n        area += rects[i].w * rects[i].h;\n        minCap = max(minCap, min(rects[i].w, rects[i].h));\n    }\n\n    double S = sqrt(max(1.0, area));\n    vector<double> caps;\n\n    double loF = 0.52, hiF = 2.35;\n    for (int k = 0; k < cnt; k++) {\n        double u = (cnt == 1 ? 0.5 : (double)k / (cnt - 1));\n        double f = exp(log(loF) + u * (log(hiF) - log(loF)));\n        caps.push_back(max(minCap, S * f));\n    }\n\n    // Extra dense points near square.\n    for (double f : {0.72, 0.80, 0.88, 0.96, 1.04, 1.12, 1.20, 1.32, 1.48}) {\n        caps.push_back(max(minCap, S * f));\n    }\n\n    sort(caps.begin(), caps.end());\n    vector<double> uniq;\n    for (double x : caps) {\n        if (uniq.empty() || fabs(x - uniq.back()) > 1e-6 * max(1.0, x)) uniq.push_back(x);\n    }\n    return uniq;\n}\n\ndouble min_final_perimeter_lb(double W, double H, double A) {\n    double S = sqrt(max(1.0, A));\n    double ans = INF;\n\n    if (W <= S && H <= S) ans = min(ans, 2.0 * S);\n    ans = min(ans, W + max(H, A / max(W, 1.0)));\n    ans = min(ans, H + max(W, A / max(H, 1.0)));\n    ans = max(ans, W + H);\n    return ans;\n}\n\nvector<Op> make_greedy_layout(const vector<RectD>& planRects,\n                              double aspect,\n                              double scale,\n                              double wOverflow,\n                              double wWaste,\n                              double wBal,\n                              double wLB,\n                              double jitter) {\n    vector<Op> ops;\n    ops.reserve(N);\n\n    vector<double> x(N), y(N), ww(N), hh(N);\n    double W = 0.0, H = 0.0;\n    double totalArea = 0.0;\n    for (auto &r : planRects) totalArea += r.w * r.h;\n\n    double S = sqrt(max(1.0, totalArea)) * scale;\n    double Wlim = S * sqrt(aspect);\n    double Hlim = S / sqrt(aspect);\n\n    double usedArea = 0.0;\n    uniform_real_distribution<double> ud(0.0, 1.0);\n\n    for (int i = 0; i < N; i++) {\n        double itemArea = planRects[i].w * planRects[i].h;\n\n        double bestCost = INF;\n        Op bestOp{i, 0, 'U', -1};\n        double bestX = 0, bestY = 0, bestW = 0, bestH = 0;\n        double bestBW = 0, bestBH = 0;\n\n        for (int r = 0; r < 2; r++) {\n            double rw = r ? planRects[i].h : planRects[i].w;\n            double rh = r ? planRects[i].w : planRects[i].h;\n\n            for (int dd = 0; dd < 2; dd++) {\n                char d = (dd == 0 ? 'U' : 'L');\n                for (int b = -1; b < i; b++) {\n                    double nx = 0, ny = 0;\n\n                    if (d == 'U') {\n                        nx = (b == -1 ? 0.0 : x[b] + ww[b]);\n                        ny = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(nx, nx + rw, x[q], x[q] + ww[q])) {\n                                ny = max(ny, y[q] + hh[q]);\n                            }\n                        }\n                    } else {\n                        ny = (b == -1 ? 0.0 : y[b] + hh[b]);\n                        nx = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(ny, ny + rh, y[q], y[q] + hh[q])) {\n                                nx = max(nx, x[q] + ww[q]);\n                            }\n                        }\n                    }\n\n                    double nW = max(W, nx + rw);\n                    double nH = max(H, ny + rh);\n                    double nUsed = usedArea + itemArea;\n\n                    double overflow = max(0.0, nW - Wlim) + max(0.0, nH - Hlim);\n                    double wasteLen = max(0.0, nW * nH - nUsed) / sqrt(max(1.0, nUsed));\n                    double bal = fabs(nW / Wlim - nH / Hlim) * sqrt(totalArea);\n                    double lb = min_final_perimeter_lb(nW, nH, totalArea);\n                    double progress = 0.25 + 0.75 * (double)(i + 1) / N;\n\n                    double cost =\n                        wLB * lb +\n                        progress * (nW + nH) +\n                        wOverflow * overflow +\n                        wWaste * wasteLen +\n                        wBal * bal +\n                        0.0007 * (nx + ny) +\n                        jitter * ud(rng) * sqrt(totalArea);\n\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestOp = {i, r, d, b};\n                        bestX = nx;\n                        bestY = ny;\n                        bestW = rw;\n                        bestH = rh;\n                        bestBW = nW;\n                        bestBH = nH;\n                    }\n                }\n            }\n        }\n\n        ops.push_back(bestOp);\n        x[i] = bestX;\n        y[i] = bestY;\n        ww[i] = bestW;\n        hh[i] = bestH;\n        W = bestBW;\n        H = bestBH;\n        usedArea += itemArea;\n    }\n\n    return ops;\n}\n\nvoid output_query(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const Op& 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    Timer timer;\n\n    cin >> N >> T >> SIGMA;\n\n    sumWObs.assign(N, 0.0);\n    sumHObs.assign(N, 0.0);\n    cntWObs.assign(N, 1);\n    cntHObs.assign(N, 1);\n\n    for (int i = 0; i < N; i++) {\n        long long w, h;\n        cin >> w >> h;\n        sumWObs[i] = (double)w;\n        sumHObs[i] = (double)h;\n    }\n\n    // Optional individual measurements when there are many extra turns and noise is large.\n    double noiseFactor = clamp_double((SIGMA - 3000.0) / 7000.0, 0.0, 1.0);\n    int extra = max(0, T - 2 * N);\n    int measureQ = min(N, (int)round(extra * noiseFactor));\n\n    if (measureQ > 0) {\n        double L0 = estimate_L_from_current_observations();\n        vector<RectD> base0 = posterior_mean_rects(L0);\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            double ia = base0[a].w * base0[a].h + 0.25 * (base0[a].w + base0[a].h) * sqrt(base0[a].w * base0[a].h);\n            double ib = base0[b].w * base0[b].h + 0.25 * (base0[b].w + base0[b].h) * sqrt(base0[b].w * base0[b].h);\n            return ia > ib;\n        });\n\n        for (int k = 0; k < measureQ; k++) {\n            int i = ids[k];\n            vector<Op> ops;\n            ops.push_back({i, 0, 'U', -1});\n            output_query(ops);\n\n            long long Wm, Hm;\n            if (!(cin >> Wm >> Hm)) return 0;\n\n            sumWObs[i] += (double)Wm;\n            sumHObs[i] += (double)Hm;\n            cntWObs[i]++;\n            cntHObs[i]++;\n        }\n    }\n\n    int remainingTurns = T - measureQ;\n    if (remainingTurns <= 0) return 0;\n\n    double Lest = estimate_L_from_current_observations();\n    vector<RectD> baseRects = posterior_mean_rects(Lest);\n\n    // Evaluation / posterior scenarios.\n    int randomScenarioCount = (N <= 50 ? 10 : 8);\n    if (remainingTurns <= 30) randomScenarioCount = min(randomScenarioCount, 6);\n\n    vector<vector<RectD>> scenarios;\n    scenarios.push_back(baseRects);\n    for (int s = 0; s < randomScenarioCount; s++) {\n        scenarios.push_back(posterior_sample_rects(Lest));\n    }\n    int S = scenarios.size();\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    int targetPool = max(450, min(1300, remainingTurns * 3));\n\n    // Shelf DP layouts.\n    int planScenarios = min(S, 5);\n    for (int ps = 0; ps < planScenarios; ps++) {\n        const auto& plan = scenarios[ps];\n        int capCnt = (ps == 0 ? 82 : 42);\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(plan, mode, capCnt);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Greedy BL-style layouts.\n    uniform_real_distribution<double> ud(0.0, 1.0);\n    int greedyAttempts = 0;\n    while ((int)pool.size() < targetPool && timer.elapsed() < 2.15) {\n        int ps = greedyAttempts % planScenarios;\n        const auto& plan = scenarios[ps];\n\n        double aspect = exp(log(0.48) + ud(rng) * (log(2.10) - log(0.48)));\n        double scale = 1.00 + 0.42 * ud(rng);\n\n        double wOverflow = 2.0 + 18.0 * ud(rng);\n        double wWaste = 0.05 + 2.50 * ud(rng);\n        double wBal = 0.02 + 1.10 * ud(rng);\n        double wLB = 1.0 + 6.0 * ud(rng);\n        double jitter = 0.000 + 0.035 * ud(rng);\n\n        vector<Op> ops = make_greedy_layout(plan, aspect, scale, wOverflow, wWaste, wBal, wLB, jitter);\n        add_candidate(pool, seen, ops, baseRects);\n        greedyAttempts++;\n    }\n\n    if (pool.empty()) {\n        // Extremely defensive fallback.\n        vector<Op> ops;\n        for (int i = 0; i < N; i++) ops.push_back({i, 0, 'U', -1});\n        add_candidate(pool, seen, ops, baseRects);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.estScore < b.estScore;\n    });\n\n    int maxKeep = max(remainingTurns, min((int)pool.size(), 1200));\n    if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n\n    int C = pool.size();\n\n    // Precompute predicted W,H,score for scenario-weighted online selection.\n    vector<float> predW(C * S), predH(C * S), predScore(C * S);\n\n    for (int c = 0; c < C; c++) {\n        for (int s = 0; s < S; s++) {\n            pair<double, double> wh;\n            if (s == 0) wh = {pool[c].baseW, pool[c].baseH};\n            else wh = simulate_ops(pool[c].ops, scenarios[s]);\n            predW[c * S + s] = (float)wh.first;\n            predH[c * S + s] = (float)wh.second;\n            predScore[c * S + s] = (float)(wh.first + wh.second);\n        }\n    }\n\n    vector<double> logWeight(S, 0.0);\n    vector<double> weight(S, 1.0 / S);\n    vector<double> bestScenarioScore(S, INF);\n    vector<char> used(C, 0);\n\n    int bestBaseIdx = 0;\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        int chosen = -1;\n        double bestVal = INF;\n\n        for (int c = 0; c < C; c++) {\n            if (used[c]) continue;\n            double val = 0.0;\n            for (int s = 0; s < S; s++) {\n                double sc = predScore[c * S + s];\n                val += weight[s] * min(bestScenarioScore[s], sc);\n            }\n            val += 1e-9 * pool[c].estScore; // stable tie-breaker\n            if (val < bestVal) {\n                bestVal = val;\n                chosen = c;\n            }\n        }\n\n        if (chosen < 0) chosen = bestBaseIdx;\n\n        output_query(pool[chosen].ops);\n\n        long long Wobs, Hobs;\n        if (!(cin >> Wobs >> Hobs)) return 0;\n\n        if (chosen >= 0 && chosen < C) {\n            used[chosen] = 1;\n\n            for (int s = 0; s < S; s++) {\n                bestScenarioScore[s] = min(bestScenarioScore[s], (double)predScore[chosen * S + s]);\n            }\n\n            // Tempered likelihood: scenario set is sparse, so avoid overconfidence.\n            double effSigma = max(2500.0, 2.25 * SIGMA);\n            for (int s = 0; s < S; s++) {\n                double dw = (double)Wobs - predW[chosen * S + s];\n                double dh = (double)Hobs - predH[chosen * S + s];\n                logWeight[s] += -0.5 * (dw * dw + dh * dh) / (effSigma * effSigma);\n            }\n\n            double mx = *max_element(logWeight.begin(), logWeight.end());\n            double sm = 0.0;\n            for (int s = 0; s < S; s++) {\n                weight[s] = exp(logWeight[s] - mx);\n                sm += weight[s];\n            }\n            if (sm <= 0 || !isfinite(sm)) {\n                fill(weight.begin(), weight.end(), 1.0 / S);\n            } else {\n                for (int s = 0; s < S; s++) {\n                    weight[s] = weight[s] / sm;\n                    // Small floor for exploration / model mismatch.\n                    weight[s] = 0.965 * weight[s] + 0.035 / S;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, M, HH;\nvector<int> A;\nvector<vector<int>> adj;\nvector<int> highOrder, lowOrder;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ULL;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct State {\n    vector<int> d;\n    vector<int> cnt;\n    long long val = 0; // sum depth[v] * A[v]\n};\n\nbool hasNeighborDepth(const vector<int>& d, int v, int dep) {\n    for (int u : adj[v]) if (d[u] == dep) return true;\n    return false;\n}\n\nvoid initState(State& s, const vector<int>& depth) {\n    s.d = depth;\n    s.cnt.assign(N, 0);\n    s.val = 0;\n    for (int v = 0; v < N; v++) {\n        s.val += 1LL * s.d[v] * A[v];\n        if (s.d[v] > 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) s.cnt[v]++;\n            }\n        }\n    }\n}\n\nbool verifyState(const State& s) {\n    if ((int)s.d.size() != N) return false;\n    for (int v = 0; v < N; v++) {\n        if (s.d[v] < 0 || s.d[v] > HH) return false;\n        if (s.d[v] > 0) {\n            bool ok = false;\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n    }\n    return true;\n}\n\nbool canMove(const State& s, int v, int nd) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n    return true;\n}\n\nvoid applyMove(State& s, int v, int nd) {\n    int od = s.d[v];\n    if (od == nd) return;\n\n    for (int w : adj[v]) {\n        if (s.d[w] > 0) {\n            if (s.d[w] - 1 == od) s.cnt[w]--;\n            if (s.d[w] - 1 == nd) s.cnt[w]++;\n        }\n    }\n\n    s.val += 1LL * (nd - od) * A[v];\n    s.d[v] = nd;\n\n    int c = 0;\n    if (nd > 0) {\n        for (int u : adj[v]) if (s.d[u] == nd - 1) c++;\n    }\n    s.cnt[v] = c;\n}\n\nbool tryRaise(State& s, int v) {\n    int od = s.d[v];\n    for (int nd = HH; nd > od; nd--) {\n        if (canMove(s, v, nd)) {\n            applyMove(s, v, nd);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool greedyImprove(State& s, int maxPass = 12) {\n    bool any = false;\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool moved = false;\n        for (int v : highOrder) {\n            if (tryRaise(s, v)) {\n                moved = true;\n                any = true;\n            }\n        }\n        if (!moved) break;\n    }\n    return any;\n}\n\nvector<int> aroundMark;\nint aroundStamp = 1;\n\nvoid greedyAround(State& s, int v) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n    auto add = [&](int x) {\n        if (aroundMark[x] != aroundStamp) {\n            aroundMark[x] = aroundStamp;\n            list.push_back(x);\n        }\n    };\n\n    add(v);\n    for (int u : adj[v]) {\n        add(u);\n        for (int w : adj[u]) add(w);\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        for (int x : list) tryRaise(s, x);\n    }\n}\n\nstruct Mode {\n    bool indepTop;\n    bool indepLower;\n    bool lookahead;\n    int kind;\n    double noise;\n};\n\ndouble coverScore(int cov, int cost, int future, int kind, double noise) {\n    double c = (double)cov;\n    double score;\n    if ((kind & 3) == 0) {\n        score = c / cost;\n    } else if ((kind & 3) == 1) {\n        score = c * c / cost;\n    } else if ((kind & 3) == 2) {\n        score = c / sqrt((double)cost);\n    } else {\n        score = c * sqrt(c) / cost;\n    }\n\n    score *= (1.0 + 0.025 * future);\n\n    if (noise > 0) {\n        score *= (1.0 + noise * (rng.nextDouble() - 0.5));\n    }\n    return score;\n}\n\nbool selectCoverLevel(\n    int k,\n    const vector<int>& target,\n    vector<int>& depth,\n    vector<char>& used,\n    bool independent,\n    const Mode& mode\n) {\n    vector<char> targetMark(N, 0), covered(N, 0), banned(N, 0);\n    for (int t : target) targetMark[t] = 1;\n\n    int rem = (int)target.size();\n    vector<int> selected;\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (used[c]) continue;\n            if (independent && banned[c]) continue;\n\n            int future = 0;\n            if (k > 0) {\n                for (int u : adj[c]) if (!used[u]) future++;\n                if (mode.lookahead && future == 0) continue;\n            }\n\n            int cov = 0;\n            if (k == HH - 1 && targetMark[c] && !covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (targetMark[u] && !covered[u]) cov++;\n            }\n            if (cov == 0) continue;\n\n            int cost = (HH - k) * A[c];\n            double sc = coverScore(cov, cost, future, mode.kind, mode.noise);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        used[best] = 1;\n        depth[best] = k;\n        selected.push_back(best);\n\n        if (independent) {\n            banned[best] = 1;\n            for (int u : adj[best]) banned[u] = 1;\n        }\n\n        auto mark = [&](int x) {\n            if (targetMark[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        if (k == HH - 1) mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    // Prune redundant selected vertices.\n    vector<int> coverCnt(N, 0);\n\n    auto addCover = [&](int c, int delta) {\n        if (k == HH - 1) {\n            coverCnt[c] += delta;\n            for (int u : adj[c]) coverCnt[u] += delta;\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u]) coverCnt[u] += delta;\n            }\n        }\n    };\n\n    for (int c : selected) {\n        if (used[c] && depth[c] == k) addCover(c, 1);\n    }\n\n    for (int t : target) {\n        if (coverCnt[t] <= 0) return false;\n    }\n\n    sort(selected.begin(), selected.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selected) {\n        if (!used[c] || depth[c] != k) continue;\n\n        bool ok = true;\n        if (k == HH - 1) {\n            if (coverCnt[c] <= 1) ok = false;\n            if (ok) {\n                for (int u : adj[c]) {\n                    if (coverCnt[u] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u] && coverCnt[u] <= 1) {\n                    ok = false;\n                    break;\n                }\n            }\n        }\n\n        if (ok) {\n            addCover(c, -1);\n            used[c] = 0;\n            depth[c] = HH;\n        }\n    }\n\n    return true;\n}\n\nbool buildChain(vector<int>& outDepth, const Mode& mode) {\n    vector<int> depth(N, HH);\n    vector<char> used(N, 0);\n\n    for (int k = HH - 1; k >= 0; k--) {\n        vector<int> target;\n        if (k == HH - 1) {\n            target.resize(N);\n            iota(target.begin(), target.end(), 0);\n        } else {\n            for (int v = 0; v < N; v++) {\n                if (depth[v] == k + 1) target.push_back(v);\n            }\n        }\n\n        if (target.empty()) continue;\n\n        bool independent = (k == HH - 1 ? mode.indepTop : mode.indepLower);\n        if (!selectCoverLevel(k, target, depth, used, independent, mode)) {\n            return false;\n        }\n    }\n\n    State s;\n    initState(s, depth);\n    if (!verifyState(s)) return false;\n\n    outDepth = depth;\n    return true;\n}\n\nbool reoptTop(State& s) {\n    if (HH == 0) return false;\n\n    int k = HH - 1;\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0), candidate(N, 0), selected(N, 0), covered(N, 0);\n    int rem = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] >= k) {\n            target[v] = 1;\n            rem++;\n        }\n    }\n    if (rem == 0) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (!target[v]) continue;\n        if (k == 0 || hasNeighborDepth(d, v, k - 1)) {\n            candidate[v] = 1;\n        }\n    }\n\n    vector<int> selectedList;\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            if (!covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n            if (cov == 0) continue;\n\n            double sc = (double)cov / A[c];\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n        selectedList.push_back(best);\n\n        auto mark = [&](int x) {\n            if (target[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    vector<int> coverCnt(N, 0);\n    auto addCover = [&](int c, int delta) {\n        coverCnt[c] += delta;\n        for (int u : adj[c]) {\n            if (target[u]) coverCnt[u] += delta;\n        }\n    };\n\n    for (int c : selectedList) addCover(c, 1);\n\n    sort(selectedList.begin(), selectedList.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selectedList) {\n        if (!selected[c]) continue;\n\n        bool ok = true;\n        if (coverCnt[c] <= 1) ok = false;\n        if (ok) {\n            for (int u : adj[c]) {\n                if (target[u] && coverCnt[u] <= 1) {\n                    ok = false;\n                    break;\n                }\n            }\n        }\n\n        if (ok) {\n            selected[c] = 0;\n            addCover(c, -1);\n        }\n    }\n\n    vector<int> nd = d;\n    for (int v = 0; v < N; v++) {\n        if (target[v]) nd[v] = HH;\n    }\n    for (int v = 0; v < N; v++) {\n        if (selected[v]) nd[v] = k;\n    }\n\n    State ns;\n    initState(ns, nd);\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n    return false;\n}\n\nbool reoptLevel(State& s, int k) {\n    if (k < 0 || k >= HH - 1) return false;\n\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0);\n    int targetCount = 0;\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k + 1) {\n            target[v] = 1;\n            targetCount++;\n        }\n    }\n    if (targetCount == 0) return false;\n\n    vector<char> candidate(N, 0), selected(N, 0), forced(N, 0), covered(N, 0);\n    vector<int> selectedList;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            candidate[v] = 1;\n            bool topSupport = hasNeighborDepth(d, v, HH - 1);\n            if (!topSupport) {\n                forced[v] = 1;\n                selected[v] = 1;\n                selectedList.push_back(v);\n            }\n        } else if (d[v] == HH) {\n            bool supp = (k == 0) || hasNeighborDepth(d, v, k - 1);\n            if (supp) candidate[v] = 1;\n        }\n    }\n\n    int rem = targetCount;\n    auto markBy = [&](int c) {\n        for (int u : adj[c]) {\n            if (target[u] && !covered[u]) {\n                covered[u] = 1;\n                rem--;\n            }\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (forced[v]) markBy(v);\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n            if (cov == 0) continue;\n\n            int cost = (HH - k) * A[c];\n            double sc = (double)cov / cost;\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n        selectedList.push_back(best);\n        markBy(best);\n    }\n\n    vector<int> coverCnt(N, 0);\n    auto addCover = [&](int c, int delta) {\n        for (int u : adj[c]) {\n            if (target[u]) coverCnt[u] += delta;\n        }\n    };\n\n    for (int c : selectedList) if (selected[c]) addCover(c, 1);\n\n    sort(selectedList.begin(), selectedList.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selectedList) {\n        if (!selected[c] || forced[c]) continue;\n\n        bool ok = true;\n        for (int u : adj[c]) {\n            if (target[u] && coverCnt[u] <= 1) {\n                ok = false;\n                break;\n            }\n        }\n\n        if (ok) {\n            selected[c] = 0;\n            addCover(c, -1);\n        }\n    }\n\n    vector<int> nd = d;\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            nd[v] = selected[v] ? k : HH;\n        } else if (d[v] == HH && selected[v]) {\n            nd[v] = k;\n        }\n    }\n\n    State ns;\n    initState(ns, nd);\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n    return false;\n}\n\nvoid polish(State& s, int passes) {\n    for (int p = 0; p < passes; p++) {\n        reoptTop(s);\n        for (int k = HH - 2; k >= 0; k--) {\n            reoptLevel(s, k);\n        }\n        greedyImprove(s, 10);\n    }\n}\n\nState makeFallback() {\n    vector<int> dist(N, -1);\n    queue<int> q;\n    dist[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u : adj[v]) {\n            if (dist[u] == -1) {\n                dist[u] = dist[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    vector<int> depth(N, 0);\n    for (int v = 0; v < N; v++) {\n        if (dist[v] < 0) depth[v] = 0;\n        else depth[v] = dist[v] % (HH + 1);\n    }\n\n    State s;\n    initState(s, depth);\n    if (!verifyState(s)) {\n        fill(depth.begin(), depth.end(), 0);\n        initState(s, depth);\n    }\n\n    greedyImprove(s, 12);\n    return s;\n}\n\nvoid anneal(State& best, double endTime) {\n    State cur = best;\n\n    double st = elapsed();\n    double duration = max(0.001, endTime - st);\n\n    double T0 = 120.0;\n    double T1 = 0.8;\n    double T = T0;\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 4095) == 0) {\n            double now = elapsed();\n            if (now >= endTime) break;\n\n            double prog = min(1.0, (now - st) / duration);\n            T = T0 * pow(T1 / T0, prog);\n\n            if ((iter & 65535) == 0 && iter > 0) {\n                greedyImprove(cur, 3);\n                if (cur.val > best.val) best = cur;\n                if (cur.val + 7000 < best.val) cur = best;\n            }\n        }\n        iter++;\n\n        int v = -1, nd = -1;\n        bool prechecked = false;\n\n        int type = rng.nextInt(100);\n\n        if (type < 30) {\n            // Add an alternative support to a vertex with few supports.\n            int w = -1;\n            for (int t = 0; t < 6; t++) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] > 0 && cur.cnt[cand] <= 1) {\n                    w = cand;\n                    break;\n                }\n            }\n            if (w == -1) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] == 0) continue;\n                w = cand;\n            }\n\n            nd = cur.d[w] - 1;\n            int bestU = -1;\n            int bestDelta = INT_MIN;\n\n            for (int u : adj[w]) {\n                if (cur.d[u] == nd) continue;\n                if (!canMove(cur, u, nd)) continue;\n\n                int delta = (nd - cur.d[u]) * A[u];\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestU = u;\n                }\n            }\n\n            if (bestU == -1) continue;\n            v = bestU;\n            prechecked = true;\n        } else if (type < 55) {\n            // Lower a low-value vertex.\n            int K = min(N, 450);\n            v = lowOrder[rng.nextInt(K)];\n            if (cur.d[v] == 0) continue;\n            nd = rng.nextInt(cur.d[v]);\n        } else if (type < 85) {\n            // Raise a high-value vertex if possible.\n            int K = min(N, 750);\n            v = highOrder[rng.nextInt(K)];\n            if (cur.d[v] == HH) continue;\n\n            nd = -1;\n            for (int x = HH; x > cur.d[v]; x--) {\n                if (canMove(cur, v, x)) {\n                    nd = x;\n                    break;\n                }\n            }\n            if (nd == -1) continue;\n            prechecked = true;\n        } else {\n            v = rng.nextInt(N);\n            nd = rng.nextInt(HH + 1);\n            if (nd == cur.d[v]) continue;\n        }\n\n        if (!prechecked && !canMove(cur, v, nd)) continue;\n\n        int delta = (nd - cur.d[v]) * A[v];\n\n        bool accept = false;\n        if (delta >= 0) {\n            accept = true;\n        } else {\n            if (delta > -30.0 * T) {\n                double prob = exp(delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n        }\n\n        if (!accept) continue;\n\n        applyMove(cur, v, nd);\n\n        if (delta < 0) {\n            greedyAround(cur, v);\n        }\n\n        if (cur.val > best.val) {\n            best = cur;\n        }\n    }\n\n    greedyImprove(best, 12);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> HH;\n\n    A.resize(N);\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        cin >> A[i];\n        seed = seed * 1000003ULL + A[i] + 97;\n    }\n\n    adj.assign(N, {});\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        seed ^= (uint64_t)(u + 1) * 1000000007ULL + (uint64_t)(v + 1) * 1000003ULL;\n    }\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        seed ^= ((uint64_t)x << 32) ^ (uint64_t)y ^ ((uint64_t)i * 11995408973635179863ULL);\n    }\n\n    if (seed == 0) seed = 88172645463325252ULL;\n    rng.x = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    highOrder.resize(N);\n    lowOrder.resize(N);\n    iota(highOrder.begin(), highOrder.end(), 0);\n    iota(lowOrder.begin(), lowOrder.end(), 0);\n\n    sort(highOrder.begin(), highOrder.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n    sort(lowOrder.begin(), lowOrder.end(), [&](int a, int b) {\n        return A[a] < A[b];\n    });\n\n    aroundMark.assign(N, 0);\n\n    State best = makeFallback();\n    polish(best, 1);\n\n    const double CONSTRUCT_LIMIT = 0.80;\n    int attempt = 0;\n\n    while (attempt < 220 && elapsed() < CONSTRUCT_LIMIT) {\n        Mode mode;\n        mode.indepTop = (attempt % 4 != 1);\n        mode.indepLower = (attempt % 2 == 0);\n        mode.lookahead = true;\n        mode.kind = attempt & 3;\n\n        if (attempt < 8) mode.noise = 0.0;\n        else mode.noise = 0.25 + 0.55 * rng.nextDouble();\n\n        vector<int> depth;\n        if (buildChain(depth, mode)) {\n            State s;\n            initState(s, depth);\n\n            polish(s, 1);\n\n            if (s.val > best.val) {\n                best = s;\n            }\n        }\n\n        attempt++;\n    }\n\n    polish(best, 2);\n\n    anneal(best, 1.86);\n\n    polish(best, 2);\n    greedyImprove(best, 12);\n\n    if (!verifyState(best)) {\n        best = makeFallback();\n    }\n\n    vector<int> parent(N, -1);\n    bool ok = true;\n\n    for (int v = 0; v < N; v++) {\n        if (best.d[v] == 0) {\n            parent[v] = -1;\n        } else {\n            int p = -1;\n            for (int u : adj[v]) {\n                if (best.d[u] == best.d[v] - 1) {\n                    p = u;\n                    break;\n                }\n            }\n            if (p == -1) {\n                ok = false;\n                break;\n            }\n            parent[v] = p;\n        }\n    }\n\n    if (!ok) {\n        for (int i = 0; i < N; i++) parent[i] = -1;\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N;\nuint32_t FULL;\nconst int MAXN = 20;\n\nstruct Op {\n    char d;\n    int p;\n};\n\nstruct GAct {\n    char d;\n    int p;\n    int k;\n};\n\nstruct State {\n    array<uint32_t, MAXN> x{}, o{};\n    int xcnt = 0;\n};\n\nState INIT;\nvector<pair<int,int>> initialXs;\nint idxAt[MAXN][MAXN];\n\nchrono::steady_clock::time_point START;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nint popc(uint32_t v) {\n    return __builtin_popcount(v);\n}\n\nint firstBit(uint32_t m) {\n    return m ? __builtin_ctz(m) : N;\n}\n\nint lastBit(uint32_t m) {\n    return m ? 31 - __builtin_clz(m) : -1;\n}\n\nchar invDir(char d) {\n    if (d == 'L') return 'R';\n    if (d == 'R') return 'L';\n    if (d == 'U') return 'D';\n    return 'U';\n}\n\nvoid appendOps(vector<Op>& ops, char d, int p, int k) {\n    for (int i = 0; i < k; i++) ops.push_back({d, p});\n}\n\nbool edgeO(const State& s, const Op& op) {\n    int p = op.p;\n    uint32_t bit = 1u << p;\n    if (op.d == 'L') return s.o[p] & 1u;\n    if (op.d == 'R') return s.o[p] & (1u << (N - 1));\n    if (op.d == 'U') return s.o[0] & bit;\n    return s.o[N - 1] & bit;\n}\n\ninline void setBit(uint32_t& m, uint32_t bit, bool v) {\n    if (v) m |= bit;\n    else m &= ~bit;\n}\n\nvoid applyOp(State& s, const Op& op) {\n    int p = op.p;\n    if (op.d == 'L') {\n        if (s.x[p] & 1u) s.xcnt--;\n        s.x[p] >>= 1;\n        s.o[p] >>= 1;\n    } else if (op.d == 'R') {\n        if (s.x[p] & (1u << (N - 1))) s.xcnt--;\n        s.x[p] = (s.x[p] << 1) & FULL;\n        s.o[p] = (s.o[p] << 1) & FULL;\n    } else if (op.d == 'U') {\n        uint32_t bit = 1u << p;\n        if (s.x[0] & bit) s.xcnt--;\n        for (int i = 0; i < N - 1; i++) {\n            bool xb = s.x[i + 1] & bit;\n            bool ob = s.o[i + 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[N - 1] &= ~bit;\n        s.o[N - 1] &= ~bit;\n    } else {\n        uint32_t bit = 1u << p;\n        if (s.x[N - 1] & bit) s.xcnt--;\n        for (int i = N - 1; i >= 1; i--) {\n            bool xb = s.x[i - 1] & bit;\n            bool ob = s.o[i - 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[0] &= ~bit;\n        s.o[0] &= ~bit;\n    }\n}\n\nvoid applyGAct(State& s, const GAct& a) {\n    Op op{a.d, a.p};\n    for (int i = 0; i < a.k; i++) applyOp(s, op);\n}\n\nvector<Op> expandGSeq(const vector<GAct>& gs) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& g : gs) total += g.k;\n    ops.reserve(total);\n    for (auto& g : gs) appendOps(ops, g.d, g.p, g.k);\n    return ops;\n}\n\nbool isPerfectFull(const vector<Op>& ops) {\n    if ((int)ops.size() > 4 * N * N) return false;\n    State s = INIT;\n    for (auto& op : ops) {\n        if (edgeO(s, op)) return false;\n        applyOp(s, op);\n    }\n    return s.xcnt == 0;\n}\n\n// Truncate to the earliest prefix that already removes all Oni.\n// Returns false if no valid prefix exists.\nbool truncateToPerfectPrefix(vector<Op>& ops) {\n    if (INIT.xcnt == 0) {\n        ops.clear();\n        return true;\n    }\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) {\n            ops.resize(t + 1);\n            return true;\n        }\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkip(const vector<Op>& ops, int l, int r) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (l <= t && t < r) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nvoid pruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n\n        int maxLen = min(50, (int)seq.size());\n        for (int len = maxLen; len >= 2 && elapsed() < until; len--) {\n            for (int i = 0; i + len <= (int)seq.size() && elapsed() < until; ) {\n                if (canPerfectSkip(seq, i, i + len)) {\n                    seq.erase(seq.begin() + i, seq.begin() + i + len);\n                    truncateToPerfectPrefix(seq);\n                    changed = true;\n                    i = max(0, i - len);\n                } else {\n                    i++;\n                }\n            }\n        }\n\n        for (int i = 0; i < (int)seq.size() && elapsed() < until; ) {\n            if (canPerfectSkip(seq, i, i + 1)) {\n                seq.erase(seq.begin() + i);\n                truncateToPerfectPrefix(seq);\n                changed = true;\n                if (i > 0) i--;\n            } else {\n                i++;\n            }\n        }\n    }\n}\n\nstruct OInfo {\n    int firstRow[MAXN], lastRow[MAXN], rowCnt[MAXN];\n    int firstCol[MAXN], lastCol[MAXN], colCnt[MAXN];\n};\n\nvoid computeOInfo(const State& s, OInfo& info) {\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.o[i];\n        info.firstRow[i] = firstBit(m);\n        info.lastRow[i] = lastBit(m);\n        info.rowCnt[i] = popc(m);\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t cm = 0;\n        uint32_t bit = 1u << j;\n        for (int i = 0; i < N; i++) {\n            if (s.o[i] & bit) cm |= 1u << i;\n        }\n        info.firstCol[j] = firstBit(cm);\n        info.lastCol[j] = lastBit(cm);\n        info.colCnt[j] = popc(cm);\n    }\n}\n\nstruct Analysis {\n    int xcnt = 0;\n    int invis = 0;\n    double sumMin = 0;\n};\n\nAnalysis analyzeState(const State& s) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    Analysis a;\n    a.xcnt = s.xcnt;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            int md = 100;\n\n            if (j < info.firstRow[i]) vis++, md = min(md, j + 1);\n            if (j > info.lastRow[i]) vis++, md = min(md, N - j);\n            if (i < info.firstCol[j]) vis++, md = min(md, i + 1);\n            if (i > info.lastCol[j]) vis++, md = min(md, N - i);\n\n            if (vis == 0) {\n                a.invis++;\n                a.sumMin += N;\n            } else {\n                a.sumMin += md;\n            }\n        }\n    }\n    return a;\n}\n\nstruct GenParam {\n    double alpha = 1.0;\n    double critW = 6.0;\n    double twoW = 2.0;\n    double multiW = 1.0;\n    double damageW = 0.0;\n};\n\nstruct Cand {\n    char d;\n    int p, k;\n    int cnt;\n    double benefit;\n    double score;\n};\n\nvector<Cand> genCandidates(const State& s, const GenParam& gp) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    static double w[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) w[i][j] = 0.0;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            if (j < info.firstRow[i]) vis++;\n            if (j > info.lastRow[i]) vis++;\n            if (i < info.firstCol[j]) vis++;\n            if (i > info.lastCol[j]) vis++;\n\n            if (vis == 1) w[i][j] = gp.critW;\n            else if (vis == 2) w[i][j] = gp.twoW;\n            else if (vis >= 3) w[i][j] = gp.multiW;\n        }\n    }\n\n    vector<Cand> res;\n    res.reserve(160);\n\n    auto addCand = [&](char d, int p, int k, int cnt, double benefit, int movedO) {\n        if (cnt <= 0) return;\n        double b = max(1e-9, benefit);\n        double sc = (double)k / pow(b, gp.alpha) + gp.damageW * movedO * k;\n        res.push_back({d, p, k, cnt, benefit, sc});\n    };\n\n    for (int i = 0; i < N; i++) {\n        // L\n        {\n            int clear = info.firstRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int j = 0; j < clear; j++) {\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('L', i, j + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n        // R\n        {\n            int clear = N - 1 - info.lastRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int j = N - 1 - t;\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('R', i, t + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n        // U\n        {\n            int clear = info.firstCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int i = 0; i < clear; i++) {\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('U', j, i + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n        // D\n        {\n            int clear = N - 1 - info.lastCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int i = N - 1 - t;\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('D', j, t + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\n// ---------- Guaranteed cover construction ----------\n\nstruct CoverCand {\n    char d;\n    int p, k;\n    uint64_t mask;\n};\n\nvector<CoverCand> buildCoverCandidates() {\n    vector<CoverCand> cands;\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        for (int j = 0; j < N; j++) {\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'L', i, j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int j = N - 1 - t;\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'R', i, t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n\n        uint64_t mask = 0;\n        for (int i = 0; i < N; i++) {\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'U', j, i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int i = N - 1 - t;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'D', j, t + 1, mask});\n            }\n        }\n    }\n\n    return cands;\n}\n\nuint64_t unionIds(const vector<int>& ids, const vector<CoverCand>& cands) {\n    uint64_t m = 0;\n    for (int id : ids) m |= cands[id].mask;\n    return m;\n}\n\nint objectiveCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    if (ids.empty()) return 0;\n    int sum = 0, mx = 0;\n    for (int id : ids) {\n        sum += 2 * cands[id].k;\n        mx = max(mx, cands[id].k);\n    }\n    return sum - mx;\n}\n\nvoid removeRedundant(vector<int>& ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int a = 0; a < (int)ids.size(); a++) {\n            uint64_t u = 0;\n            for (int b = 0; b < (int)ids.size(); b++) if (a != b) {\n                u |= cands[ids[b]].mask;\n            }\n            if (u == ALL) {\n                ids.erase(ids.begin() + a);\n                changed = true;\n                break;\n            }\n        }\n    }\n}\n\nvector<int> greedyCover(int pre, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    vector<int> ids;\n    uint64_t covered = 0;\n\n    if (pre >= 0) {\n        ids.push_back(pre);\n        covered |= cands[pre].mask;\n    }\n\n    while (covered != ALL) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            uint64_t nm = cands[i].mask & ~covered;\n            if (!nm) continue;\n\n            int nc = __builtin_popcountll(nm);\n            int cost = 2 * cands[i].k;\n            double sc;\n\n            if (mode == 0) sc = cost / (double)nc;\n            else if (mode == 1) sc = cost / pow((double)nc, 1.3);\n            else if (mode == 2) sc = (cost - 0.3 * cands[i].k) / pow((double)nc, 1.1);\n            else if (mode == 3) sc = cost / (double)(nc * nc);\n            else sc = (cost + 0.05 * __builtin_popcountll(cands[i].mask)) / pow((double)nc, 1.5);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) break;\n        ids.push_back(best);\n        covered |= cands[best].mask;\n    }\n\n    removeRedundant(ids, cands, ALL);\n    return ids;\n}\n\nvector<int> improveCoverPlan(vector<int> ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    removeRedundant(ids, cands, ALL);\n\n    for (int iter = 0; iter < 12; iter++) {\n        int curObj = objectiveCover(ids, cands);\n        vector<int> bestIds = ids;\n        int bestObj = curObj;\n\n        vector<char> in(cands.size(), 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int c = 0; c < (int)cands.size(); c++) {\n            if (in[c]) continue;\n            vector<int> tmp = ids;\n            tmp.push_back(c);\n            removeRedundant(tmp, cands, ALL);\n            if (unionIds(tmp, cands) != ALL) continue;\n\n            int obj = objectiveCover(tmp, cands);\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestIds = tmp;\n            }\n        }\n\n        if (bestObj < curObj) ids = bestIds;\n        else break;\n    }\n\n    return ids;\n}\n\nstruct Plan {\n    vector<int> ids;\n    int obj;\n};\n\nstring keyIds(vector<int> ids) {\n    sort(ids.begin(), ids.end());\n    string s;\n    for (int id : ids) {\n        s += to_string(id);\n        s += ',';\n    }\n    return s;\n}\n\nvector<Plan> generateCoverPlans(const vector<CoverCand>& cands) {\n    int M = (int)initialXs.size();\n    uint64_t ALL = (M == 64 ? ~0ULL : ((1ULL << M) - 1));\n\n    vector<Plan> plans;\n    unordered_set<string> seen;\n\n    auto addPlan = [&](vector<int> ids) {\n        if (ids.empty()) return;\n        removeRedundant(ids, cands, ALL);\n        if (unionIds(ids, cands) != ALL) return;\n        string key = keyIds(ids);\n        if (seen.insert(key).second) {\n            plans.push_back({ids, objectiveCover(ids, cands)});\n        }\n    };\n\n    for (int mode = 0; mode < 5; mode++) {\n        addPlan(greedyCover(-1, mode, cands, ALL));\n        for (int pre = 0; pre < (int)cands.size(); pre++) {\n            addPlan(greedyCover(pre, mode, cands, ALL));\n        }\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    int top = min(25, (int)plans.size());\n    for (int i = 0; i < top; i++) {\n        addPlan(improveCoverPlan(plans[i].ids, cands, ALL));\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    if ((int)plans.size() > 60) plans.resize(60);\n    return plans;\n}\n\nvector<int> orderedIds(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = plan.ids;\n\n    if (variant == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k > cands[b].k;\n        });\n    } else if (variant == 3) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (cands[a].d != cands[b].d) return cands[a].d < cands[b].d;\n            if (cands[a].p != cands[b].p) return cands[a].p < cands[b].p;\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant >= 4) {\n        for (int i = (int)ids.size() - 1; i >= 1; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ids[i], ids[j]);\n        }\n    }\n\n    return ids;\n}\n\nvector<Op> buildRoundTripOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n    if (ids.empty()) return ops;\n\n    int maxK = -1;\n    vector<int> finals;\n    for (int id : ids) {\n        if (cands[id].k > maxK) {\n            maxK = cands[id].k;\n            finals.clear();\n            finals.push_back(id);\n        } else if (cands[id].k == maxK) {\n            finals.push_back(id);\n        }\n    }\n\n    int finalId = finals[variant % finals.size()];\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += 2 * cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        if (id == finalId) continue;\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n        appendOps(ops, invDir(c.d), c.p, c.k);\n    }\n\n    auto& f = cands[finalId];\n    appendOps(ops, f.d, f.p, f.k);\n    return ops;\n}\n\nvector<Op> buildOneWayOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n    }\n    return ops;\n}\n\nvector<Op> makeHintSequence() {\n    vector<Op> ops;\n\n    for (auto [i, j] : initialXs) {\n        int bestK = 1e9;\n        char bestD = 'L';\n\n        auto upd = [&](char d, int k) {\n            if (k < bestK) {\n                bestK = k;\n                bestD = d;\n            }\n        };\n\n        uint32_t leftMask = (j == 0 ? 0u : ((1u << j) - 1));\n        if ((INIT.o[i] & leftMask) == 0) upd('L', j + 1);\n\n        uint32_t rightMask = FULL & ~((1u << (j + 1)) - 1);\n        if ((INIT.o[i] & rightMask) == 0) upd('R', N - j);\n\n        uint32_t bit = 1u << j;\n\n        bool ok = true;\n        for (int r = 0; r < i; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('U', i + 1);\n\n        ok = true;\n        for (int r = i + 1; r < N; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('D', N - i);\n\n        if (bestK < 1e9) {\n            appendOps(ops, bestD, (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n            appendOps(ops, invDir(bestD), (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n        }\n    }\n\n    return ops;\n}\n\n// ---------- Direct search ----------\n\nuint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nuint64_t hashState(const State& s) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (int i = 0; i < N; i++) {\n        uint64_t v = ((uint64_t)s.x[i] << 32) ^ s.o[i] ^ (uint64_t)i * 0x9e3779b97f4a7c15ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\ndouble stateHeuristic(const State& s) {\n    Analysis a = analyzeState(s);\n    return 0.32 * a.sumMin + 4.5 * a.invis + 0.15 * a.xcnt;\n}\n\nstruct TrialParam {\n    GenParam gen;\n    double noise = 0.0;\n    int topK = 1;\n    double topBias = 2.0;\n    double lookInvW = 0.0;\n    double lookSumW = 0.0;\n};\n\nTrialParam makeTrialParam(int t, RNG& rng) {\n    TrialParam p;\n\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.lookInvW = 4.0;\n        p.lookSumW = 0.015;\n    } else if (t == 1) {\n        p.gen = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.lookInvW = 3.0;\n        p.lookSumW = 0.010;\n    } else if (t == 2) {\n        p.gen = {1.5, 4.0, 1.8, 1.0, 0.02};\n    } else if (t == 3) {\n        p.gen = {0.85, 10.0, 2.5, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.15;\n        p.lookInvW = 2.0;\n    } else if (t == 4) {\n        p.gen = {1.2, 8.0, 3.0, 1.0, 0.03};\n        p.topK = 2;\n    } else if (t == 5) {\n        p.gen = {0.55, 5.0, 1.5, 1.0, 0.00};\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.9;\n        p.gen.critW = 3.0 + rng.nextDouble() * 8.0;\n        p.gen.twoW = 1.2 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.04;\n        p.noise = 0.15 + rng.nextDouble() * 0.9;\n        p.topK = 1 + rng.nextInt(8);\n        p.topBias = 1.5 + rng.nextDouble() * 3.0;\n\n        if (t % 7 == 0) {\n            p.lookInvW = 1.5 + rng.nextDouble() * 3.0;\n            p.lookSumW = 0.004 + rng.nextDouble() * 0.012;\n        }\n    }\n\n    return p;\n}\n\nvector<Op> directTrial(const TrialParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = INIT;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n\n        vector<Cand> viable;\n        viable.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            double score = c.score;\n\n            if (tp.lookInvW > 0 || tp.lookSumW > 0) {\n                State tmp = st;\n                applyGAct(tmp, {c.d, c.p, c.k});\n                Analysis a = analyzeState(tmp);\n\n                if (a.xcnt > 0 && a.invis == a.xcnt) score += 1e6;\n                score += tp.lookInvW * a.invis;\n                score += tp.lookSumW * a.sumMin;\n            }\n\n            if (tp.noise > 0) {\n                double z = tp.noise * (2.0 * rng.nextDouble() - 1.0);\n                score *= exp(z);\n            }\n\n            c.score = score;\n            viable.push_back(c);\n        }\n\n        if (viable.empty()) return {};\n\n        sort(viable.begin(), viable.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        int m = min(tp.topK, (int)viable.size());\n        int idx = 0;\n        if (m > 1) {\n            idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.topBias) * m));\n        }\n\n        Cand ch = viable[idx];\n\n        GAct ga{ch.d, ch.p, ch.k};\n        applyGAct(st, ga);\n        seq.push_back(ga);\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nstruct BeamState {\n    State st;\n    int g;\n    vector<GAct> seq;\n    double eval;\n    uint64_t h;\n};\n\nvector<Op> beamSearch(int moveLimit, double until, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    GenParam gp;\n    gp.alpha = 1.15;\n    gp.critW = 7.5;\n    gp.twoW = 2.4;\n    gp.multiW = 1.0;\n    gp.damageW = 0.015;\n\n    const int WIDTH = 260;\n    const int PER_STATE = 12;\n\n    vector<BeamState> beam;\n    beam.push_back({INIT, 0, {}, stateHeuristic(INIT), hashState(INIT)});\n\n    int bestG = INT_MAX;\n    vector<GAct> bestSeq;\n\n    for (int depth = 0; depth < 45 && elapsed() < until; depth++) {\n        vector<BeamState> next;\n        next.reserve(WIDTH * PER_STATE);\n\n        for (auto& bs : beam) {\n            if (elapsed() >= until) break;\n            if (bs.st.xcnt == 0) {\n                if (bs.g < bestG) {\n                    bestG = bs.g;\n                    bestSeq = bs.seq;\n                }\n                continue;\n            }\n\n            vector<Cand> cands = genCandidates(bs.st, gp);\n            if (cands.empty()) continue;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                return a.score < b.score;\n            });\n\n            int take = min(PER_STATE, (int)cands.size());\n            for (int ci = 0; ci < take; ci++) {\n                const Cand& c = cands[ci];\n                int ng = bs.g + c.k;\n                if (ng > moveLimit) continue;\n\n                State ns = bs.st;\n                applyGAct(ns, {c.d, c.p, c.k});\n\n                BeamState child;\n                child.st = ns;\n                child.g = ng;\n                child.seq = bs.seq;\n                child.seq.push_back({c.d, c.p, c.k});\n                child.h = hashState(ns);\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestG) {\n                        bestG = ng;\n                        bestSeq = child.seq;\n                    }\n                    continue;\n                }\n\n                child.eval = ng + stateHeuristic(ns);\n                next.push_back(std::move(child));\n            }\n        }\n\n        if (next.empty()) break;\n\n        sort(next.begin(), next.end(), [](const BeamState& a, const BeamState& b) {\n            return a.eval < b.eval;\n        });\n\n        vector<BeamState> nb;\n        nb.reserve(WIDTH);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(WIDTH * 2);\n\n        for (auto& s : next) {\n            if (seen.insert(s.h).second) {\n                nb.push_back(std::move(s));\n                if ((int)nb.size() >= WIDTH) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    if (bestG < INT_MAX) return expandGSeq(bestSeq);\n    return {};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START = chrono::steady_clock::now();\n\n    cin >> N;\n    FULL = (1u << N) - 1;\n\n    INIT.x.fill(0);\n    INIT.o.fill(0);\n    INIT.xcnt = 0;\n    memset(idxAt, -1, sizeof(idxAt));\n\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') {\n                idxAt[i][j] = (int)initialXs.size();\n                initialXs.push_back({i, j});\n                INIT.x[i] |= 1u << j;\n                INIT.xcnt++;\n            } else if (C[i][j] == 'o') {\n                INIT.o[i] |= 1u << j;\n            }\n        }\n    }\n\n    uint64_t seed = hashState(INIT) ^ 0xa5a5a5a5deadbeefULL;\n    RNG rng(seed);\n\n    const double HARD = 1.85;\n\n    vector<Op> best = makeHintSequence();\n    truncateToPerfectPrefix(best);\n\n    vector<CoverCand> coverCands = buildCoverCandidates();\n    vector<Plan> plans = generateCoverPlans(coverCands);\n\n    auto consider = [&](vector<Op> ops, double pruneUntil) {\n        if (ops.empty()) return;\n        if (!truncateToPerfectPrefix(ops)) return;\n        if (pruneUntil > elapsed()) pruneSequence(ops, pruneUntil);\n        if (isPerfectFull(ops) && ops.size() < best.size()) {\n            best = std::move(ops);\n        }\n    };\n\n    if (!plans.empty()) {\n        vector<Op> ops = buildRoundTripOps(plans[0], coverCands, 0, rng);\n        consider(ops, 0.20);\n    }\n\n    pruneSequence(best, min(0.22, HARD));\n\n    // Try several guaranteed cover orders and aggressive one-way orders.\n    for (int pi = 0; pi < (int)plans.size() && pi < 10 && elapsed() < 0.45; pi++) {\n        for (int v = 0; v < 6 && elapsed() < 0.45; v++) {\n            {\n                vector<Op> ops = buildOneWayOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.020));\n            }\n            {\n                vector<Op> ops = buildRoundTripOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.025));\n            }\n        }\n    }\n\n    pruneSequence(best, min(0.50, HARD));\n\n    // Beam search for dynamic one-way sweeps.\n    if (elapsed() < 1.05) {\n        vector<Op> bops = beamSearch((int)best.size() + 70, 1.05, rng);\n        consider(bops, min(1.15, elapsed() + 0.08));\n    }\n\n    // Randomized greedy dynamic trials.\n    int trial = 0;\n    int pruneCnt = 0;\n    while (elapsed() < 1.70) {\n        TrialParam tp = makeTrialParam(trial, rng);\n        int limit = min(4 * N * N, (int)best.size() + 70);\n\n        vector<Op> ops = directTrial(tp, limit, rng);\n        if (!ops.empty()) {\n            double until = elapsed();\n            if ((int)ops.size() < (int)best.size() + 50 && pruneCnt < 25) {\n                until = min(1.72, elapsed() + 0.018);\n                pruneCnt++;\n            }\n            consider(ops, until);\n        }\n\n        trial++;\n    }\n\n    if (elapsed() < HARD) {\n        pruneSequence(best, HARD);\n    }\n\n    if (!isPerfectFull(best)) {\n        best = makeHintSequence();\n        truncateToPerfectPrefix(best);\n    }\n\n    for (auto& op : best) {\n        cout << op.d << ' ' << op.p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 100;\nconstexpr int MAXE = 200;\n\nint N, L;\narray<int, MAXN> T;\narray<int, MAXN> Cdes;      // slightly adjusted target when T0=0\narray<int, MAXN> demandIn;  // desired incoming counts: Cdes[i] - (i==0)\nvector<int> activeChoices;\nvector<int> validZs;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int randint(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n} rng;\n\ntemplate<class Tvec>\nvoid shuffle_vec(vector<Tvec>& v) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nchrono::steady_clock::time_point st_time;\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - st_time).count();\n}\n\nstruct Cand {\n    array<int, MAXN> a, b;\n    array<unsigned char, MAXE> prot; // protected backbone edges\n};\n\nstruct SimResult {\n    long long err;\n    array<int, MAXN> cnt;\n    int last;\n};\n\nstruct Entry {\n    long long err;\n    Cand cand;\n    SimResult res;\n};\n\nCand bestCand;\nSimResult bestRes;\nlong long bestErr = (1LL << 60);\nvector<Entry> pool;\n\ninline long long absl(long long x) { return x >= 0 ? x : -x; }\n\nlong long cellCost(long long diff, int mode) {\n    long long a = absl(diff);\n    if (mode == 0) return diff * diff;\n    if (mode == 1) return a;\n    return diff * diff + 1000LL * a;\n}\n\nvoid getDest(const Cand& c, array<int, MAXE>& dest) {\n    for (int i = 0; i < N; ++i) {\n        dest[2 * i] = c.a[i];\n        dest[2 * i + 1] = c.b[i];\n    }\n}\n\nvoid setEdge(Cand& c, int e, int to) {\n    int v = e / 2;\n    if (e % 2 == 0) c.a[v] = to;\n    else c.b[v] = to;\n}\n\nSimResult simulate(const Cand& c) {\n    SimResult r;\n    r.cnt.fill(0);\n\n    int x = 0;\n    r.cnt[0] = 1;\n\n    for (int step = 1; step < L; ++step) {\n        int nx = (r.cnt[x] & 1) ? c.a[x] : c.b[x];\n        x = nx;\n        ++r.cnt[x];\n    }\n\n    r.last = x;\n    long long e = 0;\n    for (int i = 0; i < N; ++i) e += llabs((long long)r.cnt[i] - T[i]);\n    r.err = e;\n    return r;\n}\n\nbool addEvaluated(const Cand& c, const SimResult& r) {\n    bool improved = false;\n    if (r.err < bestErr) {\n        bestErr = r.err;\n        bestCand = c;\n        bestRes = r;\n        improved = true;\n    }\n\n    if ((int)pool.size() < 8 || r.err < pool.back().err) {\n        pool.push_back({r.err, c, r});\n        sort(pool.begin(), pool.end(), [](const Entry& x, const Entry& y) {\n            return x.err < y.err;\n        });\n        while ((int)pool.size() > 8) pool.pop_back();\n    }\n    return improved;\n}\n\nbool consider(const Cand& c) {\n    SimResult r = simulate(c);\n    return addEvaluated(c, r);\n}\n\nvoid optimizeItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty() || items.empty()) return;\n\n    vector<int> order = items;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        bool improved = false;\n        if (randomize) shuffle_vec(order);\n\n        // single move\n        for (int e : order) {\n            int ww = w[e];\n            if (ww == 0) continue;\n\n            int old = dest[e];\n            long long oldCostOld = cellCost(loads[old] - dem[old], objMode);\n            long long bestDelta = 0;\n            int bestY = old;\n\n            for (int y : choices) {\n                if (y == old) continue;\n                long long delta =\n                    cellCost(loads[old] - ww - dem[old], objMode) +\n                    cellCost(loads[y] + ww - dem[y], objMode) -\n                    oldCostOld -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestY = y;\n                }\n            }\n\n            if (bestY != old) {\n                loads[old] -= ww;\n                loads[bestY] += ww;\n                dest[e] = bestY;\n                improved = true;\n            }\n        }\n\n        // swap destinations of two items\n        int M = (int)order.size();\n        for (int ii = 0; ii < M; ++ii) {\n            int e = order[ii];\n            int we = w[e];\n            if (we == 0) continue;\n\n            for (int jj = ii + 1; jj < M; ++jj) {\n                int f = order[jj];\n                int wf = w[f];\n                if (wf == 0 || we == wf) continue;\n\n                int x = dest[e], y = dest[f];\n                if (x == y) continue;\n\n                long long nx = loads[x] - we + wf;\n                long long ny = loads[y] - wf + we;\n\n                long long delta =\n                    cellCost(nx - dem[x], objMode) +\n                    cellCost(ny - dem[y], objMode) -\n                    cellCost(loads[x] - dem[x], objMode) -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < 0) {\n                    loads[x] = nx;\n                    loads[y] = ny;\n                    swap(dest[e], dest[f]);\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid assignItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty()) return;\n\n    vector<int> order = items;\n    if (randomize) shuffle_vec(order);\n    stable_sort(order.begin(), order.end(), [&](int e1, int e2) {\n        return w[e1] > w[e2];\n    });\n\n    int root = choices[0];\n\n    for (int e : order) {\n        int ww = w[e];\n        if (ww == 0) {\n            dest[e] = root;\n            continue;\n        }\n\n        vector<pair<long long, int>> cand;\n        cand.reserve(choices.size());\n\n        for (int y : choices) {\n            long long delta =\n                cellCost(loads[y] + ww - dem[y], objMode) -\n                cellCost(loads[y] - dem[y], objMode);\n            cand.push_back({delta, y});\n        }\n\n        nth_element(cand.begin(), cand.begin() + min((int)cand.size(), max(1, topR)) - 1,\n                    cand.end());\n        sort(cand.begin(), cand.begin() + min((int)cand.size(), max(1, topR)));\n\n        int take = min((int)cand.size(), max(1, topR));\n        int idx = 0;\n        if (take > 1) {\n            int r = rng.randint(100);\n            if (r >= 70) idx = 1 + rng.randint(take - 1);\n        }\n\n        int y = cand[idx].second;\n        dest[e] = y;\n        loads[y] += ww;\n    }\n\n    optimizeItems(dest, w, items, choices, loads, dem, objMode, maxPass, randomize);\n}\n\nCand buildSimpleCycle(bool activeOnly) {\n    Cand c;\n    c.prot.fill(0);\n\n    if (activeOnly && !activeChoices.empty()) {\n        int root = activeChoices[0];\n        for (int i = 0; i < N; ++i) c.a[i] = c.b[i] = root;\n\n        int m = (int)activeChoices.size();\n        for (int k = 0; k < m; ++k) {\n            int v = activeChoices[k];\n            int to = activeChoices[(k + 1) % m];\n            c.a[v] = c.b[v] = to;\n        }\n    } else {\n        for (int i = 0; i < N; ++i) c.a[i] = c.b[i] = (i + 1) % N;\n    }\n\n    return c;\n}\n\nCand buildBackbone(\n    int fixedParity, // 0: a-edge fixed, 1: b-edge fixed\n    int z,\n    int K,\n    int noiseAmp,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct NK {\n        int key, dem, node;\n    };\n    vector<NK> keys;\n    keys.reserve(activeChoices.size());\n\n    for (int v : activeChoices) {\n        int key = demandIn[v];\n        if (noiseAmp > 0) key += rng.randint(2 * noiseAmp + 1) - noiseAmp;\n        keys.push_back({key, demandIn[v], v});\n    }\n\n    sort(keys.begin(), keys.end(), [](const NK& x, const NK& y) {\n        if (x.key != y.key) return x.key > y.key;\n        if (x.dem != y.dem) return x.dem > y.dem;\n        return x.node < y.node;\n    });\n\n    vector<int> base;\n    for (auto& x : keys) base.push_back(x.node);\n\n    vector<int> order;\n    int m = (int)base.size();\n    if (m == 0) {\n        order.push_back(0);\n        m = 1;\n    } else {\n        K = max(1, min(K, m));\n        for (int r = 0; r < K; ++r) {\n            for (int idx = r; idx < m; idx += K) order.push_back(base[idx]);\n        }\n    }\n\n    root = order[0];\n    dest.fill(root);\n\n    array<char, MAXN> isAct;\n    isAct.fill(0);\n    for (int v : order) isAct[v] = 1;\n\n    vector<int> flexItems;\n    flexItems.reserve(MAXE);\n\n    for (int k = 0; k < (int)order.size(); ++k) {\n        int s = order[k];\n        int to = order[(k + 1) % order.size()];\n\n        int fixedIdx = 2 * s + fixedParity;\n        int flexIdx = 2 * s + (1 - fixedParity);\n\n        dest[fixedIdx] = to;\n        prot[fixedIdx] = 1;\n        loads[to] += w[fixedIdx];\n\n        flexItems.push_back(flexIdx);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (isAct[i]) continue;\n        for (int p = 0; p < 2; ++p) {\n            int e = 2 * i + p;\n            if (w[e] > 0) flexItems.push_back(e);\n            else dest[e] = root;\n        }\n    }\n\n    assignItems(dest, w, flexItems, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    Cand c;\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n    c.prot = prot;\n    return c;\n}\n\nCand rebalanceCandidate(\n    const Entry& base,\n    bool fullReassign,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    array<int, MAXE> dest;\n    getDest(base.cand, dest);\n\n    array<unsigned char, MAXE> prot = base.cand.prot;\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = base.res.cnt[i] - (base.res.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    array<long long, MAXN> loads;\n    loads.fill(0);\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n\n    if (fullReassign) {\n        for (int e = 0; e < 2 * N; ++e) {\n            if (prot[e]) {\n                loads[dest[e]] += w[e];\n            } else {\n                items.push_back(e);\n                dest[e] = root;\n            }\n        }\n\n        assignItems(dest, w, items, activeChoices, loads, demandIn,\n                    objMode, topR, maxPass, randomize);\n    } else {\n        for (int e = 0; e < 2 * N; ++e) {\n            loads[dest[e]] += w[e];\n            if (!prot[e]) items.push_back(e);\n        }\n\n        optimizeItems(dest, w, items, activeChoices, loads, demandIn,\n                      objMode, maxPass, randomize);\n    }\n\n    Cand c;\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n    c.prot = prot;\n    return c;\n}\n\nbool validZ(int z) {\n    if (z < 0 || z >= N) return false;\n    if (Cdes[z] <= 0) return false;\n    if (z == 0 && Cdes[0] <= 1) return false;\n    return true;\n}\n\nint randomZ() {\n    if (!validZs.empty()) return validZs[rng.randint((int)validZs.size())];\n    for (int i = 0; i < N; ++i) if (Cdes[i] > 0) return i;\n    return 0;\n}\n\nbool tryLocalImprove(double TL) {\n    array<int, MAXE> dest;\n    getDest(bestCand, dest);\n\n    array<int, MAXE> w;\n    for (int i = 0; i < N; ++i) {\n        int q = bestRes.cnt[i] - (bestRes.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct Change {\n        long long delta;\n        int type; // 0 move, 1 swap\n        int e, f, y;\n    };\n\n    vector<Change> moves;\n    moves.reserve(20000);\n\n    // single edge move\n    for (int e = 0; e < 2 * N; ++e) {\n        if (bestCand.prot[e]) continue;\n        int ww = w[e];\n        if (ww == 0) continue;\n\n        int old = dest[e];\n        for (int y : activeChoices) {\n            if (y == old) continue;\n\n            long long delta =\n                llabs((long long)bestRes.cnt[old] - ww - T[old]) +\n                llabs((long long)bestRes.cnt[y] + ww - T[y]) -\n                llabs((long long)bestRes.cnt[old] - T[old]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) moves.push_back({delta, 0, e, -1, y});\n        }\n    }\n\n    sort(moves.begin(), moves.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    int testLimit = min(12, (int)moves.size());\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n        setEdge(c, moves[i].e, moves[i].y);\n        SimResult r = simulate(c);\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    vector<Change> swaps;\n    swaps.reserve(20000);\n\n    // swap two free edge destinations\n    for (int e = 0; e < 2 * N; ++e) {\n        if (bestCand.prot[e] || w[e] == 0) continue;\n        for (int f = e + 1; f < 2 * N; ++f) {\n            if (bestCand.prot[f] || w[f] == 0) continue;\n\n            int x = dest[e], y = dest[f];\n            if (x == y) continue;\n\n            int we = w[e], wf = w[f];\n            if (we == wf) continue;\n\n            long long nx = (long long)bestRes.cnt[x] - we + wf;\n            long long ny = (long long)bestRes.cnt[y] - wf + we;\n\n            long long delta =\n                llabs(nx - T[x]) + llabs(ny - T[y]) -\n                llabs((long long)bestRes.cnt[x] - T[x]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) swaps.push_back({delta, 1, e, f, -1});\n        }\n    }\n\n    sort(swaps.begin(), swaps.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    testLimit = min(12, (int)swaps.size());\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n        int e = swaps[i].e, f = swaps[i].f;\n        setEdge(c, e, dest[f]);\n        setEdge(c, f, dest[e]);\n        SimResult r = simulate(c);\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\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    cin >> N >> L;\n    uint64_t seed = 123456789;\n    for (int i = 0; i < N; ++i) {\n        cin >> T[i];\n        seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    }\n    rng = RNG(seed);\n    st_time = chrono::steady_clock::now();\n\n    Cdes = T;\n\n    // If T0=0, employee 0 is still used in week 1.\n    // Aim for count[0]=1 and reduce one count from the largest other target.\n    if (T[0] == 0) {\n        Cdes[0] = 1;\n        int k = 1;\n        for (int i = 1; i < N; ++i) if (T[i] > T[k]) k = i;\n        --Cdes[k];\n    }\n\n    for (int i = 0; i < N; ++i) demandIn[i] = Cdes[i];\n    --demandIn[0];\n    if (demandIn[0] < 0) demandIn[0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (demandIn[i] > 0) activeChoices.push_back(i);\n    }\n    if (activeChoices.empty()) {\n        int k = max_element(Cdes.begin(), Cdes.begin() + N) - Cdes.begin();\n        activeChoices.push_back(k);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (validZ(i)) validZs.push_back(i);\n    }\n    if (validZs.empty()) {\n        for (int i = 0; i < N; ++i) if (Cdes[i] > 0) validZs.push_back(i);\n    }\n\n    // Baselines.\n    consider(buildSimpleCycle(false));\n    consider(buildSimpleCycle(true));\n\n    vector<int> zlist;\n    auto addZ = [&](int z) {\n        if (!validZ(z)) return;\n        if (find(zlist.begin(), zlist.end(), z) == zlist.end()) zlist.push_back(z);\n    };\n\n    int maxC = 0, minPos = -1;\n    for (int i = 0; i < N; ++i) {\n        if (Cdes[i] > Cdes[maxC]) maxC = i;\n        if (Cdes[i] > 0 && validZ(i)) {\n            if (minPos == -1 || Cdes[i] < Cdes[minPos]) minPos = i;\n        }\n    }\n    addZ(maxC);\n    addZ(0);\n    if (minPos != -1) addZ(minPos);\n    if (zlist.empty() && !validZs.empty()) zlist.push_back(validZs[0]);\n\n    const double TL = 1.85;\n    const double PHASE1 = 0.95;\n    const double PHASE2 = 1.52;\n\n    // Deterministic backbone variants.\n    for (int z : zlist) {\n        for (int fixed = 0; fixed < 2; ++fixed) {\n            for (int K = 1; K <= 6; ++K) {\n                for (int mode : {0, 2}) {\n                    if (elapsed_sec() > PHASE1) break;\n                    Cand c = buildBackbone(fixed, z, K, 0, mode, 1, 5, false);\n                    consider(c);\n                }\n            }\n        }\n    }\n\n    // Randomized backbone construction.\n    int amps[] = {0, 30, 80, 150, 300, 800, 2000};\n    while (elapsed_sec() < PHASE1) {\n        int z = randomZ();\n        int fixed = rng.randint(2);\n        int K = 1 + rng.randint(8);\n        int noise = amps[rng.randint(7)];\n        int mode = rng.randint(3);\n        int topR = 1 + rng.randint(4);\n\n        Cand c = buildBackbone(fixed, z, K, noise, mode, topR, 3, true);\n        consider(c);\n    }\n\n    // Rebalance good candidates using actual simulated edge usages.\n    int it = 0;\n    while (elapsed_sec() < PHASE2 && !pool.empty()) {\n        Entry base = pool[it % pool.size()];\n        bool full = (it % 3 != 1);\n        int mode = it % 3;\n        int topR = full ? (1 + rng.randint(4)) : 1;\n        int maxPass = full ? 5 : 8;\n\n        Cand c = rebalanceCandidate(base, full, mode, topR, maxPass, true);\n        consider(c);\n        ++it;\n    }\n\n    // Final local validated modifications and extra random rebalances.\n    bool localAllowed = true;\n    while (elapsed_sec() < TL) {\n        if (localAllowed) {\n            if (tryLocalImprove(TL)) {\n                localAllowed = true;\n                continue;\n            }\n            localAllowed = false;\n        }\n\n        if (pool.empty() || elapsed_sec() >= TL) break;\n\n        Entry base = pool[rng.randint((int)pool.size())];\n        bool full = rng.randint(2);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(4)) : 1;\n        int maxPass = full ? 4 : 6;\n\n        bool imp = consider(rebalanceCandidate(base, full, mode, topR, maxPass, true));\n        if (imp) localAllowed = true;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestCand.a[i] << ' ' << bestCand.b[i] << '\\n';\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, varp, norm2;\n    vector<int> sx_int, sy_int;\n    vector<unsigned long long> hilb;\n\n    vector<float> distBase; // uncertainty-aware estimated distance\n    vector<float> distRank; // optimistic distance for query neighbor selection\n    vector<unsigned char> known; // queried edge flag\n\n    vector<float> bonusMat;\n    vector<vector<pair<int, float>>> bonusAdj;\n\n    unordered_set<unsigned long long> usedQueries;\n    unordered_map<unsigned long long, vector<pair<int,int>>> responseMap;\n\n    int queryCount = 0;\n    float knownEvalFactor;\n    float knownFinalFactor;\n\n    mt19937 rng{1234567};\n\n    int ID(int i, int j) const { return i * N + j; }\n\n    static unsigned long long hilbertOrder(int x, int y) {\n        const int B = 14;\n        const int SZ = 1 << B;\n        unsigned long long d = 0;\n        for (int s = SZ / 2; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (unsigned long long)s * (unsigned long long)s * ((3 * rx) ^ ry);\n            if (ry == 0) {\n                if (rx == 1) {\n                    x = SZ - 1 - x;\n                    y = SZ - 1 - y;\n                }\n                swap(x, y);\n            }\n        }\n        return d;\n    }\n\n    unsigned long long subsetHash(vector<int> s) const {\n        sort(s.begin(), s.end());\n        unsigned long long h = 1469598103934665603ULL;\n        h ^= (unsigned long long)s.size();\n        h *= 1099511628211ULL;\n        for (int v : s) {\n            h ^= (unsigned long long)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    }\n\n    void readInput() {\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); varp.resize(N); norm2.resize(N);\n        sx_int.resize(N); sy_int.resize(N); hilb.resize(N);\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            double wx = rx[i] - lx[i];\n            double wy = ry[i] - ly[i];\n            varp[i] = (wx * wx + wy * wy) / 12.0;\n            norm2[i] = cx[i] * cx[i] + cy[i] * cy[i];\n        }\n\n        const int SZ = 1 << 14;\n        for (int i = 0; i < N; i++) {\n            sx_int[i] = min(SZ - 1, max(0, (int)llround(cx[i] * (SZ - 1) / 10000.0)));\n            sy_int[i] = min(SZ - 1, max(0, (int)llround(cy[i] * (SZ - 1) / 10000.0)));\n            hilb[i] = hilbertOrder(sx_int[i], sy_int[i]);\n        }\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        knownEvalFactor = (float)(0.72 - 0.22 * unc);   // 0.72 -> 0.50\n        knownFinalFactor = (float)(0.82 - 0.22 * unc);  // 0.82 -> 0.60\n    }\n\n    void computeDistances() {\n        distBase.assign(N * N, 0.0f);\n        distRank.assign(N * N, 0.0f);\n\n        const double alpha = 0.70;\n\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 cd = sqrt(dx * dx + dy * dy);\n\n                double base = sqrt(dx * dx + dy * dy + alpha * (varp[i] + varp[j]));\n\n                double gx = 0.0, gy = 0.0;\n                if (rx[i] < lx[j]) gx = lx[j] - rx[i];\n                else if (rx[j] < lx[i]) gx = lx[i] - rx[j];\n\n                if (ry[i] < ly[j]) gy = ly[j] - ry[i];\n                else if (ry[j] < ly[i]) gy = ly[i] - ry[j];\n\n                double minRect = sqrt(gx * gx + gy * gy);\n                double rankd = 0.70 * minRect + 0.30 * cd;\n\n                distBase[ID(i, j)] = distBase[ID(j, i)] = (float)base;\n                distRank[ID(i, j)] = distRank[ID(j, i)] = (float)rankd;\n            }\n        }\n        known.assign(N * N, 0);\n    }\n\n    vector<pair<int,int>> askNew(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        usedQueries.insert(h);\n\n        cout << \"? \" << subset.size();\n        for (int v : subset) cout << ' ' << v;\n        cout << '\\n';\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        int l = (int)subset.size();\n        ret.reserve(l - 1);\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            if (a > b) swap(a, b);\n            ret.emplace_back(a, b);\n        }\n        queryCount++;\n        responseMap[h] = ret;\n        return ret;\n    }\n\n    vector<pair<int,int>> getOrAsk(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        auto it = responseMap.find(h);\n        if (it != responseMap.end() && (int)it->second.size() == (int)subset.size() - 1) {\n            return it->second;\n        }\n        if (queryCount >= Q) return {};\n        return askNew(subset);\n    }\n\n    void addKnownEdges(const vector<pair<int,int>>& es) {\n        for (auto [a, b] : es) {\n            if (a > b) swap(a, b);\n            known[ID(a, b)] = known[ID(b, a)] = 1;\n        }\n    }\n\n    vector<int> buildSubsetGlobal(int center, int variant, int mode) {\n        vector<pair<float,int>> arr;\n        arr.reserve(N - 1);\n        for (int v = 0; v < N; v++) {\n            if (v == center) continue;\n            float d = (mode == 0 ? distRank[ID(center, v)] : distBase[ID(center, v)]);\n            arr.emplace_back(d, v);\n        }\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n            for (int i = 0; i < common; i++) sub.push_back(arr[i].second);\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n        return sub;\n    }\n\n    vector<int> buildSubsetInGroup(int center, const vector<int>& group, int variant) {\n        vector<pair<float,int>> arr;\n        arr.reserve(group.size());\n        for (int v : group) {\n            if (v == center) continue;\n            arr.emplace_back(distBase[ID(center, v)], v);\n        }\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n            for (int i = 0; i < common; i++) sub.push_back(arr[i].second);\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n        return sub;\n    }\n\n    int reserveFinalQueryCount() const {\n        int res = 0;\n        int chunk = L - 1;\n        for (int g : G) {\n            if (g <= 2) continue;\n            if (g <= L) {\n                res++;\n            } else {\n                int total = g - 1;\n                int full = total / chunk;\n                int rem = total % chunk;\n                res += full;\n                if (rem >= 2) res++;\n            }\n        }\n        return min(res, Q);\n    }\n\n    void performPrequeries(int targetQueries) {\n        if (targetQueries <= 0) return;\n\n        vector<int> byUnc(N), byHilb(N);\n        iota(byUnc.begin(), byUnc.end(), 0);\n        iota(byHilb.begin(), byHilb.end(), 0);\n\n        sort(byUnc.begin(), byUnc.end(), [&](int a, int b) {\n            if (varp[a] != varp[b]) return varp[a] > varp[b];\n            return a < b;\n        });\n        sort(byHilb.begin(), byHilb.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n\n        vector<int> centers;\n        vector<char> seen(N, 0);\n        for (int t = 0; t < N; t++) {\n            int c1 = byUnc[t];\n            if (!seen[c1]) {\n                seen[c1] = 1;\n                centers.push_back(c1);\n            }\n            int c2 = byHilb[(t * 37) % N];\n            if (!seen[c2]) {\n                seen[c2] = 1;\n                centers.push_back(c2);\n            }\n        }\n\n        for (int c : centers) {\n            if (queryCount >= targetQueries) break;\n            for (int v = 0; v < 4 && queryCount < targetQueries; v++) {\n                int mode = v & 1;\n                int variant = v / 2;\n                auto sub = buildSubsetGlobal(c, variant, mode);\n                if ((int)sub.size() < 2) continue;\n                unsigned long long h = subsetHash(sub);\n                if (usedQueries.count(h)) continue;\n                auto ret = askNew(sub);\n                addKnownEdges(ret);\n                break;\n            }\n        }\n\n        int attempts = 0;\n        while (queryCount < targetQueries && attempts < 5000) {\n            int c = attempts % N;\n            int variant = (attempts / N) % 6;\n            int mode = (attempts / (N * 6)) & 1;\n            attempts++;\n\n            auto sub = buildSubsetGlobal(c, variant, mode);\n            if ((int)sub.size() < 2) continue;\n            unsigned long long h = subsetHash(sub);\n            if (usedQueries.count(h)) continue;\n            auto ret = askNew(sub);\n            addKnownEdges(ret);\n        }\n    }\n\n    float evalWeight(int u, int v) const {\n        float d = distBase[ID(u, v)];\n        if (known[ID(u, v)]) d *= knownEvalFactor;\n        return d;\n    }\n\n    double primCostEval(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        if (n <= 1) return 0.0;\n        vector<float> best(n, 1e30f);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\n\n        double cost = 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 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n            cost += best[v];\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    float w = evalWeight(vs[v], vs[u]);\n                    if (w < best[u]) best[u] = w;\n                }\n            }\n        }\n        return cost;\n    }\n\n    double evalCandidate(const vector<int>& gid) const {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n\n        for (int i = 0; i < N; i++) {\n            if (gid[i] < 0 || gid[i] >= M) return 1e100;\n            groups[gid[i]].push_back(i);\n        }\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) return 1e100;\n        }\n\n        double score = 0.0;\n        for (int k = 0; k < M; k++) score += primCostEval(groups[k]);\n        return score;\n    }\n\n    vector<vector<int>> makeCityOrders() {\n        vector<vector<int>> orders;\n        const int S = (1 << 14) - 1;\n\n        auto addHilbert = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n                    if (type == 1) { tx = y; ty = x; }\n                    else if (type == 2) { tx = S - x; ty = y; }\n                    else if (type == 3) { tx = x; ty = S - y; }\n                    else if (type == 4) { tx = S - x; ty = S - y; }\n                    else if (type == 5) { tx = S - y; ty = x; }\n                    return hilbertOrder(tx, ty);\n                };\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 6; t++) addHilbert(t);\n\n        auto addSort = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                double ka, kb;\n                if (type == 0) { ka = cx[a] * 10001.0 + cy[a]; kb = cx[b] * 10001.0 + cy[b]; }\n                else if (type == 1) { ka = cy[a] * 10001.0 + cx[a]; kb = cy[b] * 10001.0 + cx[b]; }\n                else if (type == 2) { ka = cx[a] + cy[a]; kb = cx[b] + cy[b]; }\n                else { ka = cx[a] - cy[a]; kb = cx[b] - cy[b]; }\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addSort(t);\n        return orders;\n    }\n\n    vector<vector<int>> makeGroupOrders() {\n        vector<vector<int>> orders;\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        orders.push_back(ids);\n\n        vector<int> asc = ids, desc = ids;\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        orders.push_back(asc);\n        orders.push_back(desc);\n\n        for (int r = 0; r < 6; r++) {\n            vector<int> p = ids;\n            shuffle(p.begin(), p.end(), rng);\n            orders.push_back(p);\n        }\n        return orders;\n    }\n\n    vector<int> partitionCandidate(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n        vector<int> gid(N, -1);\n        int pos = 0;\n        for (int g : groupOrder) {\n            for (int t = 0; t < G[g]; t++) {\n                gid[cityOrder[pos++]] = g;\n            }\n        }\n        return gid;\n    }\n\n    struct EP {\n        float w;\n        int u, v;\n        bool operator<(const EP& other) const {\n            if (w != other.w) return w < other.w;\n            if (u != other.u) return u < other.u;\n            return v < other.v;\n        }\n    };\n\n    vector<EP> makeSortedPairs() {\n        vector<EP> ps;\n        ps.reserve(N * (N - 1) / 2);\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                ps.push_back({evalWeight(i, j), i, j});\n            }\n        }\n        sort(ps.begin(), ps.end());\n        return ps;\n    }\n\n    vector<int> greedyCandidate(const vector<int>& groupOrder, const vector<EP>& pairs) {\n        vector<int> gid(N, -1);\n        vector<char> alive(N, 1);\n        int rem = N;\n        int ptr = 0;\n\n        auto addCity = [&](vector<int>& sel, int v) {\n            if (!alive[v]) return;\n            alive[v] = 0;\n            rem--;\n            sel.push_back(v);\n        };\n\n        for (int gr : groupOrder) {\n            int need = G[gr];\n            vector<int> sel;\n            sel.reserve(need);\n\n            if (need == rem) {\n                for (int i = 0; i < N; i++) if (alive[i]) {\n                    gid[i] = gr;\n                    alive[i] = 0;\n                }\n                rem = 0;\n                continue;\n            }\n\n            if (need == 1) {\n                double mx = 0.0, my = 0.0;\n                for (int i = 0; i < N; i++) if (alive[i]) {\n                    mx += cx[i];\n                    my += cy[i];\n                }\n                mx /= rem;\n                my /= rem;\n\n                int best = -1;\n                double bestVal = -1.0;\n                for (int i = 0; i < N; i++) if (alive[i]) {\n                    double dx = cx[i] - mx;\n                    double dy = cy[i] - my;\n                    double val = dx * dx + dy * dy + 0.05 * varp[i];\n                    if (val > bestVal) {\n                        bestVal = val;\n                        best = i;\n                    }\n                }\n                addCity(sel, best);\n            } else {\n                while (ptr < (int)pairs.size() && !(alive[pairs[ptr].u] && alive[pairs[ptr].v])) ptr++;\n                if (ptr < (int)pairs.size()) {\n                    addCity(sel, pairs[ptr].u);\n                    addCity(sel, pairs[ptr].v);\n                } else {\n                    for (int i = 0; i < N && (int)sel.size() < min(2, need); i++) {\n                        if (alive[i]) addCity(sel, i);\n                    }\n                }\n\n                vector<float> best(N, 1e30f);\n                for (int v = 0; v < N; v++) if (alive[v]) {\n                    for (int s : sel) best[v] = min(best[v], evalWeight(v, s));\n                }\n\n                while ((int)sel.size() < need) {\n                    int bv = -1;\n                    for (int v = 0; v < N; v++) if (alive[v]) {\n                        if (bv == -1 || best[v] < best[bv]) bv = v;\n                    }\n                    if (bv == -1) break;\n                    addCity(sel, bv);\n                    for (int v = 0; v < N; v++) if (alive[v]) {\n                        best[v] = min(best[v], evalWeight(v, bv));\n                    }\n                }\n            }\n\n            for (int v : sel) gid[v] = gr;\n        }\n\n        return gid;\n    }\n\n    void kdRec(vector<int> cities, vector<int> gids, vector<int>& assign, int depth, int mode, mt19937& rr) {\n        if (gids.size() == 1) {\n            int g = gids[0];\n            for (int c : cities) assign[c] = g;\n            return;\n        }\n\n        int n = (int)cities.size();\n\n        double minx = 1e100, maxx = -1e100, miny = 1e100, maxy = -1e100;\n        for (int c : cities) {\n            minx = min(minx, cx[c]); maxx = max(maxx, cx[c]);\n            miny = min(miny, cy[c]); maxy = max(maxy, cy[c]);\n        }\n        double rxr = maxx - minx, ryr = maxy - miny;\n\n        int axis;\n        if (mode % 3 == 0) axis = (rxr >= ryr ? 0 : 1);\n        else if (mode % 3 == 1) axis = depth & 1;\n        else axis = (rxr < ryr ? 0 : 1);\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            double ka = axis == 0 ? cx[a] : cy[a];\n            double kb = axis == 0 ? cx[b] : cy[b];\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        vector<int> order = gids;\n        if (mode >= 3) shuffle(order.begin(), order.end(), rr);\n        else if (mode == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] > G[b];\n                return a < b;\n            });\n        } else if (mode == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] < G[b];\n                return a < b;\n            });\n        }\n\n        vector<char> dp(n + 1, 0);\n        vector<int> parS(n + 1, -1), parG(n + 1, -1);\n        dp[0] = 1;\n        for (int g : order) {\n            int s = G[g];\n            for (int sum = n - s; sum >= 0; sum--) {\n                if (dp[sum] && !dp[sum + s]) {\n                    dp[sum + s] = 1;\n                    parS[sum + s] = sum;\n                    parG[sum + s] = g;\n                }\n            }\n        }\n\n        int target = n / 2;\n        int best = -1, bd = 1e9;\n        for (int s = 1; s < n; s++) if (dp[s]) {\n            int d = abs(s - target);\n            if (d < bd) {\n                bd = d;\n                best = s;\n            }\n        }\n        if (best == -1) best = G[gids[0]];\n\n        vector<char> selected(M, 0);\n        int cur = best;\n        while (cur > 0) {\n            int g = parG[cur];\n            if (g < 0) break;\n            selected[g] = 1;\n            cur = parS[cur];\n        }\n\n        vector<int> leftG, rightG;\n        for (int g : gids) {\n            if (selected[g]) leftG.push_back(g);\n            else rightG.push_back(g);\n        }\n        if (leftG.empty() || rightG.empty()) {\n            leftG.clear(); rightG.clear();\n            int acc = 0;\n            for (int g : gids) {\n                if (acc + G[g] <= best && leftG.empty() == false) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else if (acc < best) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else {\n                    rightG.push_back(g);\n                }\n            }\n            if (leftG.empty() || rightG.empty()) {\n                leftG = {gids[0]};\n                rightG.assign(gids.begin() + 1, gids.end());\n                best = G[gids[0]];\n            }\n        }\n\n        bool flip = (mode >= 3 && ((depth + mode) & 1));\n        vector<int> leftC, rightC;\n        if (!flip) {\n            leftC.assign(cities.begin(), cities.begin() + best);\n            rightC.assign(cities.begin() + best, cities.end());\n        } else {\n            leftC.assign(cities.end() - best, cities.end());\n            rightC.assign(cities.begin(), cities.end() - best);\n        }\n\n        kdRec(leftC, leftG, assign, depth + 1, mode, rr);\n        kdRec(rightC, rightG, assign, depth + 1, mode, rr);\n    }\n\n    vector<int> kdCandidate(int mode) {\n        vector<int> cities(N), gids(M), assign(N, -1);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n        mt19937 rr(1000 + mode * 97);\n        kdRec(cities, gids, assign, 0, mode, rr);\n        return assign;\n    }\n\n    void buildBonus() {\n        bonusMat.assign(N * N, 0.0f);\n        bonusAdj.assign(N, {});\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        double coef = 0.20 + 0.30 * unc;\n        double cap = 2.0e6;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (!known[ID(i, j)]) continue;\n                double d = distBase[ID(i, j)];\n                float b = (float)min(cap, coef * d * d);\n                bonusMat[ID(i, j)] = bonusMat[ID(j, i)] = b;\n                bonusAdj[i].push_back({j, b});\n                bonusAdj[j].push_back({i, b});\n            }\n        }\n    }\n\n    void localSearch(vector<int>& gid, int maxPass) {\n        vector<double> sxg(M, 0.0), syg(M, 0.0), sqg(M, 0.0);\n        for (int i = 0; i < N; i++) {\n            int g = gid[i];\n            sxg[g] += cx[i];\n            syg[g] += cy[i];\n            sqg[g] += norm2[i];\n        }\n\n        vector<float> ktg((size_t)N * M, 0.0f);\n        for (int u = 0; u < N; u++) {\n            for (auto [v, b] : bonusAdj[u]) if (u < v) {\n                ktg[(size_t)u * M + gid[v]] += b;\n                ktg[(size_t)v * M + gid[u]] += b;\n            }\n        }\n\n        auto deltaReplace = [&](int g, int out, int in) -> double {\n            double nsx = sxg[g] - cx[out] + cx[in];\n            double nsy = syg[g] - cy[out] + cy[in];\n            double oldS2 = sxg[g] * sxg[g] + syg[g] * syg[g];\n            double newS2 = nsx * nsx + nsy * nsy;\n            return (-norm2[out] + norm2[in]) - (newS2 - oldS2) / G[g];\n        };\n\n        auto applySwap = [&](int i, int j, int A, int B) {\n            sxg[A] += -cx[i] + cx[j];\n            syg[A] += -cy[i] + cy[j];\n            sqg[A] += -norm2[i] + norm2[j];\n\n            sxg[B] += -cx[j] + cx[i];\n            syg[B] += -cy[j] + cy[i];\n            sqg[B] += -norm2[j] + norm2[i];\n\n            for (auto [t, b] : bonusAdj[i]) {\n                ktg[(size_t)t * M + A] -= b;\n                ktg[(size_t)t * M + B] += b;\n            }\n            for (auto [t, b] : bonusAdj[j]) {\n                ktg[(size_t)t * M + B] -= b;\n                ktg[(size_t)t * M + A] += b;\n            }\n\n            gid[i] = B;\n            gid[j] = A;\n        };\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            int swaps = 0;\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    int A = gid[i], B = gid[j];\n                    if (A == B) continue;\n\n                    double ds = deltaReplace(A, i, j) + deltaReplace(B, j, i);\n\n                    float bij = bonusMat[ID(i, j)];\n                    double before = ktg[(size_t)i * M + A] + ktg[(size_t)j * M + B];\n                    double after = ktg[(size_t)i * M + B] + ktg[(size_t)j * M + A] - 2.0 * bij;\n                    double delta = ds - (after - before);\n\n                    if (delta < -1e-7) {\n                        applySwap(i, j, A, B);\n                        swaps++;\n                    }\n                }\n            }\n            if (swaps == 0) break;\n        }\n    }\n\n    vector<int> makeGrouping() {\n        if (M == 1) return vector<int>(N, 0);\n\n        struct Cand {\n            double score;\n            vector<int> gid;\n        };\n        vector<Cand> top;\n        const int TOPK = 8;\n\n        auto addCand = [&](vector<int> gid) {\n            double sc = evalCandidate(gid);\n            if (sc > 1e90) return;\n            if ((int)top.size() < TOPK) {\n                top.push_back({sc, move(gid)});\n            } else {\n                int worst = 0;\n                for (int i = 1; i < (int)top.size(); i++) {\n                    if (top[i].score > top[worst].score) worst = i;\n                }\n                if (sc < top[worst].score) top[worst] = {sc, move(gid)};\n            }\n        };\n\n        auto cityOrders = makeCityOrders();\n        auto groupOrders = makeGroupOrders();\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                addCand(partitionCandidate(co, go));\n            }\n        }\n\n        auto pairs = makeSortedPairs();\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        vector<int> asc = ids, desc = ids;\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        addCand(greedyCandidate(asc, pairs));\n        addCand(greedyCandidate(ids, pairs));\n        addCand(greedyCandidate(desc, pairs));\n\n        for (int mode = 0; mode < 6; mode++) {\n            addCand(kdCandidate(mode));\n        }\n\n        if (top.empty()) {\n            auto co = cityOrders[0];\n            auto go = groupOrders[0];\n            return partitionCandidate(co, go);\n        }\n\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        buildBonus();\n\n        vector<int> best = top[0].gid;\n        double bestScore = top[0].score;\n\n        int lim = min(6, (int)top.size());\n        int passes = (M > 250 ? 12 : 9);\n\n        for (int i = 0; i < lim; i++) {\n            vector<int> gid = top[i].gid;\n            localSearch(gid, passes);\n            double sc = evalCandidate(gid);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = move(gid);\n            }\n        }\n\n        return best;\n    }\n\n    vector<vector<int>> buildGroups(const vector<int>& gid) {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n        for (int i = 0; i < N; i++) groups[gid[i]].push_back(i);\n\n        bool ok = true;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() != G[k]) ok = false;\n\n        if (!ok) {\n            groups.assign(M, {});\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n            int pos = 0;\n            for (int k = 0; k < M; k++) {\n                for (int t = 0; t < G[k]; t++) groups[k].push_back(ids[pos++]);\n            }\n        }\n\n        return groups;\n    }\n\n    void performFinalQueries(\n        vector<vector<int>>& groups,\n        vector<char>& exact,\n        vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        exact.assign(M, 0);\n        exactEdges.assign(M, {});\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                auto ret = getOrAsk(groups[k]);\n                if ((int)ret.size() == g - 1) {\n                    addKnownEdges(ret);\n                    exact[k] = 1;\n                    exactEdges[k] = ret;\n                }\n            } else {\n                vector<int> ord = groups[k];\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                    return a < b;\n                });\n\n                int connector = ord[0];\n                int pos = 1;\n                while (pos < g) {\n                    int s = min(L - 1, g - pos);\n                    if (s >= 2) {\n                        vector<int> sub;\n                        sub.reserve(s + 1);\n                        sub.push_back(connector);\n                        for (int t = 0; t < s; t++) sub.push_back(ord[pos + t]);\n\n                        auto ret = getOrAsk(sub);\n                        if (!ret.empty()) addKnownEdges(ret);\n                    }\n                    connector = ord[pos + s - 1];\n                    pos += s;\n                }\n            }\n        }\n\n        if (queryCount >= Q) return;\n\n        vector<int> candGroups;\n        int maxG = 0;\n        vector<vector<int>> ords(M);\n        for (int k = 0; k < M; k++) {\n            if (exact[k]) continue;\n            int g = (int)groups[k].size();\n            if (g < 3) continue;\n            candGroups.push_back(k);\n            ords[k] = groups[k];\n            sort(ords[k].begin(), ords[k].end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n            maxG = max(maxG, g);\n        }\n\n        for (int variant = 0; variant < 5 && queryCount < Q; variant++) {\n            for (int r = 0; r < maxG && queryCount < Q; r++) {\n                for (int k : candGroups) {\n                    if (queryCount >= Q) break;\n                    if (r >= (int)ords[k].size()) continue;\n\n                    int center = ords[k][r];\n                    auto sub = buildSubsetInGroup(center, groups[k], variant);\n                    if ((int)sub.size() < 3) continue;\n                    unsigned long long h = subsetHash(sub);\n                    if (usedQueries.count(h)) continue;\n\n                    auto ret = askNew(sub);\n                    addKnownEdges(ret);\n                }\n            }\n        }\n    }\n\n    vector<pair<int,int>> finalPrimEdges(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n\n        vector<float> best(n, 1e30f);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\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 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n            if (par[v] != -1) edges.push_back({vs[v], vs[par[v]]});\n\n            for (int u = 0; u < n; u++) if (!used[u]) {\n                int a = vs[v], b = vs[u];\n                float w = distBase[ID(a, b)];\n                if (known[ID(a, b)]) w *= knownFinalFactor;\n                if (w < best[u]) {\n                    best[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        return edges;\n    }\n\n    void outputAnswer(\n        const vector<vector<int>>& groups,\n        const vector<char>& exact,\n        const vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        vector<vector<pair<int,int>>> ansEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n            if (g <= 1) {\n                ansEdges[k] = {};\n            } else if (g == 2) {\n                ansEdges[k] = {{groups[k][0], groups[k][1]}};\n            } else if (exact[k]) {\n                ansEdges[k] = exactEdges[k];\n            } else {\n                ansEdges[k] = finalPrimEdges(groups[k]);\n            }\n        }\n\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << '\\n';\n\n            for (auto [a, b] : ansEdges[k]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n\n    void solve() {\n        readInput();\n        computeDistances();\n\n        usedQueries.reserve(Q * 4 + 10);\n        responseMap.reserve(Q * 4 + 10);\n\n        int reserveQ = reserveFinalQueryCount();\n        int preBudget = max(0, Q - reserveQ);\n\n        performPrequeries(preBudget);\n\n        vector<int> gid = makeGrouping();\n        auto groups = buildGroups(gid);\n\n        vector<char> exact;\n        vector<vector<pair<int,int>>> exactEdges;\n        performFinalQueries(groups, exact, exactEdges);\n\n        outputAnswer(groups, exact, exactEdges);\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}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 20;\nstatic const int MAXV = 400;\nstatic const int INF = 1e9;\n\nstruct Grid {\n    uint32_t row[MAXN];\n    uint32_t col[MAXN];\n    int cnt;\n    uint64_t hash;\n    Grid() {\n        memset(row, 0, sizeof(row));\n        memset(col, 0, sizeof(col));\n        cnt = 0;\n        hash = 0;\n    }\n};\n\nstruct Solver {\n    int N, M, V;\n    int LIMIT;\n    uint32_t FULL;\n    vector<int> pos;\n\n    int rr[MAXV], cc[MAXV];\n    int mv[MAXV][4];\n\n    int dr[4] = {-1, 1, 0, 0};\n    int dc[4] = {0, 0, -1, 1};\n    int opp[4] = {1, 0, 3, 2};\n\n    bool future[45][MAXV];\n\n    uint64_t zob[MAXV];\n    uint64_t rngState;\n\n    int seen[MAXV], distArr[MAXV], prevArr[MAXV], que[MAXV];\n    unsigned char actArr[MAXV];\n    int stamp = 1;\n\n    int validBits[45], inBits[45];\n    bool isPlanOpt[45][16];\n    vector<int> planOpts[45];\n\n    chrono::steady_clock::time_point startTime;\n\n    vector<string> candidates;\n    string pureFallback;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    uint64_t rnd() {\n        uint64_t z = (rngState += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    inline char enc(int type, int d) const {\n        return char(type * 4 + d);\n    }\n\n    inline bool isBlocked(const Grid& g, int v) const {\n        return (g.row[rr[v]] >> cc[v]) & 1u;\n    }\n\n    inline void setBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (!(g.row[r] & br)) {\n            g.row[r] |= br;\n            g.col[c] |= (1u << r);\n            g.cnt++;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void clearBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (g.row[r] & br) {\n            g.row[r] &= ~br;\n            g.col[c] &= ~(1u << r);\n            g.cnt--;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void toggleBlock(Grid& g, int v) {\n        if (isBlocked(g, v)) clearBlock(g, v);\n        else setBlock(g, v);\n    }\n\n    inline int highestBit(uint32_t x) const {\n        return 31 - __builtin_clz(x);\n    }\n\n    inline int slideDestRC(const Grid& g, int r, int c, int d) const {\n        if (d == 0) { // U\n            uint32_t mask = g.col[c] & ((1u << r) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return (b + 1) * N + c;\n            }\n            return c;\n        } else if (d == 1) { // D\n            uint32_t mask = g.col[c] & (FULL ^ ((1u << (r + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return (b - 1) * N + c;\n            }\n            return (N - 1) * N + c;\n        } else if (d == 2) { // L\n            uint32_t mask = g.row[r] & ((1u << c) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return r * N + (b + 1);\n            }\n            return r * N;\n        } else { // R\n            uint32_t mask = g.row[r] & (FULL ^ ((1u << (c + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return r * N + (b - 1);\n            }\n            return r * N + (N - 1);\n        }\n    }\n\n    inline int slideDest(const Grid& g, int v, int d) const {\n        return slideDestRC(g, rr[v], cc[v], d);\n    }\n\n    void nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n    }\n\n    int bfsSearch(const Grid& g, int s, int t, bool storePath) {\n        if (s < 0 || t < 0) return INF;\n        if (isBlocked(g, s) || isBlocked(g, t)) return INF;\n        if (s == t) return 0;\n\n        nextStamp();\n        int head = 0, tail = 0;\n        que[tail++] = s;\n        seen[s] = stamp;\n        distArr[s] = 0;\n        if (storePath) prevArr[s] = -1;\n\n        while (head < tail) {\n            int v = que[head++];\n            int nd = distArr[v] + 1;\n            int r = rr[v], c = cc[v];\n\n            // Slide edges first.\n            for (int d = 0; d < 4; d++) {\n                int to = slideDestRC(g, r, c, d);\n                if (to == v) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(1, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n\n            // Move edges.\n            for (int d = 0; d < 4; d++) {\n                int to = mv[v][d];\n                if (to < 0 || isBlocked(g, to)) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(0, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n        }\n        return INF;\n    }\n\n    int bfsDist(const Grid& g, int s, int t) {\n        return bfsSearch(g, s, t, false);\n    }\n\n    bool bfsPath(const Grid& g, int s, int t, string& out) {\n        int d = bfsSearch(g, s, t, true);\n        if (d >= INF) return false;\n        out.clear();\n        int v = t;\n        while (v != s) {\n            out.push_back(char(actArr[v]));\n            v = prevArr[v];\n            if (v < 0) return false;\n        }\n        reverse(out.begin(), out.end());\n        return true;\n    }\n\n    void init() {\n        V = N * N;\n        LIMIT = 2 * N * M;\n        FULL = (1u << N) - 1u;\n\n        for (int v = 0; v < V; v++) {\n            rr[v] = v / N;\n            cc[v] = v % N;\n        }\n\n        for (int v = 0; v < V; v++) {\n            for (int d = 0; d < 4; d++) {\n                int nr = rr[v] + dr[d];\n                int nc = cc[v] + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) mv[v][d] = nr * N + nc;\n                else mv[v][d] = -1;\n            }\n        }\n\n        memset(future, 0, sizeof(future));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                future[k][pos[t]] = true;\n            }\n        }\n\n        rngState = 1234567891234567ULL;\n        for (int p : pos) {\n            rngState ^= uint64_t(p + 1009) * 0x9e3779b97f4a7c15ULL;\n            rnd();\n        }\n        for (int i = 0; i < V; i++) zob[i] = rnd();\n\n        memset(seen, 0, sizeof(seen));\n\n        memset(isPlanOpt, 0, sizeof(isPlanOpt));\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            inBits[k] = 0;\n            validBits[k] = 0;\n            for (int d = 0; d < 4; d++) {\n                int q = mv[p][d];\n                if (q < 0) continue;\n                inBits[k] |= (1 << d);\n                if (!future[k][q]) validBits[k] |= (1 << d);\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~validBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                // Do not intentionally block every in-board neighbour.\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planOpts[k].push_back(sub);\n                isPlanOpt[k][sub] = true;\n            }\n            if (planOpts[k].empty()) {\n                planOpts[k].push_back(0);\n                isPlanOpt[k][0] = true;\n            }\n        }\n    }\n\n    string makePureMoves() {\n        string s;\n        int cur = pos[0];\n        int r = rr[cur], c = cc[cur];\n\n        for (int k = 1; k < M; k++) {\n            int gr = rr[pos[k]], gc = cc[pos[k]];\n            while (r < gr) {\n                s.push_back(enc(0, 1));\n                r++;\n            }\n            while (r > gr) {\n                s.push_back(enc(0, 0));\n                r--;\n            }\n            while (c < gc) {\n                s.push_back(enc(0, 3));\n                c++;\n            }\n            while (c > gc) {\n                s.push_back(enc(0, 2));\n                c--;\n            }\n        }\n        return s;\n    }\n\n    int firstCompletionPrefix(const string& acts) {\n        if (M <= 1) return 0;\n\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return -1;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) { // Move\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return -1;\n                p = to;\n            } else if (type == 1) { // Slide\n                p = slideDest(g, p, d);\n            } else { // Alter\n                int to = mv[p][d];\n                if (to < 0) return -1;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                nxt++;\n                if (nxt == M) return t + 1;\n            }\n        }\n        return -1;\n    }\n\n    void addCandidate(const string& acts) {\n        int p = firstCompletionPrefix(acts);\n        if (p < 0 || p > LIMIT) return;\n        string t = acts.substr(0, p);\n        candidates.push_back(move(t));\n    }\n\n    string greedyDelete(string a) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return \"\";\n        a.resize(pref);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (size_t i = 0; i < a.size();) {\n                if (elapsed() > 1.90) return a;\n                string b = a;\n                b.erase(b.begin() + i);\n                int p = firstCompletionPrefix(b);\n                if (p >= 0 && p <= LIMIT) {\n                    b.resize(p);\n                    a.swap(b);\n                    changed = true;\n                    if (i > 0) --i;\n                    if (i > a.size()) i = a.size();\n                } else {\n                    ++i;\n                }\n            }\n            if (!changed) break;\n        }\n\n        for (int w = 2; w <= 3; w++) {\n            bool any = true;\n            while (any) {\n                any = false;\n                for (size_t i = 0; i + w <= a.size();) {\n                    if (elapsed() > 1.92) return a;\n                    string b = a;\n                    b.erase(i, w);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        a.swap(b);\n                        any = true;\n                        if (i > 0) --i;\n                        if (i > a.size()) i = a.size();\n                    } else {\n                        ++i;\n                    }\n                }\n            }\n        }\n\n        return a;\n    }\n\n    int dirToward(int a, int b) const {\n        int vr = rr[b] - rr[a];\n        int vc = cc[b] - cc[a];\n        if (abs(vr) >= abs(vc)) {\n            if (vr < 0) return 0;\n            if (vr > 0) return 1;\n        }\n        if (vc < 0) return 2;\n        if (vc > 0) return 3;\n        return 0;\n    }\n\n    int evalPlan(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int dist = bfsDist(g, p, pos[k + 1]);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    bool buildFromMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            int bestDir = -1;\n            int bestActual = noDist;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    if (isBlocked(tg, p)) continue;\n                    setBlock(tg, p);\n\n                    int dist = bfsDist(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                        bestActual = actual;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                acts.push_back(enc(0, bestDir));       // move out\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));  // alter back to block previous square\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n            (void)bestActual;\n        }\n\n        return true;\n    }\n\n    vector<int> makeZeroMasks() {\n        return vector<int>(M - 1, 0);\n    }\n\n    vector<int> makeDenseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeExitMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int m = validBits[k];\n            int ex = dirToward(pos[k], pos[k + 1]);\n            m &= ~(1 << ex);\n\n            while (!isPlanOpt[k][m]) {\n                bool removed = false;\n                for (int d = 0; d < 4; d++) {\n                    if (m & (1 << d)) {\n                        m &= ~(1 << d);\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) {\n                    m = 0;\n                    break;\n                }\n            }\n            masks[k] = m;\n        }\n        return masks;\n    }\n\n    vector<int> makeSparseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 100;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = abs(pc - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planOpts[k].size());\n            masks[k] = planOpts[k][id];\n        }\n        return masks;\n    }\n\n    pair<int, vector<int>> coordinateDescent(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlan(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlan(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    struct Node {\n        int parent;\n        string add;\n    };\n\n    struct BeamState {\n        Grid g;\n        int cost;\n        int node;\n    };\n\n    string solveBeam(int keepPerBeta) {\n        vector<int> betas = {0, 70, 130, 190, 250};\n\n        vector<Node> nodes;\n        nodes.push_back({-1, \"\"});\n\n        BeamState init;\n        init.cost = 0;\n        init.node = 0;\n        vector<BeamState> beam;\n        beam.push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            vector<BeamState> gen;\n            gen.reserve(beam.size() * 40);\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(beam.size() * 64 + 100);\n            mp.max_load_factor(0.7);\n\n            int p = pos[k];\n            int goal = pos[k + 1];\n\n            auto addState = [&](const BeamState& parent, const Grid& ng, int newCost, const string& app) {\n                if (newCost > LIMIT) return;\n\n                auto it = mp.find(ng.hash);\n                if (it != mp.end()) {\n                    int idx = it->second;\n                    if (newCost >= gen[idx].cost) return;\n                }\n\n                int nodeId = (int)nodes.size();\n                nodes.push_back({parent.node, app});\n\n                BeamState ns;\n                ns.g = ng;\n                ns.cost = newCost;\n                ns.node = nodeId;\n\n                if (it == mp.end()) {\n                    mp[ng.hash] = (int)gen.size();\n                    gen.push_back(ns);\n                } else {\n                    gen[it->second] = ns;\n                }\n            };\n\n            for (const BeamState& st : beam) {\n                int candBits = 0;\n                for (int d = 0; d < 4; d++) {\n                    int q = mv[p][d];\n                    if (q < 0) continue;\n                    bool blk = isBlocked(st.g, q);\n                    if (blk || !future[k][q]) candBits |= (1 << d);\n                }\n\n                // Normal alterations at the target.\n                for (int sub = candBits;; sub = (sub - 1) & candBits) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    string path;\n                    if (bfsPath(ng, p, goal, path)) {\n                        string app = prep + path;\n                        addState(st, ng, st.cost + (int)app.size(), app);\n                    }\n\n                    if (sub == 0) break;\n                }\n\n                // Also try moving one step away and blocking the square just visited.\n                vector<int> backSubs;\n                backSubs.push_back(0);\n                for (int d = 0; d < 4; d++) if (candBits & (1 << d)) backSubs.push_back(1 << d);\n\n                for (int sub : backSubs) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    if (isBlocked(ng, p)) continue;\n\n                    for (int e = 0; e < 4; e++) {\n                        int nb = mv[p][e];\n                        if (nb < 0 || isBlocked(ng, nb)) continue;\n\n                        Grid bg = ng;\n                        setBlock(bg, p);\n\n                        string path;\n                        if (!bfsPath(bg, nb, goal, path)) continue;\n\n                        string app = prep;\n                        app.push_back(enc(0, e));\n                        app.push_back(enc(2, opp[e]));\n                        app += path;\n\n                        addState(st, bg, st.cost + (int)app.size(), app);\n                    }\n                }\n            }\n\n            if (gen.empty()) return \"\";\n\n            if (k == M - 2) {\n                int best = 0;\n                for (int i = 1; i < (int)gen.size(); i++) {\n                    if (gen[i].cost < gen[best].cost) best = i;\n                }\n\n                vector<int> chain;\n                for (int id = gen[best].node; id != -1; id = nodes[id].parent) {\n                    chain.push_back(id);\n                }\n                reverse(chain.begin(), chain.end());\n\n                string res;\n                for (int id : chain) res += nodes[id].add;\n                return res;\n            }\n\n            vector<char> mark(gen.size(), 0);\n            vector<int> idx(gen.size());\n            iota(idx.begin(), idx.end(), 0);\n\n            for (int beta : betas) {\n                int K = min(keepPerBeta, (int)idx.size());\n                auto comp = [&](int a, int b) {\n                    long long ea = 100LL * gen[a].cost - 1LL * beta * gen[a].g.cnt;\n                    long long eb = 100LL * gen[b].cost - 1LL * beta * gen[b].g.cnt;\n                    if (ea != eb) return ea < eb;\n                    return gen[a].cost < gen[b].cost;\n                };\n\n                if (K < (int)idx.size()) {\n                    nth_element(idx.begin(), idx.begin() + K, idx.end(), comp);\n                }\n\n                for (int i = 0; i < K; i++) mark[idx[i]] = 1;\n            }\n\n            vector<BeamState> nxt;\n            nxt.reserve(keepPerBeta * (int)betas.size());\n\n            for (int i = 0; i < (int)gen.size(); i++) {\n                if (mark[i]) nxt.push_back(gen[i]);\n            }\n\n            if (nxt.empty()) {\n                int best = min_element(gen.begin(), gen.end(), [](const BeamState& a, const BeamState& b) {\n                    return a.cost < b.cost;\n                }) - gen.begin();\n                nxt.push_back(gen[best]);\n            }\n\n            beam.swap(nxt);\n        }\n\n        return \"\";\n    }\n\n    void solve() {\n        cin >> N >> M;\n        pos.resize(M);\n        for (int i = 0; i < M; i++) {\n            int r, c;\n            cin >> r >> c;\n            pos[i] = r * N + c;\n        }\n\n        startTime = chrono::steady_clock::now();\n        init();\n\n        pureFallback = makePureMoves();\n        addCandidate(pureFallback);\n\n        // Beam search candidate.\n        string beamAns = solveBeam(25);\n        if (!beamAns.empty()) addCandidate(beamAns);\n\n        // Plan-coordinate-descent candidates.\n        vector<pair<int, vector<int>>> maskCands;\n\n        vector<vector<int>> starts;\n        starts.push_back(makeZeroMasks());\n        starts.push_back(makeDenseMasks());\n        starts.push_back(makeExitMasks());\n        starts.push_back(makeSparseMasks());\n        for (int i = 0; i < 4; i++) starts.push_back(makeRandomMasks());\n\n        double planEnd = 1.55;\n\n        for (auto st : starts) {\n            if (elapsed() > planEnd) break;\n            auto res = coordinateDescent(st, 3, planEnd);\n            maskCands.push_back(res);\n        }\n\n        if (maskCands.empty()) {\n            vector<int> z = makeZeroMasks();\n            maskCands.push_back({evalPlan(z), z});\n        }\n\n        sort(maskCands.begin(), maskCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedMaskKeys;\n        vector<double> backBetas = {-1.0, 0.0, 1.0, 1.5, 2.0, 2.5, 3.0};\n\n        int used = 0;\n        for (auto& pr : maskCands) {\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedMaskKeys.count(key)) continue;\n            usedMaskKeys.insert(key);\n\n            for (double beta : backBetas) {\n                string acts;\n                if (buildFromMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            used++;\n            if (used >= 8) break;\n        }\n\n        if (candidates.empty()) candidates.push_back(pureFallback);\n\n        // Choose best raw candidate, then try deletion-based cleanup.\n        string best = candidates[0];\n        for (const string& s : candidates) {\n            if (s.size() < best.size()) best = s;\n        }\n\n        vector<int> order(candidates.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return candidates[a].size() < candidates[b].size();\n        });\n\n        for (int id : order) {\n            if (elapsed() > 1.88) break;\n            string improved = greedyDelete(candidates[id]);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        if ((int)best.size() > LIMIT || firstCompletionPrefix(best) < 0) {\n            best = pureFallback;\n        }\n\n        const string A = \"MSA\";\n        const string D = \"UDLR\";\n\n        for (unsigned char ch : best) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            cout << A[type] << ' ' << D[d] << '\\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\n    return 0;\n}"},"2":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Rect {\n    int a, b, c, d;\n};\n\nstatic uint64_t splitmix64_hash(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nclass Solver {\n    static constexpr int SZ = 10000;\n    static constexpr double TIME_LIMIT = 4.82;\n\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    vector<double> rd, invR;\n    FastRNG rng;\n    Timer timer;\n\n    struct State {\n        vector<Rect> rect;\n        vector<double> val;\n        double total = 0.0;\n    };\n\n    struct Move {\n        bool ok = false;\n        int dir = 0;\n        int coord = 0;\n        double newScore = 0.0;\n        double delta = 0.0;\n    };\n\n    struct PairMove {\n        bool ok = false;\n        int orient = 0; // 0: vertical, 1: horizontal\n        int i = -1, j = -1;\n        int coord = 0;\n        double newScoreI = 0.0;\n        double newScoreJ = 0.0;\n        double delta = 0.0;\n    };\n\n    struct SplitCand {\n        int orient;\n        int k;\n        int t;\n        double cost;\n    };\n\n    long long rectArea(const Rect& rc) const {\n        return 1LL * (rc.c - rc.a) * (rc.d - rc.b);\n    }\n\n    double scoreOne(int i, long long s) const {\n        double ratio;\n        if (s <= r[i]) ratio = (double)s * invR[i];\n        else ratio = rd[i] / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    static double scoreRatio(long long s, long long target) {\n        double ratio;\n        if (s <= target) ratio = (double)s / (double)target;\n        else ratio = (double)target / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    State makeState(const vector<Rect>& rects) const {\n        State st;\n        st.rect = rects;\n        st.val.assign(n, 0.0);\n        st.total = 0.0;\n        for (int i = 0; i < n; i++) {\n            st.val[i] = scoreOne(i, rectArea(st.rect[i]));\n            st.total += st.val[i];\n        }\n        return st;\n    }\n\n    int clampLL(long long v, int lo, int hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return (int)v;\n    }\n\n    bool yOverlap(const Rect& p, const Rect& q) const {\n        return max(p.b, q.b) < min(p.d, q.d);\n    }\n\n    bool xOverlap(const Rect& p, const Rect& q) const {\n        return max(p.a, q.a) < min(p.c, q.c);\n    }\n\n    void sortIds(vector<int>& ord, int orient) const {\n        if (orient == 0) {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (x[u] != x[v]) return x[u] < x[v];\n                return y[u] < y[v];\n            });\n        } else {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (y[u] != y[v]) return y[u] < y[v];\n                return x[u] < x[v];\n            });\n        }\n    }\n\n    void buildRec(const vector<int>& ids, const Rect& box, vector<Rect>& out, double temp) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return;\n        }\n\n        long long totalR = 0;\n        for (int id : ids) totalR += r[id];\n\n        long long A = rectArea(box);\n        int W = box.c - box.a;\n        int H = box.d - box.b;\n\n        vector<SplitCand> cands;\n        cands.reserve(m * 40);\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<int> ord = ids;\n            sortIds(ord, orient);\n\n            long long pref = 0;\n            for (int k = 1; k < m; k++) {\n                pref += r[ord[k - 1]];\n\n                int lo, hi;\n                if (orient == 0) {\n                    int xl = x[ord[k - 1]];\n                    int xr = x[ord[k]];\n                    lo = max(box.a + 1, xl + 1);\n                    hi = min(box.c - 1, xr);\n                } else {\n                    int yl = y[ord[k - 1]];\n                    int yr = y[ord[k]];\n                    lo = max(box.b + 1, yl + 1);\n                    hi = min(box.d - 1, yr);\n                }\n\n                if (lo > hi) continue;\n\n                vector<int> ts;\n                ts.reserve(32);\n\n                auto addT = [&](int t) {\n                    if (t < lo || t > hi) return;\n                    for (int u : ts) if (u == t) return;\n                    ts.push_back(t);\n                };\n\n                auto addReal = [&](long double real) {\n                    long long f = (long long)floorl(real);\n                    for (long long v = f - 2; v <= f + 2; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                    long long rr = (long long)llroundl(real);\n                    for (long long v = rr - 1; v <= rr + 1; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                };\n\n                if (orient == 0) {\n                    long double prop = box.a + ((long double)A * pref / totalR) / H;\n                    long double exactL = box.a + (long double)pref / H;\n                    long double exactR = box.a + ((long double)A - (long double)(totalR - pref)) / H;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                } else {\n                    long double prop = box.b + ((long double)A * pref / totalR) / W;\n                    long double exactL = box.b + (long double)pref / W;\n                    long double exactR = box.b + ((long double)A - (long double)(totalR - pref)) / W;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                }\n\n                addT(lo);\n                addT(hi);\n\n                for (int t : ts) {\n                    long long leftA;\n                    if (orient == 0) leftA = 1LL * (t - box.a) * H;\n                    else leftA = 1LL * W * (t - box.b);\n\n                    long long rightA = A - leftA;\n                    if (leftA <= 0 || rightA <= 0) continue;\n\n                    double sc =\n                        k * scoreRatio(leftA, pref) +\n                        (m - k) * scoreRatio(rightA, totalR - pref);\n\n                    double loss = 1.0 - sc / m;\n\n                    auto aspectPenalty = [&](int ww, int hh, int cnt) -> double {\n                        if (cnt <= 1) return 0.0;\n                        double ar = max((double)ww / hh, (double)hh / ww);\n                        return 0.00025 * (cnt / (double)m) * max(0.0, log(ar) - 2.0);\n                    };\n\n                    double cost = loss;\n                    cost += 0.00020 * abs(m - 2 * k) / (double)m;\n\n                    if (orient == 0) {\n                        cost += aspectPenalty(t - box.a, H, k);\n                        cost += aspectPenalty(box.c - t, H, m - k);\n                    } else {\n                        cost += aspectPenalty(W, t - box.b, k);\n                        cost += aspectPenalty(W, box.d - t, m - k);\n                    }\n\n                    cands.push_back({orient, k, t, cost});\n                }\n            }\n        }\n\n        if (cands.empty()) {\n            for (int id : ids) {\n                out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            }\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int chosen = 0;\n        if (temp > 1e-12) {\n            double bestCost = cands[0].cost;\n            double maxDiff = max(0.03, temp * 12.0);\n\n            vector<pair<int, double>> cumulative;\n            double sum = 0.0;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                double diff = cands[i].cost - bestCost;\n                if (diff > maxDiff) continue;\n                double w = exp(-diff / temp);\n                if (w < 1e-12) continue;\n                sum += w;\n                cumulative.push_back({i, sum});\n            }\n\n            if (sum > 0.0) {\n                double z = rng.nextDouble() * sum;\n                for (auto [idx, cum] : cumulative) {\n                    if (z <= cum) {\n                        chosen = idx;\n                        break;\n                    }\n                }\n            }\n        }\n\n        SplitCand sp = cands[chosen];\n\n        vector<int> ord = ids;\n        sortIds(ord, sp.orient);\n\n        vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n        vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n        if (sp.orient == 0) {\n            Rect L{box.a, box.b, sp.t, box.d};\n            Rect R{sp.t, box.b, box.c, box.d};\n            buildRec(leftIds, L, out, temp);\n            buildRec(rightIds, R, out, temp);\n        } else {\n            Rect B{box.a, box.b, box.c, sp.t};\n            Rect T{box.a, sp.t, box.c, box.d};\n            buildRec(leftIds, B, out, temp);\n            buildRec(rightIds, T, out, temp);\n        }\n    }\n\n    vector<Rect> buildRecursive(double temp) {\n        vector<Rect> out(n);\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        buildRec(ids, Rect{0, 0, SZ, SZ}, out, temp);\n        return out;\n    }\n\n    vector<Rect> buildUnit() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; i++) {\n            rects[i] = {x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        return rects;\n    }\n\n    pair<int, int> legalInterval(const State& st, int i, int dir) const {\n        const Rect& ri = st.rect[i];\n\n        if (dir == 0) {\n            int lo = 0;\n            int hi = min(x[i], ri.c - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.a < ri.c) {\n                    lo = max(lo, rj.c);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 1) {\n            int lo = max(x[i] + 1, ri.a + 1);\n            int hi = SZ;\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.c > ri.a) {\n                    hi = min(hi, rj.a);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 2) {\n            int lo = 0;\n            int hi = min(y[i], ri.d - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (xOverlap(ri, rj) && rj.b < ri.d) {\n                    lo = max(lo, rj.d);\n                }\n            }\n            return {lo, hi};\n        }\n\n        int lo = max(y[i] + 1, ri.b + 1);\n        int hi = SZ;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& rj = st.rect[j];\n            if (xOverlap(ri, rj) && rj.d > ri.b) {\n                hi = min(hi, rj.b);\n            }\n        }\n        return {lo, hi};\n    }\n\n    int getCoord(const Rect& rc, int dir) const {\n        if (dir == 0) return rc.a;\n        if (dir == 1) return rc.c;\n        if (dir == 2) return rc.b;\n        return rc.d;\n    }\n\n    void setCoord(Rect& rc, int dir, int v) {\n        if (dir == 0) rc.a = v;\n        else if (dir == 1) rc.c = v;\n        else if (dir == 2) rc.b = v;\n        else rc.d = v;\n    }\n\n    long long areaAfterCoord(const Rect& rc, int dir, int coord) const {\n        if (dir == 0) return 1LL * (rc.c - coord) * (rc.d - rc.b);\n        if (dir == 1) return 1LL * (coord - rc.a) * (rc.d - rc.b);\n        if (dir == 2) return 1LL * (rc.c - rc.a) * (rc.d - coord);\n        return 1LL * (rc.c - rc.a) * (coord - rc.b);\n    }\n\n    Move bestEdgeDir(const State& st, int i, int dir) const {\n        Move mv;\n        mv.ok = false;\n\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return mv;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n\n        mv.ok = true;\n        mv.dir = dir;\n        mv.coord = cur;\n        mv.newScore = st.val[i];\n        mv.delta = 0.0;\n\n        int cand[48];\n        int cnt = 0;\n\n        auto addCand = [&](int v) {\n            if (v < lo) v = lo;\n            if (v > hi) v = hi;\n            for (int k = 0; k < cnt; k++) if (cand[k] == v) return;\n            cand[cnt++] = v;\n        };\n\n        addCand(cur);\n        addCand(lo);\n        addCand(hi);\n\n        long double real;\n        if (dir == 0 || dir == 1) {\n            int h = rc.d - rc.b;\n            long double wantW = (long double)r[i] / h;\n            if (dir == 0) real = rc.c - wantW;\n            else real = rc.a + wantW;\n        } else {\n            int w = rc.c - rc.a;\n            long double wantH = (long double)r[i] / w;\n            if (dir == 2) real = rc.d - wantH;\n            else real = rc.b + wantH;\n        }\n\n        long long f = (long long)floorl(real);\n        for (long long v = f - 5; v <= f + 5; v++) {\n            addCand(clampLL(v, lo, hi));\n        }\n\n        double bestScore = st.val[i];\n        int bestCoord = cur;\n\n        for (int k = 0; k < cnt; k++) {\n            int v = cand[k];\n            long long ar = areaAfterCoord(rc, dir, v);\n            double ns = scoreOne(i, ar);\n            if (ns > bestScore + 1e-15) {\n                bestScore = ns;\n                bestCoord = v;\n            }\n        }\n\n        mv.coord = bestCoord;\n        mv.newScore = bestScore;\n        mv.delta = bestScore - st.val[i];\n        return mv;\n    }\n\n    Move bestMove(const State& st, int i) const {\n        Move best;\n        best.ok = false;\n        best.delta = 0.0;\n        best.newScore = st.val[i];\n\n        for (int dir = 0; dir < 4; dir++) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) continue;\n            if (!best.ok || mv.delta > best.delta) best = mv;\n        }\n        return best;\n    }\n\n    void applyCoord(State& st, int i, int dir, int coord, double newScore) {\n        setCoord(st.rect[i], dir, coord);\n        st.total += newScore - st.val[i];\n        st.val[i] = newScore;\n    }\n\n    void applyMove(State& st, int i, const Move& mv) {\n        applyCoord(st, i, mv.dir, mv.coord, mv.newScore);\n    }\n\n    PairMove bestPairVertical(const State& st, int li, int ri) const {\n        PairMove pm;\n        pm.ok = false;\n        pm.orient = 0;\n        pm.i = li;\n        pm.j = ri;\n\n        if (li == ri) return pm;\n        const Rect& L = st.rect[li];\n        const Rect& R = st.rect[ri];\n\n        if (L.c > R.a) return pm;\n        if (!yOverlap(L, R)) return pm;\n\n        int lo1 = max(x[li] + 1, L.a + 1);\n        int hi1 = SZ;\n\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(L, K) && K.c > L.a) {\n                hi1 = min(hi1, K.a);\n            }\n        }\n\n        int lo2 = 0;\n        int hi2 = min(x[ri], R.c - 1);\n\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(R, K) && K.a < R.c) {\n                lo2 = max(lo2, K.c);\n            }\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int hL = L.d - L.b;\n        int hR = R.d - R.b;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * (t - L.a) * hL;\n            long long a2 = 1LL * (R.c - t) * hR;\n            return scoreOne(li, a1) + scoreOne(ri, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(L.c, lo, hi));\n        test(clampLL(R.a, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) {\n                test(clampLL(v, lo, hi));\n            }\n        };\n\n        addReal((long double)L.a + (long double)r[li] / hL);\n        addReal((long double)R.c - (long double)r[ri] / hR);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * (bestT - L.a) * hL;\n        long long a2 = 1LL * (R.c - bestT) * hR;\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(li, a1);\n        pm.newScoreJ = scoreOne(ri, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[li] - st.val[ri];\n        return pm;\n    }\n\n    PairMove bestPairHorizontal(const State& st, int bi, int ti) const {\n        PairMove pm;\n        pm.ok = false;\n        pm.orient = 1;\n        pm.i = bi;\n        pm.j = ti;\n\n        if (bi == ti) return pm;\n        const Rect& B = st.rect[bi];\n        const Rect& T = st.rect[ti];\n\n        if (B.d > T.b) return pm;\n        if (!xOverlap(B, T)) return pm;\n\n        int lo1 = max(y[bi] + 1, B.b + 1);\n        int hi1 = SZ;\n\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(B, K) && K.d > B.b) {\n                hi1 = min(hi1, K.b);\n            }\n        }\n\n        int lo2 = 0;\n        int hi2 = min(y[ti], T.d - 1);\n\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(T, K) && K.b < T.d) {\n                lo2 = max(lo2, K.d);\n            }\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int wB = B.c - B.a;\n        int wT = T.c - T.a;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * wB * (t - B.b);\n            long long a2 = 1LL * wT * (T.d - t);\n            return scoreOne(bi, a1) + scoreOne(ti, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(B.d, lo, hi));\n        test(clampLL(T.b, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) {\n                test(clampLL(v, lo, hi));\n            }\n        };\n\n        addReal((long double)B.b + (long double)r[bi] / wB);\n        addReal((long double)T.d - (long double)r[ti] / wT);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * wB * (bestT - B.b);\n        long long a2 = 1LL * wT * (T.d - bestT);\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(bi, a1);\n        pm.newScoreJ = scoreOne(ti, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[bi] - st.val[ti];\n        return pm;\n    }\n\n    void applyPair(State& st, const PairMove& pm) {\n        int i = pm.i;\n        int j = pm.j;\n\n        if (pm.orient == 0) {\n            st.rect[i].c = pm.coord;\n            st.rect[j].a = pm.coord;\n        } else {\n            st.rect[i].d = pm.coord;\n            st.rect[j].b = pm.coord;\n        }\n\n        st.total += pm.newScoreI - st.val[i];\n        st.total += pm.newScoreJ - st.val[j];\n\n        st.val[i] = pm.newScoreI;\n        st.val[j] = pm.newScoreJ;\n    }\n\n    void shuffleVector(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int selectBad(const State& st) {\n        int best = rng.nextInt(n);\n        double bv = st.val[best];\n\n        int K = min(n, 6);\n        for (int k = 1; k < K; k++) {\n            int j = rng.nextInt(n);\n            if (st.val[j] < bv) {\n                bv = st.val[j];\n                best = j;\n            }\n        }\n        return best;\n    }\n\n    bool greedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ord);\n\n            bool any = false;\n            for (int id : ord) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairGreedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            shuffleVector(ord);\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < n; ai++) {\n                int i = ord[ai];\n                for (int bj = ai + 1; bj < n; bj++) {\n                    if ((checks++ & 255) == 0 && timer.elapsed() > stopTime) {\n                        return globalAny;\n                    }\n\n                    int j = ord[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.ok = false;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    void randomGreedyOps(State& st, int ops, double stopTime) {\n        for (int op = 0; op < ops; op++) {\n            if ((op & 255) == 0 && timer.elapsed() > stopTime) break;\n\n            int i;\n            if (rng.nextDouble() < 0.85) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Move mv = bestMove(st, i);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyMove(st, i, mv);\n            }\n        }\n    }\n\n    bool randomPairMove(State& st) {\n        int i;\n        if (rng.nextDouble() < 0.80) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n\n        static constexpr int K = 8;\n        int cand[K];\n        int gap[K];\n        int cnt = 0;\n\n        auto addCand = [&](int j, int g) {\n            if (cnt < K) {\n                cand[cnt] = j;\n                gap[cnt] = g;\n                cnt++;\n            } else {\n                int worst = 0;\n                for (int t = 1; t < K; t++) {\n                    if (gap[t] > gap[worst]) worst = t;\n                }\n                if (g < gap[worst] || rng.nextDouble() < 0.02) {\n                    cand[worst] = j;\n                    gap[worst] = g;\n                }\n            }\n        };\n\n        const Rect& R = st.rect[i];\n\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = st.rect[j];\n\n            if (dir == 0) {\n                if (Q.c <= R.a && yOverlap(Q, R)) addCand(j, R.a - Q.c);\n            } else if (dir == 1) {\n                if (R.c <= Q.a && yOverlap(R, Q)) addCand(j, Q.a - R.c);\n            } else if (dir == 2) {\n                if (Q.d <= R.b && xOverlap(Q, R)) addCand(j, R.b - Q.d);\n            } else {\n                if (R.d <= Q.b && xOverlap(R, Q)) addCand(j, Q.b - R.d);\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int pos = 0;\n        for (int t = 1; t < cnt; t++) {\n            if (gap[t] < gap[pos]) pos = t;\n        }\n        if (rng.nextDouble() < 0.35) pos = rng.nextInt(cnt);\n\n        int j = cand[pos];\n\n        PairMove mv;\n        if (dir == 0) mv = bestPairVertical(st, j, i);\n        else if (dir == 1) mv = bestPairVertical(st, i, j);\n        else if (dir == 2) mv = bestPairHorizontal(st, j, i);\n        else mv = bestPairHorizontal(st, i, j);\n\n        if (mv.ok && mv.delta > 1e-12) {\n            applyPair(st, mv);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomResize(State& st, double temp, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.55) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return false;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n        if (lo == hi) return false;\n\n        int coord = cur;\n        double q = rng.nextDouble();\n\n        if (q < 0.25) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) return false;\n            coord = mv.coord;\n        } else if (q < 0.80) {\n            long long ar = rectArea(rc);\n            bool under = ar < r[i];\n            bool preferImprove = rng.nextDouble() < 0.72;\n\n            int sign;\n            if (dir == 0 || dir == 2) {\n                sign = under ? -1 : +1;\n            } else {\n                sign = under ? +1 : -1;\n            }\n            if (!preferImprove) sign = -sign;\n\n            int maxd = (sign < 0 ? cur - lo : hi - cur);\n            if (maxd <= 0) {\n                sign = -sign;\n                maxd = (sign < 0 ? cur - lo : hi - cur);\n            }\n\n            if (maxd > 0) {\n                int step = 1 + (int)(3000.0 * (1.0 - progress) * (1.0 - progress));\n                int d = 1 + rng.nextInt(min(maxd, step));\n                coord = cur + sign * d;\n            } else {\n                coord = lo + rng.nextInt(hi - lo + 1);\n            }\n        } else {\n            coord = lo + rng.nextInt(hi - lo + 1);\n        }\n\n        if (coord == cur) return false;\n\n        long long newArea = areaAfterCoord(rc, dir, coord);\n        double ns = scoreOne(i, newArea);\n        double delta = ns - st.val[i];\n\n        if (delta >= 0.0 || rng.nextDouble() < exp(delta / max(temp, 1e-9))) {\n            applyCoord(st, i, dir, coord, ns);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomShift(State& st, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.5) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int orient = rng.nextInt(2);\n        Rect& ri = st.rect[i];\n\n        int lo, hi;\n\n        if (orient == 0) {\n            lo = max(-ri.a, x[i] + 1 - ri.c);\n            hi = min(SZ - ri.c, x[i] - ri.a);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!yOverlap(ri, rj)) continue;\n\n                if (rj.c <= ri.a) lo = max(lo, rj.c - ri.a);\n                else if (rj.a >= ri.c) hi = min(hi, rj.a - ri.c);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.a += d;\n            ri.c += d;\n            return true;\n        } else {\n            lo = max(-ri.b, y[i] + 1 - ri.d);\n            hi = min(SZ - ri.d, y[i] - ri.b);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!xOverlap(ri, rj)) continue;\n\n                if (rj.d <= ri.b) lo = max(lo, rj.d - ri.b);\n                else if (rj.b >= ri.d) hi = min(hi, rj.b - ri.d);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.b += d;\n            ri.d += d;\n            return true;\n        }\n    }\n\n    State initialSolution() {\n        constexpr double INIT_END = 0.78;\n\n        State best;\n        bool hasBest = false;\n\n        auto consider = [&](const State& st) {\n            if (!hasBest || st.total > best.total) {\n                best = st;\n                hasBest = true;\n            }\n        };\n\n        {\n            vector<Rect> rects = buildRecursive(0.0);\n            State st = makeState(rects);\n            greedyPasses(st, 5, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            randomGreedyOps(st, 6 * n, INIT_END);\n            consider(st);\n        }\n\n        if (timer.elapsed() < INIT_END) {\n            vector<Rect> rects = buildUnit();\n            State st = makeState(rects);\n            greedyPasses(st, 7, INIT_END);\n            randomGreedyOps(st, 12 * n, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            consider(st);\n        }\n\n        while (timer.elapsed() < INIT_END) {\n            double temp = 0.00035 * pow(180.0, rng.nextDouble());\n            vector<Rect> rects = buildRecursive(temp);\n            State st = makeState(rects);\n\n            greedyPasses(st, 2, INIT_END);\n            randomGreedyOps(st, 3 * n, INIT_END);\n            consider(st);\n        }\n\n        return best;\n    }\n\n    State improve(State bestState) {\n        State cur = bestState;\n\n        double preEnd = min(TIME_LIMIT - 0.75, timer.elapsed() + 0.30);\n        pairGreedyPasses(cur, 2, preEnd);\n        greedyPasses(cur, 2, preEnd);\n        if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n        double saStart = timer.elapsed();\n        double saEnd = TIME_LIMIT - 0.35;\n\n        int iter = 0;\n        double progress = 0.0;\n        double temp = 0.05;\n\n        while (true) {\n            if ((iter & 1023) == 0) {\n                double now = timer.elapsed();\n                if (now > saEnd) break;\n\n                progress = (now - saStart) / max(1e-9, saEnd - saStart);\n                progress = min(1.0, max(0.0, progress));\n\n                double T0 = 0.050;\n                double T1 = 0.00001;\n                temp = T0 * pow(T1 / T0, progress);\n            }\n\n            double q = rng.nextDouble();\n\n            if (q < 0.06) {\n                randomShift(cur, progress);\n            } else if (q < 0.34) {\n                int i;\n                if (rng.nextDouble() < 0.82) i = selectBad(cur);\n                else i = rng.nextInt(n);\n\n                Move mv = bestMove(cur, i);\n                if (mv.ok && mv.delta > 1e-12) {\n                    applyMove(cur, i, mv);\n                }\n            } else if (q < 0.62) {\n                randomPairMove(cur);\n            } else {\n                randomResize(cur, temp, progress);\n            }\n\n            if (cur.total > bestState.total + 1e-12) {\n                bestState = cur;\n            }\n\n            if ((iter & 65535) == 0) {\n                double threshold = max(1.0, 0.015 * n);\n                if (cur.total < bestState.total - threshold) {\n                    cur = bestState;\n                }\n            }\n\n            iter++;\n        }\n\n        cur = bestState;\n\n        int stagnant = 0;\n        while (timer.elapsed() < TIME_LIMIT) {\n            bool imp = false;\n\n            imp |= pairGreedyPasses(cur, 1, TIME_LIMIT);\n            imp |= greedyPasses(cur, 1, TIME_LIMIT);\n\n            for (int k = 0; k < 384 && timer.elapsed() < TIME_LIMIT; k++) {\n                if (rng.nextDouble() < 0.35) {\n                    if (randomPairMove(cur)) imp = true;\n                } else {\n                    int i;\n                    if (rng.nextDouble() < 0.90) i = selectBad(cur);\n                    else i = rng.nextInt(n);\n\n                    Move mv = bestMove(cur, i);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(cur, i, mv);\n                        imp = true;\n                    }\n                }\n\n                if (cur.total > bestState.total + 1e-12) {\n                    bestState = cur;\n                }\n            }\n\n            if (cur.total > bestState.total + 1e-12) {\n                bestState = cur;\n            }\n\n            if (!imp) {\n                stagnant++;\n                if (stagnant >= 5) break;\n            } else {\n                stagnant = 0;\n            }\n        }\n\n        return bestState;\n    }\n\n    bool validateRects(const vector<Rect>& v) const {\n        if ((int)v.size() != n) return false;\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = v[i];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[i] && x[i] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[i] && y[i] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (xOverlap(v[i], v[j]) && yOverlap(v[i], v[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n);\n        y.resize(n);\n        r.resize(n);\n        rd.resize(n);\n        invR.resize(n);\n\n        uint64_t seed = 1234567891234567ULL;\n        for (int i = 0; i < n; i++) {\n            cin >> x[i] >> y[i] >> r[i];\n            rd[i] = (double)r[i];\n            invR[i] = 1.0 / rd[i];\n\n            uint64_t z = ((uint64_t)x[i] << 32) ^ ((uint64_t)y[i] << 16) ^ (uint64_t)r[i];\n            seed ^= splitmix64_hash(z + seed);\n        }\n        rng = FastRNG(seed);\n\n        timer.reset();\n\n        State bestState = initialSolution();\n        bestState = improve(bestState);\n\n        if (!validateRects(bestState.rect)) {\n            bestState = makeState(buildUnit());\n        }\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = bestState.rect[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc002":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int V = N * N;\n    static constexpr int MAXT = V + 5;\n    static constexpr int MAXB = (V + 63) / 64;\n\n    using Bits = array<uint64_t, MAXB>;\n\n    int si, sj;\n    int startCell;\n    int M;\n\n    int tile[V];\n    int val[V];\n    int tilePot[MAXT];\n\n    int adj[V][4];\n    int adjN[V];\n    int borderDist[V];\n\n    int vis[MAXT];\n    int visitToken = 1;\n\n    int seenCell[V];\n    int seenTile[MAXT];\n    int seenBest[MAXT];\n    int bfsStamp = 1;\n    int que[V];\n\n    Timer timer;\n    RNG rng;\n\n    // Some margin against 2.0 sec.\n    double TL = 1.93;\n\n    vector<int> bestCells;\n    vector<int> bestCum;\n    int bestScore = 0;\n\n    vector<int> curCells;\n\n    struct Params {\n        int reachW = 0;\n        int scoreW = 0;\n        int degW = 0;\n        int noise = 0;\n        int locW = 0;\n        int lossW = 0;\n        int endPenalty = 0;\n        int borderW = 0;\n        int straightW = 0;\n        int cntW = 0;\n    };\n\n    struct FloodResult {\n        int pot;\n        int cnt;\n    };\n\n    void buildAdj() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                adjN[c] = 0;\n                borderDist[c] = min(min(i, N - 1 - i), min(j, N - 1 - j));\n\n                if (i > 0) adj[c][adjN[c]++] = c - N;\n                if (i + 1 < N) adj[c][adjN[c]++] = c + N;\n                if (j > 0) adj[c][adjN[c]++] = c - 1;\n                if (j + 1 < N) adj[c][adjN[c]++] = c + 1;\n            }\n        }\n    }\n\n    void read() {\n        cin >> si >> sj;\n        startCell = si * N + sj;\n\n        uint64_t h = 0x123456789abcdefULL;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix(si);\n        mix(sj);\n\n        int maxTid = -1;\n        for (int i = 0; i < V; i++) {\n            cin >> tile[i];\n            maxTid = max(maxTid, tile[i]);\n            mix((uint64_t)tile[i] + 1009);\n        }\n\n        M = maxTid + 1;\n\n        for (int i = 0; i < V; i++) {\n            cin >> val[i];\n            mix((uint64_t)val[i] + 9176);\n        }\n\n        fill(tilePot, tilePot + MAXT, 0);\n        for (int i = 0; i < V; i++) {\n            tilePot[tile[i]] = max(tilePot[tile[i]], val[i]);\n        }\n\n        memset(vis, 0, sizeof(vis));\n        memset(seenCell, 0, sizeof(seenCell));\n        memset(seenTile, 0, sizeof(seenTile));\n\n        rng = RNG(h);\n        buildAdj();\n    }\n\n    int newVisitToken() {\n        ++visitToken;\n        if (visitToken == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            visitToken = 1;\n        }\n        return visitToken;\n    }\n\n    int newBfsStamp() {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            memset(seenCell, 0, sizeof(seenCell));\n            memset(seenTile, 0, sizeof(seenTile));\n            bfsStamp = 1;\n        }\n        return bfsStamp;\n    }\n\n    inline bool bitTest(const Bits& bits, int tid) const {\n        return (bits[tid >> 6] >> (tid & 63)) & 1ULL;\n    }\n\n    inline void bitSet(Bits& bits, int tid) const {\n        bits[tid >> 6] |= 1ULL << (tid & 63);\n    }\n\n    inline int degreeAfterToken(int cell, int forbidTid, int token) {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localNeighborSumToken(int cell, int forbidTid, int token) {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int degreeAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localSumAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    FloodResult floodPotential(int start, int forbidTid, int token) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (tid == forbidTid) continue;\n                if (vis[tid] == token) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    Params makeParams(bool flood) {\n        Params p;\n\n        if (flood) {\n            int rwArr[4] = {6, 8, 10, 12};\n            int exArr[5] = {0, 0, 2, 4, 6};\n\n            p.reachW = rwArr[rng.nextInt(4)];\n            p.scoreW = p.reachW + exArr[rng.nextInt(5)];\n\n            if (rng.nextInt(10) < 8) {\n                p.degW = 40 + rng.nextInt(260);\n            } else {\n                p.degW = -(20 + rng.nextInt(100));\n            }\n\n            p.noise = 20 + rng.nextInt(250);\n            p.locW = (rng.nextInt(4) == 0 ? 1 : 0);\n            p.cntW = rng.nextInt(6);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(16) : -rng.nextInt(8));\n            p.straightW = rng.nextInt(101) - 50;\n        } else {\n            p.scoreW = 4 + rng.nextInt(18);\n\n            int mode = rng.nextInt(10);\n            if (mode < 5) {\n                p.degW = 200 + rng.nextInt(700);\n            } else if (mode < 8) {\n                p.degW = 50 + rng.nextInt(250);\n            } else {\n                p.degW = -(20 + rng.nextInt(120));\n            }\n\n            p.noise = 100 + rng.nextInt(900);\n            p.locW = rng.nextInt(4);\n            p.lossW = rng.nextInt(8);\n            p.endPenalty = 3000 + rng.nextInt(7000);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(25) : -rng.nextInt(10));\n            p.straightW = rng.nextInt(121) - 60;\n        }\n\n        return p;\n    }\n\n    Params makePilotParam() {\n        Params p;\n        p.scoreW = 8 + rng.nextInt(22);\n\n        int mode = rng.nextInt(100);\n        if (mode < 55) {\n            p.degW = 180 + rng.nextInt(620);\n        } else if (mode < 85) {\n            p.degW = 30 + rng.nextInt(220);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = rng.nextInt(5);\n        p.lossW = rng.nextInt(9);\n        p.endPenalty = 3500 + rng.nextInt(8000);\n        p.borderW = (rng.nextInt(100) < 82 ? rng.nextInt(26) : -rng.nextInt(12));\n        p.straightW = rng.nextInt(151) - 75;\n        p.noise = 0;\n        return p;\n    }\n\n    int runGreedy(int cut, bool useFlood, const Params& par) {\n        int token = newVisitToken();\n\n        curCells.clear();\n\n        int L = (int)bestCells.size();\n        cut = max(0, min(cut, L - 1));\n        int len = cut + 1;\n\n        for (int i = 0; i < len; i++) {\n            int c = bestCells[i];\n            curCells.push_back(c);\n            vis[tile[c]] = token;\n        }\n\n        int score = bestCum[len - 1];\n        int pos = curCells.back();\n\n        int iter = 0;\n\n        while (true) {\n            if ((iter++ & 15) == 0 && timer.elapsed() > TL) break;\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (vis[tid] != token) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int prev = -1;\n            int lastDiff = 999999;\n            if ((int)curCells.size() >= 2) {\n                prev = curCells[(int)curCells.size() - 2];\n                lastDiff = pos - prev;\n            }\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterToken(cell, tid, token);\n                int loc = (par.locW ? localNeighborSumToken(cell, tid, token) : 0);\n\n                long long ev = 0;\n\n                if (useFlood) {\n                    FloodResult fr = floodPotential(cell, tid, token);\n                    ev += 1LL * par.reachW * fr.pot;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.cntW * fr.cnt;\n                } else {\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                    if (deg == 0 && nc > 1) {\n                        ev -= par.endPenalty;\n                    }\n                }\n\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                if (par.noise > 0) {\n                    ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n                }\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            vis[tid] = token;\n            score += val[nxt];\n            curCells.push_back(nxt);\n            pos = nxt;\n        }\n\n        return score;\n    }\n\n    void setBestFrom(const vector<int>& cells, int /*score*/) {\n        bestCells = cells;\n\n        bestCum.resize(bestCells.size());\n        int s = 0;\n        for (int i = 0; i < (int)bestCells.size(); i++) {\n            s += val[bestCells[i]];\n            bestCum[i] = s;\n        }\n        bestScore = s;\n    }\n\n    void considerCurrent(int score) {\n        if (score > bestScore || (score == bestScore && curCells.size() > bestCells.size())) {\n            setBestFrom(curCells, score);\n        }\n    }\n\n    int chooseCut() {\n        int L = (int)bestCells.size();\n        if (L <= 1) return 0;\n\n        int r = rng.nextInt(100);\n\n        if (r < 25) return 0;\n\n        int cut = 0;\n\n        if (r < 68) {\n            int maxSuf = min(L - 1, 900);\n            int a = 1 + rng.nextInt(maxSuf);\n            int b = 1 + rng.nextInt(maxSuf);\n            int suf;\n            if (rng.nextInt(100) < 75) {\n                suf = min(a, b);\n            } else {\n                suf = max(a, b);\n            }\n            cut = L - 1 - suf;\n        } else if (r < 88) {\n            int a = rng.nextInt(L - 1);\n            int b = rng.nextInt(L - 1);\n            cut = max(a, b);\n        } else {\n            cut = rng.nextInt(L - 1);\n        }\n\n        return max(0, min(cut, L - 2));\n    }\n\n    int rolloutScore(Bits& bits, int prev, int pos, int score, const Params& par, vector<int>* suffix) const {\n        while (true) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterBits(bits, cell, tid);\n                int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                long long ev = 0;\n                ev += 1LL * par.scoreW * val[cell];\n                ev -= 1LL * par.degW * deg;\n                ev += 1LL * par.locW * loc;\n                ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                // Deterministic tie-breaker is intentional for reproducible rollout evaluation.\n                if (ev > bestEval || (ev == bestEval && cell < candCell[bestIdx])) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            if (suffix) suffix->push_back(nxt);\n\n            prev = pos;\n            pos = nxt;\n        }\n\n        return score;\n    }\n\n    void considerRolloutPath(\n        const vector<int>& prefix,\n        int cand,\n        const Bits& bitsAfterCand,\n        int prev,\n        int scoreAfterCand,\n        const Params& par,\n        int estimatedScore\n    ) {\n        if (estimatedScore < bestScore) return;\n\n        Bits b = bitsAfterCand;\n        vector<int> suffix;\n        suffix.reserve(1000);\n\n        int exactScore = rolloutScore(b, prev, cand, scoreAfterCand, par, &suffix);\n\n        if (exactScore > bestScore ||\n            (exactScore == bestScore && prefix.size() + 1 + suffix.size() > bestCells.size())) {\n            vector<int> full;\n            full.reserve(prefix.size() + 1 + suffix.size());\n            full.insert(full.end(), prefix.begin(), prefix.end());\n            full.push_back(cand);\n            full.insert(full.end(), suffix.begin(), suffix.end());\n            setBestFrom(full, exactScore);\n        }\n    }\n\n    int runPilot(int cut, int variants) {\n        int L = (int)bestCells.size();\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> path;\n        path.reserve(V);\n\n        Bits bits;\n        bits.fill(0);\n\n        for (int i = 0; i <= cut; i++) {\n            int c = bestCells[i];\n            path.push_back(c);\n            bitSet(bits, tile[c]);\n        }\n\n        int score = bestCum[cut];\n        int pos = path.back();\n        int prev = (path.size() >= 2 ? path[path.size() - 2] : -1);\n\n        Params pars[4];\n        variants = max(1, min(variants, 4));\n        for (int i = 0; i < variants; i++) pars[i] = makePilotParam();\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int bestSim = -1;\n                int bestPar = 0;\n                Bits bestBitsAfter;\n                int scoreAfter = score + val[cell];\n\n                for (int r = 0; r < variants; r++) {\n                    Bits b = bits;\n                    bitSet(b, tid);\n\n                    int simScore = rolloutScore(b, pos, cell, scoreAfter, pars[r], nullptr);\n\n                    if (simScore > bestSim) {\n                        bestSim = simScore;\n                        bestPar = r;\n                        bestBitsAfter = bits;\n                        bitSet(bestBitsAfter, tid);\n                    }\n                }\n\n                if (bestSim >= bestScore) {\n                    considerRolloutPath(path, cell, bestBitsAfter, pos, scoreAfter, pars[bestPar], bestSim);\n                }\n\n                long long ev = 1LL * bestSim * 1000;\n                ev += 3LL * val[cell];\n\n                // Small diversification; terminal rollout score remains dominant.\n                ev += rng.nextInt(1001) - 500;\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            path.push_back(nxt);\n\n            prev = pos;\n            pos = nxt;\n\n            if (score > bestScore || (score == bestScore && path.size() > bestCells.size())) {\n                setBestFrom(path, score);\n            }\n\n            if ((++iter & 7) == 0 && timer.elapsed() > TL) break;\n        }\n\n        if (score > bestScore || (score == bestScore && path.size() > bestCells.size())) {\n            setBestFrom(path, score);\n        }\n\n        return score;\n    }\n\n    struct BeamNode {\n        int parent;\n        int cell;\n        int score;\n    };\n\n    struct BeamState {\n        Bits bits;\n        int pos;\n        int prev;\n        int score;\n        int node;\n        long long eval;\n    };\n\n    void runBeam(double endTime, int width) {\n        if (timer.elapsed() >= endTime) return;\n\n        vector<BeamNode> nodes;\n        nodes.reserve(width * 1200);\n\n        vector<BeamState> cur, nxt, cand;\n        cur.reserve(width);\n        nxt.reserve(width);\n        cand.reserve(width * 4 + 10);\n\n        BeamState init;\n        init.bits.fill(0);\n        bitSet(init.bits, tile[startCell]);\n        init.pos = startCell;\n        init.prev = -1;\n        init.score = val[startCell];\n        init.node = 0;\n        init.eval = init.score;\n\n        nodes.push_back({-1, startCell, val[startCell]});\n        cur.push_back(init);\n\n        int localBestScore = val[startCell];\n        int localBestNode = 0;\n\n        int degBias = -120 + rng.nextInt(241);\n        int noise = 2000 + rng.nextInt(4000);\n\n        for (int depth = 0; depth < M && !cur.empty(); depth++) {\n            if (timer.elapsed() >= endTime) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    int tid = tile[nb];\n\n                    if (bitTest(st.bits, tid)) continue;\n\n                    BeamState ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.prev = st.pos;\n                    ch.pos = nb;\n                    ch.score = st.score + val[nb];\n                    ch.node = st.node;\n\n                    int deg = degreeAfterBits(st.bits, nb, tid);\n                    int loc = localSumAfterBits(st.bits, nb, tid);\n\n                    long long ev = 1LL * ch.score * 100;\n                    ev += 3LL * loc;\n                    ev += 1LL * degBias * deg;\n                    ev -= 10LL * borderDist[nb];\n\n                    if (deg == 0) ev -= 4000;\n                    ev += rng.nextInt(noise);\n\n                    ch.eval = ev;\n                    cand.push_back(ch);\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            nxt.clear();\n\n            for (auto& ch : cand) {\n                int parent = ch.node;\n                nodes.push_back({parent, ch.pos, ch.score});\n                ch.node = (int)nodes.size() - 1;\n\n                if (ch.score > localBestScore) {\n                    localBestScore = ch.score;\n                    localBestNode = ch.node;\n                }\n\n                nxt.push_back(std::move(ch));\n            }\n\n            cur.swap(nxt);\n        }\n\n        if (localBestScore >= bestScore) {\n            vector<int> cells;\n            int x = localBestNode;\n            while (x != -1) {\n                cells.push_back(nodes[x].cell);\n                x = nodes[x].parent;\n            }\n            reverse(cells.begin(), cells.end());\n\n            if (localBestScore > bestScore ||\n                (localBestScore == bestScore && cells.size() > bestCells.size())) {\n                setBestFrom(cells, localBestScore);\n            }\n        }\n\n        // Complete several beam prefixes with deterministic rollouts.\n        if (!cur.empty() && timer.elapsed() < endTime + 0.08) {\n            int take = min<int>(20, cur.size());\n            nth_element(\n                cur.begin(),\n                cur.begin() + take,\n                cur.end(),\n                [](const BeamState& a, const BeamState& b) {\n                    return a.score > b.score;\n                }\n            );\n            cur.resize(take);\n\n            for (auto& st : cur) {\n                if (timer.elapsed() > endTime + 0.10) break;\n\n                vector<int> prefix;\n                int x = st.node;\n                while (x != -1) {\n                    prefix.push_back(nodes[x].cell);\n                    x = nodes[x].parent;\n                }\n                reverse(prefix.begin(), prefix.end());\n\n                Params p = makePilotParam();\n                Bits b = st.bits;\n                vector<int> suffix;\n                suffix.reserve(1000);\n\n                int sc = rolloutScore(b, st.prev, st.pos, st.score, p, &suffix);\n\n                if (sc > bestScore ||\n                    (sc == bestScore && prefix.size() + suffix.size() > bestCells.size())) {\n                    vector<int> full = prefix;\n                    full.insert(full.end(), suffix.begin(), suffix.end());\n                    setBestFrom(full, sc);\n                }\n            }\n        }\n    }\n\n    string cellsToMoves(const vector<int>& cells) const {\n        string s;\n        s.reserve(cells.size());\n\n        for (int i = 1; i < (int)cells.size(); i++) {\n            int d = cells[i] - cells[i - 1];\n\n            if (d == -N) s.push_back('U');\n            else if (d == N) s.push_back('D');\n            else if (d == -1) s.push_back('L');\n            else if (d == 1) s.push_back('R');\n        }\n\n        return s;\n    }\n\n    string solve() {\n        timer.reset();\n\n        bestCells.clear();\n        bestCum.clear();\n\n        bestCells.push_back(startCell);\n        bestCum.push_back(val[startCell]);\n        bestScore = val[startCell];\n\n        curCells.reserve(V);\n\n        // Quick initial diverse paths.\n        for (int i = 0; i < 22 && timer.elapsed() < 0.09; i++) {\n            bool flood = (i % 6 == 0);\n            Params par = makeParams(flood);\n            int sc = runGreedy(0, flood, par);\n            considerCurrent(sc);\n        }\n\n        // Beam gives useful early-prefix diversity.\n        runBeam(0.24, 280);\n\n        // Main phase: mix pilot rollout search and previous greedy suffix repair.\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            double e = timer.elapsed();\n\n            int cut = 0;\n            if (iter > 8 && bestCells.size() >= 2 && rng.nextInt(100) >= 35) {\n                cut = chooseCut();\n            }\n\n            int mode = rng.nextInt(100);\n\n            if (mode < 62 && e < TL - 0.015) {\n                int variants;\n                if (e < 0.85) variants = 2;\n                else variants = (rng.nextInt(100) < 35 ? 2 : 1);\n\n                runPilot(cut, variants);\n            } else {\n                int floodProb = (e < 0.80 ? 38 : 52);\n                bool flood = (rng.nextInt(100) < floodProb);\n                Params par = makeParams(flood);\n\n                int sc = runGreedy(cut, flood, par);\n                considerCurrent(sc);\n            }\n\n            iter++;\n        }\n\n        return cellsToMoves(bestCells);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read();\n\n    cout << solver.solve() << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int LINE_VARS = 2 * N;          // 30 horizontal rows + 30 vertical columns\nstatic constexpr int BINS = 4;\nstatic constexpr int HBIN_VARS = N * BINS;\nstatic constexpr int BIN_VARS = 2 * N * BINS;\nstatic constexpr int SEG_VARS = 2 * LINE_VARS;   // 2 segments for each line\nstatic constexpr int EXPLORE_TURNS = 100;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    return min(hi, max(lo, x));\n}\n\nstatic inline int popcnt(uint32_t x) {\n    return __builtin_popcount(x);\n}\n\nstatic inline uint32_t lowMask(int x) {\n    if (x <= 0) return 0;\n    return (1u << x) - 1u; // x <= 29\n}\n\nstruct RidgeModel {\n    int n;\n    vector<double> ata;\n    vector<double> atb;\n\n    RidgeModel(int n_ = 0) : n(n_), ata(n_ * n_, 0.0), atb(n_, 0.0) {}\n\n    void addObservation(const vector<pair<int, int>>& counts, int steps, double result) {\n        if (steps <= 0) return;\n\n        vector<pair<int, double>> f;\n        f.reserve(counts.size());\n\n        double inv_steps = 1.0 / steps;\n        for (auto [idx, cnt] : counts) {\n            if (cnt > 0) f.push_back({idx, cnt * inv_steps});\n        }\n\n        double target = result * inv_steps;\n\n        for (auto [ia, va] : f) {\n            double* row = &ata[ia * n];\n            atb[ia] += va * target;\n            for (auto [ib, vb] : f) {\n                row[ib] += va * vb;\n            }\n        }\n    }\n\n    void solve(const vector<double>& prior, double lambda, vector<double>& out) const {\n        vector<double> a = ata;\n        vector<double> b(n);\n\n        for (int i = 0; i < n; i++) {\n            a[i * n + i] += lambda;\n            b[i] = atb[i] + lambda * prior[i];\n        }\n\n        // Cholesky decomposition: A = L L^T, lower triangle is used.\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j <= i; j++) {\n                double sum = a[i * n + j];\n                for (int k = 0; k < j; k++) {\n                    sum -= a[i * n + k] * a[j * n + k];\n                }\n\n                if (i == j) {\n                    if (sum < 1e-9) sum = 1e-9;\n                    a[i * n + j] = sqrt(sum);\n                } else {\n                    a[i * n + j] = sum / a[j * n + j];\n                }\n            }\n        }\n\n        vector<double> y(n);\n        for (int i = 0; i < n; i++) {\n            double sum = b[i];\n            for (int k = 0; k < i; k++) sum -= a[i * n + k] * y[k];\n            y[i] = sum / a[i * n + i];\n        }\n\n        out.assign(n, 0.0);\n        for (int i = n - 1; i >= 0; i--) {\n            double sum = y[i];\n            for (int k = i + 1; k < n; k++) sum -= a[k * n + i] * out[k];\n            out[i] = sum / a[i * n + i];\n            out[i] = clampd(out[i], 1000.0, 9000.0);\n        }\n    }\n};\n\nstruct Observation {\n    int result = 0;\n    int steps = 0;\n    array<uint32_t, LINE_VARS> mask;\n\n    Observation() {\n        mask.fill(0);\n    }\n};\n\nstruct Solver {\n    RidgeModel lineModel;\n    RidgeModel binModel;\n\n    vector<double> lineEst;\n    vector<double> binDelta;\n    vector<double> segEst;\n\n    array<int, LINE_VARS> lineSeen{};\n    array<int, BIN_VARS> binSeen{};\n    array<int, LINE_VARS> split{};\n    array<int, SEG_VARS> segSupport{};\n\n    vector<Observation> observations;\n\n    mt19937 rng;\n    int turn = 0;\n    double segGlobalConf = 0.0;\n\n    Solver()\n        : lineModel(LINE_VARS),\n          binModel(BIN_VARS),\n          lineEst(LINE_VARS, 5000.0),\n          binDelta(BIN_VARS, 0.0),\n          segEst(SEG_VARS, 5000.0),\n          rng(1234567) {\n        lineSeen.fill(0);\n        binSeen.fill(0);\n        split.fill(14);\n        segSupport.fill(0);\n    }\n\n    static int hVar(int i, int j) {\n        int q = j * BINS / (N - 1);\n        return i * BINS + q;\n    }\n\n    static int vVar(int i, int j) {\n        int q = i * BINS / (N - 1);\n        return HBIN_VARS + j * BINS + q;\n    }\n\n    double globalWeight() const {\n        return clampd(turn / 300.0, 0.0, 1.0);\n    }\n\n    double binWeight() const {\n        return clampd((turn - 80) / 420.0, 0.0, 1.0);\n    }\n\n    double segmentWeight() const {\n        double t = clampd((turn - 110) / 390.0, 0.0, 1.0);\n        return t * segGlobalConf;\n    }\n\n    double hCost(int i, int j) const {\n        int line = i;\n        int bv = hVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (j < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        raw = clampd(raw, 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCost(int i, int j) const {\n        int line = N + j;\n        int bv = vVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (i < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        raw = clampd(raw, 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    static void appendVertical(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    }\n\n    static void appendHorizontal(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    }\n\n    string makeDirect(int si, int sj, int ti, int tj, bool horizontalFirst) const {\n        string s;\n        if (horizontalFirst) {\n            appendHorizontal(s, sj, tj);\n            appendVertical(s, si, ti);\n        } else {\n            appendVertical(s, si, ti);\n            appendHorizontal(s, sj, tj);\n        }\n        return s;\n    }\n\n    string makeViaRow(int si, int sj, int ti, int tj, int r) const {\n        string s;\n        appendVertical(s, si, r);\n        appendHorizontal(s, sj, tj);\n        appendVertical(s, r, ti);\n        return s;\n    }\n\n    string makeViaCol(int si, int sj, int ti, int tj, int c) const {\n        string s;\n        appendHorizontal(s, sj, c);\n        appendVertical(s, si, ti);\n        appendHorizontal(s, c, tj);\n        return s;\n    }\n\n    bool validatePath(int si, int sj, int ti, int tj, const string& path) const {\n        array<char, N * N> vis{};\n        int r = si, c = sj;\n        vis[r * N + c] = 1;\n\n        for (char ch : path) {\n            if (ch == 'U') r--;\n            else if (ch == 'D') r++;\n            else if (ch == 'L') c--;\n            else if (ch == 'R') c++;\n            else return false;\n\n            if (r < 0 || r >= N || c < 0 || c >= N) return false;\n\n            int id = r * N + c;\n            if (vis[id]) return false;\n            vis[id] = 1;\n        }\n\n        return r == ti && c == tj;\n    }\n\n    double estimatePathCost(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCost(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCost(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCost(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCost(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double explorationSeenScore(int si, int sj, const string& path) const {\n        array<char, LINE_VARS> lu{};\n        array<char, BIN_VARS> bu{};\n\n        int r = si, c = sj;\n\n        for (char ch : path) {\n            int line = -1, bv = -1;\n\n            if (ch == 'R') {\n                line = r;\n                bv = hVar(r, c);\n                c++;\n            } else if (ch == 'L') {\n                c--;\n                line = r;\n                bv = hVar(r, c);\n            } else if (ch == 'D') {\n                line = N + c;\n                bv = vVar(r, c);\n                r++;\n            } else if (ch == 'U') {\n                r--;\n                line = N + c;\n                bv = vVar(r, c);\n            }\n\n            if (line >= 0) lu[line] = 1;\n            if (bv >= 0) bu[bv] = 1;\n        }\n\n        double score = 0.0;\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lu[i]) score += lineSeen[i];\n        }\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (bu[i]) score += 0.35 * binSeen[i];\n        }\n\n        return score;\n    }\n\n    string chooseBestDirect(int si, int sj, int ti, int tj) const {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        return (c1 <= c2 ? p1 : p2);\n    }\n\n    string chooseExplorationPath(int si, int sj, int ti, int tj) {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        double s1 = explorationSeenScore(si, sj, p1);\n        double s2 = explorationSeenScore(si, sj, p2);\n\n        double bonus = 1500.0 * (1.0 - turn / double(EXPLORE_TURNS));\n\n        double v1 = c1 + bonus * s1;\n        double v2 = c2 + bonus * s2;\n\n        if (abs(v1 - v2) < 1e-9) {\n            return (rng() & 1) ? p1 : p2;\n        }\n        return (v1 <= v2 ? p1 : p2);\n    }\n\n    string bestCorridorPath(int si, int sj, int ti, int tj) const {\n        string best;\n        double bestCost = 1e100;\n\n        auto consider = [&](const string& p) {\n            if (!validatePath(si, sj, ti, tj, p)) return;\n\n            double c = estimatePathCost(si, sj, p);\n            if (c < bestCost - 1e-9 ||\n                (abs(c - bestCost) < 1e-9 && (best.empty() || p.size() < best.size()))) {\n                bestCost = c;\n                best = p;\n            }\n        };\n\n        consider(makeDirect(si, sj, ti, tj, true));\n        consider(makeDirect(si, sj, ti, tj, false));\n\n        for (int r = 0; r < N; r++) {\n            consider(makeViaRow(si, sj, ti, tj, r));\n        }\n        for (int c = 0; c < N; c++) {\n            consider(makeViaCol(si, sj, ti, tj, c));\n        }\n\n        if (best.empty()) best = chooseBestDirect(si, sj, ti, tj);\n        return best;\n    }\n\n    string dijkstra(int si, int sj, int ti, int tj) const {\n        int S = si * N + sj;\n        int T = ti * N + tj;\n\n        const double INF = 1e100;\n        vector<double> dist(N * N, INF);\n        vector<int> pre(N * N, -1);\n        vector<char> pmove(N * N, 0);\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[S] = 0.0;\n        pre[S] = S;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n\n            if (d > dist[u] + 1e-9) continue;\n            if (u == T) break;\n\n            int r = u / N;\n            int c = u % N;\n\n            int dirs[4];\n            bool used[4] = {};\n            int m = 0;\n\n            auto addDir = [&](int x) {\n                if (!used[x]) {\n                    used[x] = true;\n                    dirs[m++] = x;\n                }\n            };\n\n            if (ti < r) addDir(0); // U\n            if (ti > r) addDir(1); // D\n            if (tj < c) addDir(2); // L\n            if (tj > c) addDir(3); // R\n            for (int x = 0; x < 4; x++) addDir(x);\n\n            for (int idx = 0; idx < 4; idx++) {\n                int dir = dirs[idx];\n\n                int nr = r, nc = c;\n                char mv = '?';\n                double w = 0.0;\n\n                if (dir == 0) {\n                    if (r == 0) continue;\n                    nr = r - 1;\n                    mv = 'U';\n                    w = vCost(r - 1, c);\n                } else if (dir == 1) {\n                    if (r == N - 1) continue;\n                    nr = r + 1;\n                    mv = 'D';\n                    w = vCost(r, c);\n                } else if (dir == 2) {\n                    if (c == 0) continue;\n                    nc = c - 1;\n                    mv = 'L';\n                    w = hCost(r, c - 1);\n                } else {\n                    if (c == N - 1) continue;\n                    nc = c + 1;\n                    mv = 'R';\n                    w = hCost(r, c);\n                }\n\n                int v = nr * N + nc;\n                double nd = d + w;\n\n                if (nd + 1e-9 < dist[v]) {\n                    dist[v] = nd;\n                    pre[v] = u;\n                    pmove[v] = mv;\n                    pq.push({nd, v});\n                }\n            }\n        }\n\n        if (pre[T] == -1) return \"\";\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmove[cur]);\n            cur = pre[cur];\n            if (cur < 0) return \"\";\n        }\n\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    string choosePath(int si, int sj, int ti, int tj) {\n        if (turn < EXPLORE_TURNS) {\n            return chooseExplorationPath(si, sj, ti, tj);\n        }\n\n        string safe = bestCorridorPath(si, sj, ti, tj);\n        string p = dijkstra(si, sj, ti, tj);\n\n        if (p.empty() || !validatePath(si, sj, ti, tj, p)) {\n            return safe;\n        }\n\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        int extraLimit;\n        if (turn < 200) extraLimit = 12;\n        else if (turn < 350) extraLimit = 25;\n        else if (turn < 500) extraLimit = 45;\n        else if (turn < 700) extraLimit = 65;\n        else extraLimit = 80 + int(20.0 * segGlobalConf);\n\n        double cd = estimatePathCost(si, sj, p);\n        double cs = estimatePathCost(si, sj, safe);\n\n        int extra = int(p.size()) - manhattan;\n\n        // Strong protection against suspiciously long detours.\n        if (extra > extraLimit) {\n            if ((int)p.size() > manhattan + 130) return safe;\n            if (cd > cs * 0.82) return safe;\n        }\n\n        // If Dijkstra is much longer than a robust corridor path, require\n        // a meaningful estimated gain.\n        int lenDiff = int(p.size()) - int(safe.size());\n        if (lenDiff > 30) {\n            double requiredRatio = 1.0 - min(0.08, 0.001 * lenDiff);\n            if (cd > cs * requiredRatio) return safe;\n        }\n\n        return p;\n    }\n\n    void updateModelsWithResult(int si, int sj, const string& path, int result) {\n        Observation ob;\n        ob.result = result;\n        ob.steps = (int)path.size();\n\n        array<int, LINE_VARS> lineCnt{};\n        array<int, BIN_VARS> binCnt{};\n\n        int r = si;\n        int c = sj;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n\n                c++;\n            } else if (ch == 'L') {\n                c--;\n\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n            } else if (ch == 'D') {\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n\n                r++;\n            } else if (ch == 'U') {\n                r--;\n\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n            }\n        }\n\n        vector<pair<int, int>> lf;\n        vector<pair<int, int>> bf;\n\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lineCnt[i] > 0) {\n                lf.push_back({i, lineCnt[i]});\n                lineSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (binCnt[i] > 0) {\n                bf.push_back({i, binCnt[i]});\n                binSeen[i]++;\n            }\n        }\n\n        lineModel.addObservation(lf, ob.steps, result);\n        binModel.addObservation(bf, ob.steps, result);\n        observations.push_back(ob);\n    }\n\n    double predictObsSegment(const Observation& ob) const {\n        double sum = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            uint32_t m = ob.mask[line];\n            if (!m) continue;\n\n            int total = popcnt(m);\n            int x = split[line];\n            int cl = popcnt(m & lowMask(x));\n            int cr = total - cl;\n\n            sum += segEst[2 * line] * cl;\n            sum += segEst[2 * line + 1] * cr;\n        }\n\n        return sum / ob.steps;\n    }\n\n    void seedSplitsFromBin() {\n        static const int bounds[3] = {8, 15, 22};\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 2) continue;\n\n            double val[BINS];\n\n            for (int q = 0; q < BINS; q++) {\n                int idx;\n                if (line < N) idx = line * BINS + q;\n                else idx = HBIN_VARS + (line - N) * BINS + q;\n\n                val[q] = lineEst[line] + binDelta[idx];\n            }\n\n            double bestDiff = 0.0;\n            int bestBoundary = split[line];\n\n            for (int q = 0; q + 1 < BINS; q++) {\n                double d = abs(val[q + 1] - val[q]);\n                if (d > bestDiff) {\n                    bestDiff = d;\n                    bestBoundary = bounds[q];\n                }\n            }\n\n            double segDiff = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (bestDiff > 450.0 &&\n                (segDiff < 700.0 || observations.size() < 180)) {\n                split[line] = bestBoundary;\n            }\n        }\n    }\n\n    void solveSegmentRidge(double lambda) {\n        RidgeModel model(SEG_VARS);\n        segSupport.fill(0);\n\n        for (const auto& ob : observations) {\n            vector<pair<int, int>> f;\n            f.reserve(16);\n\n            for (int line = 0; line < LINE_VARS; line++) {\n                uint32_t m = ob.mask[line];\n                if (!m) continue;\n\n                int total = popcnt(m);\n                int x = split[line];\n                int cl = popcnt(m & lowMask(x));\n                int cr = total - cl;\n\n                if (cl > 0) {\n                    f.push_back({2 * line, cl});\n                    segSupport[2 * line] += cl;\n                }\n                if (cr > 0) {\n                    f.push_back({2 * line + 1, cr});\n                    segSupport[2 * line + 1] += cr;\n                }\n            }\n\n            model.addObservation(f, ob.steps, ob.result);\n        }\n\n        vector<double> prior(SEG_VARS);\n        for (int i = 0; i < SEG_VARS; i++) {\n            prior[i] = lineEst[i / 2];\n        }\n\n        model.solve(prior, lambda, segEst);\n    }\n\n    void refineSplits() {\n        int m = (int)observations.size();\n        if (m < 60) return;\n\n        vector<double> pred(m);\n        vector<double> target(m);\n\n        for (int i = 0; i < m; i++) {\n            pred[i] = predictObsSegment(observations[i]);\n            target[i] = observations[i].result / double(observations[i].steps);\n        }\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            double v0 = segEst[2 * line];\n            double v1 = segEst[2 * line + 1];\n\n            if (abs(v0 - v1) < 250.0) continue;\n\n            int active = 0;\n            for (const auto& ob : observations) {\n                if (ob.mask[line]) active++;\n            }\n\n            if (active < 8) continue;\n\n            int oldX = split[line];\n            uint32_t oldMask = lowMask(oldX);\n\n            double bestSSE = 1e100;\n            double oldSSE = 1e100;\n            int bestX = oldX;\n\n            for (int x = 1; x <= 28; x++) {\n                uint32_t xm = lowMask(x);\n                double sse = 0.0;\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    double baseResidualTarget = target[idx] - pred[idx] + oldContr;\n\n                    int newLeft = popcnt(mask & xm);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    double res = baseResidualTarget - newContr;\n                    sse += res * res;\n                }\n\n                if (x == oldX) oldSSE = sse;\n\n                if (sse < bestSSE) {\n                    bestSSE = sse;\n                    bestX = x;\n                }\n            }\n\n            double threshold = max(20000.0, 0.001 * oldSSE);\n\n            if (bestX != oldX && bestSSE + threshold < oldSSE) {\n                uint32_t newMask = lowMask(bestX);\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    int newLeft = popcnt(mask & newMask);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    pred[idx] += newContr - oldContr;\n                }\n\n                split[line] = bestX;\n            }\n        }\n    }\n\n    void updateSegmentConfidence() {\n        int strong = 0;\n        int usable = 0;\n        double sumConf = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 3) continue;\n            if (segSupport[2 * line] < 6) continue;\n            if (segSupport[2 * line + 1] < 6) continue;\n\n            usable++;\n\n            double d = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (d > 900.0) strong++;\n            sumConf += clampd((d - 500.0) / 1500.0, 0.0, 1.0);\n        }\n\n        double c1 = clampd((strong - 4) / 18.0, 0.0, 1.0);\n\n        double c2 = 0.0;\n        if (usable > 0) {\n            double avg = sumConf / usable;\n            c2 = clampd((avg - 0.12) / 0.38, 0.0, 1.0);\n        }\n\n        segGlobalConf = max(c1, 0.8 * c2);\n    }\n\n    void solveModels(int observationsCount) {\n        vector<double> priorLine(LINE_VARS, 5000.0);\n        lineModel.solve(priorLine, 0.1, lineEst);\n\n        int binPeriod = (observationsCount < 300 ? 10 : 20);\n        if (observationsCount % binPeriod == 0) {\n            vector<double> priorBin(BIN_VARS);\n\n            for (int i = 0; i < N; i++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[i * BINS + q] = lineEst[i];\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[HBIN_VARS + j * BINS + q] = lineEst[N + j];\n                }\n            }\n\n            double prog = min(1.0, observationsCount / 800.0);\n            double lambdaBin = 1.5 - prog; // 1.5 -> 0.5\n\n            vector<double> absBin;\n            binModel.solve(priorBin, lambdaBin, absBin);\n\n            for (int i = 0; i < BIN_VARS; i++) {\n                binDelta[i] = absBin[i] - priorBin[i];\n            }\n        }\n\n        if (observationsCount >= 80) {\n            int segPeriod = (observationsCount < 300 ? 20 : 30);\n\n            if (observationsCount % segPeriod == 0) {\n                seedSplitsFromBin();\n\n                double prog = min(1.0, observationsCount / 900.0);\n                double lambdaSeg = 0.9 - 0.55 * prog; // 0.9 -> 0.35\n\n                solveSegmentRidge(lambdaSeg);\n                refineSplits();\n                solveSegmentRidge(lambdaSeg);\n                updateSegmentConfidence();\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.turn = k;\n\n        string path = solver.choosePath(si, sj, ti, tj);\n\n        cout << path << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.updateModelsWithResult(si, sj, path, result);\n        solver.solveModels(k + 1);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int SZ = 20;\nstatic const int CELLS = 400;\nstatic const int POS = 800;\nstatic const int DOT = 8;\nstatic const int MAXPLEN = 20;\nstatic const int MAXL = 12;\nstatic const int MASK_WORDS = 13;\n\nusing Mask = array<uint64_t, MASK_WORDS>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int randint(int n) {\n        return (int)(next() % n);\n    }\n    double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\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\nint M_input;\nint U;\nint TOTAL;\ndouble avgLen = 0.0;\nint maxLenInput = 0;\n\nvector<string> uniqStr;\nvector<vector<uint8_t>> S;\nvector<int> Ls, W;\n\nuint16_t posCell[POS][MAXPLEN];\nvector<uint32_t> cellIncs[CELLS];\n\nint nearVal[13][13];\n\nXorShift rng;\n\ninline int countDotsVec(const vector<uint8_t>& g) {\n    int d = 0;\n    for (auto x : g) if (x == DOT) d++;\n    return d;\n}\n\nvoid initNearVal() {\n    memset(nearVal, 0, sizeof(nearVal));\n    for (int l = 1; l <= 12; l++) {\n        for (int m = 0; m <= l; m++) {\n            int q = l - m;\n            nearVal[l][m] = q * q * q;\n        }\n    }\n}\n\nvoid initPosCells() {\n    for (int pos = 0; pos < POS; pos++) {\n        for (int p = 0; p < MAXPLEN; p++) {\n            if (pos < 400) {\n                int r = pos / SZ;\n                int c = pos % SZ;\n                posCell[pos][p] = r * SZ + (c + p) % SZ;\n            } else {\n                int q = pos - 400;\n                int r = q / SZ;\n                int c = q % SZ;\n                posCell[pos][p] = ((r + p) % SZ) * SZ + c;\n            }\n        }\n    }\n}\n\nvoid buildIncidences() {\n    long long totalInc = 0;\n    for (int i = 0; i < U; i++) totalInc += 1LL * POS * Ls[i];\n    int reserveEach = (int)(totalInc / CELLS + 100);\n    for (int c = 0; c < CELLS; c++) cellIncs[c].reserve(reserveEach);\n\n    for (int sid = 0; sid < U; sid++) {\n        int base = sid * POS;\n        for (int pos = 0; pos < POS; pos++) {\n            int pid = base + pos;\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[pos][p];\n                uint32_t code = (uint32_t(pid) << 3) | uint32_t(S[sid][p]);\n                cellIncs[cell].push_back(code);\n            }\n        }\n    }\n}\n\nstruct State {\n    vector<uint8_t> grid;\n    vector<uint8_t> mism;\n    vector<uint16_t> cover;\n    vector<array<uint16_t, 13>> hist;\n    vector<array<int16_t, 13>> hdelta;\n\n    int obj = 0;\n\n    vector<int> markP, markS;\n    vector<int16_t> deltaM, deltaC;\n    vector<int> touchedP, touchedS;\n    int tagP = 1, tagS = 1;\n\n    void init() {\n        int Ptot = U * POS;\n        grid.assign(CELLS, DOT);\n        mism.assign(Ptot, 0);\n        cover.assign(U, 0);\n        hist.resize(U);\n        hdelta.resize(U);\n        for (auto& a : hist) a.fill(0);\n        for (auto& a : hdelta) a.fill(0);\n\n        markP.assign(Ptot, 0);\n        markS.assign(U, 0);\n        deltaM.assign(Ptot, 0);\n        deltaC.assign(U, 0);\n        touchedP.reserve(250000);\n        touchedS.reserve(U);\n    }\n\n    void nextTagP() {\n        ++tagP;\n        if (tagP == INT_MAX) {\n            fill(markP.begin(), markP.end(), 0);\n            tagP = 1;\n        }\n    }\n\n    void nextTagS() {\n        ++tagS;\n        if (tagS == INT_MAX) {\n            fill(markS.begin(), markS.end(), 0);\n            tagS = 1;\n        }\n    }\n\n    void build(const vector<uint8_t>& g) {\n        grid = g;\n        fill(cover.begin(), cover.end(), 0);\n        obj = 0;\n\n        for (int sid = 0; sid < U; sid++) {\n            hist[sid].fill(0);\n            int base = sid * POS;\n            const auto& str = S[sid];\n            int len = Ls[sid];\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = 0;\n                for (int p = 0; p < len; p++) {\n                    if (grid[posCell[pos][p]] != str[p]) m++;\n                }\n                mism[base + pos] = (uint8_t)m;\n                hist[sid][m]++;\n            }\n\n            cover[sid] = hist[sid][0];\n            if (cover[sid] > 0) obj += W[sid];\n        }\n    }\n\n    int evalChanges(const int cells[], const uint8_t vals[], int cnt) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        auto addSid = [&](int sid, int dc) {\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                deltaC[sid] = 0;\n                touchedS.push_back(sid);\n            }\n            deltaC[sid] += (int16_t)dc;\n        };\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (oldm == 0 && newm > 0) addSid(sid, -1);\n            else if (oldm > 0 && newm == 0) addSid(sid, +1);\n        }\n\n        int delta = 0;\n        for (int sid : touchedS) {\n            int cc = cover[sid];\n            int nc = cc + deltaC[sid];\n            if (cc == 0 && nc > 0) delta += W[sid];\n            else if (cc > 0 && nc == 0) delta -= W[sid];\n        }\n        return delta;\n    }\n\n    long long evalChangesSoft(const int cells[], const uint8_t vals[], int cnt, long long exactBonus) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                hdelta[sid].fill(0);\n                touchedS.push_back(sid);\n            }\n\n            hdelta[sid][oldm]--;\n            hdelta[sid][newm]++;\n        }\n\n        long long exactDelta = 0;\n        long long nearDelta = 0;\n\n        for (int sid : touchedS) {\n            int oldCov = cover[sid];\n            int newCov = hist[sid][0] + hdelta[sid][0];\n\n            if (oldCov == 0 && newCov > 0) exactDelta += W[sid];\n            else if (oldCov > 0 && newCov == 0) exactDelta -= W[sid];\n\n            int len = Ls[sid];\n\n            int oldMin = 0;\n            while (oldMin <= len && hist[sid][oldMin] == 0) oldMin++;\n\n            int newMin = 0;\n            while (newMin <= len && hist[sid][newMin] + hdelta[sid][newMin] <= 0) newMin++;\n\n            nearDelta += 1LL * W[sid] * (nearVal[len][newMin] - nearVal[len][oldMin]);\n\n            int oldRed = min(oldCov, 4);\n            int newRed = min(newCov, 4);\n            nearDelta += 80LL * W[sid] * (newRed - oldRed);\n        }\n\n        return exactDelta * exactBonus + nearDelta;\n    }\n\n    void changeCell(int cell, uint8_t newc) {\n        int oldc = grid[cell];\n        if (oldc == newc) return;\n\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            bool was = (oldc != req);\n            bool now = (newc != req);\n            if (was == now) continue;\n\n            int sid = pid / POS;\n            int m = mism[pid];\n\n            if (!was && now) {\n                hist[sid][m]--;\n                hist[sid][m + 1]++;\n\n                if (m == 0) {\n                    cover[sid]--;\n                    if (cover[sid] == 0) obj -= W[sid];\n                }\n                mism[pid] = (uint8_t)(m + 1);\n            } else {\n                hist[sid][m]--;\n                hist[sid][m - 1]++;\n\n                if (m == 1) {\n                    if (cover[sid] == 0) obj += W[sid];\n                    cover[sid]++;\n                }\n                mism[pid] = (uint8_t)(m - 1);\n            }\n        }\n\n        grid[cell] = newc;\n    }\n\n    void applyChanges(const int cells[], const uint8_t vals[], int cnt) {\n        for (int i = 0; i < cnt; i++) changeCell(cells[i], vals[i]);\n    }\n};\n\nstruct Best {\n    int obj = -1;\n    int dots = 1000000000;\n    vector<uint8_t> grid;\n\n    void consider(const State& st) {\n        int d = countDotsVec(st.grid);\n        bool upd = false;\n        if (st.obj > obj) upd = true;\n        else if (st.obj == obj) {\n            if (st.obj == TOTAL) {\n                if (d > dots) upd = true;\n            } else {\n                if (grid.empty() || d < dots) upd = true;\n            }\n        }\n\n        if (upd) {\n            obj = st.obj;\n            dots = d;\n            grid = st.grid;\n        }\n    }\n};\n\nvector<uint8_t> strToVec(const string& s) {\n    vector<uint8_t> v;\n    v.reserve(s.size());\n    for (char c : s) v.push_back((uint8_t)(c - 'A'));\n    return v;\n}\n\nstring mergeLinear(const string& a, const string& b, int& ovOut) {\n    if (a.empty()) {\n        ovOut = 0;\n        return b;\n    }\n    if (b.empty()) {\n        ovOut = 0;\n        return a;\n    }\n\n    if (a.find(b) != string::npos) {\n        ovOut = (int)b.size();\n        return a;\n    }\n    if (b.find(a) != string::npos) {\n        ovOut = (int)a.size();\n        return b;\n    }\n\n    int bestOv = -1;\n    string best;\n\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            a.compare(a.size() - ov, ov, b, 0, ov) == 0) {\n            bestOv = ov;\n            best = a + b.substr(ov);\n            break;\n        }\n    }\n\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            b.compare(b.size() - ov, ov, a, 0, ov) == 0) {\n            if (ov > bestOv) {\n                bestOv = ov;\n                best = b + a.substr(ov);\n            }\n            break;\n        }\n    }\n\n    if (bestOv >= 0) {\n        ovOut = bestOv;\n        return best;\n    }\n\n    if ((int)a.size() + (int)b.size() <= MAXPLEN) {\n        ovOut = 0;\n        return a + b;\n    }\n\n    ovOut = -1;\n    return \"\";\n}\n\nbool containsInSegment(const string& seg, const string& sub) {\n    if ((int)sub.size() > MAXPLEN) return false;\n    if ((int)seg.size() == SZ) {\n        string t = seg + seg.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    } else {\n        if (sub.size() > seg.size()) return false;\n        return seg.find(sub) != string::npos;\n    }\n}\n\nstruct Segment {\n    vector<uint8_t> ch;\n    int val;\n};\n\nvector<Segment> generateSegments() {\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int minOv;\n    if (avgLen >= 8.0) minOv = 4;\n    else if (avgLen >= 6.0) minOv = 3;\n    else minOv = 2;\n\n    vector<string> segs;\n\n    for (int id : ids) {\n        const string& s = uniqStr[id];\n        bool contained = false;\n        int bestIdx = -1;\n        int bestOv = -1;\n        string bestMerged;\n\n        for (int i = 0; i < (int)segs.size(); i++) {\n            if (segs[i].find(s) != string::npos) {\n                contained = true;\n                break;\n            }\n\n            int ov;\n            string merged = mergeLinear(segs[i], s, ov);\n            if (!merged.empty() && (int)merged.size() <= MAXPLEN && ov > bestOv) {\n                bestOv = ov;\n                bestIdx = i;\n                bestMerged = merged;\n            }\n        }\n\n        if (contained) continue;\n\n        if (bestIdx != -1 && bestOv >= minOv) {\n            segs[bestIdx] = bestMerged;\n        } else {\n            segs.push_back(s);\n        }\n    }\n\n    sort(segs.begin(), segs.end());\n    segs.erase(unique(segs.begin(), segs.end()), segs.end());\n\n    vector<Segment> res;\n    for (auto& seg : segs) {\n        int val = 0;\n        for (int i = 0; i < U; i++) {\n            if (containsInSegment(seg, uniqStr[i])) val += W[i];\n        }\n        if (val >= 2) {\n            Segment sg;\n            sg.ch = strToVec(seg);\n            sg.val = val;\n            res.push_back(std::move(sg));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Segment& a, const Segment& b) {\n        if (a.val != b.val) return a.val > b.val;\n        return a.ch.size() > b.ch.size();\n    });\n\n    if ((int)res.size() > 260) res.resize(260);\n    return res;\n}\n\nstruct CItem {\n    int type;\n    int idx;\n    int len;\n    int val;\n    int group;\n    uint32_t rnd;\n};\n\nconst vector<uint8_t>& getItemChars(const CItem& it, const vector<Segment>& segs) {\n    if (it.type == 0) return S[it.idx];\n    return segs[it.idx].ch;\n}\n\nvector<uint8_t> constructGreedy(int mode, const vector<Segment>& segs, Timer& timer, double endTime) {\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<CItem> items;\n\n    if (mode == 1 || mode == 2) {\n        int lim = min((int)segs.size(), avgLen >= 7.0 ? 130 : 190);\n        for (int i = 0; i < lim; i++) {\n            items.push_back({1, i, (int)segs[i].ch.size(), segs[i].val,\n                             mode == 1 ? 0 : 0, (uint32_t)rng.next()});\n        }\n    }\n\n    for (int sid = 0; sid < U; sid++) {\n        int group = (mode == 1 ? 1 : 0);\n        items.push_back({0, sid, Ls[sid], W[sid], group, (uint32_t)rng.next()});\n    }\n\n    sort(items.begin(), items.end(), [&](const CItem& a, const CItem& b) {\n        if (a.group != b.group) return a.group < b.group;\n\n        if (mode == 2) {\n            int sa = a.val * 1000 + a.len * 50 + int(a.rnd & 127);\n            int sb = b.val * 1000 + b.len * 50 + int(b.rnd & 127);\n            return sa > sb;\n        }\n\n        if (a.len != b.len) return a.len > b.len;\n        if (a.val != b.val) return a.val > b.val;\n        return a.rnd < b.rnd;\n    });\n\n    int processed = 0;\n    for (const CItem& it : items) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n\n        const auto& ch = getItemChars(it, segs);\n        int len = (int)ch.size();\n\n        int bestPos = -1;\n        int bestScore = INT_MIN;\n        bool already = false;\n\n        for (int pos = 0; pos < POS; pos++) {\n            int match = 0;\n            bool conflict = false;\n\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[pos][p];\n                int g = grid[cell];\n                if (g == DOT) continue;\n                if (g == ch[p]) match++;\n                else {\n                    conflict = true;\n                    break;\n                }\n            }\n\n            if (!conflict) {\n                if (match == len) {\n                    already = true;\n                    break;\n                }\n\n                int score = match * 10000 - (len - match) * 5 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestPos = pos;\n                }\n            }\n        }\n\n        if (already) continue;\n\n        if (bestPos != -1) {\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n    }\n\n    return grid;\n}\n\nbool lineContains(const string& line, const string& sub) {\n    if (line.empty()) return false;\n    if ((int)line.size() == SZ) {\n        string t = line + line.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    }\n    if (sub.size() > line.size()) return false;\n    return line.find(sub) != string::npos;\n}\n\nvector<uint8_t> constructRowPack(Timer& timer, double endTime) {\n    vector<string> rows(SZ, \"\");\n\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    vector<uint32_t> rk(U);\n    for (int i = 0; i < U; i++) rk[i] = (uint32_t)rng.next();\n\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        if (W[a] != W[b]) return W[a] > W[b];\n        return rk[a] < rk[b];\n    });\n\n    int processed = 0;\n    for (int sid : ids) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n        const string& s = uniqStr[sid];\n\n        bool covered = false;\n        for (auto& row : rows) {\n            if (lineContains(row, s)) {\n                covered = true;\n                break;\n            }\n        }\n        if (covered) continue;\n\n        int bestR = -1;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        for (int r = 0; r < SZ; r++) {\n            int ov;\n            string merged;\n            if (rows[r].empty()) {\n                ov = 0;\n                merged = s;\n            } else {\n                merged = mergeLinear(rows[r], s, ov);\n            }\n\n            if (merged.empty() || (int)merged.size() > SZ) continue;\n\n            int score = ov * 1000 + (rows[r].empty() ? 0 : 100) - (int)merged.size();\n            if (score > bestScore) {\n                bestScore = score;\n                bestR = r;\n                bestMerged = merged;\n            }\n        }\n\n        if (bestR != -1) rows[bestR] = bestMerged;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nint makePlacementChanges(const State& st, int sid, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    const auto& str = S[sid];\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = str[p];\n        if (st.grid[cell] != ch) {\n            cells[cnt] = cell;\n            vals[cnt] = ch;\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nbool tryInsert(State& st, int sid, int K, int maxChange, bool allowZero, double temp, int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    const int MAXK = 12;\n    K = min(K, MAXK);\n\n    int candPos[MAXK];\n    uint32_t candKey[MAXK];\n    int candN = 0;\n\n    auto updateWorst = [&]() {\n        int wi = 0;\n        for (int i = 1; i < candN; i++) {\n            if (candKey[i] > candKey[wi]) wi = i;\n        }\n        return wi;\n    };\n\n    int base = sid * POS;\n\n    for (int pos = 0; pos < POS; pos++) {\n        int m = st.mism[base + pos];\n        if (m == 0) return false;\n        if (m > maxChange) continue;\n\n        uint32_t key = (uint32_t(m) << 20) | uint32_t(rng.next() & ((1u << 20) - 1));\n        if (candN < K) {\n            candPos[candN] = pos;\n            candKey[candN] = key;\n            candN++;\n        } else {\n            int wi = updateWorst();\n            if (key < candKey[wi]) {\n                candPos[wi] = pos;\n                candKey[wi] = key;\n            }\n        }\n    }\n\n    if (candN == 0) return false;\n\n    int bestD = INT_MIN;\n    int bestCnt = 0;\n    int bestCells[20];\n    uint8_t bestVals[20];\n\n    int tmpCells[20];\n    uint8_t tmpVals[20];\n\n    for (int i = 0; i < candN; i++) {\n        int cnt = makePlacementChanges(st, sid, candPos[i], tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 30) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nvoid shuffleVec(vector<int>& v) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nint softCellSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    static const long long EXACT_BONUS = 3000000LL;\n\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int exactImpTotal = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int changes = 0;\n        int exactImp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            long long bestScore = 0;\n            int bestCh = old;\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                long long sc = st.evalChangesSoft(oneCell, oneVal, 1, EXACT_BONUS);\n                if (sc > bestScore || (sc == bestScore && sc > 0 && rng.randint(2) == 0)) {\n                    bestScore = sc;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestScore > 0) {\n                int before = st.obj;\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                exactImp += st.obj - before;\n                changes++;\n                if (st.obj >= best.obj) best.consider(st);\n                if (st.obj == TOTAL) return exactImpTotal + exactImp;\n            }\n        }\n\n        exactImpTotal += exactImp;\n        if (changes == 0) break;\n    }\n\n    best.consider(st);\n    return exactImpTotal;\n}\n\ninline int maskWeight(const Mask& m) {\n    int sum = 0;\n    for (int w = 0; w < MASK_WORDS; w++) {\n        uint64_t x = m[w];\n        while (x) {\n            int b = __builtin_ctzll(x);\n            int id = w * 64 + b;\n            if (id < U) sum += W[id];\n            x &= x - 1;\n        }\n    }\n    return sum;\n}\n\nvoid buildLossMasks(const State& st, vector<Mask>& masks) {\n    for (auto& m : masks) m.fill(0);\n\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] != 1) continue;\n\n        int base = sid * POS;\n        int exactPos = -1;\n        for (int pos = 0; pos < POS; pos++) {\n            if (st.mism[base + pos] == 0) {\n                exactPos = pos;\n                break;\n            }\n        }\n        if (exactPos < 0) continue;\n\n        int word = sid >> 6;\n        uint64_t bit = 1ULL << (sid & 63);\n\n        for (int p = 0; p < Ls[sid]; p++) {\n            int cell = posCell[exactPos][p];\n            masks[cell][word] |= bit;\n        }\n    }\n}\n\nint approxPlacementLoss(const State& st, const vector<Mask>& masks, int sid, int pos, int& cnt) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = S[sid][p];\n        if (st.grid[cell] == ch) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    tmp[sid >> 6] &= ~(1ULL << (sid & 63));\n    return maskWeight(tmp);\n}\n\nbool tryInsertConflict(State& st, int sid, const vector<Mask>& masks,\n                       int kLoss, int kMis, bool allowZero, double temp,\n                       int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 250 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[20];\n    uint8_t bestVals[20];\n\n    int tmpCells[20];\n    uint8_t tmpVals[20];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 1200LL - 1LL * c.cnt * 30LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 45) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nvoid conflictSearch(State& st, Timer& timer, double endTime, Best& best) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 5 == 0) buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) {\n            if (st.cover[sid] == 0) unc.push_back(sid);\n        }\n        if (unc.empty()) break;\n\n        int sid = unc[rng.randint((int)unc.size())];\n\n        int samples = min(26, (int)unc.size());\n        int bestKey = -1;\n        for (int t = 0; t < samples; t++) {\n            int x = unc[rng.randint((int)unc.size())];\n            int key = Ls[x] * 100 + W[x] * 35 + rng.randint(120);\n            if (key > bestKey) {\n                bestKey = key;\n                sid = x;\n            }\n        }\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.12 + 1.15 * frac;\n\n        int d;\n        bool ok = tryInsertConflict(st, sid, masks, 9, 5, true, temp, d);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 8);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 150) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n                iter = 0;\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nint repairPass(State& st, Timer& timer, double endTime, int K, int maxChange,\n               bool allowZero, double temp, Best& best) {\n    vector<int> ids;\n    ids.reserve(U);\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] == 0) ids.push_back(sid);\n    }\n    if (ids.empty()) return 0;\n\n    shuffleVec(ids);\n    stable_sort(ids.begin(), ids.end(), [](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int before = st.obj;\n    int applied = 0;\n\n    for (int sid : ids) {\n        if (timer.elapsed() > endTime) break;\n        if (st.cover[sid] > 0) continue;\n\n        int d;\n        if (tryInsert(st, sid, K, maxChange, allowZero, temp, d)) {\n            applied++;\n            if (d > 0 || st.obj == TOTAL) best.consider(st);\n            if (st.obj == TOTAL) break;\n        }\n    }\n\n    best.consider(st);\n    return st.obj - before + applied / 1000000;\n}\n\nvoid fillDots(State& st, Timer& timer, double endTime, Best& best) {\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] != DOT) continue;\n\n        int bestD = INT_MIN;\n        int bestCh = 0;\n        oneCell[0] = cell;\n\n        for (int ch = 0; ch < 8; ch++) {\n            oneVal[0] = (uint8_t)ch;\n            int d = st.evalChanges(oneCell, oneVal, 1);\n            if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n                bestD = d;\n                bestCh = ch;\n            }\n        }\n\n        oneVal[0] = (uint8_t)bestCh;\n        st.applyChanges(oneCell, oneVal, 1);\n        best.consider(st);\n\n        if (st.obj == TOTAL) return;\n    }\n\n    best.consider(st);\n}\n\nint cellHillSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int totalImp = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int imp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            int bestD = 0;\n            int bestCh = old;\n\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                int d = st.evalChanges(oneCell, oneVal, 1);\n                if (d > bestD || (d == bestD && d > 0 && rng.randint(2) == 0)) {\n                    bestD = d;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestD > 0) {\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                imp += bestD;\n                best.consider(st);\n                if (st.obj == TOTAL) return totalImp + imp;\n            }\n        }\n\n        totalImp += imp;\n        if (imp == 0) break;\n    }\n\n    best.consider(st);\n    return totalImp;\n}\n\nbool hasDots(const vector<uint8_t>& g) {\n    for (auto x : g) if (x == DOT) return true;\n    return false;\n}\n\nvoid localSearch(State& st, Timer& timer, double endTime, Best& best) {\n    best.consider(st);\n    if (st.obj == TOTAL) return;\n\n    int maxChFull = (avgLen >= 8.0 ? 5 : 6);\n\n    if (hasDots(st.grid)) {\n        for (int pass = 0; pass < 2 && timer.elapsed() < endTime; pass++) {\n            int before = st.obj;\n            repairPass(st, timer, endTime, 3, maxLenInput, false, -1.0, best);\n            if (st.obj == TOTAL) return;\n            if (st.obj == before) break;\n        }\n    }\n\n    if (st.obj == TOTAL) return;\n\n    if (hasDots(st.grid)) {\n        fillDots(st, timer, endTime, best);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() + 0.05 < endTime && st.obj < TOTAL) {\n        softCellSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n    }\n\n    for (int cyc = 0; cyc < 2 && timer.elapsed() < endTime; cyc++) {\n        int before = st.obj;\n        repairPass(st, timer, endTime, 5, maxChFull, false, -1.0, best);\n        if (st.obj == TOTAL) return;\n\n        cellHillSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n\n        if (st.obj <= before && cyc > 0) break;\n    }\n\n    if (timer.elapsed() < endTime && st.obj < TOTAL) {\n        conflictSearch(st, timer, endTime, best);\n    }\n\n    best.consider(st);\n}\n\nvoid dotMaximize(Best& best, State& st, Timer& timer, double endTime) {\n    if (best.obj < TOTAL) return;\n\n    st.build(best.grid);\n    if (st.obj < TOTAL) return;\n\n    vector<pair<int,int>> order;\n    order.reserve(CELLS);\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (st.grid[cell] == DOT) continue;\n\n        int impact = 0;\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            if (st.grid[cell] == req && st.mism[pid] == 0) {\n                int sid = pid / POS;\n                impact += (st.cover[sid] <= 1 ? 1000 * W[sid] : 1);\n            }\n        }\n        impact = impact * 1024 + rng.randint(1024);\n        order.push_back({impact, cell});\n    }\n\n    sort(order.begin(), order.end());\n\n    int oneCell[1];\n    uint8_t oneVal[1] = {(uint8_t)DOT};\n\n    for (auto [_, cell] : order) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] == DOT) continue;\n\n        oneCell[0] = cell;\n        int d = st.evalChanges(oneCell, oneVal, 1);\n        if (st.obj + d == TOTAL) {\n            st.applyChanges(oneCell, oneVal, 1);\n        }\n    }\n\n    best.consider(st);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin;\n    cin >> Nin >> M_input;\n\n    vector<string> input(M_input);\n    uint64_t h = 1469598103934665603ULL;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M_input * 2);\n\n    int totalLen = 0;\n    for (int i = 0; i < M_input; i++) {\n        cin >> input[i];\n        mp[input[i]]++;\n        totalLen += (int)input[i].size();\n        maxLenInput = max(maxLenInput, (int)input[i].size());\n        for (char c : input[i]) {\n            h ^= (uint64_t)c;\n            h *= 1099511628211ULL;\n        }\n    }\n\n    rng = XorShift(88172645463325252ULL ^ h);\n\n    vector<pair<string,int>> pairs;\n    pairs.reserve(mp.size());\n    for (auto& kv : mp) pairs.push_back(kv);\n    sort(pairs.begin(), pairs.end());\n\n    U = (int)pairs.size();\n    TOTAL = M_input;\n    avgLen = (double)totalLen / M_input;\n\n    uniqStr.reserve(U);\n    S.reserve(U);\n    Ls.reserve(U);\n    W.reserve(U);\n\n    for (auto& kv : pairs) {\n        uniqStr.push_back(kv.first);\n        S.push_back(strToVec(kv.first));\n        Ls.push_back((int)kv.first.size());\n        W.push_back(kv.second);\n    }\n\n    Timer timer;\n\n    initNearVal();\n    initPosCells();\n    buildIncidences();\n\n    vector<Segment> segments = generateSegments();\n\n    State st;\n    st.init();\n\n    Best best;\n\n    vector<int> modes;\n    if (avgLen <= 5.0) modes = {0, 3, 1, 2};\n    else modes = {1, 0, 3, 2};\n\n    const double SEARCH_END = 2.62;\n    const double FINAL_END = 2.88;\n\n    for (int r = 0; r < (int)modes.size() && timer.elapsed() < SEARCH_END; r++) {\n        vector<uint8_t> grid;\n\n        if (modes[r] == 3) {\n            grid = constructRowPack(timer, SEARCH_END);\n        } else {\n            grid = constructGreedy(modes[r], segments, timer, SEARCH_END);\n        }\n\n        st.build(grid);\n\n        double rem = SEARCH_END - timer.elapsed();\n        int left = (int)modes.size() - r;\n        double slice = max(0.05, rem / max(1, left));\n        double endTime = min(SEARCH_END, timer.elapsed() + slice);\n\n        localSearch(st, timer, endTime, best);\n\n        if (best.obj == TOTAL) break;\n    }\n\n    if (best.grid.empty()) {\n        vector<uint8_t> g(CELLS);\n        for (int i = 0; i < CELLS; i++) g[i] = rng.randint(8);\n        st.build(g);\n        best.consider(st);\n    }\n\n    if (best.obj == TOTAL) {\n        dotMaximize(best, st, timer, FINAL_END);\n    } else {\n        st.build(best.grid);\n\n        if (hasDots(st.grid)) {\n            fillDots(st, timer, FINAL_END, best);\n        }\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.05 < FINAL_END) {\n            softCellSweep(st, timer, FINAL_END, best, 1);\n        }\n\n        if (st.obj < TOTAL && timer.elapsed() < FINAL_END) {\n            conflictSearch(st, timer, FINAL_END, best);\n        }\n\n        if (best.obj == TOTAL) {\n            dotMaximize(best, st, timer, FINAL_END);\n        } else {\n            st.build(best.grid);\n            if (hasDots(st.grid)) fillDots(st, timer, FINAL_END, best);\n\n            if (st.obj < TOTAL) {\n                cellHillSweep(st, timer, FINAL_END, best, 3);\n            }\n\n            if (best.obj == TOTAL) {\n                dotMaximize(best, st, timer, FINAL_END);\n            }\n        }\n    }\n\n    if (best.obj < TOTAL) {\n        for (auto& x : best.grid) {\n            if (x == DOT) x = rng.randint(8);\n        }\n    }\n\n    for (int r = 0; r < SZ; r++) {\n        string line;\n        line.reserve(SZ);\n        for (int c = 0; c < SZ; c++) {\n            uint8_t x = best.grid[r * SZ + c];\n            if (x == DOT) line.push_back('.');\n            else line.push_back(char('A' + x));\n        }\n        cout << line << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Dinic {\n    struct Edge {\n        int to, rev;\n        long long cap;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic(int n = 0) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, long long cap) {\n        Edge a{to, (int)g[to].size(), cap};\n        Edge b{fr, (int)g[fr].size(), 0};\n        g[fr].push_back(a);\n        g[to].push_back(b);\n    }\n\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\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return level[t] >= 0;\n    }\n\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n\n        for (int &i = it[v]; i < (int)g[v].size(); i++) {\n            Edge &e = g[v][i];\n\n            if (e.cap <= 0 || level[v] + 1 != level[e.to]) continue;\n\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if (ret > 0) {\n                e.cap -= ret;\n                g[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n\n        return 0;\n    }\n\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        const long long INF = (1LL << 60);\n\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n\n            while (true) {\n                long long f = dfs(s, t, INF);\n                if (!f) break;\n                flow += f;\n            }\n        }\n\n        return flow;\n    }\n\n    vector<int> reachable_from(int s) {\n        vector<int> vis(n, 0);\n        queue<int> q;\n        vis[s] = 1;\n        q.push(s);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return vis;\n    }\n};\n\nstruct Solver {\n    static constexpr int INF16 = 65535;\n\n    Timer timer;\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0, S = 0;\n    vector<vector<int>> id;\n    vector<int> rr, cc, wt;\n    vector<array<int, 4>> nbr;\n\n    vector<uint16_t> distMat, parMat;\n\n    vector<int> hid, vid;\n    vector<vector<int>> hCells, vCells;\n    vector<int> visVal;\n    vector<int> segMinH, segMinV;\n\n    vector<int> bestSafeSeq;\n    vector<int> bestFinalSeq;\n    vector<vector<int>> bestFinalEdges;\n    long long bestSafeCost = (1LL << 60);\n    long long bestFinalCost = (1LL << 60);\n\n    inline int D(int a, int b) const {\n        return distMat[(size_t)a * R + b];\n    }\n\n    inline int Sym(int a, int b) const {\n        return D(a, b) + wt[a];\n    }\n\n    char moveChar(int a, int b) const {\n        if (rr[b] == rr[a] - 1) return 'U';\n        if (rr[b] == rr[a] + 1) return 'D';\n        if (cc[b] == cc[a] - 1) return 'L';\n        return 'R';\n    }\n\n    void readInput() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void buildRoadGraph() {\n        id.assign(N, vector<int>(N, -1));\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    rr.push_back(i);\n                    cc.push_back(j);\n                    wt.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n\n        S = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        int di[4] = {-1, 1, 0, 0};\n        int dj[4] = {0, 0, -1, 1};\n\n        for (int v = 0; v < R; v++) {\n            int i = rr[v], j = cc[v];\n\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 && id[ni][nj] >= 0) {\n                    nbr[v][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void buildSegments() {\n        hid.assign(R, -1);\n        vid.assign(R, -1);\n\n        for (int i = 0; i < N; i++) {\n            int j = 0;\n            while (j < N) {\n                if (id[i][j] < 0) {\n                    j++;\n                    continue;\n                }\n\n                int h = (int)hCells.size();\n                hCells.push_back({});\n\n                while (j < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    hid[v] = h;\n                    hCells.back().push_back(v);\n                    j++;\n                }\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            int i = 0;\n            while (i < N) {\n                if (id[i][j] < 0) {\n                    i++;\n                    continue;\n                }\n\n                int vseg = (int)vCells.size();\n                vCells.push_back({});\n\n                while (i < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    vid[v] = vseg;\n                    vCells.back().push_back(v);\n                    i++;\n                }\n            }\n        }\n\n        visVal.assign(R, 0);\n        for (int v = 0; v < R; v++) {\n            visVal[v] = (int)hCells[hid[v]].size() + (int)vCells[vid[v]].size() - 1;\n        }\n    }\n\n    void computeAPSP() {\n        distMat.assign((size_t)R * R, INF16);\n        parMat.assign((size_t)R * R, 0);\n\n        vector<uint16_t> dist(R), par(R);\n        vector<int> score(R);\n        vector<unsigned char> used(R);\n        vector<vector<int>> buckets(10);\n        for (auto &b : buckets) b.reserve(max(1, R / 2));\n\n        for (int s = 0; s < R; s++) {\n            fill(dist.begin(), dist.end(), (uint16_t)INF16);\n            fill(par.begin(), par.end(), 0);\n            fill(score.begin(), score.end(), -1);\n            fill(used.begin(), used.end(), 0);\n            for (auto &b : buckets) b.clear();\n\n            dist[s] = 0;\n            par[s] = s;\n            score[s] = visVal[s];\n            buckets[0].push_back(s);\n\n            int cur = 0, done = 0;\n            while (done < R) {\n                auto &bk = buckets[cur % 10];\n\n                if (bk.empty()) {\n                    cur++;\n                    continue;\n                }\n\n                int v = bk.back();\n                bk.pop_back();\n\n                if (used[v] || dist[v] != cur) continue;\n\n                used[v] = 1;\n                done++;\n\n                for (int k = 0; k < 4; k++) {\n                    int to = nbr[v][k];\n                    if (to < 0 || used[to]) continue;\n\n                    int nd = cur + wt[to];\n                    int ns = score[v] + visVal[to];\n\n                    if (nd < dist[to] || (nd == dist[to] && ns > score[to])) {\n                        dist[to] = (uint16_t)nd;\n                        par[to] = (uint16_t)v;\n                        score[to] = ns;\n                        buckets[nd % 10].push_back(to);\n                    }\n                }\n            }\n\n            memcpy(distMat.data() + (size_t)s * R, dist.data(), sizeof(uint16_t) * R);\n            memcpy(parMat.data() + (size_t)s * R, par.data(), sizeof(uint16_t) * R);\n        }\n    }\n\n    void computeSegmentApprox() {\n        segMinH.assign(hCells.size(), 1e9);\n        segMinV.assign(vCells.size(), 1e9);\n\n        for (int v = 0; v < R; v++) {\n            int rt = D(S, v) + D(v, S);\n            segMinH[hid[v]] = min(segMinH[hid[v]], rt);\n            segMinV[vid[v]] = min(segMinV[vid[v]], rt);\n        }\n    }\n\n    void getPathCellsUnordered(int a, int b, vector<int> &out) const {\n        out.clear();\n        if (a == b) return;\n\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            int p = parMat[(size_t)a * R + cur];\n            cur = p;\n\n            if (++cnt > R + 5) {\n                out.clear();\n                return;\n            }\n        }\n    }\n\n    void getPathCellsOrdered(int a, int b, vector<int> &out) const {\n        getPathCellsUnordered(a, b, out);\n        reverse(out.begin(), out.end());\n    }\n\n    long long routeCost(const vector<int> &seq) const {\n        if (seq.empty()) return (1LL << 60);\n\n        long long ret = 0;\n        int m = (int)seq.size();\n\n        for (int i = 0; i < m; i++) {\n            ret += D(seq[i], seq[(i + 1) % m]);\n        }\n\n        return ret;\n    }\n\n    struct Cover {\n        const Solver *sol = nullptr;\n        vector<int> cntH, cntV;\n        int bad = 0;\n\n        void init(const Solver *s) {\n            sol = s;\n            cntH.assign(sol->hCells.size(), 0);\n            cntV.assign(sol->vCells.size(), 0);\n            bad = sol->R;\n        }\n\n        void addH(int h, int delta) {\n            int old = cntH[h];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad++;\n                }\n            }\n\n            cntH[h] = neu;\n        }\n\n        void addV(int v, int delta) {\n            int old = cntV[v];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad++;\n                }\n            }\n\n            cntV[v] = neu;\n        }\n\n        void addCell(int p, int delta) {\n            addH(sol->hid[p], delta);\n            addV(sol->vid[p], delta);\n        }\n    };\n\n    bool checkpointFull(const vector<int> &seq) const {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n\n        return cov.bad == 0;\n    }\n\n    void buildStaticEdges(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        int m = (int)seq.size();\n        edgeCells.assign(m, {});\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, edgeCells[i]);\n        }\n    }\n\n    bool actualFullEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (seq.empty()) return false;\n\n        Cover cov;\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                for (int p : edgeCells[i]) cov.addCell(p, +1);\n            }\n        } else {\n            vector<int> path;\n            for (int i = 0; i < m; i++) {\n                int a = seq[i], b = seq[(i + 1) % m];\n                getPathCellsUnordered(a, b, path);\n                for (int p : path) cov.addCell(p, +1);\n            }\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool actualFull(const vector<int> &seq) const {\n        static const vector<vector<int>> emptyEdges;\n        return actualFullEdges(seq, emptyEdges);\n    }\n\n    vector<int> constructCellCover(double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<unsigned char> covered(R, 0);\n        vector<int> remH(hCells.size()), remV(vCells.size());\n\n        for (int h = 0; h < (int)hCells.size(); h++) remH[h] = (int)hCells[h].size();\n        for (int v = 0; v < (int)vCells.size(); v++) remV[v] = (int)vCells[v].size();\n\n        int uncovered = R;\n\n        auto mark = [&](int q) {\n            if (!covered[q]) {\n                covered[q] = 1;\n                uncovered--;\n                remH[hid[q]]--;\n                remV[vid[q]]--;\n            }\n        };\n\n        auto addCover = [&](int p) {\n            for (int q : hCells[hid[p]]) mark(q);\n            for (int q : vCells[vid[p]]) mark(q);\n        };\n\n        addCover(S);\n\n        vector<double> gp(R + 1, 1.0);\n        for (int g = 1; g <= R; g++) gp[g] = pow((double)g, alpha);\n\n        while (uncovered > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = remH[hid[p]] + remV[vid[p]] - (covered[p] ? 0 : 1);\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int p = 0; p < R; p++) {\n                    if (!covered[p]) {\n                        bestP = p;\n                        bestPos = 0;\n                        break;\n                    }\n                }\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            addCover(bestP);\n        }\n\n        return seq;\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCoverWeights(const vector<long long> &wH,\n                                                                const vector<long long> &wV) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        long long sumW = 0;\n        for (long long x : wH) sumW += x;\n        for (long long x : wV) sumW += x;\n\n        int SRC = 0;\n        int offH = 1;\n        int offV = offH + nH;\n        int SNK = offV + nV;\n\n        Dinic din(SNK + 1);\n\n        for (int h = 0; h < nH; h++) din.add_edge(SRC, offH + h, wH[h]);\n        for (int v = 0; v < nV; v++) din.add_edge(offV + v, SNK, wV[v]);\n\n        long long INF = sumW + 1;\n\n        for (int p = 0; p < R; p++) {\n            din.add_edge(offH + hid[p], offV + vid[p], INF);\n        }\n\n        din.max_flow(SRC, SNK);\n        vector<int> reach = din.reachable_from(SRC);\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int h = 0; h < nH; h++) selH[h] = !reach[offH + h];\n        for (int v = 0; v < nV; v++) selV[v] = reach[offV + v];\n\n        for (int p = 0; p < R; p++) {\n            if (!selH[hid[p]] && !selV[vid[p]]) selH[hid[p]] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCover(int type) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<long long> wH(nH), wV(nV);\n\n        auto calcW = [&](int minRT, int len, int tp, bool isH) -> long long {\n            len = max(1, len);\n\n            if (tp == 0) return 1;\n            if (tp == 1) return 100 + minRT / 40;\n            if (tp == 2) return 1 + minRT / 20;\n            if (tp == 3) return 1 + minRT / len;\n            if (tp == 4) return 1 + (10LL * minRT) / max(1, len * len);\n            if (tp == 5) return (len <= 1 ? 10000LL + minRT : 1LL + minRT / max(1, 30 * len));\n            if (tp == 6) return max(1LL, 2000LL / len) + minRT / 100;\n            if (tp == 7) {\n                long long base = 1 + minRT / max(1, 18 * len);\n                return isH ? base * 9 : base * 11;\n            }\n\n            return 1 + minRT / max(1, (int)(8.0 * sqrt((double)len)));\n        };\n\n        for (int h = 0; h < nH; h++) {\n            wH[h] = calcW(segMinH[h], (int)hCells[h].size(), type, true);\n        }\n\n        for (int v = 0; v < nV; v++) {\n            wV[v] = calcW(segMinV[v], (int)vCells[v].size(), type, false);\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    pair<vector<char>, vector<char>> preferenceCover(int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int lh = (int)hCells[h].size();\n            int lv = (int)vCells[v].size();\n\n            bool chooseH = true;\n\n            if (mode == 0) {\n                if (lh != lv) chooseH = lh > lv;\n                else chooseH = segMinH[h] <= segMinV[v];\n            } else if (mode == 1) {\n                long long sh = 1000LL * segMinH[h] / max(1, lh);\n                long long sv = 1000LL * segMinV[v] / max(1, lv);\n                chooseH = sh <= sv;\n            } else {\n                long long sh = 100000LL * segMinH[h] / max(1, lh * lh);\n                long long sv = 100000LL * segMinV[v] / max(1, lv * lv);\n                chooseH = sh <= sv;\n            }\n\n            if (chooseH) selH[h] = 1;\n            else selV[v] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> insertionWeightedVertexCover(const vector<int> &base, int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        const int INF = 1e9;\n        vector<int> insH(nH, INF), insV(nV, INF);\n\n        int m = (int)base.size();\n\n        for (int p = 0; p < R; p++) {\n            int best = INF;\n\n            for (int i = 0; i < m; i++) {\n                int a = base[i], b = base[(i + 1) % m];\n                int extra = D(a, p) + D(p, b) - D(a, b);\n                if (extra < best) best = extra;\n            }\n\n            insH[hid[p]] = min(insH[hid[p]], best);\n            insV[vid[p]] = min(insV[vid[p]], best);\n        }\n\n        vector<long long> wH(nH), wV(nV);\n\n        for (int h = 0; h < nH; h++) {\n            int len = max(1, (int)hCells[h].size());\n            int c = insH[h] == INF ? segMinH[h] : insH[h];\n\n            if (mode == 0) wH[h] = 1 + c / len;\n            else wH[h] = 1 + (10LL * c) / max(1, len * len) + segMinH[h] / 250;\n        }\n\n        for (int v = 0; v < nV; v++) {\n            int len = max(1, (int)vCells[v].size());\n            int c = insV[v] == INF ? segMinV[v] : insV[v];\n\n            if (mode == 0) wV[v] = 1 + c / len;\n            else wV[v] = 1 + (10LL * c) / max(1, len * len) + segMinV[v] / 250;\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    vector<int> constructSegmentCover(const vector<char> &selH, const vector<char> &selV,\n                                      double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<char> touchH(hCells.size(), 0), touchV(vCells.size(), 0);\n\n        int remain = 0;\n        for (char x : selH) if (x) remain++;\n        for (char x : selV) if (x) remain++;\n\n        auto touch = [&](int p) {\n            int h = hid[p], v = vid[p];\n\n            if (selH[h] && !touchH[h]) {\n                touchH[h] = 1;\n                remain--;\n            }\n\n            if (selV[v] && !touchV[v]) {\n                touchV[v] = 1;\n                remain--;\n            }\n        };\n\n        touch(S);\n\n        double gp[3] = {1.0, 1.0, pow(2.0, alpha)};\n\n        while (remain > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = 0;\n                if (selH[hid[p]] && !touchH[hid[p]]) gain++;\n                if (selV[vid[p]] && !touchV[vid[p]]) gain++;\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int h = 0; h < (int)selH.size() && bestP < 0; h++) {\n                    if (selH[h] && !touchH[h]) bestP = hCells[h][0];\n                }\n\n                for (int v = 0; v < (int)selV.size() && bestP < 0; v++) {\n                    if (selV[v] && !touchV[v]) bestP = vCells[v][0];\n                }\n\n                bestPos = 0;\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            touch(bestP);\n        }\n\n        return seq;\n    }\n\n    bool twoOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n\n        for (int i = 0; i < m - 1; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            reverse(seq.begin() + bi + 1, seq.begin() + bk + 1);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool orOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        int bestDelta = 0, bi = -1, bj = -1;\n\n        for (int i = 1; i < m; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int removeCost = Sym(prev, x) + Sym(x, next) - Sym(prev, next);\n\n            for (int j = 0; j < m; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j], b = seq[(j + 1) % m];\n                int addCost = Sym(a, x) + Sym(x, b) - Sym(a, b);\n                int delta = addCost - removeCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            int x = seq[bi];\n            seq.erase(seq.begin() + bi);\n\n            int pos;\n            if (bj > bi) pos = bj;\n            else pos = bj + 1;\n\n            seq.insert(seq.begin() + pos, x);\n            return true;\n        }\n\n        return false;\n    }\n\n    void optimizeOrder(vector<int> &seq, double limit) {\n        while (timer.elapsed() < limit) {\n            bool improved = false;\n\n            if (twoOptOnce(seq)) improved = true;\n            if (timer.elapsed() >= limit) break;\n            if (orOptOnce(seq)) improved = true;\n\n            if (!improved) break;\n        }\n    }\n\n    void safeRemove(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n\n            for (int i = 1; i < m; i++) {\n                int x = seq[i];\n\n                cov.addCell(x, -1);\n\n                if (cov.bad == 0) {\n                    int prev = seq[i - 1];\n                    int next = seq[(i + 1) % m];\n                    int save = D(prev, x) + D(x, next) - D(prev, next);\n\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestIdx = i;\n                    }\n                }\n\n                cov.addCell(x, +1);\n            }\n\n            if (bestIdx < 0) break;\n\n            cov.addCell(seq[bestIdx], -1);\n            seq.erase(seq.begin() + bestIdx);\n        }\n    }\n\n    void improveReplace(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                token++;\n                if (token == INT_MAX) {\n                    fill(seen.begin(), seen.end(), 0);\n                    token = 1;\n                }\n\n                cov.addCell(old, -1);\n\n                auto evalCand = [&](int p) {\n                    if (seen[p] == token) return;\n                    seen[p] = token;\n\n                    if (p == old) return;\n\n                    int newCost = D(prev, p) + D(p, next);\n                    int delta = newCost - oldCost;\n\n                    if (delta >= bestDelta) return;\n\n                    cov.addCell(p, +1);\n\n                    if (cov.bad == 0) {\n                        bestDelta = delta;\n                        bestIdx = i;\n                        bestP = p;\n                    }\n\n                    cov.addCell(p, -1);\n                };\n\n                for (int p : hCells[hid[old]]) evalCand(p);\n                for (int p : vCells[vid[old]]) evalCand(p);\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    void buildActualCover(const vector<int> &seq, Cover &cov, vector<vector<int>> &edgeCells) const {\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n        edgeCells.assign(m, {});\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, edgeCells[i]);\n\n            for (int p : edgeCells[i]) cov.addCell(p, +1);\n        }\n    }\n\n    void applyPath(Cover &cov, const vector<int> &path, int delta) const {\n        for (int p : path) cov.addCell(p, delta);\n    }\n\n    vector<int> dynamicShortestPath(int a, int b, const Cover &cov) const {\n        vector<int> fallback;\n        getPathCellsUnordered(a, b, fallback);\n\n        if (a == b) return {};\n\n        int target = D(a, b);\n        if (target >= INF16) return fallback;\n\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<int> badH(nH, 0), badV(nV, 0);\n\n        if (cov.bad > 0) {\n            for (int q = 0; q < R; q++) {\n                if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                    badH[hid[q]]++;\n                    badV[vid[q]]++;\n                }\n            }\n        }\n\n        vector<int> reward(R, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int g = 0;\n\n            if (cov.cntH[h] == 0) g += badH[h];\n            if (cov.cntV[v] == 0) g += badV[v];\n            if (cov.cntH[h] == 0 && cov.cntV[v] == 0) g--;\n\n            reward[p] = g * 10000 + min(visVal[p], 9999);\n        }\n\n        vector<int> nodes;\n        nodes.reserve(R);\n\n        for (int p = 0; p < R; p++) {\n            if (D(a, p) + D(p, b) == target) nodes.push_back(p);\n        }\n\n        sort(nodes.begin(), nodes.end(), [&](int x, int y) {\n            int dx = D(a, x), dy = D(a, y);\n            if (dx != dy) return dx < dy;\n            return x < y;\n        });\n\n        const long long NEG = -(1LL << 60);\n        vector<long long> dp(R, NEG);\n        vector<int> parent(R, -1);\n\n        dp[a] = 0;\n        parent[a] = a;\n\n        for (int v : nodes) {\n            if (dp[v] == NEG) continue;\n\n            int dv = D(a, v);\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n                if (to < 0) continue;\n\n                if (dv + wt[to] != D(a, to)) continue;\n                if (D(a, to) + D(to, b) != target) continue;\n\n                long long ndp = dp[v] + reward[to];\n\n                if (ndp > dp[to]) {\n                    dp[to] = ndp;\n                    parent[to] = v;\n                }\n            }\n        }\n\n        if (parent[b] < 0) return fallback;\n\n        vector<int> out;\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            cur = parent[cur];\n\n            if (cur < 0 || ++cnt > R + 5) return fallback;\n        }\n\n        return out;\n    }\n\n    bool pathRemove(vector<int> &seq, vector<vector<int>> &edgeCells, double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        Cover cov;\n        buildActualCover(seq, cov, edgeCells);\n\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n            vector<int> bestNewPath;\n\n            for (int i = 1; i < m; i++) {\n                int prev = seq[i - 1];\n                int x = seq[i];\n                int next = seq[(i + 1) % m];\n\n                int save = D(prev, x) + D(x, next) - D(prev, next);\n                if (save < bestSave) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n\n                vector<int> np;\n                getPathCellsUnordered(prev, next, np);\n\n                applyPath(cov, np, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand = np;\n\n                applyPath(cov, np, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    vector<int> dp = dynamicShortestPath(prev, next, cov);\n\n                    applyPath(cov, dp, +1);\n\n                    if (cov.bad == 0) {\n                        ok = true;\n                        cand = dp;\n                    }\n\n                    applyPath(cov, dp, -1);\n                }\n\n                if (ok && save > bestSave) {\n                    bestSave = save;\n                    bestIdx = i;\n                    bestNewPath = cand;\n                }\n\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            applyPath(cov, edgeCells[bestIdx - 1], -1);\n            applyPath(cov, edgeCells[bestIdx], -1);\n            applyPath(cov, bestNewPath, +1);\n\n            seq.erase(seq.begin() + bestIdx);\n            edgeCells[bestIdx - 1] = bestNewPath;\n            edgeCells.erase(edgeCells.begin() + bestIdx);\n        }\n\n        return cov.bad == 0;\n    }\n\n    void updateFinalStatic(const vector<int> &seq) {\n        long long c = routeCost(seq);\n\n        if (c < bestFinalCost) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges.clear();\n        }\n    }\n\n    void updateFinalRoute(const vector<int> &seq, const vector<vector<int>> &edgeCells) {\n        long long c = routeCost(seq);\n        if (c >= bestFinalCost) return;\n\n        if (!actualFullEdges(seq, edgeCells)) return;\n\n        bestFinalCost = c;\n        bestFinalSeq = seq;\n        bestFinalEdges = edgeCells;\n    }\n\n    void updateSafe(const vector<int> &seq) {\n        if (!checkpointFull(seq)) return;\n\n        long long c = routeCost(seq);\n\n        if (c < bestSafeCost) {\n            bestSafeCost = c;\n            bestSafeSeq = seq;\n        }\n\n        updateFinalStatic(seq);\n    }\n\n    void processCandidate(vector<int> seq, bool heavy) {\n        if (seq.empty()) return;\n\n        double lim = min(2.48, timer.elapsed() + (heavy ? 0.20 : 0.07));\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n        if (timer.elapsed() < lim) safeRemove(seq, lim);\n\n        if (heavy && timer.elapsed() < lim) {\n            improveReplace(seq, lim);\n            safeRemove(seq, lim);\n        }\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.60) {\n            vector<int> pseq = seq;\n            vector<vector<int>> pedges;\n\n            double plim = min(2.66, timer.elapsed() + (heavy ? 0.08 : 0.045));\n            bool dyn = heavy || timer.elapsed() < 1.80;\n\n            if (pathRemove(pseq, pedges, plim, dyn)) {\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    string buildOutput(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        string ans;\n        ans.reserve(200000);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                int cur = seq[i];\n\n                for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                    int p = edgeCells[i][k];\n                    ans.push_back(moveChar(cur, p));\n                    cur = p;\n                }\n            }\n\n            return ans;\n        }\n\n        vector<int> path;\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsOrdered(a, b, path);\n\n            int cur = a;\n\n            for (int p : path) {\n                ans.push_back(moveChar(cur, p));\n                cur = p;\n            }\n        }\n\n        return ans;\n    }\n\n    string dfsFallback() const {\n        vector<vector<int>> child(R);\n        vector<int> par(R, -1);\n        queue<int> q;\n\n        par[S] = S;\n        q.push(S);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n\n                if (to >= 0 && par[to] < 0) {\n                    par[to] = v;\n                    child[v].push_back(to);\n                    q.push(to);\n                }\n            }\n        }\n\n        string ans;\n        ans.reserve(max(0, 2 * (R - 1)));\n\n        function<void(int)> dfs = [&](int v) {\n            for (int to : child[v]) {\n                ans.push_back(moveChar(v, to));\n                dfs(to);\n                ans.push_back(moveChar(to, v));\n            }\n        };\n\n        dfs(S);\n        return ans;\n    }\n\n    void finalPolish() {\n        if (bestSafeSeq.empty() || timer.elapsed() > 2.72) return;\n\n        vector<int> seq = bestSafeSeq;\n        double lim = 2.84;\n\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n        improveReplace(seq, lim);\n        safeRemove(seq, lim);\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.87) {\n            vector<int> pseq = seq;\n            vector<vector<int>> pedges;\n\n            if (pathRemove(pseq, pedges, 2.92, true)) {\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    void solve() {\n        readInput();\n        buildRoadGraph();\n        buildSegments();\n        computeAPSP();\n        computeSegmentApprox();\n\n        vector<pair<double, double>> cellParams = {\n            {1.25, 0.0},\n            {1.00, 0.0},\n            {1.50, 0.0},\n            {0.75, 0.0},\n            {1.25, 30.0},\n            {1.70, 80.0}\n        };\n\n        for (int i = 0; i < (int)cellParams.size(); i++) {\n            if (i > 0 && timer.elapsed() > 2.08) break;\n\n            auto [a, l] = cellParams[i];\n            vector<int> seq = constructCellCover(a, l);\n            processCandidate(seq, i == 0);\n        }\n\n        vector<int> vcTypes = {0, 3, 5, 4, 2, 6, 1, 7};\n\n        for (int tp : vcTypes) {\n            if (timer.elapsed() > 2.30) break;\n\n            auto [selH, selV] = weightedVertexCover(tp);\n\n            vector<int> seq = constructSegmentCover(selH, selV, 1.0, 25.0);\n            processCandidate(seq, false);\n\n            if (timer.elapsed() > 2.30) break;\n\n            if (tp == 0) {\n                vector<int> seq2 = constructSegmentCover(selH, selV, 1.0, 0.0);\n                processCandidate(seq2, false);\n            }\n        }\n\n        for (int mode = 0; mode < 3; mode++) {\n            if (timer.elapsed() > 2.35) break;\n\n            auto [selH, selV] = preferenceCover(mode);\n            vector<int> seq = constructSegmentCover(selH, selV, 1.2, 10.0);\n            processCandidate(seq, false);\n        }\n\n        if (!bestSafeSeq.empty()) {\n            for (int mode = 0; mode < 2; mode++) {\n                if (timer.elapsed() > 2.38) break;\n\n                auto [selH, selV] = insertionWeightedVertexCover(bestSafeSeq, mode);\n                vector<int> seq = constructSegmentCover(selH, selV, 1.0, 15.0);\n                processCandidate(seq, false);\n            }\n        }\n\n        finalPolish();\n\n        if (!bestFinalSeq.empty() && actualFullEdges(bestFinalSeq, bestFinalEdges)) {\n            cout << buildOutput(bestFinalSeq, bestFinalEdges) << '\\n';\n        } else if (!bestSafeSeq.empty() && actualFull(bestSafeSeq)) {\n            static const vector<vector<int>> emptyEdges;\n            cout << buildOutput(bestSafeSeq, emptyEdges) << '\\n';\n        } else {\n            cout << dfsFallback() << '\\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\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconst int MAXN = 1000;\nconst int MAXM = 20;\nconst int MAXK = 20;\n\nint N, M, K, R;\nint reqv[MAXN][MAXK];\n\nvector<int> children_[MAXN];\n\nint statusTask[MAXN]; // 0: unstarted, 1: running, 2: done\nint remDep[MAXN];\nint readyDay[MAXN];\n\nint sumReq[MAXN];\nint descCnt[MAXN];\n\ndouble baseDur[MAXN];\ndouble predDur[MAXM][MAXN];\ndouble sumPred[MAXN];\ndouble upRank_[MAXN];\n\ndouble priorSkill[MAXK];\nint initSkill[MAXK];\nint upperSkill[MAXK];\n\nstatic bitset<MAXN> reachBits[MAXN];\n\nstruct Member {\n    int skill[MAXK];\n    vector<int> obsTask;\n    vector<int> obsDur;\n    int task = -1;\n    int startDay = 0;\n};\n\nMember members_[MAXM];\n\ninline double expectedTimeFromW(int w) {\n    if (w <= 0) return 1.0;\n    if (w == 1) return 13.0 / 7.0;\n    if (w == 2) return 17.0 / 7.0;\n    if (w == 3) return 22.0 / 7.0;\n    return (double)w;\n}\n\ninline int calcW(int task, const int skill[]) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        if (reqv[task][k] > skill[k]) {\n            w += reqv[task][k] - skill[k];\n        }\n    }\n    return w;\n}\n\ninline double durationWithSkill(int task, const int skill[]) {\n    return expectedTimeFromW(calcW(task, skill));\n}\n\ninline double obsLoss(int w, int t) {\n    double p = expectedTimeFromW(w);\n    double diff = p - t;\n    return diff * diff;\n}\n\nconst double PRIOR_W = 0.003;\n\ninline double priorLossComp(int k, int v) {\n    double diff = v - priorSkill[k];\n    return PRIOR_W * diff * diff;\n}\n\nvoid optimizeMember(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return;\n\n    vector<int> w(O);\n    for (int i = 0; i < O; i++) {\n        w[i] = calcW(mem.obsTask[i], mem.skill);\n    }\n\n    double curPrior = 0.0;\n    for (int k = 0; k < K; k++) {\n        curPrior += priorLossComp(k, mem.skill[k]);\n    }\n\n    double curObj = curPrior;\n    for (int i = 0; i < O; i++) {\n        curObj += obsLoss(w[i], mem.obsDur[i]);\n    }\n\n    const int MAX_PASS = 4;\n\n    for (int pass = 0; pass < MAX_PASS; pass++) {\n        bool improved = false;\n\n        for (int k = 0; k < K; k++) {\n            int oldVal = mem.skill[k];\n            double priorExcept = curPrior - priorLossComp(k, oldVal);\n\n            int bestVal = oldVal;\n            double bestObj = curObj;\n\n            for (int v = 0; v <= upperSkill[k]; v++) {\n                if (v == oldVal) continue;\n\n                double obj = priorExcept + priorLossComp(k, v);\n\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > v) {\n                        newContrib = reqv[task][k] - v;\n                    }\n\n                    int nw = w[i] - oldContrib + newContrib;\n                    obj += obsLoss(nw, mem.obsDur[i]);\n\n                    if (obj >= bestObj) break;\n                }\n\n                if (obj + 1e-9 < bestObj) {\n                    bestObj = obj;\n                    bestVal = v;\n                }\n            }\n\n            if (bestVal != oldVal) {\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > bestVal) {\n                        newContrib = reqv[task][k] - bestVal;\n                    }\n\n                    w[i] += newContrib - oldContrib;\n                }\n\n                mem.skill[k] = bestVal;\n                curPrior = priorExcept + priorLossComp(k, bestVal);\n                curObj = bestObj;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid updateMemberPredictions(int j) {\n    Member &mem = members_[j];\n\n    double nobs = (double)mem.obsTask.size();\n    double trust = 0.0;\n    if (nobs > 0) trust = nobs / (nobs + 3.0);\n\n    for (int i = 0; i < N; i++) {\n        double pSkill = durationWithSkill(i, mem.skill);\n        double np = trust * pSkill + (1.0 - trust) * baseDur[i];\n\n        sumPred[i] += np - predDur[j][i];\n        predDur[j][i] = np;\n    }\n}\n\nvoid recomputeRanks() {\n    for (int i = N - 1; i >= 0; i--) {\n        if (statusTask[i] == 2) {\n            upRank_[i] = 0.0;\n            continue;\n        }\n\n        double mx = 0.0;\n        for (int v : children_[i]) {\n            if (statusTask[v] != 2) {\n                mx = max(mx, upRank_[v]);\n            }\n        }\n\n        double avg = sumPred[i] / M;\n        upRank_[i] = avg + 0.015 * sumReq[i] + mx;\n    }\n}\n\ndouble taskPriority(int task, int day) {\n    double pr = upRank_[task];\n\n    pr += 0.015 * descCnt[task];\n    pr += 0.25 * (double)children_[task].size();\n\n    int unlock = 0;\n    for (int v : children_[task]) {\n        if (statusTask[v] == 0 && remDep[v] == 1) unlock++;\n    }\n    pr += 2.0 * unlock;\n\n    if (readyDay[task] > 0) {\n        pr += 0.015 * max(0, day - readyDay[task]);\n    }\n\n    return pr;\n}\n\ndouble edgeScore(int member, int task, double prio) {\n    double avg = sumPred[task] / M;\n    double p = predDur[member][task];\n\n    // High priority, globally long tasks, and good personal match are preferred.\n    return prio + 0.4 * avg - p;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n\n    int V;\n    vector<vector<Edge>> graph;\n\n    MinCostFlow(int n = 0) {\n        init(n);\n    }\n\n    void init(int n) {\n        V = n;\n        graph.assign(V, {});\n    }\n\n    void addEdge(int fr, int to, int cap, ll cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge r{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(r);\n    }\n\n    pair<int, ll> minCostFlow(int s, int t, int maxf) {\n        const ll INF = (1LL << 62);\n\n        int flow = 0;\n        ll cost = 0;\n\n        vector<ll> h(V, 0), dist(V);\n        vector<int> prevv(V), preve(V);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != cd) continue;\n\n                for (int i = 0; i < (int)graph[v].size(); i++) {\n                    Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n\n                    ll nd = dist[v] + e.cost + h[v] - h[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INF) break;\n\n            for (int v = 0; v < V; v++) {\n                if (dist[v] < INF) h[v] += dist[v];\n            }\n\n            int add = maxf - flow;\n            ll pathCost = 0;\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                add = min(add, e.cap);\n                pathCost += e.cost;\n            }\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= add;\n                graph[v][e.rev].cap += add;\n            }\n\n            flow += add;\n            cost += pathCost * add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> K >> R)) return 0;\n\n    for (int i = 0; i < N; i++) {\n        sumReq[i] = 0;\n        for (int k = 0; k < K; k++) {\n            cin >> reqv[i][k];\n            sumReq[i] += reqv[i][k];\n        }\n    }\n\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u;\n        --v;\n        children_[u].push_back(v);\n        remDep[v]++;\n    }\n\n    double pi = acos(-1.0);\n    double priorComp = 40.0 * sqrt(2.0 / (pi * K));\n\n    for (int k = 0; k < K; k++) {\n        priorSkill[k] = priorComp;\n        initSkill[k] = (int)round(priorComp);\n        initSkill[k] = max(0, min(60, initSkill[k]));\n        upperSkill[k] = 60;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int k = 0; k < K; k++) {\n            members_[j].skill[k] = initSkill[k];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        baseDur[i] = durationWithSkill(i, initSkill);\n        sumPred[i] = 0.0;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int i = 0; i < N; i++) {\n            predDur[j][i] = baseDur[i];\n            sumPred[i] += predDur[j][i];\n        }\n    }\n\n    for (int i = N - 1; i >= 0; i--) {\n        for (int v : children_[i]) {\n            reachBits[i] |= reachBits[v];\n            reachBits[i].set(v);\n        }\n        descCnt[i] = (int)reachBits[i].count();\n    }\n\n    for (int i = 0; i < N; i++) {\n        statusTask[i] = 0;\n        readyDay[i] = (remDep[i] == 0 ? 1 : -1);\n    }\n\n    static double prioArr[MAXN];\n\n    for (int day = 1;; day++) {\n        recomputeRanks();\n\n        vector<int> idle;\n        for (int j = 0; j < M; j++) {\n            if (members_[j].task < 0) idle.push_back(j);\n        }\n\n        vector<int> readyTasks;\n        for (int i = 0; i < N; i++) {\n            if (statusTask[i] == 0 && remDep[i] == 0) {\n                readyTasks.push_back(i);\n            }\n        }\n\n        vector<pair<int, int>> assignments;\n\n        if (!idle.empty() && !readyTasks.empty()) {\n            for (int task : readyTasks) {\n                prioArr[task] = taskPriority(task, day);\n            }\n\n            vector<int> sortedReady = readyTasks;\n            sort(sortedReady.begin(), sortedReady.end(), [&](int a, int b) {\n                if (prioArr[a] != prioArr[b]) return prioArr[a] > prioArr[b];\n                return a < b;\n            });\n\n            vector<int> candidates;\n            vector<char> inCand(N, 0);\n\n            auto addCandidate = [&](int task) {\n                if (!inCand[task]) {\n                    inCand[task] = 1;\n                    candidates.push_back(task);\n                }\n            };\n\n            int topC = min((int)sortedReady.size(), max(200, (int)idle.size() * 10));\n            for (int i = 0; i < topC; i++) {\n                addCandidate(sortedReady[i]);\n            }\n\n            const int BEST_PER_MEMBER = 10;\n\n            for (int member : idle) {\n                priority_queue<\n                    pair<double, int>,\n                    vector<pair<double, int>>,\n                    greater<pair<double, int>>\n                > pq;\n\n                for (int task : readyTasks) {\n                    double sc = edgeScore(member, task, prioArr[task]);\n                    if ((int)pq.size() < BEST_PER_MEMBER) {\n                        pq.push({sc, task});\n                    } else if (sc > pq.top().first) {\n                        pq.pop();\n                        pq.push({sc, task});\n                    }\n                }\n\n                while (!pq.empty()) {\n                    addCandidate(pq.top().second);\n                    pq.pop();\n                }\n            }\n\n            int I = (int)idle.size();\n            int C = (int)candidates.size();\n            int F = min(I, min(C, (int)readyTasks.size()));\n\n            if (F > 0) {\n                int S = 0;\n                int memberBase = 1;\n                int taskBase = memberBase + I;\n                int T = taskBase + C;\n\n                MinCostFlow mcf(T + 1);\n\n                for (int i = 0; i < I; i++) {\n                    mcf.addEdge(S, memberBase + i, 1, 0);\n                }\n\n                for (int c = 0; c < C; c++) {\n                    mcf.addEdge(taskBase + c, T, 1, 0);\n                }\n\n                const ll SCALE = 1000;\n                const ll OFFSET = 1000000000000000LL;\n\n                for (int i = 0; i < I; i++) {\n                    int member = idle[i];\n                    for (int c = 0; c < C; c++) {\n                        int task = candidates[c];\n                        double sc = edgeScore(member, task, prioArr[task]);\n                        ll isc = llround(sc * SCALE);\n                        ll cost = OFFSET - isc;\n                        if (cost < 0) cost = 0;\n                        mcf.addEdge(memberBase + i, taskBase + c, 1, cost);\n                    }\n                }\n\n                mcf.minCostFlow(S, T, F);\n\n                for (int i = 0; i < I; i++) {\n                    int node = memberBase + i;\n\n                    for (auto &e : mcf.graph[node]) {\n                        if (e.to >= taskBase && e.to < taskBase + C && e.cap == 0) {\n                            int member = idle[i];\n                            int task = candidates[e.to - taskBase];\n\n                            if (members_[member].task < 0 &&\n                                statusTask[task] == 0 &&\n                                remDep[task] == 0) {\n                                assignments.push_back({member, task});\n                            }\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        for (auto [member, task] : assignments) {\n            members_[member].task = task;\n            members_[member].startDay = day;\n            statusTask[task] = 1;\n        }\n\n        cout << assignments.size();\n        for (auto [member, task] : assignments) {\n            cout << ' ' << member + 1 << ' ' << task + 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int nFinished;\n        if (!(cin >> nFinished)) return 0;\n        if (nFinished == -1) return 0;\n\n        for (int x = 0; x < nFinished; x++) {\n            int f;\n            cin >> f;\n            --f;\n\n            int task = members_[f].task;\n            if (task < 0) continue;\n\n            int dur = day - members_[f].startDay + 1;\n\n            statusTask[task] = 2;\n            members_[f].task = -1;\n\n            members_[f].obsTask.push_back(task);\n            members_[f].obsDur.push_back(dur);\n\n            optimizeMember(f);\n            updateMemberPredictions(f);\n\n            for (int v : children_[task]) {\n                remDep[v]--;\n                if (remDep[v] == 0 && statusTask[v] == 0) {\n                    readyDay[v] = day + 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NORD = 1000;\nstatic constexpr int OFF = 1000;\nstatic constexpr int NID = 2001;\nstatic constexpr int INF = 1e9;\n\nint X[NID], Y[NID];\nint orderCentral[NORD + 1];\nvector<unsigned short> distMat;\n\ninline int distId(int a, int b) {\n    return distMat[a * NID + b];\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int m) {\n        return (int)(next() % (uint64_t)m);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct InsertRes {\n    int delta;\n    int p;\n    int q;\n};\n\nstruct Solution {\n    vector<int> route;\n    bitset<NORD + 1> selected;\n    int len = INF;\n};\n\nint routeCost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distId(route[i], route[i + 1]);\n    }\n    return s;\n}\n\nint selectedCount(const Solution& sol) {\n    return (int)sol.selected.count();\n}\n\nvector<int> selectedList(const Solution& sol) {\n    vector<int> v;\n    v.reserve(50);\n    for (int i = 1; i <= NORD; i++) {\n        if (sol.selected.test(i)) v.push_back(i);\n    }\n    return v;\n}\n\nInsertRes bestInsertion(const vector<int>& route, int oid) {\n    static constexpr int MAXG = 205;\n\n    int G = (int)route.size() - 1;\n    int P = oid;\n    int D = OFF + oid;\n    int pd = distId(P, D);\n\n    int addP[MAXG], addD[MAXG], consec[MAXG];\n    int suf[MAXG + 1], sufIdx[MAXG + 1];\n\n    for (int g = 0; g < G; g++) {\n        int A = route[g];\n        int B = route[g + 1];\n        int base = distId(A, B);\n\n        int dAP = distId(A, P);\n        int dPB = distId(P, B);\n        int dAD = distId(A, D);\n        int dDB = distId(D, B);\n\n        addP[g] = dAP + dPB - base;\n        addD[g] = dAD + dDB - base;\n        consec[g] = dAP + pd + dDB - base;\n    }\n\n    suf[G] = INF;\n    sufIdx[G] = -1;\n    for (int g = G - 1; g >= 0; g--) {\n        if (addD[g] <= suf[g + 1]) {\n            suf[g] = addD[g];\n            sufIdx[g] = g;\n        } else {\n            suf[g] = suf[g + 1];\n            sufIdx[g] = sufIdx[g + 1];\n        }\n    }\n\n    InsertRes best{INF, 0, 0};\n\n    for (int p = 0; p < G; p++) {\n        if (consec[p] < best.delta) {\n            best = {consec[p], p, p};\n        }\n        if (p + 1 < G) {\n            int cost = addP[p] + suf[p + 1];\n            if (cost < best.delta) {\n                best = {cost, p, sufIdx[p + 1]};\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid insertOrder(vector<int>& route, int oid, const InsertRes& res) {\n    int P = oid;\n    int D = OFF + oid;\n\n    if (res.q == res.p) {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.p + 2, D);\n    } else {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.q + 2, D);\n    }\n}\n\nSolution buildGreedy(int seed) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    auto add = [&](int oid, const InsertRes& res) {\n        insertOrder(sol.route, oid, res);\n        sol.selected.set(oid);\n        sol.len += res.delta;\n        cnt++;\n    };\n\n    if (seed > 0) {\n        InsertRes res = bestInsertion(sol.route, seed);\n        add(seed, res);\n    }\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        add(bestOid, best);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildFromPool(const vector<int>& pool) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid : pool) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        if (bestOid == -1) {\n            for (int oid = 1; oid <= NORD; oid++) {\n                if (sol.selected.test(oid)) continue;\n\n                InsertRes res = bestInsertion(sol.route, oid);\n                int tie = orderCentral[oid];\n\n                if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                    best = res;\n                    bestOid = oid;\n                    bestTie = tie;\n                }\n            }\n        }\n\n        insertOrder(sol.route, bestOid, best);\n        sol.selected.set(bestOid);\n        sol.len += best.delta;\n        cnt++;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildRandomizedGreedy(const vector<int>& pool, XorShift& rng, int topR, int bias) {\n    struct Choice {\n        int rank;\n        int oid;\n        InsertRes res;\n    };\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    for (int cnt = 0; cnt < 50; cnt++) {\n        Choice top[16];\n        int ts = 0;\n\n        auto consider = [&](int oid) {\n            if (sol.selected.test(oid)) return;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rank = res.delta + bias * orderCentral[oid] / 100;\n\n            Choice c{rank, oid, res};\n\n            if (ts < topR) {\n                top[ts++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < ts; i++) {\n                    if (top[i].rank > top[worst].rank) worst = i;\n                }\n                if (c.rank < top[worst].rank) top[worst] = c;\n            }\n        };\n\n        for (int oid : pool) consider(oid);\n\n        if (ts == 0) {\n            for (int oid = 1; oid <= NORD; oid++) consider(oid);\n        }\n\n        sort(top, top + ts, [](const Choice& a, const Choice& b) {\n            if (a.rank != b.rank) return a.rank < b.rank;\n            return a.oid < b.oid;\n        });\n\n        int pick = 0;\n        if (ts > 1) {\n            int r = rng.nextInt(100);\n            if (r < 55) pick = 0;\n            else if (r < 75) pick = min(1, ts - 1);\n            else if (r < 90) pick = min(2, ts - 1);\n            else pick = rng.nextInt(ts);\n        }\n\n        Choice c = top[pick];\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nvector<Solution> buildBeam(const vector<int>& pool, int W, int K, int bias) {\n    struct State {\n        vector<int> route;\n        bitset<NORD + 1> selected;\n        int len;\n    };\n\n    struct Choice {\n        int rank;\n        int len;\n        int oid;\n        InsertRes res;\n    };\n\n    vector<State> beam;\n    State init;\n    init.route = {0, 0};\n    init.selected.reset();\n    init.len = 0;\n    beam.push_back(init);\n\n    for (int step = 0; step < 50; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int oid) {\n                if (st.selected.test(oid)) return;\n\n                InsertRes res = bestInsertion(st.route, oid);\n                int nl = st.len + res.delta;\n                int rank = nl + bias * orderCentral[oid] / 100;\n\n                Choice c{rank, nl, oid, res};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int oid : pool) consider(oid);\n\n            if (ts == 0) {\n                for (int oid = 1; oid <= NORD; oid++) consider(oid);\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                if (a.rank != b.rank) return a.rank < b.rank;\n                return a.oid < b.oid;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                insertOrder(ch.route, top[i].oid, top[i].res);\n                ch.selected.set(top[i].oid);\n                ch.len = top[i].len;\n                children.push_back(std::move(ch));\n            }\n        }\n\n        if (children.empty()) break;\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            return a.len < b.len;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    vector<Solution> res;\n    for (auto& st : beam) {\n        if ((int)st.selected.count() != 50) continue;\n\n        Solution sol;\n        sol.route = std::move(st.route);\n        sol.selected = st.selected;\n        sol.len = routeCost(sol.route);\n        res.push_back(std::move(sol));\n    }\n\n    sort(res.begin(), res.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    return res;\n}\n\nvector<int> removeOrderRoute(const vector<int>& route, int oid) {\n    vector<int> nr;\n    nr.reserve(route.size() - 2);\n\n    int P = oid;\n    int D = OFF + oid;\n\n    for (int id : route) {\n        if (id != P && id != D) nr.push_back(id);\n    }\n    return nr;\n}\n\nbool twoOptDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n    vector<int> sel = selectedList(sol);\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n\n        bool timeout = false;\n\n        for (int l = 1; l <= n - 3; l++) {\n            if ((l & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int A = sol.route[l - 1];\n            int B = sol.route[l];\n            int oldAB = distId(A, B);\n\n            for (int r = l + 1; r <= n - 2; r++) {\n                int C = sol.route[r];\n                int D = sol.route[r + 1];\n\n                int delta = distId(A, C) + distId(B, D) - oldAB - distId(C, D);\n                if (delta >= bestDelta) continue;\n\n                bool ok = true;\n                for (int oid : sel) {\n                    int pp = pos[oid];\n                    int dd = pos[OFF + oid];\n\n                    if (l <= pp && dd <= r) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta < 0) {\n            reverse(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSegmentMove(const vector<int>& sel, const int pos[], int l, int r, int k) {\n    for (int oid : sel) {\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        bool inP = (l <= pp && pp <= r);\n        bool inD = (l <= dd && dd <= r);\n\n        if (inP && !inD) {\n            if (!(k < dd)) return false;\n        } else if (!inP && inD) {\n            if (!(k >= pp)) return false;\n        }\n    }\n\n    return true;\n}\n\nbool orOptDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen) {\n    bool any = false;\n    vector<int> sel = selectedList(sol);\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        int bestK = -1;\n\n        int checks = 0;\n        bool timeout = false;\n\n        for (int len = 2; len <= maxSegLen; len++) {\n            for (int l = 1; l + len - 1 <= n - 2; l++) {\n                int r = l + len - 1;\n\n                int oldLR = distId(sol.route[l - 1], sol.route[l]) +\n                            distId(sol.route[r], sol.route[r + 1]);\n\n                for (int k = 0; k <= n - 2; k++) {\n                    if (++checks % 4096 == 0 && timer.elapsed() >= deadline) {\n                        timeout = true;\n                        break;\n                    }\n\n                    if (k >= l - 1 && k <= r) continue;\n\n                    int delta =\n                        distId(sol.route[l - 1], sol.route[r + 1]) +\n                        distId(sol.route[k], sol.route[l]) +\n                        distId(sol.route[r], sol.route[k + 1]) -\n                        oldLR -\n                        distId(sol.route[k], sol.route[k + 1]);\n\n                    if (delta >= bestDelta) continue;\n\n                    if (!validSegmentMove(sel, pos, l, r, k)) continue;\n\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                    bestK = k;\n                }\n\n                if (timeout) break;\n            }\n            if (timeout) break;\n        }\n\n        if (bestDelta < 0) {\n            int segLen = bestR - bestL + 1;\n            vector<int> seg(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n\n            if (bestK < bestL) {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                sol.route.insert(sol.route.begin() + bestK + 1, seg.begin(), seg.end());\n            } else {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                int ins = bestK - segLen + 1;\n                sol.route.insert(sol.route.begin() + ins, seg.begin(), seg.end());\n            }\n\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool routeDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen = 4) {\n    bool any = false;\n\n    for (int rep = 0; rep < 5 && timer.elapsed() < deadline; rep++) {\n        bool moved = false;\n\n        if (twoOptDescent(sol, timer, deadline)) moved = true;\n\n        if (timer.elapsed() >= deadline) break;\n\n        if (orOptDescent(sol, timer, deadline, maxSegLen)) moved = true;\n\n        if (!moved) break;\n        any = true;\n    }\n\n    sol.len = routeCost(sol.route);\n    return any;\n}\n\nbool findAndApplyBestPairMove(Solution& sol, Timer& timer, double deadline) {\n    int cur = sol.len;\n    vector<int> sel = selectedList(sol);\n\n    int bestNewLen = cur;\n    int bestRem = -1;\n    int bestIns = -1;\n\n    for (int idx = 0; idx < (int)sel.size(); idx++) {\n        if (timer.elapsed() >= deadline) break;\n\n        int rem = sel[idx];\n        vector<int> tmp = removeOrderRoute(sol.route, rem);\n        int lenTmp = routeCost(tmp);\n\n        {\n            InsertRes res = bestInsertion(tmp, rem);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = rem;\n            }\n        }\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(tmp, oid);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = oid;\n            }\n        }\n    }\n\n    if (bestRem == -1) return false;\n\n    vector<int> tmp = removeOrderRoute(sol.route, bestRem);\n\n    if (bestIns != bestRem) {\n        sol.selected.reset(bestRem);\n        sol.selected.set(bestIns);\n    }\n\n    InsertRes res = bestInsertion(tmp, bestIns);\n    insertOrder(tmp, bestIns, res);\n\n    sol.route.swap(tmp);\n    sol.len = routeCost(sol.route);\n\n    return sol.len < cur;\n}\n\nvoid localImprove(Solution& sol, Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 4);\n\n        if (timer.elapsed() >= deadline) break;\n\n        bool moved = findAndApplyBestPairMove(sol, timer, deadline);\n        if (!moved) break;\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nSolution rebuildFixedOrder(const Solution& base, vector<int> orders) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    for (int oid : orders) {\n        InsertRes res = bestInsertion(sol.route, oid);\n        insertOrder(sol.route, oid, res);\n        sol.len += res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildFixedGreedy(const Solution& base) {\n    vector<int> orders = selectedList(base);\n    int m = (int)orders.size();\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    vector<char> used(m, 0);\n\n    for (int cnt = 0; cnt < m; cnt++) {\n        int bestIdx = -1;\n        InsertRes best{INF, 0, 0};\n\n        for (int i = 0; i < m; i++) {\n            if (used[i]) continue;\n\n            InsertRes res = bestInsertion(sol.route, orders[i]);\n            if (res.delta < best.delta) {\n                best = res;\n                bestIdx = i;\n            }\n        }\n\n        used[bestIdx] = 1;\n        insertOrder(sol.route, orders[bestIdx], best);\n        sol.len += best.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildSequentialBeam(const Solution& base, int W, int K) {\n    vector<int> orders = selectedList(base);\n    int M = (int)orders.size();\n    if (M != 50) return base;\n\n    struct State {\n        uint64_t picked;\n        uint64_t delivered;\n        int last;\n        int cost;\n        int eval;\n        vector<int> route;\n    };\n\n    struct Choice {\n        int rank;\n        int node;\n        int idx;\n        int type;\n        int add;\n    };\n\n    uint64_t fullMask = (1ULL << M) - 1ULL;\n\n    vector<State> beam;\n    State init;\n    init.picked = 0;\n    init.delivered = 0;\n    init.last = 0;\n    init.cost = 0;\n    init.eval = 0;\n    init.route = {0};\n    beam.push_back(init);\n\n    for (int step = 0; step < 2 * M; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int node, int idx, int type) {\n                int add = distId(st.last, node);\n                int rank = add + distId(node, 0) / 6;\n\n                Choice c{rank, node, idx, type, add};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int j = 0; j < M; j++) {\n                uint64_t bit = 1ULL << j;\n\n                if (!(st.picked & bit)) {\n                    consider(orders[j], j, 0);\n                } else if (!(st.delivered & bit)) {\n                    consider(OFF + orders[j], j, 1);\n                }\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                return a.rank < b.rank;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                uint64_t bit = 1ULL << top[i].idx;\n\n                if (top[i].type == 0) ch.picked |= bit;\n                else ch.delivered |= bit;\n\n                ch.last = top[i].node;\n                ch.cost += top[i].add;\n                ch.eval = ch.cost + distId(ch.last, 0);\n                ch.route.push_back(top[i].node);\n\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    int best = -1;\n    int bestCost = INF;\n\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (beam[i].delivered != fullMask) continue;\n\n        int c = beam[i].cost + distId(beam[i].last, 0);\n        if (c < bestCost) {\n            bestCost = c;\n            best = i;\n        }\n    }\n\n    if (best == -1) return base;\n\n    Solution sol;\n    sol.selected = base.selected;\n    sol.route = std::move(beam[best].route);\n    sol.route.push_back(0);\n    sol.len = routeCost(sol.route);\n\n    return sol;\n}\n\nvoid tryRebuilds(Solution& sol, XorShift& rng, Timer& timer, double deadline) {\n    if (timer.elapsed() >= deadline) return;\n\n    {\n        Solution g = rebuildFixedGreedy(sol);\n        routeDescent(g, timer, min(deadline, timer.elapsed() + 0.035), 3);\n        if (g.len < sol.len) sol = std::move(g);\n    }\n\n    if (timer.elapsed() < deadline) {\n        Solution b = rebuildSequentialBeam(sol, 80, 8);\n        routeDescent(b, timer, min(deadline, timer.elapsed() + 0.040), 3);\n        if (b.len < sol.len) sol = std::move(b);\n    }\n\n    for (int it = 0; it < 2 && timer.elapsed() < deadline; it++) {\n        vector<int> orders = selectedList(sol);\n\n        for (int i = (int)orders.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(orders[i], orders[j]);\n        }\n\n        Solution r = rebuildFixedOrder(sol, orders);\n        routeDescent(r, timer, min(deadline, timer.elapsed() + 0.030), 3);\n\n        if (r.len < sol.len) sol = std::move(r);\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nstruct Cand {\n    int rankCost;\n    int oid;\n    InsertRes res;\n};\n\nSolution ruinRecreate(const Solution& base, int k, XorShift& rng, Timer& timer, double deadline) {\n    Solution sol = base;\n    vector<int> sel = selectedList(base);\n    k = min(k, (int)sel.size());\n\n    vector<char> rem(NORD + 1, 0);\n    vector<int> toRemove;\n\n    int strategy = rng.nextInt(3);\n\n    if (strategy == 0) {\n        vector<pair<int, int>> savings;\n        savings.reserve(sel.size());\n\n        for (int oid : sel) {\n            vector<int> tmp = removeOrderRoute(base.route, oid);\n            int l = routeCost(tmp);\n            savings.push_back({base.len - l, oid});\n        }\n\n        sort(savings.begin(), savings.end(), [](const auto& a, const auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int topLimit = min(25, (int)savings.size());\n\n        while ((int)toRemove.size() < k) {\n            int idx;\n            if (rng.nextInt(100) < 75) idx = rng.nextInt(topLimit);\n            else idx = rng.nextInt((int)savings.size());\n\n            int oid = savings[idx].second;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 1) {\n        while ((int)toRemove.size() < k) {\n            int oid = sel[rng.nextInt((int)sel.size())];\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else {\n        int pos[NID];\n        for (int i = 0; i < (int)base.route.size(); i++) {\n            pos[base.route[i]] = i;\n        }\n\n        int seed = sel[rng.nextInt((int)sel.size())];\n        int sp = pos[seed];\n        int sd = pos[OFF + seed];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int pp = pos[oid];\n            int dd = pos[OFF + oid];\n\n            int sc = min({\n                abs(pp - sp),\n                abs(pp - sd),\n                abs(dd - sp),\n                abs(dd - sd)\n            });\n\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    }\n\n    for (int oid : toRemove) {\n        sol.selected.reset(oid);\n    }\n\n    vector<int> nr;\n    nr.reserve(base.route.size());\n\n    for (int id : base.route) {\n        if (id == 0) {\n            nr.push_back(id);\n        } else {\n            int oid = (id <= OFF ? id : id - OFF);\n            if (!rem[oid]) nr.push_back(id);\n        }\n    }\n\n    sol.route.swap(nr);\n    sol.len = routeCost(sol.route);\n\n    int removedPenalty = 8 + rng.nextInt(40);\n\n    for (int t = 0; t < k; t++) {\n        static constexpr int R = 6;\n        Cand top[R];\n        int topSize = 0;\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rankCost = res.delta + (rem[oid] ? removedPenalty : 0);\n\n            Cand c{rankCost, oid, res};\n\n            if (topSize < R) {\n                top[topSize++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < R; i++) {\n                    if (top[i].rankCost > top[worst].rankCost) worst = i;\n                }\n                if (c.rankCost < top[worst].rankCost) top[worst] = c;\n            }\n        }\n\n        sort(top, top + topSize, [](const Cand& a, const Cand& b) {\n            return a.rankCost < b.rankCost;\n        });\n\n        int pick = 0;\n        if (topSize > 1) {\n            int roll = rng.nextInt(100);\n            if (roll < 62) pick = 0;\n            else if (roll < 82) pick = min(1, topSize - 1);\n            else if (roll < 93) pick = min(2, topSize - 1);\n            else pick = rng.nextInt(topSize);\n        }\n\n        Cand c = top[pick];\n\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    if (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 3);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nbool validate(const Solution& sol) {\n    if (selectedCount(sol) != 50) return false;\n    if (sol.route.empty()) return false;\n    if (sol.route.front() != 0 || sol.route.back() != 0) return false;\n\n    vector<int> pp(NORD + 1, -1), dd(NORD + 1, -1);\n\n    for (int i = 0; i < (int)sol.route.size(); i++) {\n        int id = sol.route[i];\n\n        if (id == 0) continue;\n\n        if (1 <= id && id <= NORD) {\n            pp[id] = i;\n        } else if (OFF < id && id <= OFF + NORD) {\n            dd[id - OFF] = i;\n        } else {\n            return false;\n        }\n    }\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (!sol.selected.test(oid)) continue;\n        if (pp[oid] == -1 || dd[oid] == -1) return false;\n        if (pp[oid] >= dd[oid]) return false;\n    }\n\n    return true;\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    for (int i = 1; i <= NORD; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n\n        X[i] = a;\n        Y[i] = b;\n        X[OFF + i] = c;\n        Y[OFF + i] = d;\n    }\n\n    distMat.assign(NID * NID, 0);\n\n    for (int i = 0; i < NID; i++) {\n        for (int j = 0; j <= i; j++) {\n            int v = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n            distMat[i * NID + j] = distMat[j * NID + i] = (unsigned short)v;\n        }\n    }\n\n    vector<pair<int, int>> firstCost;\n    firstCost.reserve(NORD);\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        int dP = distId(0, oid);\n        int dD = distId(0, OFF + oid);\n        int pd = distId(oid, OFF + oid);\n\n        orderCentral[oid] = dP + dD;\n        firstCost.push_back({dP + pd + dD, oid});\n    }\n\n    sort(firstCost.begin(), firstCost.end());\n\n    Timer timer;\n    XorShift rng(1234567891234567ull);\n\n    vector<int> allIds(NORD);\n    iota(allIds.begin(), allIds.end(), 1);\n\n    vector<Solution> candidates;\n\n    auto addCandidate = [&](Solution sol) {\n        if (selectedCount(sol) == 50) {\n            sol.len = routeCost(sol.route);\n            candidates.push_back(std::move(sol));\n        }\n    };\n\n    addCandidate(buildGreedy(firstCost[0].second));\n\n    const double INIT_DEAD = 0.60;\n\n    if (timer.elapsed() < INIT_DEAD) {\n        auto sols = buildBeam(allIds, 10, 4, 0);\n        for (int i = 0; i < (int)sols.size() && i < 5; i++) {\n            addCandidate(std::move(sols[i]));\n        }\n    }\n\n    if (timer.elapsed() < INIT_DEAD) {\n        auto sols = buildBeam(allIds, 8, 4, 5);\n        for (int i = 0; i < (int)sols.size() && i < 4; i++) {\n            addCandidate(std::move(sols[i]));\n        }\n    }\n\n    vector<vector<int>> sortedModes;\n\n    for (int mode = 0; mode < 6; mode++) {\n        vector<pair<int, int>> score;\n        score.reserve(NORD);\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            int dP = distId(0, oid);\n            int dD = distId(0, OFF + oid);\n            int pd = distId(oid, OFF + oid);\n\n            int linf = max({\n                abs(X[oid] - 400),\n                abs(Y[oid] - 400),\n                abs(X[OFF + oid] - 400),\n                abs(Y[OFF + oid] - 400)\n            });\n\n            int mid = abs(X[oid] + X[OFF + oid] - 800) +\n                      abs(Y[oid] + Y[OFF + oid] - 800);\n\n            int sc;\n\n            if (mode == 0) {\n                sc = dP + dD;\n            } else if (mode == 1) {\n                sc = max(dP, dD) * 2000 + dP + dD;\n            } else if (mode == 2) {\n                sc = dP + dD + pd;\n            } else if (mode == 3) {\n                sc = linf * 2000 + dP + dD;\n            } else if (mode == 4) {\n                sc = max(dP, dD) * 3 + min(dP, dD);\n            } else {\n                sc = dP + dD + mid;\n            }\n\n            score.push_back({sc, oid});\n        }\n\n        sort(score.begin(), score.end());\n\n        vector<int> ord;\n        ord.reserve(NORD);\n        for (auto [sc, oid] : score) ord.push_back(oid);\n        sortedModes.push_back(std::move(ord));\n    }\n\n    vector<int> poolSizes = {50, 60, 80, 100, 140, 200, 300};\n\n    for (int mode = 0; mode < (int)sortedModes.size(); mode++) {\n        for (int ps : poolSizes) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<int> pool(sortedModes[mode].begin(), sortedModes[mode].begin() + ps);\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    if (timer.elapsed() < INIT_DEAD) {\n        vector<int> pool(sortedModes[0].begin(), sortedModes[0].begin() + 300);\n        auto sols = buildBeam(pool, 8, 4, 0);\n        for (int i = 0; i < (int)sols.size() && i < 4; i++) {\n            addCandidate(std::move(sols[i]));\n        }\n    }\n\n    for (int idx = 1; idx < 20 && timer.elapsed() < INIT_DEAD; idx++) {\n        addCandidate(buildGreedy(firstCost[idx].second));\n    }\n\n    while (timer.elapsed() < INIT_DEAD && (int)candidates.size() < 55) {\n        if (rng.nextInt(2) == 0) {\n            addCandidate(buildRandomizedGreedy(allIds, rng, 8, 0));\n        } else {\n            vector<int> pool(sortedModes[rng.nextInt((int)sortedModes.size())].begin(),\n                             sortedModes[rng.nextInt((int)sortedModes.size())].begin() + 300);\n            addCandidate(buildRandomizedGreedy(pool, rng, 8, 2));\n        }\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    if (candidates.empty()) {\n        candidates.push_back(buildGreedy(firstCost[0].second));\n    }\n\n    const double QUICK_DEAD = 0.78;\n\n    for (int i = 0; i < (int)candidates.size() && i < 12 && timer.elapsed() < QUICK_DEAD; i++) {\n        double sub = min(QUICK_DEAD, timer.elapsed() + 0.025);\n        routeDescent(candidates[i], timer, sub, 3);\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    Solution bestOverall = candidates[0];\n\n    const double LOCAL_DEAD = 1.32;\n\n    int starts = min(5, (int)candidates.size());\n\n    for (int i = 0; i < starts && timer.elapsed() < LOCAL_DEAD; i++) {\n        Solution sol = candidates[i];\n\n        double sub = min(LOCAL_DEAD, timer.elapsed() + 0.15);\n        localImprove(sol, timer, sub);\n\n        if (sol.len < bestOverall.len) {\n            bestOverall = std::move(sol);\n        }\n    }\n\n    const double REBUILD_DEAD = 1.43;\n\n    if (timer.elapsed() < REBUILD_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, REBUILD_DEAD);\n        localImprove(bestOverall, timer, REBUILD_DEAD);\n    }\n\n    Solution current = bestOverall;\n\n    const double LNS_DEAD = 1.86;\n\n    while (timer.elapsed() < LNS_DEAD) {\n        if (LNS_DEAD - timer.elapsed() < 0.04) break;\n\n        int roll = rng.nextInt(100);\n        int k;\n\n        if (roll < 60) {\n            k = 3 + rng.nextInt(5);       // 3..7\n        } else if (roll < 90) {\n            k = 8 + rng.nextInt(6);       // 8..13\n        } else {\n            k = 14 + rng.nextInt(7);      // 14..20\n        }\n\n        const Solution& base = (rng.nextInt(5) == 0 ? current : bestOverall);\n\n        Solution cand = ruinRecreate(base, k, rng, timer, LNS_DEAD);\n\n        if (cand.len < bestOverall.len) {\n            bestOverall = std::move(cand);\n\n            double sub = min(LNS_DEAD, timer.elapsed() + 0.10);\n            localImprove(bestOverall, timer, sub);\n\n            if (timer.elapsed() < LNS_DEAD) {\n                tryRebuilds(bestOverall, rng, timer, min(LNS_DEAD, timer.elapsed() + 0.05));\n            }\n\n            current = bestOverall;\n        } else {\n            int diff = cand.len - current.len;\n            double progress = min(1.0, timer.elapsed() / LNS_DEAD);\n            double temp = 45.0 * (1.0 - progress) + 3.0;\n\n            if (diff < 0 || rng.nextDouble() < exp(-(double)diff / temp)) {\n                current = std::move(cand);\n            }\n\n            if (current.len > bestOverall.len + 350) {\n                current = bestOverall;\n            }\n        }\n    }\n\n    const double FINAL_DEAD = 1.91;\n\n    if (timer.elapsed() < FINAL_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, min(FINAL_DEAD, timer.elapsed() + 0.06));\n    }\n\n    localImprove(bestOverall, timer, FINAL_DEAD);\n\n    bestOverall.len = routeCost(bestOverall.route);\n\n    if (!validate(bestOverall)) {\n        bestOverall = buildGreedy(firstCost[0].second);\n    }\n\n    cout << 50;\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (bestOverall.selected.test(oid)) {\n            cout << ' ' << oid;\n        }\n    }\n    cout << '\\n';\n\n    cout << bestOverall.route.size();\n    for (int id : bestOverall.route) {\n        cout << ' ' << X[id] << ' ' << Y[id];\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 SAMPLES = 64;\nstatic constexpr int INF = 1e9;\n\n// Blend between clairvoyant Monte Carlo estimate and deterministic expected-weight estimate.\nstatic constexpr double BLEND = 0.22;\n\nstruct DSU {\n    int p[N];\n    int comps;\n\n    void init() {\n        comps = N;\n        for (int i = 0; i < N; i++) p[i] = -1;\n    }\n\n    int find(int x) const {\n        while (p[x] >= 0) x = p[x];\n        return x;\n    }\n\n    bool same(int a, int b) const {\n        return find(a) == find(b);\n    }\n\n    bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (p[a] > p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        comps--;\n        return true;\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next() % uint64_t(r - l + 1));\n    }\n};\n\nint xcoord[N], ycoord[N];\nint U[M], V[M], D[M];\n\nstatic int sampleW[SAMPLES][M];\nstatic int orderSample[SAMPLES][M];\nstatic int orderMean[M];\n\nint bottleneck_sample(int s, int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderSample[s][pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return sampleW[s][e];\n        }\n    }\n    return INF;\n}\n\nint bottleneck_mean(int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderMean[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return 2 * D[e];\n        }\n    }\n    return INF;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    for (int i = 0; i < N; i++) {\n        cin >> xcoord[i] >> ycoord[i];\n    }\n\n    uint64_t seed = 123456789;\n    for (int i = 0; i < N; i++) {\n        seed ^= uint64_t(xcoord[i] + 1009) * 0x9e3779b97f4a7c15ULL;\n        seed ^= uint64_t(ycoord[i] + 9176) * 0xbf58476d1ce4e5b9ULL;\n    }\n\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n\n        long long dx = xcoord[U[i]] - xcoord[V[i]];\n        long long dy = ycoord[U[i]] - ycoord[V[i]];\n        D[i] = int(sqrt(double(dx * dx + dy * dy)) + 0.5);\n\n        seed ^= uint64_t(U[i] + 1) * 0x94d049bb133111ebULL;\n        seed ^= uint64_t(V[i] + 1) * 0x2545f4914f6cdd1dULL;\n    }\n\n    SplitMix64 rng(seed);\n\n    // Antithetic Monte Carlo samples.\n    for (int s = 0; s < SAMPLES; s += 2) {\n        for (int e = 0; e < M; e++) {\n            int range = 2 * D[e] + 1;\n            int k = int(rng.next() % uint64_t(range));\n            sampleW[s][e] = D[e] + k;\n            sampleW[s + 1][e] = 3 * D[e] - k;\n        }\n    }\n\n    vector<int> ids(M);\n    iota(ids.begin(), ids.end(), 0);\n\n    for (int s = 0; s < SAMPLES; s++) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (sampleW[s][a] != sampleW[s][b]) return sampleW[s][a] < sampleW[s][b];\n            return a < b;\n        });\n        for (int i = 0; i < M; i++) orderSample[s][i] = ids[i];\n    }\n\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n    for (int i = 0; i < M; i++) orderMean[i] = ids[i];\n\n    DSU accepted;\n    accepted.init();\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        cin >> l;\n\n        int ans = 0;\n\n        if (!accepted.same(U[i], V[i])) {\n            int det = bottleneck_mean(i, U[i], V[i], accepted);\n\n            if (det >= INF) {\n                // This edge is necessary for future connectivity.\n                ans = 1;\n            } else {\n                long long sum = 0;\n                for (int s = 0; s < SAMPLES; s++) {\n                    int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                    sum += b;\n                }\n\n                double mc = double(sum) / SAMPLES;\n                double threshold = mc + BLEND * (double(det) - mc);\n\n                if (double(l) <= threshold) ans = 1;\n            }\n\n            if (ans) accepted.unite(U[i], V[i]);\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int G = 30;\nconst int INF = 1e9;\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar DIR_CH[4] = {'U', 'D', 'L', 'R'};\n\nint dirId(char ch) {\n    ch = toupper(ch);\n    if (ch == 'U') return 0;\n    if (ch == 'D') return 1;\n    if (ch == 'L') return 2;\n    return 3;\n}\n\nbool inside(int r, int c) {\n    return 0 <= r && r < G && 0 <= c && c < G;\n}\n\nstruct Pet {\n    int r, c, t;\n};\n\npair<int,int> toPhysCoord(int r, int c, int ori) {\n    if (ori == 0) return {r, c};             // corridor = bottom\n    if (ori == 1) return {G - 1 - r, c};     // corridor = top\n    if (ori == 2) return {c, r};             // corridor = right\n    return {c, G - 1 - r};                   // corridor = left\n}\n\npair<int,int> toLogCoord(int pr, int pc, int ori) {\n    if (ori == 0) return {pr, pc};\n    if (ori == 1) return {G - 1 - pr, pc};\n    if (ori == 2) return {pc, pr};\n    return {G - 1 - pc, pr};\n}\n\nint chooseOrientation(const vector<Pet>& petsPhys, const vector<pair<int,int>>& humansPhys) {\n    double best = 1e100;\n    int bestOri = 0;\n\n    for (int ori = 0; ori < 4; ori++) {\n        double cost = 0.0;\n\n        for (auto p : petsPhys) {\n            auto [r, c] = toLogCoord(p.r, p.c, ori);\n            int distCorr = G - 1 - r;\n\n            double w = 1.0;\n            if (p.t == 4) w = 3.0;      // dog\n            else if (p.t == 3) w = 1.5;\n            else if (p.t == 5) w = 1.4;\n            else if (p.t == 2) w = 1.2;\n\n            int near = max(0, 12 - distCorr);\n            cost += w * near * near;\n            if (r >= 28) cost += 100.0 * w;\n        }\n\n        for (auto h : humansPhys) {\n            auto [r, c] = toLogCoord(h.first, h.second, ori);\n            int bestStand = 100;\n            for (int s = 2; s <= 26; s += 4) {\n                bestStand = min(bestStand, abs(c - s));\n            }\n            cost += 0.5 * (G - 1 - r) + 0.2 * bestStand;\n        }\n\n        if (cost < best) {\n            best = cost;\n            bestOri = ori;\n        }\n    }\n\n    return bestOri;\n}\n\nstruct Task {\n    int stand;\n    vector<int> walls;\n    int assigned = -1; // -1: free, >=0: human id, -2: finished\n};\n\nstruct HState {\n    int task = -1;\n    int phase = 0;\n    int wait = 0;\n    int home = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, ori;\n    int turnNo = 0;\n\n    vector<Pet> pets;\n    vector<pair<int,int>> humans;\n\n    bool blocked[G][G]{};\n    bool petOcc[G][G]{};\n    bool humanOcc[G][G]{};\n    bool resBuild[G][G]{};\n    bool resMove[G][G]{};\n\n    vector<Task> tasks;\n    vector<HState> hs;\n\n    char logToPhys[256]{};\n    char physToLog[256]{};\n\n    static constexpr int FREE = 0;\n    static constexpr int GO = 1;\n    static constexpr int UP = 2;\n    static constexpr int DOWN = 3;\n    static constexpr int RET = 4;\n\n    static constexpr int ASSIGN_LIMIT = 190;\n    static constexpr int BUILD_LIMIT = 265;\n    static constexpr int WAIT_UNTIL = 230;\n    static constexpr int WAIT_LIMIT = 2;\n\n    Solver(int n,\n           const vector<Pet>& petsPhys,\n           int m,\n           const vector<pair<int,int>>& humansPhys,\n           int orientation)\n        : N(n), M(m), ori(orientation)\n    {\n        initDirectionMaps();\n\n        pets.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto [r, c] = toLogCoord(petsPhys[i].r, petsPhys[i].c, ori);\n            pets[i] = {r, c, petsPhys[i].t};\n        }\n\n        humans.resize(M);\n        for (int i = 0; i < M; i++) {\n            humans[i] = toLogCoord(humansPhys[i].first, humansPhys[i].second, ori);\n        }\n\n        initTasks();\n\n        hs.resize(M);\n        for (int i = 0; i < M; i++) {\n            hs[i].home = (i + 1) * G / (M + 1);\n        }\n    }\n\n    void initDirectionMaps() {\n        memset(logToPhys, 0, sizeof(logToPhys));\n        memset(physToLog, 0, sizeof(physToLog));\n\n        int br = 15, bc = 15;\n        for (char ch : string(\"UDLR\")) {\n            int d = dirId(ch);\n            auto p1 = toPhysCoord(br, bc, ori);\n            auto p2 = toPhysCoord(br + DR[d], bc + DC[d], ori);\n            int rr = p2.first - p1.first;\n            int cc = p2.second - p1.second;\n\n            char pc = '?';\n            if (rr == -1 && cc == 0) pc = 'U';\n            if (rr == 1 && cc == 0) pc = 'D';\n            if (rr == 0 && cc == -1) pc = 'L';\n            if (rr == 0 && cc == 1) pc = 'R';\n\n            logToPhys[(int)ch] = pc;\n            physToLog[(int)pc] = ch;\n        }\n    }\n\n    void initTasks() {\n        // Logical wall columns: 1,3,5,...,27.\n        // Each task uses an even stand column and builds both adjacent walls.\n        for (int s = 2; s <= 26; s += 4) {\n            Task t;\n            t.stand = s;\n            t.walls = {s - 1, s + 1};\n            tasks.push_back(t);\n        }\n    }\n\n    void buildOcc() {\n        memset(petOcc, 0, sizeof(petOcc));\n        memset(humanOcc, 0, sizeof(humanOcc));\n\n        for (auto &p : pets) {\n            if (inside(p.r, p.c)) petOcc[p.r][p.c] = true;\n        }\n        for (auto &h : humans) {\n            if (inside(h.first, h.second)) humanOcc[h.first][h.second] = true;\n        }\n    }\n\n    void resetReservations() {\n        memset(resBuild, 0, sizeof(resBuild));\n        memset(resMove, 0, sizeof(resMove));\n    }\n\n    bool canBuild(int i, char lowerDir) {\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (petOcc[r][c]) return false;\n        if (humanOcc[r][c]) return false;\n        if (resMove[r][c]) return false;\n\n        for (int k = 0; k < 4; k++) {\n            int nr = r + DR[k], nc = c + DC[k];\n            if (inside(nr, nc) && petOcc[nr][nc]) return false;\n        }\n\n        return true;\n    }\n\n    bool canMove(int i, char upperDir) {\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (blocked[r][c]) return false;\n        if (resBuild[r][c]) return false;\n        return true;\n    }\n\n    bool issueBuild(int i, char lowerDir, vector<char>& act) {\n        lowerDir = tolower(lowerDir);\n        if (!canBuild(i, lowerDir)) return false;\n\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = lowerDir;\n        resBuild[r][c] = true;\n        return true;\n    }\n\n    bool issueMove(int i, char upperDir, vector<char>& act) {\n        upperDir = toupper(upperDir);\n        if (!canMove(i, upperDir)) return false;\n\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = upperDir;\n        resMove[r][c] = true;\n        return true;\n    }\n\n    bool taskComplete(int tid) {\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) return false;\n            }\n        }\n        return true;\n    }\n\n    int countRemainingBuilds(int tid) {\n        int cnt = 0;\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int shortestDist(pair<int,int> st, pair<int,int> goal) {\n        if (!inside(goal.first, goal.second)) return INF;\n        if (blocked[goal.first][goal.second]) return INF;\n\n        int dist[G][G];\n        for (int r = 0; r < G; r++) for (int c = 0; c < G; c++) dist[r][c] = -1;\n\n        queue<pair<int,int>> q;\n        dist[st.first][st.second] = 0;\n        q.push(st);\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            if (r == goal.first && c == goal.second) return dist[r][c];\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (dist[nr][nc] != -1) continue;\n\n                dist[nr][nc] = dist[r][c] + 1;\n                q.push({nr, nc});\n            }\n        }\n\n        return INF;\n    }\n\n    char bfsMove(int i, const vector<pair<int,int>>& goals) {\n        bool goal[G][G]{};\n        int goalCnt = 0;\n\n        for (auto [r, c] : goals) {\n            if (!inside(r, c)) continue;\n            if (blocked[r][c]) continue;\n            if (resBuild[r][c]) continue;\n            if (!goal[r][c]) {\n                goal[r][c] = true;\n                goalCnt++;\n            }\n        }\n\n        if (goalCnt == 0) return '.';\n\n        int sr = humans[i].first;\n        int sc = humans[i].second;\n\n        if (goal[sr][sc]) return '.';\n\n        bool vis[G][G]{};\n        char first[G][G]{};\n\n        queue<pair<int,int>> q;\n        vis[sr][sc] = true;\n        q.push({sr, sc});\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (resBuild[nr][nc]) continue;\n                if (vis[nr][nc]) continue;\n\n                vis[nr][nc] = true;\n                first[nr][nc] = (r == sr && c == sc ? DIR_CH[d] : first[r][c]);\n\n                if (goal[nr][nc]) return first[nr][nc];\n\n                q.push({nr, nc});\n            }\n        }\n\n        return '.';\n    }\n\n    int taskPriority(int tid) {\n        int s = tasks[tid].stand;\n        int pr = 0;\n\n        for (auto &p : pets) {\n            int w = 1;\n            if (p.t == 4) w = 6;\n            else if (p.t == 5) w = 3;\n            else if (p.t == 3) w = 3;\n            else if (p.t == 2) w = 2;\n\n            if (p.r <= 28) {\n                int dc = abs(p.c - s);\n                if (dc <= 2) pr += w * (3 - dc);\n                else if (dc <= 4) pr += 1;\n            } else {\n                if (abs(p.c - s) <= 2) pr += 1;\n            }\n        }\n\n        return pr;\n    }\n\n    void normalizeStates() {\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task == -1) continue;\n\n            int tid = hs[i].task;\n            bool comp = taskComplete(tid);\n\n            if (comp) hs[i].phase = RET;\n            if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n            if (humans[i].first == 29 && hs[i].phase == RET) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n            }\n        }\n    }\n\n    void assignTasks() {\n        if (turnNo > ASSIGN_LIMIT) return;\n\n        while (true) {\n            int bestI = -1, bestT = -1;\n            double bestVal = -1e100;\n\n            for (int i = 0; i < M; i++) {\n                if (hs[i].task != -1) continue;\n\n                for (int tid = 0; tid < (int)tasks.size(); tid++) {\n                    if (tasks[tid].assigned != -1) continue;\n                    if (taskComplete(tid)) continue;\n\n                    int stand = tasks[tid].stand;\n                    if (blocked[28][stand]) continue;\n\n                    int dist = shortestDist(humans[i], {29, stand});\n                    if (dist >= INF) continue;\n\n                    int rem = countRemainingBuilds(tid);\n                    int estimate = dist + rem + 58;\n                    if (turnNo + estimate > BUILD_LIMIT + 8) continue;\n\n                    double val = 50.0 * taskPriority(tid) - dist;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestI = i;\n                        bestT = tid;\n                    }\n                }\n            }\n\n            if (bestI == -1) break;\n\n            hs[bestI].task = bestT;\n            hs[bestI].phase = GO;\n            hs[bestI].wait = 0;\n            tasks[bestT].assigned = bestI;\n        }\n    }\n\n    array<bool, G> computeDoorTargets() {\n        array<bool, G> need;\n        need.fill(false);\n\n        struct Comp {\n            int area = 0;\n            int pets = 0;\n            bool protect = false;\n            vector<int> doors;\n        };\n\n        int compId[G][G];\n        for (int r = 0; r < G; r++) {\n            for (int c = 0; c < G; c++) compId[r][c] = -1;\n        }\n\n        vector<Comp> comps;\n\n        for (int sr = 0; sr <= 28; sr++) {\n            for (int sc = 0; sc < G; sc++) {\n                if (blocked[sr][sc]) continue;\n                if (compId[sr][sc] != -1) continue;\n\n                int id = (int)comps.size();\n                comps.push_back(Comp());\n\n                queue<pair<int,int>> q;\n                compId[sr][sc] = id;\n                q.push({sr, sc});\n\n                while (!q.empty()) {\n                    auto [r, c] = q.front();\n                    q.pop();\n\n                    comps[id].area++;\n\n                    if (r == 28 && !blocked[29][c]) {\n                        comps[id].doors.push_back(c);\n                    }\n\n                    for (int d = 0; d < 4; d++) {\n                        int nr = r + DR[d], nc = c + DC[d];\n                        if (!inside(nr, nc)) continue;\n                        if (nr == 29) continue; // bottom corridor excluded\n                        if (blocked[nr][nc]) continue;\n                        if (compId[nr][nc] != -1) continue;\n\n                        compId[nr][nc] = id;\n                        q.push({nr, nc});\n                    }\n                }\n            }\n        }\n\n        int corridorPets = 0;\n\n        for (auto &p : pets) {\n            if (p.r == 29) {\n                corridorPets++;\n            } else if (0 <= p.r && p.r <= 28) {\n                int id = compId[p.r][p.c];\n                if (id >= 0) comps[id].pets++;\n            }\n        }\n\n        for (auto &h : humans) {\n            if (h.first <= 28) {\n                int id = compId[h.first][h.second];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        // Protect components currently needed by active builders.\n        for (int i = 0; i < M; i++) {\n            int tid = hs[i].task;\n            if (tid == -1) continue;\n            if (hs[i].phase == RET) continue;\n            if (taskComplete(tid)) continue;\n\n            int s = tasks[tid].stand;\n            if (!blocked[28][s]) {\n                int id = compId[28][s];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        int baseArea = 0;\n        for (int c = 0; c < G; c++) {\n            if (!blocked[29][c]) baseArea++;\n        }\n\n        int basePets = corridorPets;\n        (void)basePets; // constant for subset choice\n\n        struct Item {\n            int comp;\n            int area;\n            int pets;\n        };\n\n        vector<Item> items;\n\n        for (int id = 0; id < (int)comps.size(); id++) {\n            auto &cp = comps[id];\n\n            if (cp.doors.empty()) continue; // already isolated from corridor\n\n            if (cp.protect || cp.pets == 0) {\n                baseArea += cp.area;\n                basePets += cp.pets;\n            } else {\n                items.push_back({id, cp.area, cp.pets});\n            }\n        }\n\n        int K = (int)items.size();\n        int maxP = N;\n\n        vector<vector<int>> dp(K + 1, vector<int>(maxP + 1, -INF));\n        vector<vector<int>> pre(K + 1, vector<int>(maxP + 1, -1));\n        vector<vector<char>> take(K + 1, vector<char>(maxP + 1, 0));\n\n        dp[0][0] = baseArea;\n\n        for (int k = 0; k < K; k++) {\n            int a = items[k].area;\n            int p = items[k].pets;\n\n            for (int q = 0; q <= maxP; q++) {\n                if (dp[k][q] < 0) continue;\n\n                // Close this component.\n                if (dp[k][q] > dp[k + 1][q]) {\n                    dp[k + 1][q] = dp[k][q];\n                    pre[k + 1][q] = q;\n                    take[k + 1][q] = 0;\n                }\n\n                // Leave it open.\n                if (q + p <= maxP && dp[k][q] + a > dp[k + 1][q + p]) {\n                    dp[k + 1][q + p] = dp[k][q] + a;\n                    pre[k + 1][q + p] = q;\n                    take[k + 1][q + p] = 1;\n                }\n            }\n        }\n\n        int bestQ = 0;\n        double bestScore = -1.0;\n\n        for (int q = 0; q <= maxP; q++) {\n            if (dp[K][q] < 0) continue;\n            double val = ldexp((double)dp[K][q], -q);\n            if (val > bestScore) {\n                bestScore = val;\n                bestQ = q;\n            }\n        }\n\n        vector<bool> include(K, false);\n        int q = bestQ;\n        for (int k = K; k >= 1; k--) {\n            include[k - 1] = take[k][q];\n            q = pre[k][q];\n            if (q < 0) break;\n        }\n\n        for (int k = 0; k < K; k++) {\n            if (include[k]) continue;\n\n            int id = items[k].comp;\n            for (int c : comps[id].doors) {\n                if (!blocked[28][c]) need[c] = true;\n            }\n        }\n\n        return need;\n    }\n\n    int tryBuildCurrentRow(int i, int tid, vector<char>& act) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (!(0 <= r && r <= 28)) return 0;\n        if (c != stand) return 0;\n\n        bool anyUnbuilt = false;\n\n        for (int wc : tasks[tid].walls) {\n            if (blocked[r][wc]) continue;\n\n            anyUnbuilt = true;\n            char low = (wc < stand ? 'l' : 'r');\n\n            if (!resBuild[r][wc] && canBuild(i, low)) {\n                issueBuild(i, low, act);\n                return 1;\n            }\n        }\n\n        return anyUnbuilt ? -1 : 0;\n    }\n\n    void moveToGoals(int i, const vector<pair<int,int>>& goals, vector<char>& act) {\n        char mv = bfsMove(i, goals);\n        if (mv != '.') issueMove(i, mv, act);\n    }\n\n    void actBuilder(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int tid = hs[i].task;\n\n        if (tid == -1) {\n            actFree(i, act, needDoor);\n            return;\n        }\n\n        bool comp = taskComplete(tid);\n        if (comp) hs[i].phase = RET;\n        if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (hs[i].phase == RET) {\n            if (r == 29) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n                actFree(i, act, needDoor);\n                return;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col = 0; col < G; col++) {\n                if (!blocked[29][col]) goals.push_back({29, col});\n            }\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        if (hs[i].phase == GO) {\n            if (!(r == 29 && c == stand)) {\n                moveToGoals(i, {{29, stand}}, act);\n                return;\n            }\n            hs[i].phase = UP;\n        }\n\n        if (c != stand) {\n            hs[i].phase = GO;\n            moveToGoals(i, {{29, stand}}, act);\n            return;\n        }\n\n        if (hs[i].phase == UP) {\n            if (r == 29) {\n                hs[i].wait = 0;\n                issueMove(i, 'U', act);\n                return;\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r > 0) {\n                issueMove(i, 'U', act);\n                return;\n            } else {\n                hs[i].phase = DOWN;\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n\n        if (hs[i].phase == DOWN) {\n            if (r == 29) {\n                if (taskComplete(tid)) {\n                    hs[i].phase = RET;\n                    actBuilder(i, act, needDoor);\n                    return;\n                } else {\n                    hs[i].phase = UP;\n                    issueMove(i, 'U', act);\n                    return;\n                }\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r < 28) {\n                issueMove(i, 'D', act);\n                return;\n            } else {\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n    }\n\n    void actFree(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n\n        if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c]) {\n            if (canBuild(i, 'u')) {\n                issueBuild(i, 'u', act);\n                return;\n            }\n        }\n\n        vector<int> cols;\n        for (int col = 0; col < G; col++) {\n            if (needDoor[col] && !blocked[28][col] && !resBuild[28][col]) {\n                cols.push_back(col);\n            }\n        }\n\n        if (!cols.empty()) {\n            bool curIllegal = false;\n            if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c] && !canBuild(i, 'u')) {\n                curIllegal = true;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col : cols) {\n                if (curIllegal && col == c && cols.size() >= 2) continue;\n                goals.push_back({29, col});\n            }\n\n            if (goals.empty()) goals.push_back({29, c});\n\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        moveToGoals(i, {{29, hs[i].home}}, act);\n    }\n\n    string decideActions() {\n        buildOcc();\n        resetReservations();\n\n        normalizeStates();\n        assignTasks();\n\n        auto needDoor = computeDoorTargets();\n\n        vector<char> act(M, '.');\n\n        vector<int> order;\n        for (int i = 0; i < M; i++) if (hs[i].task != -1) order.push_back(i);\n        for (int i = 0; i < M; i++) if (hs[i].task == -1) order.push_back(i);\n\n        for (int i : order) {\n            if (hs[i].task != -1) actBuilder(i, act, needDoor);\n            else actFree(i, act, needDoor);\n        }\n\n        string s;\n        s.reserve(M);\n        for (int i = 0; i < M; i++) s.push_back(act[i]);\n        return s;\n    }\n\n    char convertAction(char ch) {\n        if (ch == '.') return '.';\n\n        bool low = islower((unsigned char)ch);\n        char up = toupper(ch);\n        char p = logToPhys[(int)up];\n\n        if (low) p = tolower(p);\n        return p;\n    }\n\n    string toPhysicalOutput(const string& logAct) {\n        string out;\n        out.reserve(logAct.size());\n\n        for (char ch : logAct) {\n            out.push_back(convertAction(ch));\n        }\n\n        return out;\n    }\n\n    void applyActions(const string& logAct) {\n        auto oldHumans = humans;\n        auto newHumans = humans;\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('a' <= a && a <= 'z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) blocked[r][c] = true;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('A' <= a && a <= 'Z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) newHumans[i] = {r, c};\n            }\n        }\n\n        humans = newHumans;\n    }\n\n    bool readPetMovesAndUpdate() {\n        for (int i = 0; i < N; i++) {\n            string s;\n            if (!(cin >> s)) return false;\n\n            if (s == \".\") continue;\n\n            for (char pc : s) {\n                if (pc == '.') continue;\n\n                char lc = physToLog[(int)pc];\n                int d = dirId(lc);\n\n                pets[i].r += DR[d];\n                pets[i].c += DC[d];\n            }\n        }\n\n        return true;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<Pet> petsPhys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> petsPhys[i].r >> petsPhys[i].c >> petsPhys[i].t;\n        petsPhys[i].r--;\n        petsPhys[i].c--;\n    }\n\n    int M;\n    cin >> M;\n\n    vector<pair<int,int>> humansPhys(M);\n    for (int i = 0; i < M; i++) {\n        cin >> humansPhys[i].first >> humansPhys[i].second;\n        humansPhys[i].first--;\n        humansPhys[i].second--;\n    }\n\n    int ori = chooseOrientation(petsPhys, humansPhys);\n    Solver solver(N, petsPhys, M, humansPhys, ori);\n\n    for (int turn = 0; turn < 300; turn++) {\n        solver.turnNo = turn;\n\n        string logAct = solver.decideActions();\n        string out = solver.toPhysicalOutput(logAct);\n\n        cout << out << endl;\n        cout.flush();\n\n        solver.applyActions(logAct);\n\n        if (!solver.readPetMovesAndUpdate()) return 0;\n    }\n\n    return 0;\n}","ahc009":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 20;\nstatic constexpr int W = 20;\nstatic constexpr int N = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr int MAXD = 400;\n\nint si_, sj_, ti_, tj_;\nint SID, TID;\ndouble pForget, qRemember;\nstring hwall[H], vwall[H - 1];\n\nint goTo[4][N]; // U D L R\nint distT[N];\n\ndouble pot[MAXL + 1][MAXD + 1];      // distance-based value\ndouble adaptVal[MAXL + 1][N];        // adaptive MDP upper-bound value\n\ndouble pref[MAXL + 1][N];\ndouble suff[MAXL + 1][N];\ndouble prefScore[MAXL + 1];\n\nchrono::steady_clock::time_point startTime;\nconst double HARD_LIMIT = 1.88;\nconst double EPS = 1e-10;\nconst string DIRS = \"UDLR\";\n\ninline int id(int i, int j) {\n    return i * W + j;\n}\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n}\n\nvoid buildGo() {\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x = id(i, j);\n            goTo[0][x] = (i > 0 && vwall[i - 1][j] == '0') ? id(i - 1, j) : x;\n            goTo[1][x] = (i + 1 < H && vwall[i][j] == '0') ? id(i + 1, j) : x;\n            goTo[2][x] = (j > 0 && hwall[i][j - 1] == '0') ? id(i, j - 1) : x;\n            goTo[3][x] = (j + 1 < W && hwall[i][j] == '0') ? id(i, j + 1) : x;\n        }\n    }\n}\n\nvoid bfsDist() {\n    fill(distT, distT + N, -1);\n    queue<int> que;\n    distT[TID] = 0;\n    que.push(TID);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n            if (distT[y] == -1) {\n                distT[y] = distT[x] + 1;\n                que.push(y);\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (distT[i] < 0) distT[i] = MAXD;\n    }\n}\n\nvoid buildPotential() {\n    for (int d = 0; d <= MAXD; d++) pot[MAXL][d] = 0.0;\n    pot[MAXL][0] = 401 - MAXL; // reward if final remembered move reaches target\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        pot[l][0] = 401 - l;\n        for (int d = 1; d <= MAXD; d++) {\n            pot[l][d] = qRemember * pot[l + 1][d - 1] + pForget * pot[l + 1][d];\n        }\n    }\n}\n\nvoid buildAdaptiveValue() {\n    fill(adaptVal[MAXL], adaptVal[MAXL] + N, 0.0);\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        double reward = 400 - l;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                adaptVal[l][v] = 0.0;\n                continue;\n            }\n\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                int u = goTo[a][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * adaptVal[l + 1][v];\n                } else if (u == v) {\n                    val = adaptVal[l + 1][v];\n                } else {\n                    val = pForget * adaptVal[l + 1][v] + qRemember * adaptVal[l + 1][u];\n                }\n\n                best = max(best, val);\n            }\n\n            adaptVal[l][v] = best;\n        }\n    }\n}\n\ndouble evaluate(const vector<int>& seq) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    double score = 0.0;\n    int L = (int)seq.size();\n\n    for (int k = 0; k < L; k++) {\n        fill(ndp, ndp + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = dp[v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                ndp[v] += m * pForget;\n            } else if (u == v) {\n                ndp[v] += m;\n            } else {\n                ndp[v] += m * pForget;\n                ndp[u] += m * qRemember;\n            }\n        }\n\n        score += reward * hit;\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return score;\n}\n\nvoid applyActionDist(const double* dp, double* ndp, int a) {\n    fill(ndp, ndp + N, 0.0);\n\n    for (int v = 0; v < N; v++) {\n        double m = dp[v];\n        if (m == 0.0) continue;\n\n        int u = goTo[a][v];\n\n        if (u == TID) {\n            ndp[v] += m * pForget;\n        } else if (u == v) {\n            ndp[v] += m;\n        } else {\n            ndp[v] += m * pForget;\n            ndp[u] += m * qRemember;\n        }\n    }\n}\n\nvoid computePrefixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(pref[0], pref[0] + N, 0.0);\n    pref[0][SID] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int k = 0; k < L; k++) {\n        fill(pref[k + 1], pref[k + 1] + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = pref[k][v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                pref[k + 1][v] += m * pForget;\n            } else if (u == v) {\n                pref[k + 1][v] += m;\n            } else {\n                pref[k + 1][v] += m * pForget;\n                pref[k + 1][u] += m * qRemember;\n            }\n        }\n\n        prefScore[k + 1] = prefScore[k] + reward * hit;\n    }\n}\n\nvoid computeSuffixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(suff[L], suff[L] + N, 0.0);\n\n    for (int k = L - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                suff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                suff[k][v] = qRemember * reward + pForget * suff[k + 1][v];\n            } else if (u == v) {\n                suff[k][v] = suff[k + 1][v];\n            } else {\n                suff[k][v] = pForget * suff[k + 1][v] + qRemember * suff[k + 1][u];\n            }\n        }\n    }\n}\n\nvoid computePrefixSuffix(const vector<int>& seq) {\n    computePrefixOnly(seq);\n    computeSuffixOnly(seq);\n}\n\nvoid completeGreedy(vector<int>& seq) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n    if ((int)seq.size() == MAXL) return;\n\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    int len = (int)seq.size();\n\n    for (int k = 0; k < len; k++) {\n        applyActionDist(dp, ndp, seq[k]);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    for (int k = len; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * adaptVal[k + 1][v]);\n                } else if (u == v) {\n                    val += m * adaptVal[k + 1][v];\n                } else {\n                    val += m * (pForget * adaptVal[k + 1][v] + qRemember * adaptVal[k + 1][u]);\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n}\n\nstruct Candidate {\n    vector<int> seq;\n    double score;\n};\n\nvoid pruneCands(vector<Candidate>& cands, int limit) {\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        return a.score > b.score;\n    });\n\n    if ((int)cands.size() > limit) cands.resize(limit);\n}\n\nvoid addCandidate(vector<Candidate>& cands, vector<int> seq, bool greedyFill = true) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n\n    if ((int)seq.size() < MAXL) {\n        if (greedyFill) {\n            completeGreedy(seq);\n        } else {\n            if (seq.empty()) seq.push_back(1);\n            while ((int)seq.size() < MAXL) seq.push_back(seq.back());\n        }\n    }\n\n    for (const auto& c : cands) {\n        if (c.seq == seq) return;\n    }\n\n    double sc = evaluate(seq);\n    cands.push_back({move(seq), sc});\n}\n\nint repCost(int d, double z) {\n    if (d <= 0) return 0;\n\n    double val = d / qRemember + z * sqrt(max(0.0, d * pForget)) / qRemember;\n    int r = (int)ceil(val - 1e-9);\n\n    r = max(r, d);\n    r = max(r, 1);\n\n    return r;\n}\n\nvoid appendRun(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt && (int)s.size() < MAXL; i++) {\n        s.push_back(a);\n    }\n}\n\nvoid appendRunRaw(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt; i++) s.push_back(a);\n}\n\nvector<int> bfsPathTo(int goal, const array<int, 4>& order) {\n    vector<int> par(N, -1), parA(N, -1);\n    queue<int> que;\n\n    par[SID] = SID;\n    que.push(SID);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        if (x == goal) break;\n\n        for (int a : order) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            if (par[y] == -1) {\n                par[y] = x;\n                parA[y] = a;\n                que.push(y);\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != SID) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> randomPathTo(int goal, int seed, int noise, int biasAway) {\n    mt19937 rng(seed);\n\n    int wgt[4][N];\n    for (int a = 0; a < 4; a++) {\n        for (int v = 0; v < N; v++) {\n            if (goTo[a][v] == v) {\n                wgt[a][v] = INT_MAX / 4;\n            } else {\n                int pen = (a == 0 || a == 2) ? biasAway : 0; // U/L penalty\n                wgt[a][v] = 1000 + pen + (int)(rng() % max(1, noise));\n            }\n        }\n    }\n\n    const int INF = 1 << 29;\n    vector<int> dist(N, INF), par(N, -1), parA(N, -1);\n    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n    dist[SID] = 0;\n    pq.push({0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd != dist[x]) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            int nd = cd + wgt[a][x];\n            if (nd < dist[y]) {\n                dist[y] = nd;\n                par[y] = x;\n                parA[y] = a;\n                pq.push({nd, y});\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != SID) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> makeCyclePath(const vector<int>& path) {\n    vector<int> s;\n    if (path.empty()) return s;\n\n    s.reserve(MAXL);\n    for (int i = 0; i < MAXL; i++) {\n        s.push_back(path[i % path.size()]);\n    }\n\n    return s;\n}\n\nvector<int> repeatEachPath(const vector<int>& path, int rep) {\n    vector<int> s;\n\n    for (int a : path) {\n        for (int r = 0; r < rep && (int)s.size() < MAXL; r++) {\n            s.push_back(a);\n        }\n\n        if ((int)s.size() >= MAXL) break;\n    }\n\n    return s;\n}\n\nvector<int> syncRunPath(const vector<int>& path, double z, int extraUnsynced = 0) {\n    vector<int> s;\n    if (path.empty()) return s;\n\n    int cell = SID;\n\n    for (int i = 0; i < (int)path.size();) {\n        int a = path[i];\n        int j = i;\n\n        while (j < (int)path.size() && path[j] == a) j++;\n\n        int d = j - i;\n        int end = cell;\n\n        for (int k = 0; k < d; k++) {\n            end = goTo[a][end];\n        }\n\n        bool synced = (end == TID || goTo[a][end] == end);\n        int r = synced ? repCost(d, z) : d + extraUnsynced;\n        r = max(r, d);\n\n        appendRun(s, a, r);\n        cell = end;\n\n        if ((int)s.size() >= MAXL) break;\n        i = j;\n    }\n\n    return s;\n}\n\nvoid addPathCandidates(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, true);\n    addCandidate(cands, makeCyclePath(path), false);\n\n    vector<int> reps = {2, 3, 4, max(2, (int)ceil(1.0 / qRemember))};\n    sort(reps.begin(), reps.end());\n    reps.erase(unique(reps.begin(), reps.end()), reps.end());\n\n    for (int r : reps) {\n        addCandidate(cands, repeatEachPath(path, r), true);\n    }\n\n    for (double z : {0.0, 0.8, 1.6}) {\n        addCandidate(cands, syncRunPath(path, z, 0), true);\n    }\n}\n\nvoid addLightPathCandidates(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, true);\n    addCandidate(cands, makeCyclePath(path), false);\n    addCandidate(cands, syncRunPath(path, 1.0, 0), true);\n}\n\nvector<int> patternFromRuns(const vector<pair<int, int>>& runs) {\n    vector<int> pat;\n    for (auto [a, c] : runs) {\n        if (c <= 0) continue;\n        appendRunRaw(pat, a, c);\n    }\n    return pat;\n}\n\nvoid addPatternCandidate(vector<Candidate>& cands, const vector<int>& prefix, const vector<int>& pattern) {\n    vector<int> s = prefix;\n\n    if ((int)s.size() > MAXL) s.resize(MAXL);\n\n    if (pattern.empty()) {\n        addCandidate(cands, s, true);\n        return;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(pattern[ptr]);\n        ptr++;\n        if (ptr == (int)pattern.size()) ptr = 0;\n    }\n\n    addCandidate(cands, s, false);\n}\n\nint cappedRep(int d, double z) {\n    if (d <= 0) return 0;\n    return min(16, repCost(d, z));\n}\n\nvoid addLineCandidates(vector<Candidate>& cands, int goal, int toward, int back, int offset) {\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<vector<int>> prefixes;\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPathTo(goal, ord);\n        if (path.empty()) continue;\n\n        prefixes.push_back(path);\n        prefixes.push_back(syncRunPath(path, 0.8, 0));\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    if (offset == 0) {\n        for (auto& pre : prefixes) {\n            addCandidate(cands, pre, true);\n        }\n        return;\n    }\n\n    vector<int> counts = {\n        offset,\n        max(offset, (int)ceil(offset / qRemember)),\n        cappedRep(offset, 0.5),\n        min(16, max(offset, 4))\n    };\n\n    sort(counts.begin(), counts.end());\n    counts.erase(unique(counts.begin(), counts.end()), counts.end());\n\n    for (auto& pre : prefixes) {\n        for (int c : counts) {\n            vector<int> pat = patternFromRuns({{toward, c}, {back, c}});\n            addPatternCandidate(cands, pre, pat);\n        }\n    }\n}\n\nvoid addSweepCandidates(vector<Candidate>& cands) {\n    vector<vector<int>> patterns;\n\n    vector<int> cs = {\n        4,\n        max(4, (int)round(4.0 / qRemember)),\n        min(14, repCost(4, 0.5)),\n        min(16, repCost(4, 1.2))\n    };\n\n    sort(cs.begin(), cs.end());\n    cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n    for (int c : cs) {\n        patterns.push_back(patternFromRuns({{0, c}, {2, c}, {1, c}, {3, c}})); // U L D R\n        patterns.push_back(patternFromRuns({{2, c}, {0, c}, {3, c}, {1, c}})); // L U R D\n    }\n\n    int up = 19 - ti_;\n    int left = 19 - tj_;\n\n    for (double z : {0.0, 0.7}) {\n        int ru = cappedRep(up, z);\n        int rl = cappedRep(left, z);\n\n        if (ru + rl > 0) {\n            patterns.push_back(patternFromRuns({{0, ru}, {2, rl}, {1, ru}, {3, rl}}));\n            patterns.push_back(patternFromRuns({{2, rl}, {0, ru}, {3, rl}, {1, ru}}));\n        }\n    }\n\n    vector<vector<int>> prefixes;\n\n    for (double z : {0.0, 1.0}) {\n        int big = min(70, repCost(19, z));\n\n        vector<int> s1;\n        appendRun(s1, 1, big);\n        appendRun(s1, 3, big);\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        appendRun(s2, 3, big);\n        appendRun(s2, 1, big);\n        prefixes.push_back(s2);\n    }\n\n    for (int chunk : {max(5, (int)round(7.0 / qRemember)), max(8, (int)round(11.0 / qRemember))}) {\n        vector<int> s1;\n        while ((int)s1.size() < 110) {\n            appendRun(s1, 1, chunk);\n            appendRun(s1, 3, chunk);\n        }\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        while ((int)s2.size() < 110) {\n            appendRun(s2, 3, chunk);\n            appendRun(s2, 1, chunk);\n        }\n        prefixes.push_back(s2);\n    }\n\n    array<int, 4> drOrder{1, 3, 0, 2};\n    vector<int> cornerPath = bfsPathTo(id(19, 19), drOrder);\n    if (!cornerPath.empty()) {\n        prefixes.push_back(cornerPath);\n        prefixes.push_back(syncRunPath(cornerPath, 0.8, 0));\n        prefixes.push_back(syncRunPath(cornerPath, 1.6, 0));\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    int used = 0;\n    for (auto& pre : prefixes) {\n        for (auto& pat : patterns) {\n            addPatternCandidate(cands, pre, pat);\n            used++;\n            if (used >= 80) break;\n        }\n        if (used >= 80) break;\n    }\n\n    addLineCandidates(cands, id(ti_, 19), 2, 3, 19 - tj_); // from right boundary, move left/right\n    addLineCandidates(cands, id(19, tj_), 0, 1, 19 - ti_); // from bottom boundary, move up/down\n}\n\npair<int, int> slideResult(int cell, int a) {\n    int c = cell;\n    int d = 0;\n\n    while (true) {\n        int u = goTo[a][c];\n        if (u == c) break;\n\n        c = u;\n        d++;\n\n        if (c == TID) break;\n    }\n\n    return {c, d};\n}\n\nvector<int> slideCandidate(double z) {\n    const double INF = 1e100;\n\n    vector<double> dc(N, INF);\n    vector<int> pre(N, -1), preA(N, -1), preD(N, 0);\n\n    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n\n    dc[SID] = 0.0;\n    pq.push({0.0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd != dc[x]) continue;\n        if (x == TID) break;\n\n        for (int a = 0; a < 4; a++) {\n            auto [to, d] = slideResult(x, a);\n            if (d == 0) continue;\n\n            double nd = cd + repCost(d, z);\n            if (nd < dc[to]) {\n                dc[to] = nd;\n                pre[to] = x;\n                preA[to] = a;\n                preD[to] = d;\n                pq.push({nd, to});\n            }\n        }\n    }\n\n    if (pre[TID] == -1) return {};\n\n    vector<pair<int, int>> segs;\n\n    int x = TID;\n    while (x != SID) {\n        segs.push_back({preA[x], preD[x]});\n        x = pre[x];\n    }\n\n    reverse(segs.begin(), segs.end());\n\n    vector<int> seq;\n    for (auto [a, d] : segs) {\n        int r = repCost(d, z);\n        appendRun(seq, a, r);\n        if ((int)seq.size() >= MAXL) break;\n    }\n\n    return seq;\n}\n\nstruct BeamNode {\n    float prob[N];\n    double score;\n    double estV;\n    double estD;\n    unsigned char seq[MAXL];\n    BeamNode() {}\n};\n\nvector<vector<int>> beamSearch(int topCount, int initialWidth) {\n    int width = initialWidth;\n\n    vector<BeamNode> cur, nxt, selected;\n    vector<int> idx;\n\n    cur.reserve(initialWidth);\n    nxt.reserve(initialWidth * 4);\n    selected.reserve(initialWidth);\n    idx.reserve(initialWidth * 4);\n\n    BeamNode root;\n    fill(root.prob, root.prob + N, 0.0f);\n    root.prob[SID] = 1.0f;\n    root.score = 0.0;\n    root.estV = adaptVal[0][SID];\n    root.estD = pot[0][distT[SID]];\n    cur.push_back(root);\n\n    for (int l = 0; l < MAXL; l++) {\n        if ((l % 5) == 0) {\n            double e = elapsedSec();\n\n            if (e > 1.35) width = min(width, 70);\n            else if (e > 1.15) width = min(width, 120);\n            else if (e > 0.95) width = min(width, 220);\n            else if (e > 0.75) width = min(width, 330);\n        }\n\n        nxt.clear();\n\n        for (const BeamNode& par : cur) {\n            for (int a = 0; a < 4; a++) {\n                BeamNode& ch = nxt.emplace_back();\n\n                fill(ch.prob, ch.prob + N, 0.0f);\n\n                if (l > 0) memcpy(ch.seq, par.seq, l * sizeof(unsigned char));\n                ch.seq[l] = (unsigned char)a;\n\n                double hit = 0.0;\n                double futureV = 0.0;\n                double futureD = 0.0;\n                const double* vrow = adaptVal[l + 1];\n                const double* drow = pot[l + 1];\n\n                for (int v = 0; v < N; v++) {\n                    float mf = par.prob[v];\n                    if (mf == 0.0f) continue;\n\n                    double m = mf;\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        double stay = m * pForget;\n                        hit += m * qRemember;\n                        ch.prob[v] += (float)stay;\n                        futureV += stay * vrow[v];\n                        futureD += stay * drow[distT[v]];\n                    } else if (u == v) {\n                        ch.prob[v] += mf;\n                        futureV += m * vrow[v];\n                        futureD += m * drow[distT[v]];\n                    } else {\n                        double stay = m * pForget;\n                        double mv = m * qRemember;\n\n                        ch.prob[v] += (float)stay;\n                        ch.prob[u] += (float)mv;\n\n                        futureV += stay * vrow[v] + mv * vrow[u];\n                        futureD += stay * drow[distT[v]] + mv * drow[distT[u]];\n                    }\n                }\n\n                ch.score = par.score + (400 - l) * hit;\n                ch.estV = ch.score + futureV;\n                ch.estD = ch.score + futureD;\n            }\n        }\n\n        int n = (int)nxt.size();\n\n        if (n > width) {\n            selected.clear();\n            vector<char> used(n, 0);\n\n            auto pick = [&](int quota, int keyType) {\n                if (quota <= 0) return;\n\n                idx.resize(n);\n                iota(idx.begin(), idx.end(), 0);\n\n                if (keyType == 0) {\n                    sort(idx.begin(), idx.end(), [&](int x, int y) {\n                        if (nxt[x].estV != nxt[y].estV) return nxt[x].estV > nxt[y].estV;\n                        return nxt[x].score > nxt[y].score;\n                    });\n                } else if (keyType == 1) {\n                    sort(idx.begin(), idx.end(), [&](int x, int y) {\n                        if (nxt[x].estD != nxt[y].estD) return nxt[x].estD > nxt[y].estD;\n                        return nxt[x].score > nxt[y].score;\n                    });\n                } else {\n                    sort(idx.begin(), idx.end(), [&](int x, int y) {\n                        if (nxt[x].score != nxt[y].score) return nxt[x].score > nxt[y].score;\n                        return nxt[x].estV > nxt[y].estV;\n                    });\n                }\n\n                int added = 0;\n                for (int idd : idx) {\n                    if (used[idd]) continue;\n\n                    used[idd] = 1;\n                    selected.push_back(nxt[idd]);\n                    added++;\n\n                    if (added >= quota) break;\n                }\n            };\n\n            int qv = width * 55 / 100;\n            int qd = width * 30 / 100;\n            int qs = width - qv - qd;\n\n            pick(qv, 0);\n            pick(qd, 1);\n            pick(qs, 2);\n\n            cur.swap(selected);\n        } else {\n            cur.swap(nxt);\n        }\n    }\n\n    vector<vector<int>> res;\n\n    int n = (int)cur.size();\n\n    idx.resize(n);\n    iota(idx.begin(), idx.end(), 0);\n\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        return cur[x].score > cur[y].score;\n    });\n\n    int take = min(topCount, n);\n\n    for (int r = 0; r < take; r++) {\n        vector<int> s(MAXL);\n        const BeamNode& node = cur[idx[r]];\n\n        for (int k = 0; k < MAXL; k++) {\n            s[k] = node.seq[k];\n        }\n\n        res.push_back(move(s));\n    }\n\n    return res;\n}\n\nvector<int> bestCrossoverSeq(const vector<int>& A, const vector<int>& B) {\n    computeSuffixOnly(B);\n    computePrefixOnly(A);\n\n    double best = -1.0;\n    int bestK = 0;\n\n    for (int k = 0; k <= MAXL; k++) {\n        double total = prefScore[k];\n\n        for (int v = 0; v < N; v++) {\n            total += pref[k][v] * suff[k][v];\n        }\n\n        if (total > best) {\n            best = total;\n            bestK = k;\n        }\n    }\n\n    vector<int> s;\n    s.reserve(MAXL);\n\n    for (int i = 0; i < bestK; i++) s.push_back(A[i]);\n    for (int i = bestK; i < MAXL; i++) s.push_back(B[i]);\n\n    return s;\n}\n\nvoid addCrossovers(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>(12, cands.size()));\n\n    int m = min<int>(8, cands.size());\n    vector<vector<int>> top;\n\n    for (int i = 0; i < m; i++) {\n        top.push_back(cands[i].seq);\n    }\n\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < m; j++) {\n            if (i == j) continue;\n\n            vector<int> s = bestCrossoverSeq(top[i], top[j]);\n            addCandidate(cands, s, false);\n        }\n    }\n}\n\nbool tryWindow(vector<int>& seq, int win, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    int masks = 1 << (2 * win);\n\n    static double buf1[N], buf2[N];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 3) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        for (int mask = 0; mask < masks; mask++) {\n            if (mask == curMask) continue;\n\n            memcpy(buf1, pref[k], sizeof(double) * N);\n\n            double* dp = buf1;\n            double* ndp = buf2;\n            double sc = prefScore[k];\n\n            int mm = mask;\n\n            for (int r = 0; r < win; r++) {\n                int a = mm & 3;\n                mm >>= 2;\n\n                fill(ndp, ndp + N, 0.0);\n\n                double hit = 0.0;\n                double reward = 400 - (k + r);\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        ndp[v] += m * pForget;\n                    } else if (u == v) {\n                        ndp[v] += m;\n                    } else {\n                        ndp[v] += m * pForget;\n                        ndp[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp, ndp);\n            }\n\n            double total = sc;\n            const double* sw = suff[k + win];\n\n            for (int v = 0; v < N; v++) {\n                total += dp[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = mask;\n            }\n        }\n    }\n\n    if (bestK != -1) {\n        int mm = bestMask;\n\n        for (int r = 0; r < win; r++) {\n            seq[bestK + r] = mm & 3;\n            mm >>= 2;\n        }\n\n        newScore = best;\n        return true;\n    }\n\n    return false;\n}\n\ndouble improve(vector<int>& seq, double deadline, int maxWindow) {\n    int L = (int)seq.size();\n    double curScore = evaluate(seq);\n\n    while (elapsedSec() < deadline) {\n        computePrefixSuffix(seq);\n        curScore = prefScore[L];\n\n        double bestScore = curScore;\n        int bestK = -1;\n        int bestC = -1;\n\n        for (int k = 0; k < L; k++) {\n            const double* row = pref[k];\n            const double* sw = suff[k + 1];\n            double base = prefScore[k];\n            double reward = 400 - k;\n\n            for (int c = 0; c < 4; c++) {\n                if (c == seq[k]) continue;\n\n                double total = base;\n\n                for (int v = 0; v < N; v++) {\n                    double m = row[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[c][v];\n                    double val;\n\n                    if (u == TID) {\n                        val = qRemember * reward + pForget * sw[v];\n                    } else if (u == v) {\n                        val = sw[v];\n                    } else {\n                        val = pForget * sw[v] + qRemember * sw[u];\n                    }\n\n                    total += m * val;\n                }\n\n                if (total > bestScore + EPS) {\n                    bestScore = total;\n                    bestK = k;\n                    bestC = c;\n                }\n            }\n        }\n\n        if (bestK != -1) {\n            seq[bestK] = bestC;\n            curScore = bestScore;\n            continue;\n        }\n\n        bool changed = false;\n\n        for (int w = 2; w <= maxWindow; w++) {\n            if (elapsedSec() > deadline - 0.015) break;\n\n            double ns;\n            if (tryWindow(seq, w, curScore, deadline, ns)) {\n                curScore = ns;\n                changed = true;\n                break;\n            }\n        }\n\n        if (!changed) break;\n    }\n\n    return evaluate(seq);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si_ >> sj_ >> ti_ >> tj_ >> pForget;\n    qRemember = 1.0 - pForget;\n\n    for (int i = 0; i < H; i++) cin >> hwall[i];\n    for (int i = 0; i < H - 1; i++) cin >> vwall[i];\n\n    SID = id(si_, sj_);\n    TID = id(ti_, tj_);\n\n    startTime = chrono::steady_clock::now();\n\n    buildGo();\n    bfsDist();\n    buildPotential();\n    buildAdaptiveValue();\n\n    vector<Candidate> cands;\n\n    // Pure adaptive-greedy completion.\n    addCandidate(cands, vector<int>{}, true);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2},\n        array<int, 4>{1, 3, 2, 0},\n        array<int, 4>{3, 1, 2, 0},\n        array<int, 4>{0, 1, 3, 2},\n        array<int, 4>{2, 3, 1, 0}\n    };\n\n    for (auto ord : orders) {\n        addPathCandidates(cands, bfsPathTo(TID, ord));\n    }\n\n    for (int r = 0; r < 6; r++) {\n        int noise = 350 + 80 * r;\n        int bias = (r % 2 == 0 ? 120 : 0);\n        addLightPathCandidates(cands, randomPathTo(TID, 10000 + r * 97, noise, bias));\n    }\n\n    addSweepCandidates(cands);\n\n    for (double z : {0.0, 0.5, 1.0, 1.5, 2.2}) {\n        vector<int> s = slideCandidate(z);\n        if (!s.empty()) addCandidate(cands, s, true);\n    }\n\n    pruneCands(cands, 70);\n\n    vector<vector<int>> beams = beamSearch(8, 420);\n    for (auto& s : beams) {\n        addCandidate(cands, s, false);\n    }\n\n    pruneCands(cands, 80);\n\n    addCrossovers(cands);\n    pruneCands(cands, 80);\n\n    if (cands.empty()) {\n        addCandidate(cands, vector<int>{}, true);\n    }\n\n    pruneCands(cands, 80);\n\n    vector<int> bestSeq = cands[0].seq;\n    double bestScore = cands[0].score;\n\n    int starts = min<int>(8, cands.size());\n\n    for (int i = 0; i < starts; i++) {\n        if (elapsedSec() > HARD_LIMIT - 0.22) break;\n\n        vector<int> seq = cands[i].seq;\n\n        double budget = (i < 3 ? 0.16 : 0.09);\n        double dl = min(HARD_LIMIT - 0.16, elapsedSec() + budget);\n        if (dl <= elapsedSec() + 0.01) break;\n\n        int mw = (i < 3 ? 3 : 2);\n        double sc = improve(seq, dl, mw);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    mt19937 rng(1234567);\n    int attempts = 0;\n\n    while (elapsedSec() < HARD_LIMIT - 0.35 && attempts < 2) {\n        vector<int> seq = bestSeq;\n\n        int changes = 4 + attempts * 4;\n        for (int i = 0; i < changes; i++) {\n            int pos = rng() % MAXL;\n            seq[pos] = rng() % 4;\n        }\n\n        double dl = min(HARD_LIMIT - 0.22, elapsedSec() + 0.10);\n        double sc = improve(seq, dl, 2);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n\n        attempts++;\n    }\n\n    if (elapsedSec() < HARD_LIMIT - 0.04) {\n        vector<int> seq = bestSeq;\n        double sc = improve(seq, HARD_LIMIT, 4);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    if ((int)bestSeq.size() > MAXL) bestSeq.resize(MAXL);\n    if ((int)bestSeq.size() < MAXL) completeGreedy(bestSeq);\n\n    string out;\n    out.reserve(MAXL);\n\n    for (int a : bestSeq) {\n        out.push_back(DIRS[a]);\n    }\n\n    cout << out << '\\n';\n\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int CELLS = N * N;\nconstexpr int PORTS = CELLS * 4;\nconstexpr int MAXLEN = 1800;\nconstexpr int MAXCOMP = 4005;\nconstexpr int BITWORDS = (CELLS + 63) / 64;\n\nusing StateArr = array<unsigned char, CELLS>;\n\nint pairDir[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\nint maskState[8];\nint segCnt[8];\nint segA[8][2], segB[8][2];\n\nint adjPort[PORTS];\nint neighCell[CELLS][4];\n\nint baseTile[CELLS];\nint optCnt[CELLS];\nint optState[CELLS][4];\n\nint moveCnt[PORTS];\nint moveNextState[PORTS][2];\nvector<int> validMoveStates;\n\nint di[4] = {0, -1, 0, 1};\nint dj[4] = {-1, 0, 1, 0};\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = seed ? seed : 88172645463325252ULL;\n        for (int i = 0; i < 20; i++) next();\n    }\n    inline uint64_t next() {\n        x ^= x << 13;\n        x ^= x >> 7;\n        x ^= x << 17;\n        return x;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct BIT {\n    int bit[MAXLEN + 2];\n    int total;\n\n    void reset() {\n        memset(bit, 0, sizeof(bit));\n        total = 0;\n    }\n\n    void add(int idx, int delta) {\n        if (idx <= 0) return;\n        total += delta;\n        for (int i = idx; i <= MAXLEN; i += i & -i) bit[i] += delta;\n    }\n\n    int kth(int k) const {\n        int idx = 0;\n        for (int pw = 2048; pw; pw >>= 1) {\n            int ni = idx + pw;\n            if (ni <= MAXLEN && bit[ni] < k) {\n                idx = ni;\n                k -= bit[ni];\n            }\n        }\n        return idx + 1;\n    }\n};\n\nstruct Stats {\n    int l1 = 0, l2 = 0;\n    int c1 = 0, c2 = 0;\n    int loops = 0;\n    int broken = 0;\n    long long score = 0;\n    long long loopSq = 0;\n};\n\nstruct Manager {\n    unsigned char st[CELLS];\n\n    int comp[PORTS];\n    vector<int> ports[MAXCOMP];\n    bool alive[MAXCOMP];\n    int compLen[MAXCOMP];\n    int compBroken[MAXCOMP];\n\n    int nextId = 0;\n    vector<int> freeIds;\n\n    BIT compBIT, loopBIT;\n    long long loopSq = 0;\n    int brokenTotal = 0;\n\n    int stackBuf[PORTS];\n\n    Manager() {\n        freeIds.reserve(MAXCOMP);\n        memset(alive, 0, sizeof(alive));\n    }\n\n    inline bool active(int p) const {\n        return pairDir[st[p >> 2]][p & 3] >= 0;\n    }\n\n    inline int internalPort(int p) const {\n        return (p & ~3) | pairDir[st[p >> 2]][p & 3];\n    }\n\n    int allocId() {\n        int id;\n        if (!freeIds.empty()) {\n            id = freeIds.back();\n            freeIds.pop_back();\n        } else {\n            id = nextId++;\n        }\n        alive[id] = true;\n        ports[id].clear();\n        return id;\n    }\n\n    void addStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, 1);\n        brokenTotal += br;\n\n        if (br == 0) {\n            loopBIT.add(len, 1);\n            loopSq += 1LL * len * len;\n        }\n    }\n\n    void removeStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, -1);\n        brokenTotal -= br;\n\n        if (br == 0) {\n            loopBIT.add(len, -1);\n            loopSq -= 1LL * len * len;\n        }\n    }\n\n    void removeComp(int id) {\n        if (id < 0 || !alive[id]) return;\n\n        removeStats(id);\n\n        for (int p : ports[id]) comp[p] = -1;\n        ports[id].clear();\n        alive[id] = false;\n        freeIds.push_back(id);\n    }\n\n    void addComponent(int start) {\n        int id = allocId();\n\n        int top = 0;\n        stackBuf[top++] = start;\n        comp[start] = id;\n        ports[id].push_back(start);\n\n        int broken = 0;\n\n        while (top) {\n            int p = stackBuf[--top];\n\n            int q = internalPort(p);\n            if (comp[q] == -1) {\n                comp[q] = id;\n                ports[id].push_back(q);\n                stackBuf[top++] = q;\n            }\n\n            int e = adjPort[p];\n            if (e != -1 && active(e)) {\n                if (comp[e] == -1) {\n                    comp[e] = id;\n                    ports[id].push_back(e);\n                    stackBuf[top++] = e;\n                }\n            } else {\n                broken++;\n            }\n        }\n\n        compLen[id] = (int)ports[id].size() / 2;\n        compBroken[id] = broken;\n        addStats(id);\n    }\n\n    void build(const StateArr &arr) {\n        for (int i = 0; i < nextId; i++) {\n            ports[i].clear();\n            alive[i] = false;\n        }\n\n        nextId = 0;\n        freeIds.clear();\n\n        compBIT.reset();\n        loopBIT.reset();\n        loopSq = 0;\n        brokenTotal = 0;\n\n        for (int i = 0; i < CELLS; i++) st[i] = arr[i];\n        fill(comp, comp + PORTS, -1);\n\n        for (int p = 0; p < PORTS; p++) {\n            if (active(p) && comp[p] == -1) addComponent(p);\n        }\n    }\n\n    void updateCell(int cell, int newState) {\n        if (st[cell] == newState) return;\n\n        int ids[20];\n        int cnt = 0;\n\n        auto addId = [&](int id) {\n            if (id < 0 || !alive[id]) return;\n            for (int k = 0; k < cnt; k++) {\n                if (ids[k] == id) return;\n            }\n            ids[cnt++] = id;\n        };\n\n        int base = cell * 4;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            addId(comp[p]);\n            int e = adjPort[p];\n            if (e != -1) addId(comp[e]);\n        }\n\n        for (int k = 0; k < cnt; k++) removeComp(ids[k]);\n\n        st[cell] = (unsigned char)newState;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            if (active(p) && comp[p] == -1) addComponent(p);\n\n            int e = adjPort[p];\n            if (e != -1 && active(e) && comp[e] == -1) addComponent(e);\n        }\n    }\n\n    Stats getStats() const {\n        Stats s;\n\n        s.loops = loopBIT.total;\n\n        if (loopBIT.total >= 1) s.l1 = loopBIT.kth(loopBIT.total);\n        if (loopBIT.total >= 2) s.l2 = loopBIT.kth(loopBIT.total - 1);\n\n        if (compBIT.total >= 1) s.c1 = compBIT.kth(compBIT.total);\n        if (compBIT.total >= 2) s.c2 = compBIT.kth(compBIT.total - 1);\n\n        s.score = 1LL * s.l1 * s.l2;\n        s.loopSq = loopSq;\n        s.broken = brokenTotal;\n\n        return s;\n    }\n\n    void exportState(StateArr &out) const {\n        for (int i = 0; i < CELLS; i++) out[i] = st[i];\n    }\n};\n\nvoid initGlobals() {\n    for (int t = 0; t < 8; t++) {\n        maskState[t] = 0;\n        segCnt[t] = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (pairDir[t][d] != -1) maskState[t] |= 1 << d;\n        }\n\n        for (int d = 0; d < 4; d++) {\n            int e = pairDir[t][d];\n            if (e != -1 && d < e) {\n                int k = segCnt[t]++;\n                segA[t][k] = d;\n                segB[t][k] = e;\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                    neighCell[id][d] = -1;\n                    adjPort[id * 4 + d] = -1;\n                } else {\n                    int nb = ni * N + nj;\n                    neighCell[id][d] = nb;\n                    adjPort[id * 4 + d] = nb * 4 + (d ^ 2);\n                }\n            }\n        }\n    }\n}\n\nvoid buildMoveTransitions() {\n    validMoveStates.clear();\n\n    for (int s = 0; s < PORTS; s++) {\n        moveCnt[s] = 0;\n\n        int c = s >> 2;\n        int d = s & 3;\n\n        if (neighCell[c][d] == -1) continue;\n\n        if (baseTile[c] >= 6) {\n            int out = d ^ 2;\n            int nb = neighCell[c][out];\n            if (nb != -1) {\n                moveNextState[s][moveCnt[s]++] = nb * 4 + (out ^ 2);\n            }\n        } else {\n            int out1 = (d + 1) & 3;\n            int out2 = (d + 3) & 3;\n\n            int nb1 = neighCell[c][out1];\n            if (nb1 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb1 * 4 + (out1 ^ 2);\n            }\n\n            int nb2 = neighCell[c][out2];\n            if (nb2 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb2 * 4 + (out2 ^ 2);\n            }\n        }\n\n        if (moveCnt[s] > 0) validMoveStates.push_back(s);\n    }\n}\n\nint stateForPair(int base, int a, int b) {\n    if (a > b) swap(a, b);\n\n    if (base < 4) {\n        if (a == 0 && b == 1) return 0;\n        if (a == 0 && b == 3) return 1;\n        if (a == 2 && b == 3) return 2;\n        if (a == 1 && b == 2) return 3;\n        return -1;\n    } else if (base < 6) {\n        if ((a == 0 && b == 1) || (a == 2 && b == 3)) return 4;\n        if ((a == 0 && b == 3) || (a == 1 && b == 2)) return 5;\n        return -1;\n    } else {\n        if (a == 0 && b == 2) return 6;\n        if (a == 1 && b == 3) return 7;\n        return -1;\n    }\n}\n\nint localQuality(const unsigned char *arr, int id, int candState) {\n    bool nbAct[4];\n\n    for (int d = 0; d < 4; d++) {\n        int nb = neighCell[id][d];\n        nbAct[d] = false;\n\n        if (nb != -1) {\n            int ns = arr[nb];\n            nbAct[d] = (maskState[ns] >> (d ^ 2)) & 1;\n        }\n    }\n\n    int cm = maskState[candState];\n    int q = 0;\n\n    for (int d = 0; d < 4; d++) {\n        bool ca = (cm >> d) & 1;\n        bool na = nbAct[d];\n\n        if (ca && na) q += 6;\n        else if (ca || na) q -= 4;\n    }\n\n    for (int k = 0; k < segCnt[candState]; k++) {\n        int a = segA[candState][k];\n        int b = segB[candState][k];\n\n        int c = (nbAct[a] ? 1 : 0) + (nbAct[b] ? 1 : 0);\n\n        if (c == 2) q += 20;\n        else if (c == 1) q -= 3;\n        else q -= 8;\n    }\n\n    return q;\n}\n\nvoid greedyImprove(StateArr &cand, RNG &rng, int sweeps, const char *fixed = nullptr) {\n    int steps = sweeps * CELLS;\n\n    for (int it = 0; it < steps; it++) {\n        int id = rng.nextInt(CELLS);\n        if (fixed && fixed[id]) continue;\n\n        int bestSt = cand[id];\n        int bestQ = -1000000000;\n        int ties = 0;\n\n        for (int k = 0; k < optCnt[id]; k++) {\n            int s = optState[id][k];\n            int q = localQuality(cand.data(), id, s);\n\n            if (q > bestQ) {\n                bestQ = q;\n                bestSt = s;\n                ties = 1;\n            } else if (q == bestQ) {\n                ties++;\n                if (rng.nextInt(ties) == 0) bestSt = s;\n            }\n        }\n\n        cand[id] = (unsigned char)bestSt;\n    }\n}\n\nlong long startValue(const Stats &s) {\n    long long compProd = 1LL * s.c1 * s.c2;\n    return s.score * 1500LL + s.loopSq * 25LL + compProd * 6LL - 120LL * s.broken;\n}\n\nlong long energyValue(const Stats &s, double progress) {\n    long long compProd = 1LL * s.c1 * s.c2;\n\n    if (progress < 0.60) {\n        return s.score * 500LL\n             + s.loopSq * 30LL\n             + compProd * 8LL\n             + 1LL * s.l1 * s.l1 * 10LL\n             + 1LL * s.l2 * s.l2 * 10LL\n             - 110LL * s.broken;\n    } else {\n        return s.score * 2500LL\n             + s.loopSq * 5LL\n             + 1LL * s.l1 * s.l1 * 3LL\n             + 1LL * s.l2 * s.l2 * 3LL\n             + compProd / 3LL\n             - 4LL * s.broken;\n    }\n}\n\nlong long finalValue(const Stats &s) {\n    return s.score * 1000000LL\n         + 1LL * s.l1 * 2000LL\n         + 1LL * s.l2 * 1000LL\n         + s.loopSq\n         - 10LL * s.broken;\n}\n\nbool betterStats(const Stats &s, long long bestScore, int bestL1, int bestL2) {\n    if (s.score != bestScore) return s.score > bestScore;\n    return s.l1 + s.l2 > bestL1 + bestL2;\n}\n\nvoid updateBestWithState(\n    const StateArr &arr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        bestState = arr;\n    }\n}\n\nvoid updateBestWithManager(\n    const Manager &mgr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        mgr.exportState(bestState);\n    }\n}\n\nstruct Cycle {\n    int len = 0;\n    uint64_t hash = 0;\n    array<uint64_t, BITWORDS> bits{};\n    vector<int> cells;\n    vector<unsigned char> states;\n};\n\nbool overlapCycle(const Cycle &a, const Cycle &b) {\n    for (int i = 0; i < BITWORDS; i++) {\n        if (a.bits[i] & b.bits[i]) return true;\n    }\n    return false;\n}\n\nstruct CycleSampler {\n    static constexpr int MIN_LEN = 16;\n    static constexpr int KEEP = 700;\n\n    vector<Cycle> cycles;\n\n    int stateSeen[PORTS];\n    int statePos[PORTS];\n    int cellSeen[CELLS];\n    int cellPos[CELLS];\n\n    int stamp = 1;\n    int minStored = MIN_LEN;\n\n    vector<int> path;\n\n    CycleSampler() {\n        memset(stateSeen, 0, sizeof(stateSeen));\n        memset(cellSeen, 0, sizeof(cellSeen));\n        path.reserve(CELLS);\n        cycles.reserve(KEEP);\n    }\n\n    void markState(int s) {\n        int pos = (int)path.size();\n        path.push_back(s);\n\n        stateSeen[s] = stamp;\n        statePos[s] = pos;\n\n        int c = s >> 2;\n        cellSeen[c] = stamp;\n        cellPos[c] = pos;\n    }\n\n    void recomputeMin() {\n        if ((int)cycles.size() < KEEP) {\n            minStored = MIN_LEN;\n            return;\n        }\n\n        minStored = 1000000;\n        for (const auto &c : cycles) minStored = min(minStored, c.len);\n    }\n\n    uint64_t calcHash(const array<uint64_t, BITWORDS> &bits, int len) {\n        uint64_t h = 1469598103934665603ULL ^ (uint64_t)len;\n        for (uint64_t x : bits) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n        return h;\n    }\n\n    void addCycle(int idx) {\n        int end = (int)path.size();\n        int len = end - idx;\n\n        if (len < MIN_LEN) return;\n        if ((int)cycles.size() >= KEEP && len < minStored) return;\n\n        Cycle cy;\n        cy.len = len;\n        cy.bits.fill(0);\n        cy.cells.reserve(len);\n        cy.states.reserve(len);\n\n        for (int p = idx; p < end; p++) {\n            int s = path[p];\n            int nxt = (p + 1 < end ? path[p + 1] : path[idx]);\n\n            int c = s >> 2;\n            int in = s & 3;\n            int out = (nxt & 3) ^ 2;\n\n            int st = stateForPair(baseTile[c], in, out);\n            if (st < 0) return;\n\n            uint64_t bit = 1ULL << (c & 63);\n            int word = c >> 6;\n\n            if (cy.bits[word] & bit) return;\n\n            cy.bits[word] |= bit;\n            cy.cells.push_back(c);\n            cy.states.push_back((unsigned char)st);\n        }\n\n        cy.hash = calcHash(cy.bits, cy.len);\n\n        for (const auto &ex : cycles) {\n            if (ex.len == cy.len && ex.hash == cy.hash && ex.bits == cy.bits) return;\n        }\n\n        if ((int)cycles.size() < KEEP) {\n            cycles.push_back(std::move(cy));\n            if ((int)cycles.size() == KEEP) recomputeMin();\n            return;\n        }\n\n        int mi = 0;\n        for (int i = 1; i < KEEP; i++) {\n            if (cycles[i].len < cycles[mi].len) mi = i;\n        }\n\n        if (cy.len > cycles[mi].len) {\n            cycles[mi] = std::move(cy);\n            recomputeMin();\n        }\n    }\n\n    int onwardScore(int ns, RNG &rng) {\n        int sc = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) sc += 4;\n            } else if (cellSeen[nn >> 2] != stamp) {\n                sc += 2;\n            }\n        }\n\n        return sc + rng.nextInt(3);\n    }\n\n    void sample(Timer &timer, double endTime, RNG &rng) {\n        if (validMoveStates.empty()) return;\n\n        int trials = 0;\n\n        while (timer.elapsed() < endTime) {\n            stamp++;\n\n            if (stamp == INT_MAX) {\n                memset(stateSeen, 0, sizeof(stateSeen));\n                memset(cellSeen, 0, sizeof(cellSeen));\n                stamp = 1;\n            }\n\n            path.clear();\n\n            int start = validMoveStates[rng.nextInt((int)validMoveStates.size())];\n            markState(start);\n\n            int inner = 0;\n\n            while ((int)path.size() < CELLS) {\n                int cur = path.back();\n                int cnt = moveCnt[cur];\n\n                if (cnt == 0) break;\n\n                int unv[2];\n                int uc = 0;\n\n                int bestIdx = -1;\n                int bestLen = -1;\n\n                for (int k = 0; k < cnt; k++) {\n                    int ns = moveNextState[cur][k];\n                    int nc = ns >> 2;\n\n                    if (stateSeen[ns] == stamp) {\n                        int idx = statePos[ns];\n                        int len = (int)path.size() - idx;\n\n                        if (len >= MIN_LEN && len > bestLen) {\n                            bestLen = len;\n                            bestIdx = idx;\n                        }\n                    } else if (cellSeen[nc] != stamp) {\n                        unv[uc++] = ns;\n                    }\n                }\n\n                if (bestIdx != -1) addCycle(bestIdx);\n\n                if (uc == 0) break;\n\n                int chosen;\n\n                if (uc == 1) {\n                    chosen = unv[0];\n                } else {\n                    int s0 = onwardScore(unv[0], rng);\n                    int s1 = onwardScore(unv[1], rng);\n\n                    if (s0 == s1) {\n                        chosen = unv[rng.nextInt(2)];\n                    } else if (s0 > s1) {\n                        chosen = (rng.nextInt(4) ? unv[0] : unv[1]);\n                    } else {\n                        chosen = (rng.nextInt(4) ? unv[1] : unv[0]);\n                    }\n                }\n\n                markState(chosen);\n\n                inner++;\n                if ((inner & 255) == 0 && timer.elapsed() >= endTime) break;\n            }\n\n            trials++;\n        }\n    }\n};\n\nvoid runSA(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    double startTime = timer.elapsed();\n    if (endTime - startTime < 0.01) return;\n\n    Stats initS = mgr.getStats();\n    updateBestWithManager(mgr, initS, bestState, bestScore, bestL1, bestL2);\n\n    int iter = 0;\n    double now = startTime;\n    double progress = 0.0;\n    double temp = 6e6;\n\n    while (true) {\n        if ((iter & 127) == 0) {\n            now = timer.elapsed();\n            if (now >= endTime) break;\n\n            progress = (now - startTime) / (endTime - startTime);\n            progress = min(1.0, max(0.0, progress));\n            temp = 6e6 * pow(2000.0 / 6e6, progress);\n        }\n\n        int ids[4];\n        int oldSt[4];\n        int newSt[4];\n        int m = 1;\n\n        int rr = rng.nextInt(100);\n\n        if (progress < 0.65 && rr < 6) {\n            m = 4;\n            int i = rng.nextInt(N - 1);\n            int j = rng.nextInt(N - 1);\n\n            ids[0] = i * N + j;\n            ids[1] = i * N + j + 1;\n            ids[2] = (i + 1) * N + j;\n            ids[3] = (i + 1) * N + j + 1;\n        } else if (progress < 0.85 && rr < 22) {\n            m = 2;\n            ids[0] = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int nb = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[ids[0]][d] != -1) {\n                    nb = neighCell[ids[0]][d];\n                    break;\n                }\n            }\n\n            ids[1] = nb;\n        } else {\n            m = 1;\n            ids[0] = rng.nextInt(CELLS);\n        }\n\n        bool changed = false;\n\n        for (int x = 0; x < m; x++) {\n            int id = ids[x];\n            int cur = mgr.st[id];\n            oldSt[x] = cur;\n\n            int ns = cur;\n\n            int smartProb = (m == 1 ? 25 : 45);\n\n            if (rng.nextInt(100) < smartProb) {\n                int bestQ = -1000000000;\n                int ties = 0;\n\n                for (int k = 0; k < optCnt[id]; k++) {\n                    int s = optState[id][k];\n                    if (s == cur) continue;\n\n                    int q = localQuality(mgr.st, id, s);\n\n                    if (q > bestQ) {\n                        bestQ = q;\n                        ns = s;\n                        ties = 1;\n                    } else if (q == bestQ) {\n                        ties++;\n                        if (rng.nextInt(ties) == 0) ns = s;\n                    }\n                }\n            } else {\n                do {\n                    ns = optState[id][rng.nextInt(optCnt[id])];\n                } while (ns == cur);\n            }\n\n            newSt[x] = ns;\n            if (ns != cur) changed = true;\n        }\n\n        if (!changed) {\n            iter++;\n            continue;\n        }\n\n        Stats oldS = mgr.getStats();\n        long long oldE = energyValue(oldS, progress);\n\n        for (int x = 0; x < m; x++) mgr.updateCell(ids[x], newSt[x]);\n\n        Stats newS = mgr.getStats();\n        long long newE = energyValue(newS, progress);\n\n        updateBestWithManager(mgr, newS, bestState, bestScore, bestL1, bestL2);\n\n        long long diff = newE - oldE;\n\n        bool accept = false;\n\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            double x = (double)diff / temp;\n            if (x > -30.0 && rng.nextDouble() < exp(x)) accept = true;\n        }\n\n        if (!accept) {\n            for (int x = m - 1; x >= 0; x--) mgr.updateCell(ids[x], oldSt[x]);\n        }\n\n        iter++;\n    }\n}\n\nvoid runHillClimb(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    mgr.build(bestState);\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 7) == 0) {\n            if (timer.elapsed() >= endTime) break;\n        }\n\n        bool pairMove = rng.nextInt(100) < 35;\n\n        if (!pairMove) {\n            int id = rng.nextInt(CELLS);\n            int cur = mgr.st[id];\n\n            Stats baseS = mgr.getStats();\n            long long bestVal = finalValue(baseS);\n            int bestSt = cur;\n\n            for (int k = 0; k < optCnt[id]; k++) {\n                int s = optState[id][k];\n                if (s == cur) continue;\n\n                mgr.updateCell(id, s);\n                Stats ns = mgr.getStats();\n                long long v = finalValue(ns);\n                mgr.updateCell(id, cur);\n\n                if (v > bestVal) {\n                    bestVal = v;\n                    bestSt = s;\n                }\n            }\n\n            if (bestSt != cur) {\n                mgr.updateCell(id, bestSt);\n                Stats s = mgr.getStats();\n                updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n            }\n        } else {\n            int id1 = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int id2 = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[id1][d] != -1) {\n                    id2 = neighCell[id1][d];\n                    break;\n                }\n            }\n\n            if (id2 == -1) {\n                iter++;\n                continue;\n            }\n\n            int old1 = mgr.st[id1];\n            int old2 = mgr.st[id2];\n\n            Stats baseS = mgr.getStats();\n            long long bestVal = finalValue(baseS);\n            int best1 = old1;\n            int best2 = old2;\n\n            for (int a = 0; a < optCnt[id1]; a++) {\n                int s1 = optState[id1][a];\n\n                for (int b = 0; b < optCnt[id2]; b++) {\n                    int s2 = optState[id2][b];\n\n                    if (s1 == old1 && s2 == old2) continue;\n\n                    mgr.updateCell(id1, s1);\n                    mgr.updateCell(id2, s2);\n\n                    Stats ns = mgr.getStats();\n                    long long v = finalValue(ns);\n\n                    mgr.updateCell(id2, old2);\n                    mgr.updateCell(id1, old1);\n\n                    if (v > bestVal) {\n                        bestVal = v;\n                        best1 = s1;\n                        best2 = s2;\n                    }\n                }\n            }\n\n            if (best1 != old1 || best2 != old2) {\n                mgr.updateCell(id1, best1);\n                mgr.updateCell(id2, best2);\n\n                Stats s = mgr.getStats();\n                updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n            }\n        }\n\n        iter++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initGlobals();\n\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        string row;\n        cin >> row;\n\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            int t = row[j] - '0';\n\n            baseTile[id] = t;\n            seed = seed * 1000003ULL + (uint64_t)(t + 17);\n        }\n    }\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n\n        if (b < 4) {\n            optCnt[id] = 4;\n            for (int k = 0; k < 4; k++) optState[id][k] = k;\n        } else if (b < 6) {\n            optCnt[id] = 2;\n            optState[id][0] = 4;\n            optState[id][1] = 5;\n        } else {\n            optCnt[id] = 2;\n            optState[id][0] = 6;\n            optState[id][1] = 7;\n        }\n    }\n\n    buildMoveTransitions();\n\n    Timer timer;\n    RNG rng(seed);\n\n    Manager mgr;\n\n    StateArr bestState{};\n    long long bestScore = -1;\n    int bestL1 = 0;\n    int bestL2 = 0;\n\n    vector<pair<long long, StateArr>> topStarts;\n\n    auto insertTop = [&](long long val, const StateArr &s) {\n        topStarts.push_back({val, s});\n\n        sort(topStarts.begin(), topStarts.end(),\n             [](const auto &a, const auto &b) {\n                 return a.first > b.first;\n             });\n\n        if ((int)topStarts.size() > 8) topStarts.pop_back();\n    };\n\n    auto evalCandidate = [&](const StateArr &cand) {\n        mgr.build(cand);\n        Stats s = mgr.getStats();\n\n        updateBestWithState(cand, s, bestState, bestScore, bestL1, bestL2);\n        insertTop(startValue(s), cand);\n    };\n\n    StateArr baseArr;\n    for (int id = 0; id < CELLS; id++) baseArr[id] = baseTile[id];\n    evalCandidate(baseArr);\n\n    CycleSampler sampler;\n    sampler.sample(timer, 0.16, rng);\n\n    auto &cycles = sampler.cycles;\n\n    sort(cycles.begin(), cycles.end(),\n         [](const Cycle &a, const Cycle &b) {\n             return a.len > b.len;\n         });\n\n    vector<tuple<long long, int, int>> topPairs;\n\n    auto insertPair = [&](long long prod, int a, int b) {\n        topPairs.emplace_back(prod, a, b);\n\n        sort(topPairs.begin(), topPairs.end(),\n             [](const auto &x, const auto &y) {\n                 return get<0>(x) > get<0>(y);\n             });\n\n        if ((int)topPairs.size() > 6) topPairs.pop_back();\n    };\n\n    int C = (int)cycles.size();\n    int I = min(C, 250);\n    int J = min(C, 700);\n\n    for (int i = 0; i < I; i++) {\n        for (int j = i + 1; j < J; j++) {\n            long long prod = 1LL * cycles[i].len * cycles[j].len;\n\n            if ((int)topPairs.size() >= 6 && prod <= get<0>(topPairs.back())) {\n                break;\n            }\n\n            if (!overlapCycle(cycles[i], cycles[j])) {\n                insertPair(prod, i, j);\n            }\n        }\n    }\n\n    auto applyCycle = [&](const Cycle &cy, StateArr &cand, array<char, CELLS> &fixed) {\n        for (int k = 0; k < cy.len; k++) {\n            int c = cy.cells[k];\n            cand[c] = cy.states[k];\n            fixed[c] = 1;\n        }\n    };\n\n    for (int p = 0; p < (int)topPairs.size(); p++) {\n        if (timer.elapsed() > 0.29) break;\n\n        int a = get<1>(topPairs[p]);\n        int b = get<2>(topPairs[p]);\n\n        for (int var = 0; var < 2; var++) {\n            if (timer.elapsed() > 0.30) break;\n\n            StateArr cand;\n            array<char, CELLS> fixed{};\n            fixed.fill(0);\n\n            if (var == 0) {\n                for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n            } else {\n                for (int id = 0; id < CELLS; id++) {\n                    cand[id] = optState[id][rng.nextInt(optCnt[id])];\n                }\n            }\n\n            applyCycle(cycles[a], cand, fixed);\n            applyCycle(cycles[b], cand, fixed);\n\n            greedyImprove(cand, rng, 7 + var, fixed.data());\n            evalCandidate(cand);\n        }\n    }\n\n    for (int sidx = 0; sidx < min(3, C); sidx++) {\n        if (timer.elapsed() > 0.31) break;\n\n        StateArr cand;\n        array<char, CELLS> fixed{};\n        fixed.fill(0);\n\n        for (int id = 0; id < CELLS; id++) {\n            cand[id] = optState[id][rng.nextInt(optCnt[id])];\n        }\n\n        applyCycle(cycles[sidx], cand, fixed);\n        greedyImprove(cand, rng, 7, fixed.data());\n        evalCandidate(cand);\n    }\n\n    constexpr int CAND_LIMIT = 70;\n    constexpr double START_END = 0.34;\n\n    for (int c = 0; c < CAND_LIMIT; c++) {\n        if (c > 4 && timer.elapsed() > START_END) break;\n\n        StateArr cand;\n\n        if (c == 0) {\n            for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n        } else {\n            for (int id = 0; id < CELLS; id++) {\n                cand[id] = optState[id][rng.nextInt(optCnt[id])];\n            }\n        }\n\n        int sweeps = 7 + (c % 4);\n        greedyImprove(cand, rng, sweeps);\n\n        evalCandidate(cand);\n    }\n\n    vector<StateArr> starts;\n\n    auto addUniqueStart = [&](const StateArr &s) {\n        for (const auto &t : starts) {\n            if (t == s) return;\n        }\n        starts.push_back(s);\n    };\n\n    addUniqueStart(bestState);\n\n    for (auto &p : topStarts) addUniqueStart(p.second);\n\n    if (starts.empty()) {\n        StateArr init;\n        for (int id = 0; id < CELLS; id++) init[id] = baseTile[id];\n        starts.push_back(init);\n        bestState = init;\n    }\n\n    double SA_END = 1.67;\n    double HILL_END = 1.92;\n\n    int runs = min(4, (int)starts.size());\n\n    for (int r = 0; r < runs; r++) {\n        double now = timer.elapsed();\n\n        if (now >= SA_END) break;\n\n        double endTime = now + (SA_END - now) / (runs - r);\n\n        mgr.build(starts[r]);\n        runSA(mgr, timer, endTime, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    if (timer.elapsed() < HILL_END) {\n        runHillClimb(mgr, timer, HILL_END, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    string ans;\n    ans.reserve(CELLS);\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n        int f = bestState[id];\n        int r;\n\n        if (b < 4) {\n            r = (f - b + 4) % 4;\n        } else {\n            r = (f == b ? 0 : 1);\n        }\n\n        ans.push_back(char('0' + r));\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#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\nint N, T, NN, M;\nvector<int> initBoard;\nint initBlank;\nint nbCell[105][4];\n\nconst int DR[4] = {-1, 1, 0, 0};\nconst int DC[4] = {0, 0, -1, 1};\nconst char DCH[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\nint targetCntArr[16];\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\nint hexVal(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return c - 'a' + 10;\n}\n\nstruct FastDSU {\n    int p[105], sz[105];\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    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 Eval {\n    int S;\n    int edges;\n};\n\nEval evalBoard(const vector<int>& bd) {\n    FastDSU dsu;\n    dsu.init(NN);\n    vector<pair<int,int>> edges;\n    edges.reserve(2 * NN);\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            if (bd[id] == 0) continue;\n            if (c + 1 < N) {\n                int j = id + 1;\n                if (bd[j] != 0 && (bd[id] & 4) && (bd[j] & 1)) {\n                    dsu.unite(id, j);\n                    edges.push_back({id, j});\n                }\n            }\n            if (r + 1 < N) {\n                int j = id + N;\n                if (bd[j] != 0 && (bd[id] & 8) && (bd[j] & 2)) {\n                    dsu.unite(id, j);\n                    edges.push_back({id, j});\n                }\n            }\n        }\n    }\n\n    int vcnt[105] = {};\n    int ecnt[105] = {};\n    for (int i = 0; i < NN; i++) {\n        if (bd[i] != 0) vcnt[dsu.find(i)]++;\n    }\n    for (auto [u, v] : edges) {\n        ecnt[dsu.find(u)]++;\n    }\n\n    int best = 0;\n    for (int i = 0; i < NN; i++) {\n        if (dsu.find(i) == i && vcnt[i] > 0 && ecnt[i] == vcnt[i] - 1) {\n            best = max(best, vcnt[i]);\n        }\n    }\n    return {best, (int)edges.size()};\n}\n\nlong long scoreFromEval(const Eval& e, int K) {\n    if (e.S == M) {\n        return llround(500000.0 * (2.0 - (double)K / T));\n    } else {\n        return llround(500000.0 * (double)e.S / M);\n    }\n}\n\nbool applyDir(vector<int>& bd, int& blank, int d) {\n    int nb = nbCell[blank][d];\n    if (nb < 0) return false;\n    swap(bd[blank], bd[nb]);\n    blank = nb;\n    return true;\n}\n\nvector<int> simulateMoves(const string& moves) {\n    vector<int> bd = initBoard;\n    int blank = initBlank;\n    for (char ch : moves) {\n        int d = dirIndex(ch);\n        if (!applyDir(bd, blank, d)) break;\n    }\n    return bd;\n}\n\nstring simplifyMoves(const string& s) {\n    string res;\n    for (char ch : s) {\n        int d = dirIndex(ch);\n        if (!res.empty() && dirIndex(res.back()) == OPP[d]) {\n            res.pop_back();\n        } else {\n            res.push_back(ch);\n        }\n    }\n    return res;\n}\n\nstruct BestAns {\n    string moves;\n    long long score = -1;\n    int S = 0;\n};\n\nvoid updateBest(BestAns& best, string mv) {\n    mv = simplifyMoves(mv);\n    if ((int)mv.size() > T) mv.resize(T);\n    vector<int> bd = simulateMoves(mv);\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nvoid updateBestKnownBoard(BestAns& best, const string& mv0, const vector<int>& bd) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nuint64_t hashBoard(const vector<int>& bd) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int x : bd) {\n        h ^= (uint64_t)(x + 1);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nbool countsMatch(const vector<int>& bd) {\n    int cnt[16] = {};\n    int z = 0;\n    for (int x : bd) {\n        if (x == 0) z++;\n        else cnt[x]++;\n    }\n    if (z != 1) return false;\n    for (int i = 0; i < 16; i++) {\n        if (cnt[i] != targetCntArr[i]) return false;\n    }\n    return true;\n}\n\nstruct Candidate {\n    vector<int> board;\n    int blank;\n    int estCost;\n    int expectedS;\n    uint64_t hash;\n};\n\nint candValue(const Candidate& c) {\n    return c.expectedS * 10000 - c.estCost;\n}\n\nvoid addCandidate(vector<Candidate>& cands, const vector<int>& bd, int estCost) {\n    if (!countsMatch(bd)) return;\n    int z = -1;\n    for (int i = 0; i < NN; i++) if (bd[i] == 0) z = i;\n    Eval e = evalBoard(bd);\n    uint64_t h = hashBoard(bd);\n    for (auto& c : cands) {\n        if (c.hash == h && c.board == bd) return;\n    }\n    Candidate nc{bd, z, estCost, e.S, h};\n    const int MAX_CAND = 30;\n    if ((int)cands.size() < MAX_CAND) {\n        cands.push_back(nc);\n    } else {\n        int worst = 0;\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (candValue(cands[i]) < candValue(cands[worst])) worst = i;\n        }\n        if (candValue(nc) > candValue(cands[worst])) cands[worst] = nc;\n    }\n}\n\nstruct Edge {\n    int a, b;\n    int ba, bb;\n};\n\nconst int DIFF_W = 1000;\nconst int POS_W = 3;\n\nstruct Change {\n    int vc = 0;\n    int verts[4];\n    int oldm[4];\n    int newm[4];\n    int dcnt[16];\n    int diffD = 0;\n    int posD = 0;\n    int energyD = 0;\n};\n\nstruct TreeState {\n    int blank;\n    vector<Edge> edges;\n    int E;\n    vector<char> inTree;\n    vector<vector<int>> adj;\n    vector<int> mask;\n    vector<int> comp;\n    int cnt[16];\n    int diff = 0;\n    int bitCost = 0;\n\n    vector<int> par, pare, qbuf, path;\n\n    TreeState(int b, const vector<int>& compMask) : blank(b), comp(compMask) {\n        for (int r = 0; r < N; r++) {\n            for (int c = 0; c < N; c++) {\n                int id = r * N + c;\n                if (id == blank) continue;\n                if (c + 1 < N) {\n                    int j = id + 1;\n                    if (j != blank) edges.push_back({id, j, 4, 1});\n                }\n                if (r + 1 < N) {\n                    int j = id + N;\n                    if (j != blank) edges.push_back({id, j, 8, 2});\n                }\n            }\n        }\n        E = (int)edges.size();\n        inTree.assign(E, 0);\n        adj.assign(NN, {});\n        mask.assign(NN, 0);\n        par.resize(NN);\n        pare.resize(NN);\n        qbuf.reserve(NN);\n        path.reserve(NN);\n    }\n\n    int other(int eid, int v) const {\n        const Edge& e = edges[eid];\n        return e.a == v ? e.b : e.a;\n    }\n\n    void addInitialEdge(int eid) {\n        const Edge& e = edges[eid];\n        inTree[eid] = 1;\n        adj[e.a].push_back(eid);\n        adj[e.b].push_back(eid);\n        mask[e.a] |= e.ba;\n        mask[e.b] |= e.bb;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(inTree.begin(), inTree.end(), 0);\n        for (auto& v : adj) v.clear();\n        fill(mask.begin(), mask.end(), 0);\n        memset(cnt, 0, sizeof(cnt));\n        diff = 0;\n        bitCost = 0;\n\n        vector<pair<long long,int>> ord;\n        ord.reserve(E);\n        for (int i = 0; i < E; i++) {\n            const Edge& e = edges[i];\n            int w = 0;\n            if (mode > 0) {\n                bool ma = comp[e.a] & e.ba;\n                bool mb = comp[e.b] & e.bb;\n                w += ma ? 2 : -1;\n                w += mb ? 2 : -1;\n                if (ma && mb) w += 2;\n                if (mode == 2) w += (int)(rng() % 3) - 1;\n            }\n            long long noise = (long long)(rng() % 1000000000U);\n            long long key = noise - (long long)w * (mode == 1 ? 1000000000LL : 300000000LL);\n            if (mode == 0) key = noise;\n            ord.push_back({key, i});\n        }\n        sort(ord.begin(), ord.end());\n\n        FastDSU dsu;\n        dsu.init(NN);\n        int selected = 0;\n        for (auto [key, id] : ord) {\n            (void)key;\n            const Edge& e = edges[id];\n            if (dsu.find(e.a) != dsu.find(e.b)) {\n                dsu.unite(e.a, e.b);\n                addInitialEdge(id);\n                selected++;\n                if (selected == M - 1) break;\n            }\n        }\n\n        for (int v = 0; v < NN; v++) {\n            if (v == blank) continue;\n            cnt[mask[v]]++;\n            bitCost += __builtin_popcount((unsigned)(mask[v] ^ comp[v]));\n        }\n        for (int t = 0; t < 16; t++) {\n            diff += abs(cnt[t] - targetCntArr[t]);\n        }\n    }\n\n    void getPath(int s, int t) {\n        fill(par.begin(), par.end(), -1);\n        qbuf.clear();\n        path.clear();\n        int head = 0;\n        par[s] = s;\n        qbuf.push_back(s);\n        while (head < (int)qbuf.size()) {\n            int v = qbuf[head++];\n            if (v == t) break;\n            for (int eid : adj[v]) {\n                if (!inTree[eid]) continue;\n                int u = other(eid, v);\n                if (par[u] == -1) {\n                    par[u] = v;\n                    pare[u] = eid;\n                    qbuf.push_back(u);\n                }\n            }\n        }\n        if (par[t] == -1) return;\n        int cur = t;\n        while (cur != s) {\n            path.push_back(pare[cur]);\n            cur = par[cur];\n        }\n    }\n\n    Change makeChange(int addId, int remId) const {\n        Change ch;\n        memset(ch.dcnt, 0, sizeof(ch.dcnt));\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < ch.vc; i++) {\n                if (ch.verts[i] == v) return i;\n            }\n            int i = ch.vc++;\n            ch.verts[i] = v;\n            ch.oldm[i] = mask[v];\n            ch.newm[i] = mask[v];\n            return i;\n        };\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        int ia = getIdx(ea.a);\n        ch.newm[ia] |= ea.ba;\n        int ib = getIdx(ea.b);\n        ch.newm[ib] |= ea.bb;\n\n        int ra = getIdx(er.a);\n        ch.newm[ra] &= ~er.ba;\n        int rb = getIdx(er.b);\n        ch.newm[rb] &= ~er.bb;\n\n        for (int i = 0; i < ch.vc; i++) {\n            if (ch.oldm[i] == ch.newm[i]) continue;\n            ch.dcnt[ch.oldm[i]]--;\n            ch.dcnt[ch.newm[i]]++;\n            int v = ch.verts[i];\n            ch.posD += __builtin_popcount((unsigned)(ch.newm[i] ^ comp[v]))\n                     - __builtin_popcount((unsigned)(ch.oldm[i] ^ comp[v]));\n        }\n        for (int t = 0; t < 16; t++) {\n            if (ch.dcnt[t]) {\n                ch.diffD += abs(cnt[t] + ch.dcnt[t] - targetCntArr[t])\n                          - abs(cnt[t] - targetCntArr[t]);\n            }\n        }\n        ch.energyD = ch.diffD * DIFF_W + ch.posD * POS_W;\n        return ch;\n    }\n\n    void removeAdj(int v, int eid) {\n        auto& a = adj[v];\n        for (int i = 0; i < (int)a.size(); i++) {\n            if (a[i] == eid) {\n                a[i] = a.back();\n                a.pop_back();\n                return;\n            }\n        }\n    }\n\n    void applySwap(int addId, int remId, const Change& ch) {\n        for (int t = 0; t < 16; t++) cnt[t] += ch.dcnt[t];\n        diff += ch.diffD;\n        bitCost += ch.posD;\n        for (int i = 0; i < ch.vc; i++) {\n            mask[ch.verts[i]] = ch.newm[i];\n        }\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        inTree[addId] = 1;\n        inTree[remId] = 0;\n        adj[ea.a].push_back(addId);\n        adj[ea.b].push_back(addId);\n        removeAdj(er.a, remId);\n        removeAdj(er.b, remId);\n    }\n\n    bool step(mt19937& rng, double temp) {\n        int addId;\n        do {\n            addId = (int)(rng() % E);\n        } while (inTree[addId]);\n\n        const Edge& e = edges[addId];\n        getPath(e.a, e.b);\n        if (path.empty()) return false;\n\n        int remId = -1;\n        Change bestCh;\n        int bestDelta = INT_MAX;\n\n        bool chooseBest = (rng() % 100) < 85;\n        if (chooseBest) {\n            for (int pe : path) {\n                Change ch = makeChange(addId, pe);\n                if (ch.energyD < bestDelta) {\n                    bestDelta = ch.energyD;\n                    bestCh = ch;\n                    remId = pe;\n                }\n            }\n        } else {\n            remId = path[rng() % path.size()];\n            bestCh = makeChange(addId, remId);\n            bestDelta = bestCh.energyD;\n        }\n\n        bool accept = false;\n        if (bestDelta <= 0) {\n            accept = true;\n        } else if (bestDelta < temp * 40.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-bestDelta / temp);\n        }\n\n        if (accept) {\n            applySwap(addId, remId, bestCh);\n            return true;\n        }\n        return false;\n    }\n\n    vector<int> getBoard() const {\n        vector<int> bd(NN, 0);\n        for (int i = 0; i < NN; i++) {\n            if (i != blank) bd[i] = mask[i];\n        }\n        return bd;\n    }\n};\n\nvector<int> makeCompMask(int targetBlank) {\n    vector<int> comp = initBoard;\n    if (initBlank != targetBlank) {\n        comp[initBlank] = initBoard[targetBlank];\n        comp[targetBlank] = 0;\n    }\n    return comp;\n}\n\nvector<int> blankChoices;\n\nvoid considerApprox(const TreeState& st, vector<int>& bestBoard, int& bestDiff, int& bestBit) {\n    if (st.diff < bestDiff || (st.diff == bestDiff && st.bitCost < bestBit)) {\n        bestDiff = st.diff;\n        bestBit = st.bitCost;\n        bestBoard = st.getBoard();\n    }\n}\n\nvoid runTreeSearch(double endTime, Timer& timer, mt19937& rng,\n                   vector<Candidate>& cands,\n                   vector<int>& bestApproxBoard,\n                   int& bestApproxDiff,\n                   int& bestApproxBit,\n                   int& restartCounter) {\n    while (timer.elapsed() < endTime) {\n        int b;\n        if (restartCounter < 5 || restartCounter % 5 != 0 || blankChoices.size() == 1) {\n            b = (N - 1) * N + (N - 1);\n        } else {\n            int idx = 1 + ((restartCounter / 5) % (blankChoices.size() - 1));\n            b = blankChoices[idx];\n        }\n\n        vector<int> comp = makeCompMask(b);\n        TreeState st(b, comp);\n\n        int mode;\n        if (restartCounter % 4 == 0) mode = 0;\n        else if (restartCounter % 4 == 1) mode = 1;\n        else mode = 2;\n\n        st.initRandom(mode, rng);\n        considerApprox(st, bestApproxBoard, bestApproxDiff, bestApproxBit);\n        if (st.diff == 0) addCandidate(cands, st.getBoard(), st.bitCost);\n\n        int maxIter = 26000 + N * 1200;\n        int localBestExact = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n            double p = (double)it / maxIter;\n            double temp = 4500.0 * pow(8.0 / 4500.0, p);\n\n            st.step(rng, temp);\n\n            if (st.diff < bestApproxDiff || (st.diff == bestApproxDiff && st.bitCost < bestApproxBit)) {\n                considerApprox(st, bestApproxBoard, bestApproxDiff, bestApproxBit);\n            }\n            if (st.diff == 0 && (st.bitCost < localBestExact || (it & 2047) == 0)) {\n                addCandidate(cands, st.getBoard(), st.bitCost);\n                localBestExact = min(localBestExact, st.bitCost);\n            }\n        }\n        if (st.diff == 0) addCandidate(cands, st.getBoard(), st.bitCost);\n        restartCounter++;\n    }\n}\n\nvector<int> adjustCountsToTarget(vector<int> bd) {\n    int cnt[16] = {};\n    for (int x : bd) if (x != 0) cnt[x]++;\n\n    while (true) {\n        vector<int> deficits;\n        bool done = true;\n        for (int t = 1; t < 16; t++) {\n            if (cnt[t] < targetCntArr[t]) deficits.push_back(t);\n            if (cnt[t] != targetCntArr[t]) done = false;\n        }\n        if (done) break;\n\n        int bestCell = -1, bestTo = -1;\n        int bestVal = INT_MIN;\n\n        for (int i = 0; i < NN; i++) {\n            int old = bd[i];\n            if (old == 0) continue;\n            if (cnt[old] <= targetCntArr[old]) continue;\n\n            for (int to : deficits) {\n                bd[i] = to;\n                Eval e = evalBoard(bd);\n                int val = e.S * 1000 + e.edges;\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestCell = i;\n                    bestTo = to;\n                }\n            }\n            bd[i] = old;\n        }\n\n        if (bestCell < 0) break;\n        int old = bd[bestCell];\n        bd[bestCell] = bestTo;\n        cnt[old]--;\n        cnt[bestTo]++;\n    }\n    return bd;\n}\n\nstruct SolveResult {\n    string moves;\n    bool reached;\n};\n\nstruct SlidingSolver {\n    vector<int> board;\n    vector<int> target;\n    vector<char> fixed;\n    string ops;\n    int blank;\n    int variant;\n    mt19937& rng;\n    Timer& timer;\n    double timeLimit;\n    int cap;\n    vector<int> dirOrder;\n    bool shuffleSources;\n\n    SlidingSolver(const vector<int>& tgt, int var, mt19937& rg, Timer& tm, double lim, int cp)\n        : board(initBoard), target(tgt), fixed(NN, 0), blank(initBlank),\n          variant(var), rng(rg), timer(tm), timeLimit(lim), cap(cp) {\n        dirOrder = {0, 1, 2, 3};\n        if (variant > 0) shuffle(dirOrder.begin(), dirOrder.end(), rng);\n        shuffleSources = variant > 0;\n    }\n\n    bool doDir(int d) {\n        int nb = nbCell[blank][d];\n        if (nb < 0) return false;\n        swap(board[blank], board[nb]);\n        blank = nb;\n        ops.push_back(DCH[d]);\n        return true;\n    }\n\n    bool placeTile(int qcell) {\n        int desired = target[qcell];\n        if (desired == 0) return false;\n\n        vector<int> sources;\n        for (int i = 0; i < NN; i++) {\n            if (!fixed[i] && i != blank && board[i] == desired) {\n                sources.push_back(i);\n            }\n        }\n        if (sources.empty()) return false;\n        if (shuffleSources) shuffle(sources.begin(), sources.end(), rng);\n\n        int total = NN * NN;\n        vector<int> parent(total, -1);\n        vector<unsigned char> pdir(total, 0);\n        vector<int> que;\n        que.reserve(total);\n\n        int goal = -1;\n        for (int p : sources) {\n            int id = p * NN + blank;\n            if (parent[id] == -1) {\n                parent[id] = -2;\n                que.push_back(id);\n                if (p == qcell) goal = id;\n            }\n        }\n\n        int head = 0;\n        while (goal == -1 && head < (int)que.size()) {\n            int id = que[head++];\n            int tile = id / NN;\n            int emp = id % NN;\n\n            for (int d : dirOrder) {\n                int nb = nbCell[emp][d];\n                if (nb < 0 || fixed[nb]) continue;\n\n                int ntile = tile;\n                int nemp = nb;\n                if (nb == tile) {\n                    ntile = emp;\n                    nemp = nb;\n                }\n\n                int nid = ntile * NN + nemp;\n                if (parent[nid] != -1) continue;\n                parent[nid] = id;\n                pdir[nid] = (unsigned char)d;\n                if (ntile == qcell) {\n                    goal = nid;\n                    break;\n                }\n                que.push_back(nid);\n            }\n        }\n\n        if (goal == -1) return false;\n\n        vector<int> path;\n        for (int cur = goal; parent[cur] != -2; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n        reverse(path.begin(), path.end());\n\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            doDir(d);\n        }\n\n        if (board[qcell] != desired) return false;\n        fixed[qcell] = 1;\n        return true;\n    }\n\n    uint64_t encodeBlock(const vector<int>& bd) const {\n        uint64_t code = 0;\n        int k = 0;\n        for (int r = N - 3; r < N; r++) {\n            for (int c = N - 3; c < N; c++) {\n                int id = r * N + c;\n                code |= (uint64_t)bd[id] << (4 * k);\n                k++;\n            }\n        }\n        return code;\n    }\n\n    int blankInCode(uint64_t code) const {\n        for (int k = 0; k < 9; k++) {\n            if (((code >> (4 * k)) & 15ULL) == 0) return k;\n        }\n        return -1;\n    }\n\n    uint64_t swapNibblesWithBlank(uint64_t code, int bk, int nk) const {\n        int val = (int)((code >> (4 * nk)) & 15ULL);\n        uint64_t maskB = 15ULL << (4 * bk);\n        uint64_t maskN = 15ULL << (4 * nk);\n        code &= ~maskB;\n        code &= ~maskN;\n        code |= (uint64_t)val << (4 * bk);\n        return code;\n    }\n\n    bool solveFinalBlock(bool targetFull) {\n        uint64_t start = encodeBlock(board);\n        uint64_t targetCode = encodeBlock(target);\n\n        if (targetFull && start == targetCode) return true;\n\n        int bnb[9][4];\n        for (int k = 0; k < 9; k++) {\n            int rr = k / 3, cc = k % 3;\n            for (int d = 0; d < 4; d++) {\n                int nr = rr + DR[d], nc = cc + DC[d];\n                if (nr < 0 || nr >= 3 || nc < 0 || nc >= 3) bnb[k][d] = -1;\n                else bnb[k][d] = nr * 3 + nc;\n            }\n        }\n\n        unordered_map<uint64_t, int> mp;\n        mp.reserve(400000);\n        mp.max_load_factor(0.7);\n\n        vector<uint64_t> states;\n        vector<int> parent;\n        vector<unsigned char> pdir;\n        states.reserve(200000);\n        parent.reserve(200000);\n        pdir.reserve(200000);\n\n        mp[start] = 0;\n        states.push_back(start);\n        parent.push_back(-1);\n        pdir.push_back(0);\n\n        int goal = -1;\n        int head = 0;\n        while (head < (int)states.size()) {\n            if ((head & 4095) == 0 && timer.elapsed() > timeLimit) break;\n            uint64_t code = states[head];\n            int bk = blankInCode(code);\n            for (int d = 0; d < 4; d++) {\n                int nk = bnb[bk][d];\n                if (nk < 0) continue;\n                uint64_t nc = swapNibblesWithBlank(code, bk, nk);\n                if (mp.find(nc) != mp.end()) continue;\n                int ni = (int)states.size();\n                mp[nc] = ni;\n                states.push_back(nc);\n                parent.push_back(head);\n                pdir.push_back((unsigned char)d);\n\n                if (targetFull && nc == targetCode) {\n                    goal = ni;\n                    head = (int)states.size();\n                    break;\n                }\n            }\n            head++;\n        }\n\n        int chosen = -1;\n        bool reached = false;\n\n        if (targetFull && goal != -1) {\n            chosen = goal;\n            reached = true;\n        } else {\n            // Choose best reachable final 3x3 state as fallback.\n            chosen = 0;\n            if (timer.elapsed() < timeLimit - 0.02) {\n                int blockIds[9];\n                int k = 0;\n                for (int r = N - 3; r < N; r++) {\n                    for (int c = N - 3; c < N; c++) {\n                        blockIds[k++] = r * N + c;\n                    }\n                }\n\n                vector<int> tmp = board;\n                int bestVal = INT_MIN;\n                for (int idx = 0; idx < (int)states.size(); idx++) {\n                    uint64_t code = states[idx];\n                    for (int j = 0; j < 9; j++) {\n                        tmp[blockIds[j]] = (int)((code >> (4 * j)) & 15ULL);\n                    }\n                    Eval e = evalBoard(tmp);\n                    int val = e.S * 1000 + e.edges;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        chosen = idx;\n                    }\n                }\n            }\n        }\n\n        vector<int> path;\n        for (int cur = chosen; parent[cur] != -1; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n        reverse(path.begin(), path.end());\n\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            doDir(d);\n        }\n\n        if (reached) {\n            for (int i = 0; i < NN; i++) {\n                if (board[i] != target[i]) return false;\n            }\n        }\n        return reached;\n    }\n\n    SolveResult run(bool targetFull) {\n        int rowMode = variant % 3;\n        int colMode = (variant / 3) % 4;\n\n        vector<int> order;\n        order.reserve(NN);\n\n        // Fix top N-3 rows.\n        for (int r = 0; r < N - 3; r++) {\n            bool rev = false;\n            if (rowMode == 1) rev = true;\n            if (rowMode == 2 && (r & 1)) rev = true;\n\n            if (!rev) {\n                for (int c = 0; c < N; c++) order.push_back(r * N + c);\n            } else {\n                for (int c = N - 1; c >= 0; c--) order.push_back(r * N + c);\n            }\n        }\n\n        // Fix left N-3 columns of the bottom 3 rows.\n        for (int c = 0; c < N - 3; c++) {\n            int a = N - 3, b = N - 2, d = N - 1;\n            vector<int> rows;\n            if (colMode == 0) rows = {a, b, d};\n            else if (colMode == 1) rows = {d, b, a};\n            else if (colMode == 2) rows = {a, d, b};\n            else rows = {b, a, d};\n\n            for (int r : rows) order.push_back(r * N + c);\n        }\n\n        for (int q : order) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                return {ops, false};\n            }\n            if (!placeTile(q)) {\n                return {ops, false};\n            }\n        }\n\n        bool reached = solveFinalBlock(targetFull);\n        return {ops, reached};\n    }\n};\n\nSolveResult solveTargetBoard(const vector<int>& target, int variant, bool targetFull,\n                             mt19937& rng, Timer& timer, double limit, int cap) {\n    SlidingSolver solver(target, variant, rng, timer, limit, cap);\n    return solver.run(targetFull);\n}\n\nvoid greedyImprove(BestAns& best, double endTime, Timer& timer, mt19937& rng) {\n    while (timer.elapsed() < endTime) {\n        vector<int> bd = initBoard;\n        int blank = initBlank;\n        string mv;\n        int last = -1;\n\n        for (int step = 0; step < T && timer.elapsed() < endTime; step++) {\n            vector<int> opts;\n            for (int d = 0; d < 4; d++) {\n                if (nbCell[blank][d] >= 0 && d != (last == -1 ? -1 : OPP[last])) {\n                    opts.push_back(d);\n                }\n            }\n            if (opts.empty()) {\n                for (int d = 0; d < 4; d++) if (nbCell[blank][d] >= 0) opts.push_back(d);\n            }\n\n            int bestD = opts[0];\n            double bestKey = -1e100;\n            Eval bestEval{0,0};\n\n            for (int d : opts) {\n                int oldBlank = blank;\n                int nb = nbCell[blank][d];\n                swap(bd[blank], bd[nb]);\n                blank = nb;\n\n                Eval e = evalBoard(bd);\n                int val = e.S * 1000 + e.edges;\n                double temp = 30.0 * (1.0 - (double)step / T) + 2.0;\n                double noise = ((rng() + 0.5) * (1.0 / 4294967296.0)) * temp * 20.0;\n                double key = val + noise;\n\n                if (key > bestKey) {\n                    bestKey = key;\n                    bestD = d;\n                    bestEval = e;\n                }\n\n                swap(bd[oldBlank], bd[blank]);\n                blank = oldBlank;\n            }\n\n            applyDir(bd, blank, bestD);\n            mv.push_back(DCH[bestD]);\n            last = bestD;\n\n            if (bestEval.S >= best.S || (step & 7) == 0) {\n                updateBestKnownBoard(best, mv, bd);\n            }\n        }\n        updateBestKnownBoard(best, mv, bd);\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n    NN = N * N;\n    M = NN - 1;\n    initBoard.assign(NN, 0);\n    memset(targetCntArr, 0, sizeof(targetCntArr));\n\n    for (int r = 0; r < N; r++) {\n        string s;\n        cin >> s;\n        for (int c = 0; c < N; c++) {\n            int v = hexVal(s[c]);\n            int id = r * N + c;\n            initBoard[id] = v;\n            if (v == 0) initBlank = id;\n            else targetCntArr[v]++;\n        }\n    }\n\n    for (int id = 0; id < NN; id++) {\n        int r = id / N, c = id % N;\n        for (int d = 0; d < 4; d++) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) nbCell[id][d] = -1;\n            else nbCell[id][d] = nr * N + nc;\n        }\n    }\n\n    Timer timer;\n\n    uint64_t seed = 88172645463393265ULL;\n    for (int x : initBoard) seed = seed * 1315423911ULL + x + 1;\n    seed += N * 1000003ULL;\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n    BestAns best;\n    updateBest(best, \"\");\n    if (best.S == M) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    // Blank candidates are restricted to the final 3x3 block.\n    int br = (N - 1) * N + (N - 1);\n    blankChoices.push_back(br);\n    vector<int> others;\n    for (int r = N - 3; r < N; r++) {\n        for (int c = N - 3; c < N; c++) {\n            int id = r * N + c;\n            if (id != br) others.push_back(id);\n        }\n    }\n    sort(others.begin(), others.end(), [&](int a, int b) {\n        int ar = a / N, ac = a % N;\n        int br2 = b / N, bc = b % N;\n        int da = abs(ar - initBlank / N) + abs(ac - initBlank % N);\n        int db = abs(br2 - initBlank / N) + abs(bc - initBlank % N);\n        return da < db;\n    });\n    for (int x : others) blankChoices.push_back(x);\n\n    vector<Candidate> candidates;\n    vector<int> bestApproxBoard;\n    int bestApproxDiff = INT_MAX;\n    int bestApproxBit = INT_MAX;\n    int restartCounter = 0;\n\n    runTreeSearch(1.85, timer, rng, candidates, bestApproxBoard, bestApproxDiff, bestApproxBit, restartCounter);\n\n    int fullCand = 0;\n    for (auto& c : candidates) if (c.expectedS == M) fullCand++;\n\n    if (fullCand == 0 && timer.elapsed() < 2.35) {\n        runTreeSearch(2.35, timer, rng, candidates, bestApproxBoard, bestApproxDiff, bestApproxBit, restartCounter);\n    } else if (fullCand < 4 && timer.elapsed() < 2.10) {\n        runTreeSearch(2.10, timer, rng, candidates, bestApproxBoard, bestApproxDiff, bestApproxBit, restartCounter);\n    }\n\n    if (!bestApproxBoard.empty()) {\n        vector<int> adj = adjustCountsToTarget(bestApproxBoard);\n        addCandidate(candidates, adj, bestApproxBit + bestApproxDiff * 100);\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n        bool af = a.expectedS == M;\n        bool bf = b.expectedS == M;\n        if (af != bf) return af > bf;\n        if (a.expectedS != b.expectedS) return a.expectedS > b.expectedS;\n        return a.estCost < b.estCost;\n    });\n\n    int candLimit = min((int)candidates.size(), 18);\n    for (int ci = 0; ci < candLimit && timer.elapsed() < 2.80; ci++) {\n        int varMax;\n        if (ci < 3) varMax = 12;\n        else if (ci < 8) varMax = 6;\n        else varMax = 3;\n\n        bool targetFull = candidates[ci].expectedS == M;\n        for (int v = 0; v < varMax && timer.elapsed() < 2.80; v++) {\n            SolveResult res = solveTargetBoard(\n                candidates[ci].board,\n                v,\n                targetFull,\n                rng,\n                timer,\n                2.82,\n                T + 200\n            );\n            updateBest(best, res.moves);\n        }\n    }\n\n    if (best.score < 500000 && timer.elapsed() < 2.83) {\n        greedyImprove(best, 2.84, timer, rng);\n    }\n\n    if ((int)best.moves.size() > T) best.moves.resize(T);\n    cout << best.moves << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint N, K_input, MAX_CUTS;\nint targetA[11];\nvector<int> Xs, Ys;\nint M_attendees;\n\nchrono::steady_clock::time_point START_TIME;\nconst double STOP_START_TIME = 2.50;\nconst double HARD_TIME_LIMIT = 2.80;\n\ndouble elapsed_time() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t state = 1;\n    uint64_t next() {\n        uint64_t z = (state += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) {\n        if (l > r) swap(l, r);\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\nRNG rng;\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key& o) const {\n        return lo == o.lo && hi == o.hi;\n    }\n};\n\nstruct KeyHash {\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    size_t operator()(const Key& k) const {\n        return (size_t)(splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1));\n    }\n};\n\nstruct Proj {\n    ll s;\n    int idx;\n    bool operator<(const Proj& o) const {\n        if (s != o.s) return s < o.s;\n        return idx < o.idx;\n    }\n};\n\nstruct Line {\n    ll A, B, C;       // A*x + B*y = C\n    vector<Proj> ord;\n};\n\nstruct LineOut {\n    ll A, B, C;\n};\n\nvector<LineOut> bestLines;\nint bestScore = -1;\nll bestValue = LLONG_MIN;\n\ninline bool getBit(const Key& k, int j) {\n    if (j < 64) return (k.lo >> j) & 1ULL;\n    return (k.hi >> (j - 64)) & 1ULL;\n}\n\ninline void flipBit(Key& k, int j) {\n    if (j < 64) k.lo ^= (1ULL << j);\n    else k.hi ^= (1ULL << (j - 64));\n}\n\nvector<Proj> computeOrder(ll A, ll B) {\n    vector<Proj> ord;\n    ord.reserve(N);\n    for (int i = 0; i < N; i++) {\n        ll s = A * (ll)Xs[i] + B * (ll)Ys[i];\n        ord.push_back({s, i});\n    }\n    sort(ord.begin(), ord.end());\n    return ord;\n}\n\nll thresholdAtRank(const vector<Proj>& ord, int rank) {\n    int n = (int)ord.size();\n    if (rank <= 0) return ord[0].s - 1;\n    if (rank >= n) return ord[n - 1].s + 1;\n\n    for (int d = 0; d <= n; d++) {\n        int b = rank - d;\n        if (0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n        b = rank + d;\n        if (d != 0 && 0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n    }\n    return (rank < n / 2 ? ord[0].s - 1 : ord[n - 1].s + 1);\n}\n\npair<ll,ll> primitive(ll A, ll B) {\n    if (A == 0 && B == 0) return {1, 0};\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) g = 1;\n    A /= g;\n    B /= g;\n    return {A, B};\n}\n\npair<ll,ll> normalFromAngle(long double theta) {\n    static const long double PI = acosl(-1.0L);\n    theta = fmodl(theta, PI);\n    if (theta < 0) theta += PI;\n\n    const long double S = 1000000.0L;\n    ll A = llround(cosl(theta) * S);\n    ll B = llround(sinl(theta) * S);\n    if (A == 0 && B == 0) A = 1;\n    return primitive(A, B);\n}\n\nlong long cellCountFormula(const vector<int>& c) {\n    long long cells = 1;\n    int sum = 0;\n    for (int x : c) sum += x;\n    cells += sum;\n    for (int i = 0; i < (int)c.size(); i++) {\n        for (int j = i + 1; j < (int)c.size(); j++) {\n            cells += 1LL * c[i] * c[j];\n        }\n    }\n    return cells;\n}\n\nvector<int> bestCounts(int G, int T) {\n    vector<int> best(G, 0), cur(G, 0);\n    long long bestCost = LLONG_MAX;\n\n    auto eval = [&]() {\n        int sum = 0, mn = 1e9, mx = -1;\n        for (int x : cur) {\n            sum += x;\n            mn = min(mn, x);\n            mx = max(mx, x);\n        }\n        if (sum > MAX_CUTS) return;\n        long long cells = cellCountFormula(cur);\n        long long diff = llabs(cells - T);\n        long long cost = diff * 100000LL + (cells < T ? 1000LL : 0LL)\n                       + (mx - mn) * 100LL + sum;\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = cur;\n        }\n    };\n\n    if (G == 2) {\n        for (int a = 0; a <= MAX_CUTS; a++) {\n            for (int b = 0; a + b <= MAX_CUTS; b++) {\n                cur[0] = a;\n                cur[1] = b;\n                eval();\n            }\n        }\n        return best;\n    }\n\n    if (G <= 4) {\n        long double denom = max(1, G * (G - 1));\n        int base = (int)round(sqrt((2.0L * T) / denom));\n        int R = (G == 4 ? 10 : 12);\n        int lo = max(0, base - R);\n        int hi = min(MAX_CUTS, base + R);\n\n        function<void(int,int)> dfs = [&](int pos, int sum) {\n            if (pos == G) {\n                eval();\n                return;\n            }\n            for (int v = lo; v <= hi; v++) {\n                if (sum + v <= MAX_CUTS) {\n                    cur[pos] = v;\n                    dfs(pos + 1, sum + v);\n                }\n            }\n        };\n        dfs(0, 0);\n    } else {\n        // For many direction classes, balanced counts are usually good.\n        for (int sum = 0; sum <= MAX_CUTS; sum++) {\n            int q = sum / G;\n            int r = sum % G;\n            for (int i = 0; i < G; i++) cur[i] = q + (i < r);\n            eval();\n        }\n    }\n\n    if (bestCost == LLONG_MAX) {\n        int v = min(MAX_CUTS / G, 1);\n        fill(best.begin(), best.end(), v);\n    }\n    return best;\n}\n\nvector<Line> makeGroup(int G, const vector<int>& counts, long double baseAngle, int initMode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n\n    for (int g = 0; g < G; g++) {\n        int m = counts[g];\n        if (m <= 0) continue;\n\n        auto [A, B] = normalFromAngle(baseAngle + PI * g / G);\n        vector<Proj> ord = computeOrder(A, B);\n\n        vector<int> ranks;\n        ranks.reserve(m);\n\n        if (initMode == 0) {\n            for (int t = 1; t <= m; t++) {\n                ranks.push_back((int)((long long)t * N / (m + 1)));\n            }\n        } else if (initMode == 1) {\n            int low = N / 20;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            for (int t = 0; t < m; t++) ranks.push_back(rng.nextInt(low, high));\n            sort(ranks.begin(), ranks.end());\n        } else {\n            for (int t = 1; t <= m; t++) {\n                long double u = (long double)t + (rng.nextDouble() - 0.5L) * 0.9L;\n                int rank = (int)llround(u * N / (m + 1));\n                rank = max(0, min(N, rank));\n                ranks.push_back(rank);\n            }\n            sort(ranks.begin(), ranks.end());\n        }\n\n        for (int rank : ranks) {\n            Line L;\n            L.A = A;\n            L.B = B;\n            L.ord = ord;\n            L.C = thresholdAtRank(L.ord, rank);\n            res.push_back(std::move(L));\n        }\n    }\n\n    if ((int)res.size() > MAX_CUTS) res.resize(MAX_CUTS);\n    return res;\n}\n\nint kForCells(int T) {\n    for (int k = 0; k <= MAX_CUTS; k++) {\n        if (1LL + 1LL * k * (k + 1) / 2 >= T) return k;\n    }\n    return MAX_CUTS;\n}\n\nvector<Line> makeGeneral(int k, int mode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n    res.reserve(k);\n\n    long double base = (k > 0 ? rng.nextDouble() * PI / k : 0);\n\n    for (int i = 0; i < k; i++) {\n        long double theta;\n        if (mode == 0) {\n            theta = base + ((long double)i + 0.5L + (rng.nextDouble() - 0.5L) * 0.8L) * PI / k;\n        } else {\n            theta = rng.nextDouble() * PI;\n        }\n\n        auto [A, B] = normalFromAngle(theta);\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n\n        int low = N / 20;\n        int high = N - low;\n        if (low > high) {\n            low = 0;\n            high = N;\n        }\n        int rank = rng.nextInt(low, high);\n        L.C = thresholdAtRank(L.ord, rank);\n\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nstruct Config {\n    int k;\n    vector<Line> lines;\n    vector<Key> pat;\n    unordered_map<Key, int, KeyHash> mp;\n    int hist[11];\n    int overStraw = 0;\n\n    Config(vector<Line>&& ls) : k((int)ls.size()), lines(std::move(ls)), pat(N) {\n        memset(hist, 0, sizeof(hist));\n    }\n\n    inline void removeEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]--;\n        else if (c > 10) overStraw -= c;\n    }\n\n    inline void addEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]++;\n        else if (c > 10) overStraw += c;\n    }\n\n    void build() {\n        mp.clear();\n        mp.reserve(N * 4 + 100);\n        mp.max_load_factor(0.7);\n        memset(hist, 0, sizeof(hist));\n        overStraw = 0;\n\n        for (int i = 0; i < N; i++) {\n            Key key{0, 0};\n            for (int j = 0; j < k; j++) {\n                ll s = lines[j].A * (ll)Xs[i] + lines[j].B * (ll)Ys[i];\n                if (s > lines[j].C) {\n                    if (j < 64) key.lo |= (1ULL << j);\n                    else key.hi |= (1ULL << (j - 64));\n                }\n            }\n            pat[i] = key;\n            mp[key]++;\n        }\n\n        for (auto& kv : mp) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) hist[c]++;\n            else if (c > 10) overStraw += c;\n        }\n    }\n\n    void decKey(const Key& key) {\n        auto it = mp.find(key);\n        int old = it->second;\n        removeEffect(old);\n        int nw = old - 1;\n        addEffect(nw);\n        if (nw == 0) mp.erase(it);\n        else it->second = nw;\n    }\n\n    void incKey(const Key& key) {\n        auto it = mp.find(key);\n        if (it == mp.end()) {\n            addEffect(1);\n            mp.emplace(key, 1);\n        } else {\n            int old = it->second;\n            removeEffect(old);\n            int nw = old + 1;\n            addEffect(nw);\n            it->second = nw;\n        }\n    }\n\n    inline void flipPoint(int idx, int j) {\n        Key old = pat[idx];\n        Key nw = old;\n        flipBit(nw, j);\n        decKey(old);\n        incKey(nw);\n        pat[idx] = nw;\n    }\n\n    int score() const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], hist[d]);\n        return sc;\n    }\n\n    int surplus() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (hist[d] > targetA[d]) s += hist[d] - targetA[d];\n        }\n        return s;\n    }\n\n    ll value() const {\n        const ll SCORE_W = 1000000000000LL;\n        const ll OVER_W = 5000LL;\n        const ll SURPLUS_W = 10000LL;\n        return (ll)score() * SCORE_W - (ll)overStraw * OVER_W - (ll)surplus() * SURPLUS_W;\n    }\n\n    int rankForC(int j) const {\n        const auto& ord = lines[j].ord;\n        int l = 0, r = N;\n        ll C = lines[j].C;\n        while (l < r) {\n            int m = (l + r) >> 1;\n            if (ord[m].s <= C) l = m + 1;\n            else r = m;\n        }\n        return l;\n    }\n\n    void sweepLine(int j) {\n        const auto& ord = lines[j].ord;\n\n        ll origVal = value();\n        int bestIdx = rankForC(j);\n        ll bestC = lines[j].C;\n        ll bestVal = origVal;\n\n        for (int i = 0; i < N; i++) {\n            if (!getBit(pat[i], j)) flipPoint(i, j);\n        }\n\n        ll valAll = value();\n        if (valAll > bestVal) {\n            bestVal = valAll;\n            bestIdx = 0;\n            bestC = ord[0].s - 1;\n        }\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = ord[idx].s;\n            while (idx < N && ord[idx].s == v) {\n                flipPoint(ord[idx].idx, j);\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = ord[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = value();\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestIdx = idx;\n                    bestC = candC;\n                }\n            }\n        }\n\n        // currently all bits of line j are 0\n        for (int t = bestIdx; t < N; t++) {\n            flipPoint(ord[t].idx, j);\n        }\n        lines[j].C = bestC;\n    }\n\n    void optimize(int passes) {\n        if (k == 0) return;\n        vector<int> order(k);\n        iota(order.begin(), order.end(), 0);\n\n        for (int p = 0; p < passes; p++) {\n            for (int i = k - 1; i > 0; i--) {\n                int j = rng.nextInt(0, i);\n                swap(order[i], order[j]);\n            }\n\n            ll before = value();\n\n            for (int t = 0; t < k; t++) {\n                sweepLine(order[t]);\n                if ((t & 7) == 0 && elapsed_time() > HARD_TIME_LIMIT) return;\n            }\n\n            if (value() <= before) break;\n        }\n    }\n\n    void replaceLineAllZero(int j, Line&& L) {\n        for (int i = 0; i < N; i++) {\n            if (getBit(pat[i], j)) flipPoint(i, j);\n        }\n        lines[j] = std::move(L);\n    }\n\n    long double lineTheta(int j) const {\n        static const long double PI = acosl(-1.0L);\n        long double th = atan2l((long double)lines[j].B, (long double)lines[j].A);\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    long double targetedTheta() const {\n        static const long double PI = acosl(-1.0L);\n\n        for (int attempt = 0; attempt < 8; attempt++) {\n            int i = rng.nextInt(0, N - 1);\n            auto it = mp.find(pat[i]);\n            if (it == mp.end()) continue;\n            int c = it->second;\n            if (c <= 1) continue;\n            if (c <= 10 && rng.nextDouble() < 0.75) continue;\n\n            Key key = pat[i];\n            int chosen = -1;\n            int seen = 0;\n            for (int r = 0; r < N; r++) {\n                if (r != i && pat[r] == key) {\n                    seen++;\n                    if (rng.nextInt(1, seen) == 1) chosen = r;\n                }\n            }\n            if (chosen >= 0) {\n                long double dx = (long double)Xs[i] - Xs[chosen];\n                long double dy = (long double)Ys[i] - Ys[chosen];\n                if (dx != 0 || dy != 0) {\n                    long double th = atan2l(dy, dx);\n                    th += (rng.nextDouble() - 0.5L) * 0.20L;\n                    th = fmodl(th, PI);\n                    if (th < 0) th += PI;\n                    return th;\n                }\n            }\n        }\n\n        return rng.nextDouble() * PI;\n    }\n\n    bool tryReplaceLineTheta(int j, long double theta) {\n        if (elapsed_time() > HARD_TIME_LIMIT - 0.02) return false;\n\n        auto [A, B] = normalFromAngle(theta);\n        if (A == lines[j].A && B == lines[j].B) return false;\n\n        ll oldVal = value();\n\n        vector<Key> oldPat = pat;\n        auto oldMp = mp;\n        int oldHist[11];\n        memcpy(oldHist, hist, sizeof(hist));\n        int oldOver = overStraw;\n        Line oldLine = lines[j];\n\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n        L.C = L.ord.back().s + 1; // initially no effect\n\n        replaceLineAllZero(j, std::move(L));\n        sweepLine(j);\n\n        if (value() > oldVal) {\n            return true;\n        }\n\n        pat = std::move(oldPat);\n        mp = std::move(oldMp);\n        memcpy(hist, oldHist, sizeof(hist));\n        overStraw = oldOver;\n        lines[j] = std::move(oldLine);\n        return false;\n    }\n\n    bool tryAddLineTheta(long double theta) {\n        if (k >= MAX_CUTS) return false;\n        if (elapsed_time() > HARD_TIME_LIMIT - 0.02) return false;\n\n        auto [A, B] = normalFromAngle(theta);\n        ll oldVal = value();\n\n        vector<Key> oldPat = pat;\n        auto oldMp = mp;\n        int oldHist[11];\n        memcpy(oldHist, hist, sizeof(hist));\n        int oldOver = overStraw;\n        int oldK = k;\n\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n        L.C = L.ord.back().s + 1; // all points are on the 0-side\n\n        lines.push_back(std::move(L));\n        k++;\n\n        sweepLine(k - 1);\n\n        if (value() > oldVal) {\n            return true;\n        }\n\n        pat = std::move(oldPat);\n        mp = std::move(oldMp);\n        memcpy(hist, oldHist, sizeof(hist));\n        overStraw = oldOver;\n        k = oldK;\n        lines.resize(oldK);\n        return false;\n    }\n\n    int addLineSearch(int trials, int maxAccept) {\n        static const long double PI = acosl(-1.0L);\n        int acc = 0;\n        for (int t = 0; t < trials && acc < maxAccept && k < MAX_CUTS; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n            long double theta;\n            if (rng.nextDouble() < 0.65) theta = targetedTheta();\n            else theta = rng.nextDouble() * PI;\n\n            if (tryAddLineTheta(theta)) acc++;\n        }\n        return acc;\n    }\n\n    int angleOptimize(int trials) {\n        static const long double PI = acosl(-1.0L);\n        if (k == 0) return 0;\n        int acc = 0;\n\n        for (int t = 0; t < trials; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n\n            int j = rng.nextInt(0, k - 1);\n            long double theta;\n            double r = rng.nextDouble();\n\n            if (r < 0.50) {\n                long double scale = 0.04L + 0.30L * rng.nextDouble();\n                theta = lineTheta(j) + (rng.nextDouble() * 2.0L - 1.0L) * scale;\n            } else if (r < 0.78) {\n                theta = targetedTheta();\n            } else {\n                theta = rng.nextDouble() * PI;\n            }\n\n            if (tryReplaceLineTheta(j, theta)) acc++;\n        }\n\n        return acc;\n    }\n};\n\nvoid updateBest(const Config& cfg) {\n    int sc = cfg.score();\n    ll val = cfg.value();\n    if (sc > bestScore || (sc == bestScore && val > bestValue)) {\n        bestScore = sc;\n        bestValue = val;\n        bestLines.clear();\n        for (const auto& L : cfg.lines) {\n            bestLines.push_back({L.A, L.B, L.C});\n        }\n    }\n}\n\nvoid runCandidate(vector<Line> lines, int passes) {\n    if ((int)lines.size() > MAX_CUTS) lines.resize(MAX_CUTS);\n    if (elapsed_time() > STOP_START_TIME) return;\n\n    Config cfg(std::move(lines));\n    cfg.build();\n    cfg.optimize(passes);\n    updateBest(cfg);\n}\n\nvector<Line> rebuildLinesFromOut(const vector<LineOut>& outs) {\n    vector<Line> res;\n    res.reserve(outs.size());\n    for (auto O : outs) {\n        Line L;\n        L.A = O.A;\n        L.B = O.B;\n        L.C = O.C;\n        L.ord = computeOrder(L.A, L.B);\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nvoid finalPolish() {\n    if (bestLines.empty()) return;\n    if (elapsed_time() > HARD_TIME_LIMIT - 0.08) return;\n\n    auto ls = rebuildLinesFromOut(bestLines);\n    Config cfg(std::move(ls));\n    cfg.build();\n\n    cfg.optimize(5);\n    updateBest(cfg);\n\n    int loops = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.04 && cfg.score() < M_attendees) {\n        cfg.addLineSearch(12, 3);\n        cfg.angleOptimize(14);\n        cfg.optimize(1);\n        updateBest(cfg);\n        loops++;\n        if (loops > 50) break;\n    }\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = 1;\n        y = 0;\n        return a;\n    }\n    ll x1, y1;\n    ll g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<ll,4> fallbackLine() {\n    return {1000000000LL, 1000000000LL, 999999999LL, 1000000000LL};\n}\n\narray<ll,4> endpoints(LineOut L) {\n    ll A = L.A, B = L.B, C = L.C;\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) return fallbackLine();\n    if (C % g != 0) return fallbackLine();\n    A /= g;\n    B /= g;\n    C /= g;\n\n    auto inside = [](ll v) {\n        return -1000000000LL <= v && v <= 1000000000LL;\n    };\n\n    if (B == 0) {\n        if (A == 0 || C % A != 0) return fallbackLine();\n        ll x = C / A;\n        if (!inside(x)) return fallbackLine();\n        return {x, 0, x, 1};\n    }\n    if (A == 0) {\n        if (B == 0 || C % B != 0) return fallbackLine();\n        ll y = C / B;\n        if (!inside(y)) return fallbackLine();\n        return {0, y, 1, y};\n    }\n\n    ll xg, yg;\n    extgcd(llabs(A), llabs(B), xg, yg);\n\n    __int128 x0 = (__int128)xg * (A >= 0 ? 1 : -1) * C;\n    __int128 y0 = (__int128)yg * (B >= 0 ? 1 : -1) * C;\n\n    ll dx = B;\n    ll dy = -A;\n\n    long double dot = (long double)x0 * (long double)dx + (long double)y0 * (long double)dy;\n    long double den = (long double)dx * dx + (long double)dy * dy;\n    ll t0 = llround(-dot / den);\n\n    __int128 bestNorm = -1;\n    __int128 bx = x0, by = y0;\n\n    for (ll dt = -6; dt <= 6; dt++) {\n        ll t = t0 + dt;\n        __int128 x = x0 + (__int128)dx * t;\n        __int128 y = y0 + (__int128)dy * t;\n        __int128 norm = x * x + y * y;\n        if (bestNorm < 0 || norm < bestNorm) {\n            bestNorm = norm;\n            bx = x;\n            by = y;\n        }\n    }\n\n    __int128 qx = bx + dx;\n    __int128 qy = by + dy;\n\n    if (bx < -1000000000LL || bx > 1000000000LL ||\n        by < -1000000000LL || by > 1000000000LL ||\n        qx < -1000000000LL || qx > 1000000000LL ||\n        qy < -1000000000LL || qy > 1000000000LL) {\n        return fallbackLine();\n    }\n\n    ll px = (ll)bx, py = (ll)by;\n    ll rx = (ll)qx, ry = (ll)qy;\n    if (px == rx && py == ry) return fallbackLine();\n    return {px, py, rx, ry};\n}\n\nLineOut canonical(LineOut L) {\n    ll g = std::gcd(llabs(L.A), llabs(L.B));\n    if (g > 0 && L.C % g == 0) {\n        L.A /= g;\n        L.B /= g;\n        L.C /= g;\n    }\n    if (L.A < 0 || (L.A == 0 && L.B < 0)) {\n        L.A = -L.A;\n        L.B = -L.B;\n        L.C = -L.C;\n    }\n    return L;\n}\n\ndouble clampd(double x, double l, double r) {\n    return max(l, min(r, x));\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K_input;\n    MAX_CUTS = min(K_input, 100);\n\n    M_attendees = 0;\n    for (int d = 1; d <= 10; d++) {\n        cin >> targetA[d];\n        M_attendees += targetA[d];\n    }\n\n    Xs.resize(N);\n    Ys.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xs[i] >> Ys[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    auto mixSeed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed(N);\n    mixSeed(K_input);\n    for (int d = 1; d <= 10; d++) mixSeed(targetA[d]);\n    for (int i = 0; i < N; i++) {\n        mixSeed((uint64_t)(Xs[i] + 20000) * 40009ULL + (uint64_t)(Ys[i] + 20000));\n    }\n    rng.state = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    double avgD = (double)N / max(1, M_attendees);\n    double smallRatio = (targetA[1] + targetA[2] + targetA[3]) / (double)M_attendees;\n    double largeRatio = (targetA[8] + targetA[9] + targetA[10]) / (double)M_attendees;\n\n    double centerFactor = 1.25 + 0.95 * (smallRatio - largeRatio) + 0.10 * (5.5 - avgD);\n    centerFactor = clampd(centerFactor, 0.70, 2.05);\n\n    auto normFactor = [&](double f) {\n        return clampd(f, 0.55, 2.60);\n    };\n\n    auto tryGroup = [&](int G, double factor, int initMode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        auto counts = bestCounts(G, T);\n        long double PI = acosl(-1.0L);\n        long double base = rng.nextDouble() * PI / G;\n        auto lines = makeGroup(G, counts, base, initMode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    auto tryGeneral = [&](double factor, int mode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        int k = kForCells(T);\n        auto lines = makeGeneral(k, mode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    // Deterministic diversified first wave.\n    tryGroup(2, centerFactor, 0, 4);\n    tryGroup(3, centerFactor, 0, 4);\n    tryGroup(4, centerFactor, 0, 3);\n    tryGroup(5, centerFactor, 0, 3);\n    tryGeneral(centerFactor, 0, 3);\n\n    tryGroup(2, centerFactor * 1.28, 2, 3);\n    tryGroup(3, centerFactor * 0.88, 2, 3);\n    tryGroup(4, centerFactor * 1.18, 2, 3);\n    tryGroup(6, centerFactor * 1.05, 0, 3);\n    tryGeneral(centerFactor * 1.28, 1, 3);\n\n    int iter = 0;\n    while (elapsed_time() < STOP_START_TIME) {\n        int typ = iter % 6;\n\n        double mult;\n        if (rng.nextDouble() < 0.15) {\n            mult = 0.50 + 2.00 * rng.nextDouble();\n        } else {\n            mult = 0.65 + 1.10 * rng.nextDouble();\n        }\n        double factor = normFactor(centerFactor * mult);\n        int initMode = rng.nextInt(0, 2);\n\n        if (typ == 0) tryGroup(2, factor, initMode, 2);\n        else if (typ == 1) tryGroup(3, factor, initMode, 2);\n        else if (typ == 2) tryGroup(4, factor, initMode, 2);\n        else if (typ == 3) tryGroup(5, factor, initMode, 2);\n        else if (typ == 4) tryGroup(6, factor, initMode, 2);\n        else tryGeneral(factor, rng.nextInt(0, 1), 2);\n\n        iter++;\n    }\n\n    finalPolish();\n\n    vector<LineOut> outputLines;\n    vector<LineOut> seen;\n    for (auto L : bestLines) {\n        LineOut C = canonical(L);\n        bool dup = false;\n        for (auto S : seen) {\n            if (S.A == C.A && S.B == C.B && S.C == C.C) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) {\n            seen.push_back(C);\n            outputLines.push_back(L);\n        }\n        if ((int)outputLines.size() == MAX_CUTS) break;\n    }\n\n    cout << outputLines.size() << '\\n';\n    for (auto L : outputLines) {\n        auto e = endpoints(L);\n        cout << e[0] << ' ' << e[1] << ' ' << e[2] << ' ' << e[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#pragma GCC optimize(\"O3,unroll-loops\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAXN = 61;\nconst int MAXC = MAXN * MAXN;\nconst int MAXTOP = 128;\n\nint N, M, C;\nint PX[MAXC], PY[MAXC];\nint WT[MAXC];\nint maxWeight = 0;\nunsigned char initDot[MAXC];\ndouble priorityVal[MAXC];\nlong long initialSum = 0;\n\nint initMinX, initMaxX, initMinY, initMaxY;\n\nconst int DX[8] = {1, 0, -1, 0, 1, -1, -1, 1};\nconst int DY[8] = {0, 1, 0, -1, 1, 1, -1, -1};\n\n// E,N / N,W / W,S / S,E and NE,NW / NW,SW / SW,SE / SE,NE\nconst int PA[8] = {0, 1, 2, 3, 4, 5, 6, 7};\nconst int PB[8] = {1, 2, 3, 0, 5, 6, 7, 4};\n\ninline int pid(int x, int y) {\n    return x * N + y;\n}\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y < N;\n}\n\ninline uint64_t rangeMask(int l, int r) {\n    int len = r - l;\n    if (len <= 0) return 0ULL;\n    return ((1ULL << len) - 1ULL) << l;\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = splitmix64(seed);\n        if (x == 0) x = 88172645463325252ULL;\n    }\n    inline uint64_t next() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n    inline double nextSigned() {\n        return nextDouble() * 2.0 - 1.0;\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 Op {\n    int p1, p2, p3, p4;\n};\n\nstruct Candidate {\n    int p1, p2, p3, p4;\n    int lenSum;\n    int area;\n};\n\nstruct Node {\n    double key;\n    Candidate cand;\n};\n\ninline void heapSiftUp(Node h[], int i) {\n    while (i > 0) {\n        int p = (i - 1) >> 1;\n        if (h[p].key <= h[i].key) break;\n        swap(h[p], h[i]);\n        i = p;\n    }\n}\n\ninline void heapSiftDown(Node h[], int n, int i = 0) {\n    while (true) {\n        int l = i * 2 + 1;\n        int r = l + 1;\n        int m = i;\n        if (l < n && h[l].key < h[m].key) m = l;\n        if (r < n && h[r].key < h[m].key) m = r;\n        if (m == i) break;\n        swap(h[i], h[m]);\n        i = m;\n    }\n}\n\ninline void heapPushTop(Node h[], int& n, int K, const Node& nd) {\n    if (n < K) {\n        h[n] = nd;\n        heapSiftUp(h, n);\n        ++n;\n    } else if (nd.key > h[0].key) {\n        h[0] = nd;\n        heapSiftDown(h, n, 0);\n    }\n}\n\nstruct Params {\n    double wcoef;\n    double perim;\n    double area;\n    double outAvg;\n    double outOpp;\n    double frontier;\n    int topK;\n    double rankPower;\n    double noise;\n};\n\nstruct State {\n    unsigned char dot[MAXC];\n    int nearestDot[8][MAXC];\n\n    uint64_t H[MAXN], V[MAXN], DPm[2 * MAXN], DMm[2 * MAXN];\n\n    vector<Op> ops;\n    long long sumW = 0;\n    bool dirtyNearest = true;\n\n    int minX, maxX, minY, maxY;\n\n    void reset() {\n        memcpy(dot, initDot, C * sizeof(unsigned char));\n        fill(H, H + MAXN, 0ULL);\n        fill(V, V + MAXN, 0ULL);\n        fill(DPm, DPm + 2 * MAXN, 0ULL);\n        fill(DMm, DMm + 2 * MAXN, 0ULL);\n        ops.clear();\n        sumW = initialSum;\n        dirtyNearest = true;\n\n        minX = initMinX;\n        maxX = initMaxX;\n        minY = initMinY;\n        maxY = initMaxY;\n    }\n\n    void buildNearest() {\n        for (int d = 0; d < 8; ++d) {\n            int dx = DX[d], dy = DY[d];\n            for (int sx = 0; sx < N; ++sx) {\n                for (int sy = 0; sy < N; ++sy) {\n                    int nx = sx + dx;\n                    int ny = sy + dy;\n                    if (inside(nx, ny)) continue;\n\n                    int cur = -1;\n                    int x = sx, y = sy;\n                    while (inside(x, y)) {\n                        int p = pid(x, y);\n                        nearestDot[d][p] = cur;\n                        if (dot[p]) cur = p;\n                        x -= dx;\n                        y -= dy;\n                    }\n                }\n            }\n        }\n        dirtyNearest = false;\n    }\n\n    void updateNearestAfterAdd(int p) {\n        for (int d = 0; d < 8; ++d) {\n            int x = PX[p] - DX[d];\n            int y = PY[p] - DY[d];\n            while (inside(x, y)) {\n                int q = pid(x, y);\n                nearestDot[d][q] = p;\n                if (dot[q]) break;\n                x -= DX[d];\n                y -= DY[d];\n            }\n        }\n    }\n\n    bool sideFree(int a, int b) const {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            uint64_t m = rangeMask(y1, y2);\n            return (V[x1] & m) == 0;\n        }\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            uint64_t m = rangeMask(x1, x2);\n            return (H[y1] & m) == 0;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n        if (abs(dx) != abs(dy)) return false;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 - y1 + N - 1;\n            uint64_t m = rangeMask(x1, x2);\n            return (DPm[line] & m) == 0;\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 + y1;\n            uint64_t m = rangeMask(x1, x2);\n            return (DMm[line] & m) == 0;\n        }\n    }\n\n    void markSide(int a, int b) {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            V[x1] |= rangeMask(y1, y2);\n            return;\n        }\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            H[y1] |= rangeMask(x1, x2);\n            return;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 - y1 + N - 1;\n            DPm[line] |= rangeMask(x1, x2);\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n            int line = x1 + y1;\n            DMm[line] |= rangeMask(x1, x2);\n        }\n    }\n\n    void applyOp(const Op& op, bool updateNearest) {\n        markSide(op.p1, op.p2);\n        markSide(op.p2, op.p3);\n        markSide(op.p3, op.p4);\n        markSide(op.p4, op.p1);\n\n        dot[op.p1] = 1;\n        sumW += WT[op.p1];\n        ops.push_back(op);\n\n        int x = PX[op.p1], y = PY[op.p1];\n        if (x < minX) minX = x;\n        if (x > maxX) maxX = x;\n        if (y < minY) minY = y;\n        if (y > maxY) maxY = y;\n\n        if (updateNearest && !dirtyNearest) {\n            updateNearestAfterAdd(op.p1);\n        } else {\n            dirtyNearest = true;\n        }\n    }\n\n    inline bool canReplay(const Op& op) const {\n        return !dot[op.p1] && dot[op.p2] && dot[op.p3] && dot[op.p4];\n    }\n\n    bool chooseCandidate(const Params& par, RNG& rng, Candidate& res) {\n        if (dirtyNearest) buildNearest();\n\n        int K = par.topK;\n        if (K < 1) K = 1;\n        if (K > MAXTOP) K = MAXTOP;\n\n        bool found = false;\n        double bestKey = -1e100;\n        int bestLen = INT_MAX;\n        Candidate bestCand{};\n\n        Node heap[MAXTOP];\n        int hsz = 0;\n\n        for (int p1 = 0; p1 < C; ++p1) {\n            if (dot[p1]) continue;\n\n            int x1 = PX[p1];\n            int y1 = PY[p1];\n\n            int ext = 0;\n            if (x1 < minX) ext += minX - x1;\n            else if (x1 > maxX) ext += x1 - maxX;\n            if (y1 < minY) ext += minY - y1;\n            else if (y1 > maxY) ext += y1 - maxY;\n\n            for (int t = 0; t < 8; ++t) {\n                int d1 = PA[t];\n                int d2 = PB[t];\n\n                int p2 = nearestDot[d1][p1];\n                if (p2 < 0) continue;\n\n                int p4 = nearestDot[d2][p1];\n                if (p4 < 0) continue;\n\n                int x3 = PX[p2] + PX[p4] - x1;\n                int y3 = PY[p2] + PY[p4] - y1;\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n\n                int p3 = pid(x3, y3);\n                if (!dot[p3]) continue;\n\n                if (nearestDot[d2][p2] != p3) continue;\n                if (nearestDot[d1][p4] != p3) continue;\n\n                if (!sideFree(p1, p2)) continue;\n                if (!sideFree(p2, p3)) continue;\n                if (!sideFree(p3, p4)) continue;\n                if (!sideFree(p4, p1)) continue;\n\n                int len1 = max(abs(PX[p2] - x1), abs(PY[p2] - y1));\n                int len2 = max(abs(PX[p4] - x1), abs(PY[p4] - y1));\n                int lenSum = len1 + len2;\n                int area = len1 * len2;\n\n                double avgOther = (WT[p2] + WT[p3] + WT[p4]) / 3.0;\n\n                double key =\n                    priorityVal[p1]\n                    + par.outAvg * (WT[p1] - avgOther)\n                    + par.outOpp * (WT[p1] - WT[p3])\n                    + par.frontier * ext\n                    - par.perim * lenSum\n                    - par.area * area;\n\n                Candidate cand{p1, p2, p3, p4, lenSum, area};\n\n                if (K == 1) {\n                    if (!found || key > bestKey + 1e-12 ||\n                        (fabs(key - bestKey) <= 1e-12 && lenSum < bestLen)) {\n                        found = true;\n                        bestKey = key;\n                        bestLen = lenSum;\n                        bestCand = cand;\n                    }\n                } else {\n                    Node nd{key, cand};\n                    heapPushTop(heap, hsz, K, nd);\n                }\n            }\n        }\n\n        if (K == 1) {\n            if (!found) return false;\n            res = bestCand;\n            return true;\n        } else {\n            if (hsz == 0) return false;\n\n            sort(heap, heap + hsz, [](const Node& a, const Node& b) {\n                return a.key > b.key;\n            });\n\n            int idx = 0;\n            if (hsz > 1) {\n                if (par.rankPower <= 0.0) {\n                    idx = rng.nextInt(hsz);\n                } else {\n                    double z = pow(rng.nextDouble(), par.rankPower);\n                    idx = (int)(z * hsz);\n                    if (idx >= hsz) idx = hsz - 1;\n                }\n            }\n\n            res = heap[idx].cand;\n            return true;\n        }\n    }\n};\n\nParams randomParam(RNG& rng) {\n    static const double wcoefs[] = {\n        0.0, 0.15, 0.35, 0.65, 0.9, 1.0, 1.0, 1.25, 1.6, 2.1\n    };\n    static const double perims[] = {\n        -1.4, -0.8, -0.4, -0.1, 0.0, 0.4, 0.9, 1.6, 2.7, 4.2, 6.5, 9.0\n    };\n    static const double areas[] = {\n        -0.025, -0.010, -0.003, 0.0, 0.0, 0.006, 0.016, 0.035, 0.070\n    };\n\n    Params p;\n    p.wcoef = wcoefs[rng.nextInt((int)(sizeof(wcoefs) / sizeof(wcoefs[0])))];\n    p.perim = perims[rng.nextInt((int)(sizeof(perims) / sizeof(perims[0])))]\n              + (rng.nextDouble() - 0.5) * 0.45;\n    p.area = areas[rng.nextInt((int)(sizeof(areas) / sizeof(areas[0])))];\n\n    p.outAvg = 0.0;\n    p.outOpp = 0.0;\n    if (rng.nextInt(100) < 60) p.outAvg = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 50) p.outOpp = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 10) p.outOpp += rng.nextDouble() * 1.8;\n\n    p.frontier = 0.0;\n    if (rng.nextInt(100) < 45) p.frontier = rng.nextDouble() * 35.0;\n\n    // Slight adaptation: sparse instances often need larger jumps,\n    // dense instances often benefit from shorter scaffolding moves.\n    if (M < 2 * N && rng.nextInt(100) < 35) {\n        p.perim -= 1.0 + rng.nextDouble() * 2.0;\n        p.area -= rng.nextDouble() * 0.025;\n        p.frontier += rng.nextDouble() * 25.0;\n    }\n    if (M > N * N / 18 && rng.nextInt(100) < 35) {\n        p.perim += rng.nextDouble() * 4.0;\n        p.area += rng.nextDouble() * 0.040;\n        p.wcoef *= 0.7;\n    }\n\n    int r = rng.nextInt(100);\n    if (r < 18) {\n        p.topK = 1;\n    } else if (r < 72) {\n        p.topK = 3 + rng.nextInt(25);\n    } else {\n        p.topK = 30 + rng.nextInt(90);\n    }\n    if (p.topK > MAXTOP) p.topK = MAXTOP;\n\n    if (p.topK == 1) {\n        p.rankPower = 1.0;\n    } else {\n        int q = rng.nextInt(100);\n        if (q < 18) p.rankPower = 1.0;\n        else if (q < 84) p.rankPower = 1.5 + rng.nextDouble() * 3.2;\n        else p.rankPower = 0.45 + rng.nextDouble() * 0.65;\n    }\n\n    if (rng.nextInt(100) < 50) p.noise = rng.nextDouble() * 0.14;\n    else p.noise = rng.nextDouble() * 0.38;\n    if (rng.nextInt(100) < 5) p.noise = rng.nextDouble() * 0.75;\n\n    return p;\n}\n\nvoid preparePriority(const Params& par, RNG& rng) {\n    double amp = par.noise * maxWeight;\n    for (int i = 0; i < C; ++i) {\n        priorityVal[i] = par.wcoef * WT[i];\n        if (amp > 1e-12) priorityVal[i] += amp * rng.nextSigned();\n    }\n}\n\nvoid runGreedy(State& st, const Params& par, RNG& rng, const Timer& timer, double TL) {\n    Candidate cand;\n    while (timer.elapsed() < TL) {\n        if (!st.chooseCandidate(par, rng, cand)) break;\n        Op op{cand.p1, cand.p2, cand.p3, cand.p4};\n        st.applyOp(op, true);\n    }\n}\n\nvoid replayDestroyed(State& st, const vector<Op>& base, RNG& rng) {\n    st.reset();\n\n    int K = (int)base.size();\n    if (K == 0) return;\n\n    int mode = rng.nextInt(100);\n\n    int cut = K;\n    int l = 0, r = 0;\n    int cx = 0, cy = 0, rad2 = 0, rx = 0, ry = 0;\n    bool circle = true;\n    double pdrop = 0.0, extra = 0.0;\n    bool dropLow = true;\n\n    if (mode < 20) {\n        int lim = min(K, 50 + rng.nextInt(950));\n        int drop = 1 + rng.nextInt(lim);\n        cut = K - drop;\n    } else if (mode < 45) {\n        pdrop = 0.01 + pow(rng.nextDouble(), 2.0) * 0.30;\n        if (rng.nextInt(100) < 10) pdrop = 0.30 + rng.nextDouble() * 0.35;\n    } else if (mode < 65) {\n        double frac = 0.02 + 0.55 * rng.nextDouble() * rng.nextDouble();\n        int maxLen = max(1, min(K, 1 + (int)(K * frac)));\n        int len = 1 + rng.nextInt(maxLen);\n        l = rng.nextInt(K - len + 1);\n        r = l + len;\n    } else if (mode < 85) {\n        const Op& op = base[rng.nextInt(K)];\n        cx = PX[op.p1];\n        cy = PY[op.p1];\n        circle = rng.nextInt(2) == 0;\n        if (circle) {\n            int rad = 2 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            rad2 = rad * rad;\n        } else {\n            rx = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            ry = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n        }\n    } else {\n        pdrop = 0.01 + rng.nextDouble() * 0.08;\n        extra = 0.05 + rng.nextDouble() * 0.32;\n        dropLow = rng.nextInt(2) == 0;\n    }\n\n    for (int i = 0; i < K; ++i) {\n        const Op& op = base[i];\n        bool keep = true;\n\n        if (mode < 20) {\n            keep = i < cut;\n        } else if (mode < 45) {\n            keep = rng.nextDouble() >= pdrop;\n        } else if (mode < 65) {\n            keep = !(l <= i && i < r);\n        } else if (mode < 85) {\n            int x = PX[op.p1];\n            int y = PY[op.p1];\n            bool inRegion;\n            if (circle) {\n                int dx = x - cx;\n                int dy = y - cy;\n                inRegion = dx * dx + dy * dy <= rad2;\n            } else {\n                inRegion = abs(x - cx) <= rx && abs(y - cy) <= ry;\n            }\n            keep = !inRegion;\n        } else {\n            double norm = (double)WT[op.p1] / maxWeight;\n            double pd = pdrop + extra * (dropLow ? (1.0 - norm) : norm);\n            if (pd > 0.80) pd = 0.80;\n            keep = rng.nextDouble() >= pd;\n        }\n\n        if (keep && st.canReplay(op)) {\n            st.applyOp(op, false);\n        }\n    }\n}\n\nstruct Solution {\n    long long sum;\n    vector<Op> ops;\n};\n\nvoid considerSolution(\n    const State& st,\n    vector<Solution>& pool,\n    vector<Op>& bestOps,\n    long long& bestSum\n) {\n    if (st.sumW > bestSum) {\n        bestSum = st.sumW;\n        bestOps = st.ops;\n    }\n\n    const int POOL_SIZE = 10;\n\n    if ((int)pool.size() >= POOL_SIZE && st.sumW <= pool.back().sum) return;\n\n    for (const auto& s : pool) {\n        if (s.sum == st.sumW && s.ops.size() == st.ops.size()) return;\n    }\n\n    Solution sol;\n    sol.sum = st.sumW;\n    sol.ops = st.ops;\n    pool.push_back(move(sol));\n\n    sort(pool.begin(), pool.end(), [](const Solution& a, const Solution& b) {\n        if (a.sum != b.sum) return a.sum > b.sum;\n        return a.ops.size() > b.ops.size();\n    });\n\n    if ((int)pool.size() > POOL_SIZE) pool.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    C = N * N;\n\n    fill(initDot, initDot + MAXC, 0);\n\n    int c = N / 2;\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y < N; ++y) {\n            int p = pid(x, y);\n            PX[p] = x;\n            PY[p] = y;\n            int dx = x - c;\n            int dy = y - c;\n            WT[p] = dx * dx + dy * dy + 1;\n            maxWeight = max(maxWeight, WT[p]);\n        }\n    }\n\n    initMinX = N;\n    initMaxX = -1;\n    initMinY = N;\n    initMaxY = -1;\n\n    uint64_t seed = splitmix64(((uint64_t)N << 32) ^ (uint64_t)M);\n\n    for (int i = 0; i < M; ++i) {\n        int x, y;\n        cin >> x >> y;\n        int p = pid(x, y);\n        initDot[p] = 1;\n\n        initMinX = min(initMinX, x);\n        initMaxX = max(initMaxX, x);\n        initMinY = min(initMinY, y);\n        initMaxY = max(initMaxY, y);\n\n        seed ^= splitmix64(((uint64_t)(i + 1) << 40) ^ ((uint64_t)x << 20) ^ (uint64_t)y);\n    }\n\n    initialSum = 0;\n    for (int p = 0; p < C; ++p) {\n        if (initDot[p]) initialSum += WT[p];\n    }\n\n    RNG rng(seed);\n\n    vector<Params> presets = {\n        {1.0,  0.0,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  0.6,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  2.8,  0.015, 0.8, 0.2,  0.0,  1, 1.0, 0.00},\n        {1.0, -0.4, -0.004, 0.4, 0.0,  0.0,  8, 2.0, 0.00},\n        {1.0,  0.5,  0.000, 1.0, 0.0,  0.0, 16, 1.7, 0.00},\n        {1.0,  4.5,  0.050, 0.0, 0.0,  0.0, 24, 2.5, 0.00},\n        {0.0,  6.0,  0.040, 0.0, 0.0,  0.0,  8, 2.2, 0.01},\n        {0.25, 3.5,  0.020, 0.2, 0.0,  0.0, 12, 2.0, 0.02},\n        {0.8,  0.0,  0.000, 0.0, 0.8, 25.0, 20, 2.2, 0.04}\n    };\n\n    State st;\n    st.ops.reserve(C);\n\n    vector<Op> bestOps;\n    bestOps.reserve(C);\n    long long bestSum = initialSum;\n\n    vector<Solution> pool;\n    pool.reserve(12);\n\n    Timer timer;\n    const double TL = 4.75;\n\n    int trial = 0;\n    while (timer.elapsed() < TL) {\n        Params par;\n        bool useLNS = false;\n\n        if (trial < (int)presets.size()) {\n            par = presets[trial];\n        } else {\n            par = randomParam(rng);\n            if (!pool.empty() && rng.nextInt(100) < 78) {\n                useLNS = true;\n            }\n        }\n\n        preparePriority(par, rng);\n\n        if (useLNS) {\n            int ps = (int)pool.size();\n            double u = rng.nextDouble();\n            int idx = (int)(u * u * ps);\n            if (idx >= ps) idx = ps - 1;\n            replayDestroyed(st, pool[idx].ops, rng);\n        } else {\n            st.reset();\n        }\n\n        runGreedy(st, par, rng, timer, TL);\n        considerSolution(st, pool, bestOps, bestSum);\n\n        ++trial;\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (const auto& op : bestOps) {\n        cout << PX[op.p1] << ' ' << PY[op.p1] << ' '\n             << PX[op.p2] << ' ' << PY[op.p2] << ' '\n             << PX[op.p3] << ' ' << PY[op.p3] << ' '\n             << PX[op.p4] << ' ' << PY[op.p4] << '\\n';\n    }\n\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint flav[100];\nint totalCnt[4];\nint remAfter[100][4];\n\nint neighs[100][4], degs_[100];\nint rightCell[100], downCell[100];\nuint8_t manhDist[100][100];\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Board {\n    uint8_t a[100];\n    int n;\n\n    Board() { clear(); }\n\n    void clear() {\n        memset(a, 0, sizeof(a));\n        n = 0;\n    }\n\n    void placeRank(int rk, int fl) {\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) {\n                if (rk == 0) {\n                    a[i] = (uint8_t)fl;\n                    n++;\n                    return;\n                }\n                rk--;\n            }\n        }\n    }\n\n    void placeCell(int pos, int fl) {\n        a[pos] = (uint8_t)fl;\n        n++;\n    }\n\n    int getEmpties(int emp[]) const {\n        int m = 0;\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) emp[m++] = i;\n        }\n        return m;\n    }\n\n    void tilt(int dir) {\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; c++) {\n                int w = 0;\n                for (int r = 0; r < 10; r++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w++ * 10 + c] = v;\n                }\n                for (int r = w; r < 10; r++) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; c++) {\n                int w = 9;\n                for (int r = 9; r >= 0; r--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w-- * 10 + c] = v;\n                }\n                for (int r = w; r >= 0; r--) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; r++) {\n                int w = 0;\n                for (int c = 0; c < 10; c++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w++] = v;\n                }\n                for (int c = w; c < 10; c++) a[r * 10 + c] = 0;\n            }\n        } else { // R\n            for (int r = 0; r < 10; r++) {\n                int w = 9;\n                for (int c = 9; c >= 0; c--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w--] = v;\n                }\n                for (int c = w; c >= 0; c--) a[r * 10 + c] = 0;\n            }\n        }\n    }\n};\n\nstruct Layout {\n    uint8_t target[100];\n    uint8_t dist[4][100];\n};\n\nvector<Layout> layouts;\nunordered_set<string> seenLayouts;\n\nvoid initTables() {\n    for (int i = 0; i < 100; i++) {\n        degs_[i] = 0;\n        rightCell[i] = downCell[i] = -1;\n    }\n\n    for (int r = 0; r < 10; r++) {\n        for (int c = 0; c < 10; c++) {\n            int id = r * 10 + c;\n            if (r > 0) neighs[id][degs_[id]++] = (r - 1) * 10 + c;\n            if (r < 9) neighs[id][degs_[id]++] = (r + 1) * 10 + c;\n            if (c > 0) neighs[id][degs_[id]++] = r * 10 + c - 1;\n            if (c < 9) neighs[id][degs_[id]++] = r * 10 + c + 1;\n\n            if (c < 9) rightCell[id] = id + 1;\n            if (r < 9) downCell[id] = id + 10;\n        }\n    }\n\n    for (int i = 0; i < 100; i++) {\n        int r1 = i / 10, c1 = i % 10;\n        for (int j = 0; j < 100; j++) {\n            int r2 = j / 10, c2 = j % 10;\n            manhDist[i][j] = (uint8_t)(abs(r1 - r2) + abs(c1 - c2));\n        }\n    }\n}\n\nll finalScoreNum(const Board& b) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    ll res = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        res += 1LL * sz * sz;\n    }\n\n    return res;\n}\n\nll evalBoard(const Board& b, int step, const Layout& L) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    int maxComp[4] = {};\n    int sumSq = 0;\n    int comps = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        comps++;\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        sumSq += sz * sz;\n        maxComp[fl] = max(maxComp[fl], sz);\n    }\n\n    int adj = 0;\n    int distCost = 0;\n    int match = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int v = b.a[i];\n        if (!v) continue;\n\n        int r = rightCell[i];\n        if (r != -1 && b.a[r] == v) adj++;\n\n        int d = downCell[i];\n        if (d != -1 && b.a[d] == v) adj++;\n\n        distCost += L.dist[v][i];\n        if (L.target[i] == v) match++;\n    }\n\n    // Optimistic future-aware component potential:\n    // If all future candies of a flavor join its largest current component,\n    // contribution is sumSq + 2 * maxComponent * remaining + constant.\n    ll compPot = sumSq;\n    for (int f = 1; f <= 3; f++) {\n        compPot += 2LL * maxComp[f] * remAfter[step][f];\n    }\n\n    int future = 99 - step;\n\n    ll val = 0;\n    val += compPot * 1000LL;\n    val += adj * 200LL;\n    val -= comps * 50LL;\n    val += match * (30LL + future);\n    val -= distCost * (20LL + 3LL * future);\n\n    return val;\n}\n\nint greedyDir(const Board& b, int step, const Layout& L) {\n    int offset = ((step + 1) * 17 + flav[step] * 31) & 3;\n\n    int bestD = 0;\n    ll bestV = LLONG_MIN;\n\n    for (int k = 0; k < 4; k++) {\n        int d = (offset + k) & 3;\n        Board nb = b;\n        nb.tilt(d);\n        ll v = evalBoard(nb, step, L);\n        if (v > bestV) {\n            bestV = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nvoid computeLayoutDist(Layout& L) {\n    for (int f = 0; f < 4; f++) {\n        for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n    }\n\n    for (int f = 1; f <= 3; f++) {\n        vector<int> cells;\n        for (int i = 0; i < 100; i++) {\n            if (L.target[i] == f) cells.push_back(i);\n        }\n\n        if (cells.empty()) {\n            for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n            continue;\n        }\n\n        for (int i = 0; i < 100; i++) {\n            int best = 100;\n            for (int p : cells) {\n                best = min(best, (int)manhDist[i][p]);\n            }\n            L.dist[f][i] = (uint8_t)best;\n        }\n    }\n}\n\nvoid addLayout(const array<uint8_t, 100>& tar) {\n    string key;\n    key.resize(100);\n    for (int i = 0; i < 100; i++) key[i] = char('0' + tar[i]);\n\n    if (!seenLayouts.insert(key).second) return;\n\n    Layout L;\n    memset(&L, 0, sizeof(L));\n    for (int i = 0; i < 100; i++) L.target[i] = tar[i];\n    computeLayoutDist(L);\n    layouts.push_back(L);\n}\n\npair<int, int> transformCoord(int r, int c, int s) {\n    if (s == 0) return {r, c};\n    if (s == 1) return {r, 9 - c};\n    if (s == 2) return {9 - r, c};\n    if (s == 3) return {9 - r, 9 - c};\n    if (s == 4) return {c, r};\n    if (s == 5) return {c, 9 - r};\n    if (s == 6) return {9 - c, r};\n    return {9 - c, 9 - r};\n}\n\nstruct PQNode {\n    int dist;\n    int tie;\n    int f;\n    int pos;\n};\n\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        if (a.dist != b.dist) return a.dist > b.dist;\n        if (a.tie != b.tie) return a.tie > b.tie;\n        return a.f > b.f;\n    }\n};\n\nint tieValue(int pos, int f, int seed) {\n    return (pos * 37 + f * 101 + seed * 17) & 1023;\n}\n\narray<uint8_t, 100> makeCornerLayout(const int seeds[4]) {\n    array<uint8_t, 100> tar;\n    tar.fill(0);\n\n    int cap[4];\n    for (int f = 1; f <= 3; f++) cap[f] = totalCnt[f];\n\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq;\n\n    for (int f = 1; f <= 3; f++) {\n        if (cap[f] > 0) {\n            int p = seeds[f];\n            pq.push({0, tieValue(p, f, seeds[f]), f, p});\n        }\n    }\n\n    int assigned = 0;\n\n    while (assigned < 100 && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n\n        int f = cur.f;\n        int p = cur.pos;\n\n        if (cap[f] <= 0 || tar[p] != 0) continue;\n\n        tar[p] = (uint8_t)f;\n        cap[f]--;\n        assigned++;\n\n        if (cap[f] > 0) {\n            for (int k = 0; k < degs_[p]; k++) {\n                int to = neighs[p][k];\n                if (tar[to] == 0) {\n                    pq.push({cur.dist + 1, tieValue(to, f, seeds[f]), f, to});\n                }\n            }\n        }\n    }\n\n    // Fallback, rarely used.\n    if (assigned < 100) {\n        for (int p = 0; p < 100; p++) {\n            if (tar[p] != 0) continue;\n\n            int bestF = -1;\n            int bestCost = 1e9;\n\n            for (int f = 1; f <= 3; f++) {\n                if (cap[f] <= 0) continue;\n\n                int cost = manhDist[p][seeds[f]];\n                bool adj = false;\n                for (int k = 0; k < degs_[p]; k++) {\n                    if (tar[neighs[p][k]] == f) adj = true;\n                }\n                if (adj) cost -= 20;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestF = f;\n                }\n            }\n\n            if (bestF == -1) {\n                for (int f = 1; f <= 3; f++) {\n                    if (cap[f] > 0) {\n                        bestF = f;\n                        break;\n                    }\n                }\n            }\n\n            tar[p] = (uint8_t)bestF;\n            cap[bestF]--;\n            assigned++;\n        }\n    }\n\n    return tar;\n}\n\nvoid generateLayouts() {\n    layouts.clear();\n    seenLayouts.clear();\n    layouts.reserve(128);\n    seenLayouts.reserve(256);\n\n    // Neutral layout: target term disabled.\n    {\n        Layout neutral;\n        memset(&neutral, 0, sizeof(neutral));\n        layouts.push_back(neutral);\n        seenLayouts.insert(string(100, '0'));\n    }\n\n    // Snake/band layouts.\n    vector<int> basePath;\n    basePath.reserve(100);\n\n    for (int r = 0; r < 10; r++) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < 10; c++) basePath.push_back(r * 10 + c);\n        } else {\n            for (int c = 9; c >= 0; c--) basePath.push_back(r * 10 + c);\n        }\n    }\n\n    for (int sym = 0; sym < 8; sym++) {\n        vector<int> path;\n        path.reserve(100);\n        bool used[100] = {};\n        bool ok = true;\n\n        for (int id : basePath) {\n            int r = id / 10, c = id % 10;\n            auto [nr, nc] = transformCoord(r, c, sym);\n            int p = nr * 10 + nc;\n            if (used[p]) ok = false;\n            used[p] = true;\n            path.push_back(p);\n        }\n\n        if (!ok) continue;\n\n        array<int, 3> perm = {1, 2, 3};\n        do {\n            array<uint8_t, 100> tar;\n            tar.fill(0);\n\n            int idx = 0;\n            for (int k = 0; k < 3; k++) {\n                int f = perm[k];\n                for (int cnt = 0; cnt < totalCnt[f]; cnt++) {\n                    tar[path[idx++]] = (uint8_t)f;\n                }\n            }\n\n            addLayout(tar);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    // Three-corner growing layouts.\n    int corners[4] = {0, 9, 90, 99};\n    for (int a = 0; a < 4; a++) {\n        for (int b = 0; b < 4; b++) if (b != a) {\n            for (int c = 0; c < 4; c++) if (c != a && c != b) {\n                int seeds[4] = {};\n                seeds[1] = corners[a];\n                seeds[2] = corners[b];\n                seeds[3] = corners[c];\n\n                auto tar = makeCornerLayout(seeds);\n                addLayout(tar);\n            }\n        }\n    }\n}\n\nint chooseLayout() {\n    constexpr int K = 3;\n\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 100; i++) {\n        seed = seed * 1000003ULL + flav[i] * 97ULL + i;\n    }\n\n    RNG rng(seed);\n    uint8_t ranks[K][100];\n\n    for (int k = 0; k < K; k++) {\n        for (int s = 0; s < 100; s++) {\n            ranks[k][s] = (uint8_t)rng.nextInt(100 - s);\n        }\n    }\n\n    int bestIdx = 0;\n    ll bestScore = LLONG_MIN;\n\n    for (int li = 0; li < (int)layouts.size(); li++) {\n        ll total = 0;\n\n        for (int k = 0; k < K; k++) {\n            Board b;\n\n            for (int s = 0; s < 100; s++) {\n                b.placeRank(ranks[k][s], flav[s]);\n\n                if (s == 99) break;\n\n                int d = greedyDir(b, s, layouts[li]);\n                b.tilt(d);\n            }\n\n            total += finalScoreNum(b);\n        }\n\n        if (total > bestScore) {\n            bestScore = total;\n            bestIdx = li;\n        }\n    }\n\n    return bestIdx;\n}\n\ndouble exactValue(const Board& b, int step);\n\ndouble exactDirValue(const Board& b, int step, int dir) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    Board bb = b;\n    bb.tilt(dir);\n\n    int emp[100];\n    int m = bb.getEmpties(emp);\n\n    if (m == 0) return (double)finalScoreNum(bb);\n\n    double sum = 0.0;\n\n    for (int i = 0; i < m; i++) {\n        Board nb = bb;\n        nb.placeCell(emp[i], flav[step + 1]);\n        sum += exactValue(nb, step + 1);\n    }\n\n    return sum / m;\n}\n\ndouble exactValue(const Board& b, int step) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        best = max(best, exactDirValue(b, step, d));\n    }\n\n    return best;\n}\n\nint exactBestDir(const Board& b, int step) {\n    int bestD = 0;\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        double v = exactDirValue(b, step, d);\n        if (v > best) {\n            best = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nstruct BeamNode {\n    Board b;\n    ll val;\n};\n\nvoid addBeamCandidate(BeamNode next[], int& cnt, int BW, const Board& b, ll val) {\n    if (cnt < BW) {\n        next[cnt].b = b;\n        next[cnt].val = val;\n        cnt++;\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < BW; i++) {\n        if (next[i].val < next[worst].val) worst = i;\n    }\n\n    if (val > next[worst].val) {\n        next[worst].b = b;\n        next[worst].val = val;\n    }\n}\n\nll simulateBeam(const Board& start, int step, const uint8_t ranks[], const Layout& L, int BW) {\n    BeamNode beam[2], nxt[2];\n\n    int bc = 1;\n    beam[0].b = start;\n    beam[0].val = 0;\n\n    for (int s = step + 1; s < 100; s++) {\n        int nc = 0;\n        ll bestFinal = -1;\n\n        for (int i = 0; i < bc; i++) {\n            Board placed = beam[i].b;\n            placed.placeRank(ranks[s], flav[s]);\n\n            if (s == 99) {\n                bestFinal = max(bestFinal, finalScoreNum(placed));\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    Board nb = placed;\n                    nb.tilt(d);\n                    ll v = evalBoard(nb, s, L);\n                    addBeamCandidate(nxt, nc, BW, nb, v);\n                }\n            }\n        }\n\n        if (s == 99) return bestFinal;\n\n        bc = nc;\n        for (int i = 0; i < bc; i++) beam[i] = nxt[i];\n    }\n\n    return finalScoreNum(start);\n}\n\nint decideMove(const Board& b, int step, const Layout& L, RNG& rng) {\n    if (step >= 99) return 0;\n\n    int rem = 99 - step;\n    double el = elapsedSec();\n\n    // Exact expectimax for the last few moves.\n    if (rem <= 5 && el < 1.72) {\n        return exactBestDir(b, step);\n    }\n\n    if (el > 1.84) {\n        return greedyDir(b, step, L);\n    }\n\n    Board first[4];\n    for (int d = 0; d < 4; d++) {\n        first[d] = b;\n        first[d].tilt(d);\n    }\n\n    int BW = (rem <= 25 ? 2 : 1);\n    int work = (BW == 1 ? 520 : 360);\n    int R = max(4, min(60, work / max(1, rem)));\n\n    if (el > 1.70) R = max(2, R / 3);\n    else if (el > 1.50) R = max(3, R / 2);\n\n    ll scores[4] = {};\n    uint8_t ranks[100];\n\n    int done = 0;\n\n    for (int it = 0; it < R; it++) {\n        if (it > 0 && (it & 3) == 0 && elapsedSec() > 1.86) break;\n\n        for (int s = step + 1; s < 100; s++) {\n            ranks[s] = (uint8_t)rng.nextInt(100 - s);\n        }\n\n        for (int d = 0; d < 4; d++) {\n            scores[d] += simulateBeam(first[d], step, ranks, L, BW);\n        }\n\n        done++;\n    }\n\n    if (done == 0) {\n        return greedyDir(b, step, L);\n    }\n\n    int bestD = 0;\n    ll bestScore = LLONG_MIN;\n    ll bestHeur = LLONG_MIN;\n\n    for (int d = 0; d < 4; d++) {\n        ll h = evalBoard(first[d], step, L);\n\n        if (scores[d] > bestScore || (scores[d] == bestScore && h > bestHeur)) {\n            bestScore = scores[d];\n            bestHeur = h;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    initTables();\n\n    for (int i = 0; i < 100; i++) {\n        if (!(cin >> flav[i])) return 0;\n        totalCnt[flav[i]]++;\n    }\n\n    int suf[4] = {};\n    for (int i = 99; i >= 0; i--) {\n        for (int f = 1; f <= 3; f++) remAfter[i][f] = suf[f];\n        suf[flav[i]]++;\n    }\n\n    generateLayouts();\n    int layoutIdx = chooseLayout();\n    Layout layout = layouts[layoutIdx];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < 100; i++) {\n        seed ^= (uint64_t)(flav[i] + 1237 * i);\n        seed *= 0xbf58476d1ce4e5b9ULL;\n    }\n\n    RNG rng(seed ^ 0xdeadbeefcafebabeULL);\n\n    Board board;\n    const char dc[4] = {'F', 'B', 'L', 'R'};\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        board.placeRank(p - 1, flav[t]);\n\n        int dir;\n        if (t == 99) {\n            dir = 0;\n        } else {\n            dir = decideMove(board, t, layout, rng);\n        }\n\n        board.tilt(dir);\n\n        cout << dc[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nconst int MAXN = 100;\nusing Row = array<ull, 2>;\n\nint M;\ndouble EPS, QV;\n\nint Ncur, Bcur, Lcur, Fcur;\nint POSBIN[MAXN];\nint FIDX[10][10];\nvector<int> PAIRCNT;\n\ndouble PMF[MAXN][MAXN];\ndouble NEGLOGP[MAXN][MAXN];\ndouble edgePenalty = 0.0;\n\nstruct Candidate {\n    uint32_t mask;\n    array<unsigned char, MAXN> deg;\n    int sum;\n};\n\nstruct Codeword {\n    uint32_t mask;\n    array<unsigned char, MAXN> deg;\n    vector<Row> rows;\n    array<double, MAXN> mixNeg;\n    vector<int> blockCnt;\n};\n\nstruct QueryFeat {\n    array<int, MAXN> degSorted;\n    array<int, MAXN> hist;\n    vector<Row> rows;\n    vector<int> blockCnt;\n};\n\nstruct Config {\n    double alpha; // sorted degree NLL weight\n    double wb;    // block edge feature weight\n    double we;    // aligned edge hamming weight\n};\n\nstruct TrainResult {\n    Config cfg;\n    int err;\n    int samples;\n};\n\nvector<Codeword> codes;\nConfig bestCfg{0.5, 0.0, 0.0};\n\ninline int thresholdBit(uint32_t mask, int idx, int B, int N) {\n    int b = (long long)idx * B / N;\n    return (mask >> b) & 1u;\n}\n\ninline void setEdge(vector<Row>& rows, int i, int j) {\n    rows[i][j >> 6] |= 1ULL << (j & 63);\n    rows[j][i >> 6] |= 1ULL << (i & 63);\n}\n\ninline bool getEdge(const vector<Row>& rows, int i, int j) {\n    return (rows[i][j >> 6] >> (j & 63)) & 1ULL;\n}\n\ninline double rnd01(mt19937_64& rng) {\n    return (rng() >> 11) * (1.0 / 9007199254740992.0);\n}\n\nvoid thresholdDegrees(uint32_t mask, int B, int N, array<int, MAXN>& degOrig) {\n    int cnt = 0;\n    for (int i = N - 1; i >= 0; --i) {\n        int bit = thresholdBit(mask, i, B, N);\n        if (bit) degOrig[i] = i + cnt;\n        else degOrig[i] = cnt;\n        if (bit) cnt++;\n    }\n}\n\nvector<Candidate> buildPool(int N, int B) {\n    vector<Candidate> pool;\n    int total = 1 << B;\n    pool.reserve(total);\n\n    unordered_set<string> seen;\n    seen.reserve(total * 2);\n\n    for (uint32_t mask = 0; mask < (uint32_t)total; ++mask) {\n        array<int, MAXN> dorig{};\n        thresholdDegrees(mask, B, N, dorig);\n\n        Candidate c;\n        c.mask = mask;\n        c.deg.fill(0);\n        c.sum = 0;\n        for (int i = 0; i < N; ++i) {\n            c.deg[i] = (unsigned char)dorig[i];\n            c.sum += dorig[i];\n        }\n        sort(c.deg.begin(), c.deg.begin() + N);\n\n        string key;\n        key.resize(N);\n        for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n        if (seen.insert(key).second) {\n            pool.push_back(c);\n        }\n    }\n    return pool;\n}\n\ninline int dist2Deg(const array<unsigned char, MAXN>& a,\n                    const array<unsigned char, MAXN>& b,\n                    int N) {\n    int s = 0;\n    for (int i = 0; i < N; ++i) {\n        int d = (int)a[i] - (int)b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstruct Selection {\n    vector<int> idx;\n    int minD2;\n};\n\nSelection selectFarthest(const vector<Candidate>& pool, int N, int m, int improveIters) {\n    int P = (int)pool.size();\n    Selection res;\n    res.minD2 = 0;\n    if (P < m) return res;\n\n    vector<int> selected;\n    vector<int> minDist(P, INT_MAX);\n    vector<char> used(P, 0);\n\n    int start = 0;\n    for (int i = 1; i < P; ++i) {\n        if (pool[i].sum < pool[start].sum) start = i;\n    }\n\n    for (int it = 0; it < m; ++it) {\n        int id;\n        if (it == 0) {\n            id = start;\n        } else {\n            id = -1;\n            int best = -1;\n            for (int i = 0; i < P; ++i) {\n                if (!used[i] && minDist[i] > best) {\n                    best = minDist[i];\n                    id = i;\n                }\n            }\n        }\n\n        used[id] = 1;\n        selected.push_back(id);\n\n        for (int i = 0; i < P; ++i) {\n            if (!used[i]) {\n                int d = dist2Deg(pool[i].deg, pool[id].deg, N);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    for (int rep = 0; rep < improveIters; ++rep) {\n        vector<int> near(m, INT_MAX);\n        int curMin = INT_MAX;\n        int worstPos = -1;\n\n        for (int i = 0; i < m; ++i) {\n            for (int j = 0; j < m; ++j) if (i != j) {\n                int d = dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N);\n                near[i] = min(near[i], d);\n            }\n            if (near[i] < curMin) {\n                curMin = near[i];\n                worstPos = i;\n            }\n        }\n\n        int bestP = -1;\n        int bestMd = curMin;\n\n        for (int p = 0; p < P; ++p) if (!used[p]) {\n            int md = INT_MAX;\n            for (int i = 0; i < m; ++i) {\n                if (i == worstPos) continue;\n                int d = dist2Deg(pool[p].deg, pool[selected[i]].deg, N);\n                md = min(md, d);\n                if (md <= curMin) break;\n            }\n            if (md > bestMd) {\n                bestMd = md;\n                bestP = p;\n            }\n        }\n\n        if (bestP == -1) break;\n\n        used[selected[worstPos]] = 0;\n        selected[worstPos] = bestP;\n        used[bestP] = 1;\n    }\n\n    int md2 = INT_MAX;\n    for (int i = 0; i < m; ++i) {\n        for (int j = i + 1; j < m; ++j) {\n            md2 = min(md2, dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N));\n        }\n    }\n\n    res.idx = selected;\n    res.minD2 = md2;\n    return res;\n}\n\nvoid setupBlocks(int N) {\n    Lcur = min(10, N);\n    Fcur = 0;\n    for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) FIDX[i][j] = -1;\n\n    for (int a = 0; a < Lcur; ++a) {\n        for (int b = a; b < Lcur; ++b) {\n            FIDX[a][b] = FIDX[b][a] = Fcur++;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        POSBIN[i] = (long long)i * Lcur / N;\n        if (POSBIN[i] >= Lcur) POSBIN[i] = Lcur - 1;\n    }\n\n    PAIRCNT.assign(Fcur, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            int f = FIDX[POSBIN[i]][POSBIN[j]];\n            PAIRCNT[f]++;\n        }\n    }\n}\n\nvector<int> computeBlockCounts(const vector<Row>& rows) {\n    vector<int> cnt(Fcur, 0);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, i, j)) {\n                int f = FIDX[POSBIN[i]][POSBIN[j]];\n                cnt[f]++;\n            }\n        }\n    }\n    return cnt;\n}\n\nvector<double> binomDist(int n, double p) {\n    vector<double> d(n + 1, 0.0);\n    if (n == 0) {\n        d[0] = 1.0;\n        return d;\n    }\n    double q = 1.0 - p;\n    d[0] = pow(q, n);\n    for (int k = 0; k < n; ++k) {\n        if (q == 0.0) {\n            d[k + 1] = (k + 1 == n ? 1.0 : 0.0);\n        } else {\n            d[k + 1] = d[k] * (double)(n - k) / (double)(k + 1) * p / q;\n        }\n    }\n    return d;\n}\n\nvoid setupPMF(int N) {\n    vector<vector<double>> keep(N), flip(N);\n    for (int n = 0; n <= N - 1; ++n) {\n        keep[n] = binomDist(n, 1.0 - EPS);\n        flip[n] = binomDist(n, EPS);\n    }\n\n    for (int d = 0; d <= N - 1; ++d) {\n        for (int x = 0; x <= N - 1; ++x) PMF[d][x] = 0.0;\n\n        int absent = N - 1 - d;\n        for (int y = 0; y <= d; ++y) {\n            for (int z = 0; z <= absent; ++z) {\n                PMF[d][y + z] += keep[d][y] * flip[absent][z];\n            }\n        }\n\n        for (int x = 0; x <= N - 1; ++x) {\n            double p = max(PMF[d][x], 1e-300);\n            NEGLOGP[d][x] = -log(p);\n        }\n    }\n}\n\nCodeword buildCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = cand.mask;\n    c.deg = cand.deg;\n    c.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : c.rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> dorig{};\n    thresholdDegrees(c.mask, Bcur, Ncur, dorig);\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (dorig[a] != dorig[b]) return dorig[a] < dorig[b];\n        return a < b;\n    });\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            int u = ord[a], v = ord[b];\n            int later = max(u, v);\n            if (thresholdBit(c.mask, later, Bcur, Ncur)) {\n                setEdge(c.rows, a, b);\n            }\n        }\n    }\n\n    c.mixNeg.fill(0.0);\n    for (int x = 0; x < Ncur; ++x) {\n        double p = 0.0;\n        for (int i = 0; i < Ncur; ++i) {\n            p += PMF[c.deg[i]][x];\n        }\n        p /= Ncur;\n        c.mixNeg[x] = -log(max(p, 1e-300));\n    }\n\n    c.blockCnt = computeBlockCounts(c.rows);\n    return c;\n}\n\nQueryFeat makeFeatureFromRows(const vector<Row>& rowsIn, const array<int, MAXN>& deg) {\n    QueryFeat q;\n    q.hist.fill(0);\n    q.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : q.rows) r = {0ULL, 0ULL};\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < Ncur; ++i) {\n        q.degSorted[i] = deg[ord[i]];\n        q.hist[q.degSorted[i]]++;\n    }\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            if (getEdge(rowsIn, ord[a], ord[b])) {\n                setEdge(q.rows, a, b);\n            }\n        }\n    }\n\n    q.blockCnt = computeBlockCounts(q.rows);\n    return q;\n}\n\nQueryFeat featureFromString(const string& s) {\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    int pos = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (s[pos++] == '1') {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    return makeFeatureFromRows(rows, deg);\n}\n\nQueryFeat simulateQuery(int k, mt19937_64& rng) {\n    const Codeword& cw = codes[k];\n\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            int g = thresholdBit(cw.mask, j, Bcur, Ncur);\n            int h = g;\n            if (rnd01(rng) < EPS) h ^= 1;\n            if (h) {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    array<int, MAXN> perm{};\n    for (int i = 0; i < Ncur; ++i) perm[i] = i;\n    for (int i = Ncur - 1; i >= 1; --i) {\n        int r = rng() % (i + 1);\n        swap(perm[i], perm[r]);\n    }\n\n    vector<Row> shuf(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : shuf) r = {0ULL, 0ULL};\n    array<int, MAXN> deg2{};\n    deg2.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        deg2[i] = deg[perm[i]];\n    }\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, perm[i], perm[j])) {\n                setEdge(shuf, i, j);\n            }\n        }\n    }\n\n    return makeFeatureFromRows(shuf, deg2);\n}\n\nint edgeMismatch(const vector<Row>& A, const vector<Row>& B) {\n    int s = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        s += __builtin_popcountll(A[i][0] ^ B[i][0]);\n        if (Ncur > 64) s += __builtin_popcountll(A[i][1] ^ B[i][1]);\n    }\n    return s / 2;\n}\n\nstruct Components {\n    double sortedCost;\n    double mixCost;\n    double blockCost;\n    int edgeMis;\n};\n\nComponents computeComponents(const QueryFeat& q, const Codeword& c) {\n    Components comp{0.0, 0.0, 0.0, 0};\n\n    for (int i = 0; i < Ncur; ++i) {\n        comp.sortedCost += NEGLOGP[c.deg[i]][q.degSorted[i]];\n    }\n\n    for (int x = 0; x < Ncur; ++x) {\n        if (q.hist[x]) comp.mixCost += q.hist[x] * c.mixNeg[x];\n    }\n\n    for (int f = 0; f < Fcur; ++f) {\n        int pairs = PAIRCNT[f];\n        if (pairs <= 0) continue;\n        double mu = EPS * pairs + QV * c.blockCnt[f];\n        double var = pairs * EPS * (1.0 - EPS) + 1.0;\n        double diff = q.blockCnt[f] - mu;\n        comp.blockCost += diff * diff / (2.0 * var);\n    }\n\n    comp.edgeMis = edgeMismatch(q.rows, c.rows);\n    return comp;\n}\n\ninline double scoreWithConfig(const Components& comp, const Config& cfg) {\n    double degCost = cfg.alpha * comp.sortedCost + (1.0 - cfg.alpha) * comp.mixCost;\n    return degCost + cfg.wb * comp.blockCost + cfg.we * edgePenalty * comp.edgeMis;\n}\n\nvector<Config> buildConfigs() {\n    vector<Config> cfgs;\n    cfgs.push_back({0.5, 0.0, 0.0}); // conservative default\n\n    vector<double> alphas = {0.0, 0.25, 0.5, 0.75, 1.0};\n    vector<double> wbs = {0.0, 0.2, 0.5, 1.0, 2.0};\n    vector<double> wes = {0.0, 0.02, 0.05, 0.1, 0.2};\n\n    for (double a : alphas) {\n        for (double wb : wbs) {\n            for (double we : wes) {\n                cfgs.push_back({a, wb, we});\n            }\n        }\n    }\n    return cfgs;\n}\n\nTrainResult trainDecoder() {\n    vector<Config> cfgs = buildConfigs();\n    int C = cfgs.size();\n\n    int R = 3;\n    if (EPS > 0.25) R = 5;\n    else if (EPS > 0.12) R = 4;\n    if (M <= 20) R += 4;\n    else if (M <= 50) R += 1;\n\n    int samples = M * R;\n    vector<int> errs(C, 0);\n\n    mt19937_64 rng(1234567ULL + (uint64_t)M * 1009ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 9176ULL\n                   + (uint64_t)Ncur * 1000003ULL);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n\n            vector<double> best(C, 1e300);\n            vector<int> bestId(C, -1);\n\n            for (int k = 0; k < M; ++k) {\n                Components comp = computeComponents(q, codes[k]);\n                for (int ci = 0; ci < C; ++ci) {\n                    double sc = scoreWithConfig(comp, cfgs[ci]);\n                    if (sc < best[ci]) {\n                        best[ci] = sc;\n                        bestId[ci] = k;\n                    }\n                }\n            }\n\n            for (int ci = 0; ci < C; ++ci) {\n                if (bestId[ci] != trueId) errs[ci]++;\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int ci = 1; ci < C; ++ci) {\n        if (errs[ci] < errs[bestC]) bestC = ci;\n    }\n\n    return {cfgs[bestC], errs[bestC], samples};\n}\n\nint predict(const QueryFeat& q) {\n    double best = 1e300;\n    int ans = 0;\n\n    for (int k = 0; k < M; ++k) {\n        Components comp = computeComponents(q, codes[k]);\n        double sc = scoreWithConfig(comp, bestCfg);\n        if (sc < best) {\n            best = sc;\n            ans = k;\n        }\n    }\n    return ans;\n}\n\nstring graphString(uint32_t mask) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(thresholdBit(mask, j, Bcur, Ncur) ? '1' : '0');\n        }\n    }\n    return s;\n}\n\nint chooseN() {\n    int minN = 4;\n    while (minN < 100 && (1LL << (minN - 1)) < M) minN++;\n\n    double r = sqrt(EPS * (1.0 - EPS)) / QV;\n    int nest = (int)ceil(4.0 + 38.0 * r * sqrt(M / 100.0) + 0.03 * M);\n    nest = max(minN, min(100, nest));\n\n    int start, end;\n    if (EPS < 0.05) {\n        start = minN;\n        end = min(100, max(nest + 15, minN + 8));\n    } else {\n        start = max(minN, nest - 20);\n        end = min(100, nest + 25);\n        if (EPS > 0.34) end = 100;\n    }\n\n    vector<int> ns;\n    for (int n = start; n <= end;) {\n        ns.push_back(n);\n        if (n < 35) n++;\n        else if (n < 75) n += 2;\n        else n += 4;\n    }\n    ns.push_back(minN);\n    ns.push_back(nest);\n    ns.push_back(100);\n    sort(ns.begin(), ns.end());\n    ns.erase(unique(ns.begin(), ns.end()), ns.end());\n\n    double target = 3.25 + 0.12 * log((double)M);\n    if (EPS > 0.25) target += 0.15;\n    if (EPS < 0.03) target -= 0.75;\n    else if (EPS < 0.07) target -= 0.30;\n    if (M <= 20) target -= 0.15;\n    target = max(2.4, target);\n\n    for (int n : ns) {\n        if (n < minN || n > 100) continue;\n        int Bs = min(n, (n >= 80 ? 12 : 11));\n        vector<Candidate> pool = buildPool(n, Bs);\n        if ((int)pool.size() < M) continue;\n\n        Selection sel = selectFarthest(pool, n, M, 0);\n        if (sel.idx.empty()) continue;\n\n        double sigma = sqrt((n - 1) * EPS * (1.0 - EPS));\n        double z = QV * sqrt((double)sel.minD2) / (2.0 * sigma);\n        if (z >= target) return n;\n    }\n\n    return 100;\n}\n\nvoid buildThresholdSolution(int initialN) {\n    int chosenN = initialN;\n    int attempts = 0;\n\n    while (true) {\n        Ncur = chosenN;\n        Bcur = min(Ncur, (Ncur >= 70 ? 14 : (Ncur >= 35 ? 13 : 12)));\n\n        vector<Candidate> pool = buildPool(Ncur, Bcur);\n        if ((int)pool.size() < M) {\n            chosenN++;\n            continue;\n        }\n\n        Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n        setupBlocks(Ncur);\n        setupPMF(Ncur);\n        edgePenalty = log((1.0 - EPS) / EPS);\n\n        codes.clear();\n        codes.reserve(M);\n        for (int id : sel.idx) {\n            codes.push_back(buildCodeword(pool[id]));\n        }\n\n        TrainResult tr = trainDecoder();\n        bestCfg = tr.cfg;\n\n        int allowed;\n        if (EPS < 0.05) allowed = max(4, tr.samples / 50);\n        else allowed = max(3, tr.samples / 100);\n\n        if (tr.err > allowed && chosenN < 100 && attempts < 3) {\n            int inc = (chosenN < 50 ? 10 : 6);\n            if (EPS > 0.3) inc = max(inc, 8);\n            chosenN = min(100, chosenN + inc);\n            attempts++;\n            continue;\n        }\n\n        break;\n    }\n}\n\n// Exact solver for epsilon = 0\nstruct ExactSolver {\n    int n, T;\n    vector<string> reps;\n    vector<int> cmap;\n    vector<array<int, 15>> trans;\n\n    int pairPos[6][6];\n\n    void prepareTrans(int n_) {\n        n = n_;\n        T = n * (n - 1) / 2;\n        for (int i = 0; i < 6; ++i) for (int j = 0; j < 6; ++j) pairPos[i][j] = -1;\n\n        int p = 0;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                pairPos[i][j] = pairPos[j][i] = p++;\n            }\n        }\n\n        vector<int> perm(n);\n        iota(perm.begin(), perm.end(), 0);\n        trans.clear();\n\n        do {\n            array<int, 15> tr{};\n            int pos = 0;\n            for (int i = 0; i < n; ++i) {\n                for (int j = i + 1; j < n; ++j) {\n                    int a = perm[i], b = perm[j];\n                    tr[pos++] = pairPos[a][b];\n                }\n            }\n            trans.push_back(tr);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    int canonicalMask(int mask) const {\n        int best = INT_MAX;\n        for (const auto& tr : trans) {\n            int val = 0;\n            for (int i = 0; i < T; ++i) {\n                val = (val << 1) | ((mask >> tr[i]) & 1);\n            }\n            if (val < best) best = val;\n        }\n        return best;\n    }\n\n    string maskToString(int mask) const {\n        string s;\n        s.resize(T);\n        for (int i = 0; i < T; ++i) {\n            s[i] = ((mask >> i) & 1) ? '1' : '0';\n        }\n        return s;\n    }\n\n    int stringToMask(const string& s) const {\n        int mask = 0;\n        for (int i = 0; i < T; ++i) {\n            if (s[i] == '1') mask |= 1 << i;\n        }\n        return mask;\n    }\n\n    void generate(int M) {\n        for (int nn = 4; nn <= 6; ++nn) {\n            prepareTrans(nn);\n            reps.clear();\n            cmap.assign(1 << T, -1);\n\n            for (int mask = 0; mask < (1 << T); ++mask) {\n                int c = canonicalMask(mask);\n                if (cmap[c] == -1) {\n                    int id = (int)reps.size();\n                    cmap[c] = id;\n                    reps.push_back(maskToString(mask));\n                    if ((int)reps.size() == M) return;\n                }\n            }\n        }\n    }\n\n    int decode(const string& s) const {\n        int mask = stringToMask(s);\n        int c = canonicalMask(mask);\n        if (0 <= c && c < (int)cmap.size() && cmap[c] != -1) return cmap[c];\n        return 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> M >> EPS;\n    QV = 1.0 - 2.0 * EPS;\n\n    if (EPS < 1e-12) {\n        ExactSolver ex;\n        ex.generate(M);\n\n        cout << ex.n << '\\n';\n        for (int i = 0; i < M; ++i) {\n            cout << ex.reps[i] << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            cin >> H;\n            int ans = ex.decode(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n        return 0;\n    }\n\n    int initialN = chooseN();\n    buildThresholdSolution(initialN);\n\n    cout << Ncur << '\\n';\n    for (int i = 0; i < M; ++i) {\n        cout << graphString(codes[i].mask) << '\\n';\n    }\n    cout.flush();\n\n    for (int q = 0; q < 100; ++q) {\n        string H;\n        cin >> H;\n        QueryFeat feat = featureFromString(H);\n        int ans = predict(feat);\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#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() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    static constexpr int INF = 1100000000;\n    static constexpr int UNREACH = 1000000000;\n    static constexpr long long DISCONN_SCORE = 4000000000000000LL;\n\n    struct Edge {\n        int u, v, w;\n        int cell;\n        uint32_t key;\n    };\n    struct Arc {\n        int to, w, id;\n    };\n    struct ScoreRes {\n        long long total;\n        vector<long long> day;\n    };\n    struct State {\n        vector<int> assign;\n        vector<int> count;\n        vector<vector<int>> dayEdges;\n        vector<int> pos;\n        vector<int> inc;\n        vector<double> dayImp;\n        vector<int> cellCnt;\n        vector<int> cutCnt;\n        vector<long long> dayScore;\n        long long totalScore = 0;\n    };\n    struct Cand {\n        int type = 0; // 1: move, 2: swap\n        int e = -1, f = -1;\n        double cheap = 1e100;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Arc>> adj;\n    vector<int> xs, ys;\n    vector<int> origDist;\n    vector<long long> load;\n    vector<vector<int>> cutAdj;\n    vector<double> stretch;\n    vector<double> impNorm;\n    vector<int> target;\n    vector<int> optSources;\n\n    static constexpr int G = 16;\n    static constexpr int C = G * G;\n    vector<vector<int>> neighCells;\n    vector<unsigned char> nearCell;\n\n    RNG rng;\n    chrono::steady_clock::time_point startTime;\n    double localEndTime = 5.65;\n\n    vector<pair<int, int>> heapBuf;\n    vector<int> distBuf;\n    vector<int> bfsVis, bfsQ;\n    int bfsStamp = 1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static uint64_t mix64(uint64_t z) {\n        z += 0x9e3779b97f4a7c15ull;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n\n    uint32_t zOrder(int x, int y) const {\n        uint32_t r = 0;\n        for (int b = 0; b < 11; b++) {\n            r |= ((x >> b) & 1u) << (2 * b);\n            r |= ((y >> b) & 1u) << (2 * b + 1);\n        }\n        return r;\n    }\n\n    int edgeCellFromSum(int sx, int sy) const {\n        int cx = min(G - 1, (sx * G) / 2001);\n        int cy = min(G - 1, (sy * G) / 2001);\n        return cx * G + cy;\n    }\n\n    void setupCells() {\n        neighCells.assign(C, {});\n        nearCell.assign(C * C, 0);\n        for (int cx = 0; cx < G; cx++) {\n            for (int cy = 0; cy < G; cy++) {\n                int c = cx * G + cy;\n                for (int dx = -1; dx <= 1; dx++) {\n                    for (int dy = -1; dy <= 1; dy++) {\n                        int nx = cx + dx, ny = cy + dy;\n                        if (0 <= nx && nx < G && 0 <= ny && ny < G) {\n                            int nc = nx * G + ny;\n                            neighCells[c].push_back(nc);\n                            nearCell[c * C + nc] = 1;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    void readInput() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        adj.assign(N, {});\n        uint64_t seed = 123456789;\n\n        for (int i = 0; i < M; i++) {\n            int u, v, w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i].u = u;\n            edges[i].v = v;\n            edges[i].w = w;\n            edges[i].cell = 0;\n            edges[i].key = 0;\n            adj[u].push_back({v, w, i});\n            adj[v].push_back({u, w, i});\n            seed ^= mix64((uint64_t)(u + 1) * 1000003ull + (uint64_t)(v + 1) * 1009ull + w);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> xs[i] >> ys[i];\n            seed ^= mix64((uint64_t)(xs[i] + 1) * 10007ull + ys[i] + i * 97ull);\n        }\n        rng.x = seed ? seed : 88172645463325252ull;\n\n        setupCells();\n\n        for (int i = 0; i < M; i++) {\n            int u = edges[i].u, v = edges[i].v;\n            int sx = xs[u] + xs[v];\n            int sy = ys[u] + ys[v];\n            edges[i].cell = edgeCellFromSum(sx, sy);\n            int hx = min(2047, (sx * 2047) / 2000);\n            int hy = min(2047, (sy * 2047) / 2000);\n            edges[i].key = zOrder(hx, hy);\n        }\n\n        target.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) target[d]++;\n\n        distBuf.assign(N, INF);\n        bfsVis.assign(N, 0);\n        bfsQ.assign(N, 0);\n        heapBuf.reserve(max(10000, 4 * M + 2 * N));\n    }\n\n    void heapPush(int d, int v) {\n        pair<int, int> val = {d, v};\n        int i = (int)heapBuf.size();\n        heapBuf.push_back(val);\n        while (i > 0) {\n            int p = (i - 1) >> 1;\n            if (heapBuf[p].first <= val.first) break;\n            heapBuf[i] = heapBuf[p];\n            i = p;\n        }\n        heapBuf[i] = val;\n    }\n\n    pair<int, int> heapPop() {\n        pair<int, int> res = heapBuf[0];\n        pair<int, int> val = heapBuf.back();\n        heapBuf.pop_back();\n        if (!heapBuf.empty()) {\n            int i = 0;\n            int n = (int)heapBuf.size();\n            while (true) {\n                int l = i * 2 + 1;\n                if (l >= n) break;\n                int r = l + 1;\n                int c = l;\n                if (r < n && heapBuf[r].first < heapBuf[l].first) c = r;\n                if (heapBuf[c].first >= val.first) break;\n                heapBuf[i] = heapBuf[c];\n                i = c;\n            }\n            heapBuf[i] = val;\n        }\n        return res;\n    }\n\n    void dijkstraOriginalParent(\n        int src,\n        vector<int>& dist,\n        vector<int>& parV,\n        vector<int>& parE,\n        vector<int>& order\n    ) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        order.clear();\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            order.push_back(v);\n            for (const auto& a : adj[v]) {\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    parV[a.to] = v;\n                    parE[a.to] = a.id;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    void dijkstraDaySource(int src, int day, const vector<int>& assign, vector<int>& dist) {\n        fill(dist.begin(), dist.end(), INF);\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            for (const auto& a : adj[v]) {\n                if (assign[a.id] == day) continue;\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    int dijkstraBetweenSkipEdge(int src, int dst, int banned) {\n        fill(distBuf.begin(), distBuf.end(), INF);\n        heapBuf.clear();\n\n        distBuf[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != distBuf[v]) continue;\n            if (v == dst) return du;\n            for (const auto& a : adj[v]) {\n                if (a.id == banned) continue;\n                int nd = du + a.w;\n                if (nd < distBuf[a.to]) {\n                    distBuf[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n        return INF;\n    }\n\n    void computeOriginalAndLoad() {\n        origDist.assign(N * N, INF);\n        load.assign(M, 0);\n\n        vector<int> dist(N), parV(N), parE(N), order;\n        vector<int> sub(N);\n\n        for (int s = 0; s < N; s++) {\n            dijkstraOriginalParent(s, dist, parV, parE, order);\n            memcpy(&origDist[s * N], dist.data(), sizeof(int) * N);\n\n            fill(sub.begin(), sub.end(), 1);\n            for (int ii = (int)order.size() - 1; ii >= 0; ii--) {\n                int v = order[ii];\n                int e = parE[v];\n                if (e != -1) {\n                    load[e] += sub[v];\n                    sub[parV[v]] += sub[v];\n                }\n            }\n        }\n    }\n\n    void detectTwoEdgeCuts() {\n        cutAdj.assign(M, {});\n        vector<int> tin(N), low(N);\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), 0);\n            fill(low.begin(), low.end(), 0);\n            int timer = 0;\n\n            auto dfs = [&](auto&& self, int v, int pe) -> void {\n                tin[v] = low[v] = ++timer;\n                for (const auto& a : adj[v]) {\n                    if (a.id == banned || a.id == pe) continue;\n                    int to = a.to;\n                    if (!tin[to]) {\n                        self(self, to, a.id);\n                        low[v] = min(low[v], low[to]);\n                        if (low[to] > tin[v]) {\n                            int f = a.id;\n                            if (banned < f) {\n                                cutAdj[banned].push_back(f);\n                                cutAdj[f].push_back(banned);\n                            }\n                        }\n                    } else {\n                        low[v] = min(low[v], tin[to]);\n                    }\n                }\n            };\n\n            dfs(dfs, 0, -1);\n        }\n\n        for (auto& v : cutAdj) {\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n    }\n\n    void computeStretch() {\n        stretch.assign(M, 0.0);\n        const double deadline = 1.35;\n\n        for (int e = 0; e < M; e++) {\n            if (elapsed() > deadline) break;\n            int u = edges[e].u;\n            int v = edges[e].v;\n            int repl = dijkstraBetweenSkipEdge(u, v, e);\n            int base = origDist[u * N + v];\n            if (repl >= INF) {\n                stretch[e] = 5.0;\n            } else {\n                stretch[e] = max(0.0, (double)(repl - base) / max(1, base));\n                stretch[e] = min(stretch[e], 8.0);\n            }\n        }\n    }\n\n    void computeImportance() {\n        double sumLoad = 0.0;\n        for (auto x : load) sumLoad += (double)x;\n        double meanLoad = max(1.0, sumLoad / max(1, M));\n\n        double avgW = 0.0;\n        for (const auto& e : edges) avgW += e.w;\n        avgW /= max(1, M);\n\n        vector<double> raw(M);\n        double sumRaw = 0.0;\n\n        for (int e = 0; e < M; e++) {\n            double r = (double)load[e] + 0.05 * meanLoad + 1.0;\n            r *= 1.0 + 0.7 * min(5.0, stretch[e]);\n            r *= 1.0 + 0.03 * min(50, (int)cutAdj[e].size());\n            r *= 0.75 + 0.25 * sqrt(max(0.1, edges[e].w / avgW));\n            raw[e] = r;\n            sumRaw += r;\n        }\n\n        double meanRaw = max(1e-9, sumRaw / max(1, M));\n        impNorm.assign(M, 1.0);\n        for (int e = 0; e < M; e++) {\n            impNorm[e] = raw[e] / meanRaw;\n            impNorm[e] = min(60.0, max(0.03, impNorm[e]));\n        }\n    }\n\n    vector<int> selectSources(int P) {\n        P = min(P, N);\n        vector<pair<uint32_t, int>> ord;\n        ord.reserve(N);\n        for (int i = 0; i < N; i++) {\n            int hx = xs[i] * 2047 / 1000;\n            int hy = ys[i] * 2047 / 1000;\n            ord.push_back({zOrder(hx, hy), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        vector<int> res;\n        vector<char> used(N, 0);\n        for (int t = 0; t < P; t++) {\n            int idx = (int)(((long long)(2 * t + 1) * N) / (2 * P));\n            idx = min(idx, N - 1);\n            int v = ord[idx].second;\n            if (used[v]) {\n                for (int k = 0; k < N; k++) {\n                    int nv = ord[(idx + k) % N].second;\n                    if (!used[nv]) {\n                        v = nv;\n                        break;\n                    }\n                }\n            }\n            used[v] = 1;\n            res.push_back(v);\n        }\n        return res;\n    }\n\n    bool isConnectedSkip(const vector<int>& assign, int day, int extraSkip = -1) {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            fill(bfsVis.begin(), bfsVis.end(), 0);\n            bfsStamp = 1;\n        }\n\n        int head = 0, tail = 0;\n        bfsVis[0] = bfsStamp;\n        bfsQ[tail++] = 0;\n        int seen = 1;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            for (const auto& a : adj[v]) {\n                if (a.id == extraSkip) continue;\n                if (assign[a.id] == day) continue;\n                int to = a.to;\n                if (bfsVis[to] == bfsStamp) continue;\n                bfsVis[to] = bfsStamp;\n                bfsQ[tail++] = to;\n                seen++;\n            }\n        }\n        return seen == N;\n    }\n\n    long long computeDayScore(\n        const vector<int>& assign,\n        int day,\n        const vector<int>& sources,\n        int removedCount,\n        bool checkConn\n    ) {\n        if (removedCount == 0) return 0;\n        if (checkConn && !isConnectedSkip(assign, day, -1)) return DISCONN_SCORE;\n\n        long long sum = 0;\n        for (int s : sources) {\n            dijkstraDaySource(s, day, assign, distBuf);\n            int base = s * N;\n            for (int v = 0; v < N; v++) {\n                int d = distBuf[v];\n                int dd = (d >= INF ? UNREACH : d);\n                int diff = dd - origDist[base + v];\n                if (diff > 0) sum += diff;\n            }\n        }\n        return sum;\n    }\n\n    ScoreRes scoreAll(const vector<int>& assign, const vector<int>& sources) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n            cnt[assign[e]]++;\n        }\n\n        ScoreRes r;\n        r.total = 0;\n        r.day.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            r.day[d] = computeDayScore(assign, d, sources, cnt[d], true);\n            r.total += r.day[d];\n        }\n        return r;\n    }\n\n    void shuffleVec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int localCellCount(const vector<int>& cellCnt, int day, int cell) const {\n        int s = 0;\n        int base = day * C;\n        for (int nb : neighCells[cell]) s += cellCnt[base + nb];\n        return s;\n    }\n\n    vector<int> buildHilbertLike(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0 || variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                int ax = xs[edges[a].u] + xs[edges[a].v];\n                int bx = xs[edges[b].u] + xs[edges[b].v];\n                if (ax != bx) return ax < bx;\n                int ay = ys[edges[a].u] + ys[edges[a].v];\n                int by = ys[edges[b].u] + ys[edges[b].v];\n                return ay < by;\n            });\n        }\n\n        vector<int> assign(M, 0);\n        vector<int> perm(D);\n        for (int b = 0; b < M; b += D) {\n            iota(perm.begin(), perm.end(), 0);\n            if (variant == 0) {\n                rotate(perm.begin(), perm.begin() + ((b / D) % D), perm.end());\n            } else {\n                shuffleVec(perm);\n            }\n            for (int i = 0; i < D && b + i < M; i++) {\n                assign[order[b + i]] = perm[i];\n            }\n        }\n        return assign;\n    }\n\n    vector<int> buildRandomBalanced() {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffleVec(order);\n\n        vector<int> days;\n        days.reserve(M);\n        for (int d = 0; d < D; d++) {\n            for (int i = 0; i < target[d]; i++) days.push_back(d);\n        }\n        shuffleVec(days);\n\n        vector<int> assign(M);\n        for (int i = 0; i < M; i++) assign[order[i]] = days[i];\n        return assign;\n    }\n\n    vector<int> buildGreedy(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (impNorm[a] != impNorm[b]) return impNorm[a] > impNorm[b];\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (cutAdj[a].size() != cutAdj[b].size()) return cutAdj[a].size() > cutAdj[b].size();\n                return impNorm[a] > impNorm[b];\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 3) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            vector<double> key(M);\n            for (int e = 0; e < M; e++) key[e] = impNorm[e] * (0.6 + 0.8 * rng.nextDouble());\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        }\n\n        vector<int> assign(M, -1);\n        vector<int> count(D, 0);\n        vector<int> inc(N * D, 0);\n        vector<double> dayImp(D, 0.0);\n        vector<int> cellCnt(D * C, 0);\n        vector<int> cutCnt(M * D, 0);\n\n        for (int e : order) {\n            int u = edges[e].u, v = edges[e].v;\n            int cell = edges[e].cell;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(D);\n\n            for (int d = 0; d < D; d++) {\n                if (count[d] >= K) continue;\n\n                int adjCnt = inc[u * D + d] + inc[v * D + d];\n                int loc = localCellCount(cellCnt, d, cell);\n                int cut = cutCnt[e * D + d];\n\n                double over = max(0, count[d] + 1 - target[d]);\n                double cost = 100000000.0 * cut;\n                cost += 25.0 * adjCnt;\n                cost += 2.0 * loc;\n                cost += 4.0 * impNorm[e] * (dayImp[d] / max(1, target[d]));\n                if (count[d] >= target[d]) cost += 600.0 * over * over;\n                else cost += 0.1 * (double)count[d] / max(1, target[d]);\n                cost += 0.01 * rng.nextDouble();\n\n                cand.push_back({cost, d});\n            }\n\n            if (cand.empty()) {\n                // Should never happen because total capacity is sufficient.\n                int best = min_element(count.begin(), count.end()) - count.begin();\n                cand.push_back({0.0, best});\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int chosen = -1;\n            for (auto [cost, d] : cand) {\n                if (isConnectedSkip(assign, d, e)) {\n                    chosen = d;\n                    break;\n                }\n            }\n            if (chosen == -1) chosen = cand[0].second;\n\n            assign[e] = chosen;\n            count[chosen]++;\n            inc[u * D + chosen]++;\n            inc[v * D + chosen]++;\n            dayImp[chosen] += impNorm[e];\n            cellCnt[chosen * C + cell]++;\n            for (int g : cutAdj[e]) cutCnt[g * D + chosen]++;\n        }\n\n        return assign;\n    }\n\n    State buildState(const vector<int>& assign, const vector<int>& sources) {\n        State st;\n        st.assign = assign;\n        st.count.assign(D, 0);\n        st.dayEdges.assign(D, {});\n        st.pos.assign(M, -1);\n        st.inc.assign(N * D, 0);\n        st.dayImp.assign(D, 0.0);\n        st.cellCnt.assign(D * C, 0);\n        st.cutCnt.assign(M * D, 0);\n        st.dayScore.assign(D, 0);\n        st.totalScore = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            st.pos[e] = (int)st.dayEdges[d].size();\n            st.dayEdges[d].push_back(e);\n            st.count[d]++;\n            st.inc[edges[e].u * D + d]++;\n            st.inc[edges[e].v * D + d]++;\n            st.dayImp[d] += impNorm[e];\n            st.cellCnt[d * C + edges[e].cell]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            for (int g : cutAdj[e]) {\n                st.cutCnt[g * D + d]++;\n            }\n        }\n\n        for (int d = 0; d < D; d++) {\n            st.dayScore[d] = computeDayScore(st.assign, d, sources, st.count[d], true);\n            st.totalScore += st.dayScore[d];\n        }\n\n        return st;\n    }\n\n    bool isCutPair(int a, int b) const {\n        const auto& v = cutAdj[a];\n        return binary_search(v.begin(), v.end(), b);\n    }\n\n    int shareCount(int a, int b) const {\n        int c = 0;\n        if (edges[a].u == edges[b].u || edges[a].u == edges[b].v) c++;\n        if (edges[a].v == edges[b].u || edges[a].v == edges[b].v) c++;\n        return c;\n    }\n\n    double placeCost(const State& st, int e, int d, int removeY) {\n        bool inD = (st.assign[e] == d);\n        int u = edges[e].u, v = edges[e].v;\n        int adjCnt = st.inc[u * D + d] + st.inc[v * D + d];\n        if (inD) adjCnt -= 2;\n        if (removeY >= 0 && st.assign[removeY] == d) {\n            adjCnt -= shareCount(e, removeY);\n        }\n        adjCnt = max(0, adjCnt);\n\n        int cut = st.cutCnt[e * D + d];\n        if (removeY >= 0 && st.assign[removeY] == d && isCutPair(e, removeY)) cut--;\n        cut = max(0, cut);\n\n        int loc = localCellCount(st.cellCnt, d, edges[e].cell);\n        if (inD) loc--;\n        if (removeY >= 0 && st.assign[removeY] == d &&\n            nearCell[edges[e].cell * C + edges[removeY].cell]) {\n            loc--;\n        }\n        loc = max(0, loc);\n\n        double impSum = st.dayImp[d];\n        if (inD) impSum -= impNorm[e];\n        if (removeY >= 0 && st.assign[removeY] == d) impSum -= impNorm[removeY];\n        impSum = max(0.0, impSum);\n\n        double cost = 1000000.0 * cut;\n        cost += 10.0 * adjCnt;\n        cost += 1.5 * loc;\n        cost += 2.0 * impNorm[e] * (impSum / max(1, target[d]));\n        return cost;\n    }\n\n    double edgeBadness(const State& st, int e, int d) {\n        return placeCost(st, e, d, -1) + 0.5 * impNorm[e];\n    }\n\n    int randomNonemptyDay(const State& st, int exclude = -1) {\n        for (int t = 0; t < 50; t++) {\n            int d = rng.nextInt(D);\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        for (int d = 0; d < D; d++) {\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        return -1;\n    }\n\n    int argMaxDay(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int d = 0; d < D; d++) {\n            if (st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int argMinDay(const State& st, int exclude = -1, bool requireNonempty = true) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int d = 0; d < D; d++) {\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int tournamentHigh(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int i = 0; i < 5; i++) {\n            int d = randomNonemptyDay(st);\n            if (d == -1) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMaxDay(st);\n        return best;\n    }\n\n    int tournamentLow(const State& st, int exclude, bool requireNonempty) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int i = 0; i < 5; i++) {\n            int d = rng.nextInt(D);\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMinDay(st, exclude, requireNonempty);\n        return best;\n    }\n\n    int selectEdge(const State& st, int day, bool bad) {\n        const auto& v = st.dayEdges[day];\n        if (v.empty()) return -1;\n\n        int best = v[rng.nextInt((int)v.size())];\n        double bv = edgeBadness(st, best, day);\n\n        int samples = min(7, (int)v.size());\n        for (int i = 1; i < samples; i++) {\n            int e = v[rng.nextInt((int)v.size())];\n            double val = edgeBadness(st, e, day);\n            if ((bad && val > bv) || (!bad && val < bv)) {\n                bv = val;\n                best = e;\n            }\n        }\n        return best;\n    }\n\n    double cheapDeltaSwap(const State& st, int e, int f) {\n        int a = st.assign[e], b = st.assign[f];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1) + placeCost(st, f, b, -1);\n        double after = placeCost(st, e, b, f) + placeCost(st, f, a, e);\n        return after - before;\n    }\n\n    double cheapDeltaMove(const State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1);\n        double after = placeCost(st, e, b, -1);\n        return after - before;\n    }\n\n    Cand proposeSwap(const State& st) {\n        Cand best;\n        best.type = 2;\n\n        for (int t = 0; t < 14; t++) {\n            int a, b;\n            int mode = rng.nextInt(100);\n\n            if (mode < 45) {\n                a = argMaxDay(st);\n                b = argMinDay(st, a, true);\n            } else if (mode < 80) {\n                a = tournamentHigh(st);\n                b = tournamentLow(st, a, true);\n            } else {\n                a = randomNonemptyDay(st);\n                b = randomNonemptyDay(st, a);\n            }\n\n            if (a < 0 || b < 0 || a == b) continue;\n\n            int e = selectEdge(st, a, true);\n            int f = selectEdge(st, b, false);\n            if (e < 0 || f < 0) continue;\n\n            double cd = cheapDeltaSwap(st, e, f);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = f;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    Cand proposeMove(const State& st) {\n        Cand best;\n        best.type = 1;\n\n        int lowBound = max(0, M / D - 2);\n        int highBound = min(K, (M + D - 1) / D + 2);\n\n        for (int t = 0; t < 12; t++) {\n            int a = -1;\n            long long av = LLONG_MIN;\n\n            if (rng.nextInt(100) < 60) {\n                for (int d = 0; d < D; d++) {\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            } else {\n                for (int k = 0; k < 8; k++) {\n                    int d = rng.nextInt(D);\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            }\n\n            if (a < 0) continue;\n\n            int b = -1;\n            long long bv = LLONG_MAX;\n            for (int k = 0; k < 8; k++) {\n                int d = rng.nextInt(D);\n                if (d == a) continue;\n                if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                if (st.dayScore[d] < bv) {\n                    bv = st.dayScore[d];\n                    b = d;\n                }\n            }\n            if (b < 0) {\n                for (int d = 0; d < D; d++) {\n                    if (d == a) continue;\n                    if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                    if (st.dayScore[d] < bv) {\n                        bv = st.dayScore[d];\n                        b = d;\n                    }\n                }\n            }\n            if (b < 0) continue;\n\n            int e = selectEdge(st, a, true);\n            if (e < 0) continue;\n\n            double cd = cheapDeltaMove(st, e, b);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = b;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    bool acceptDelta(const State& st, long long delta, bool isMove) {\n        if (delta <= 0) return true;\n\n        double avg = max(1.0, st.totalScore / (double)max(1, D));\n        double prog = min(1.0, elapsed() / localEndTime);\n        double factor = isMove ? 0.004 : 0.008;\n        double T = avg * (factor * (1.0 - prog) + 0.00002);\n\n        if (T <= 1.0) return false;\n        if ((double)delta > T * 20.0) return false;\n        return rng.nextDouble() < exp(-(double)delta / T);\n    }\n\n    void applySwap(State& st, int e, int f, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e], pf = st.pos[f];\n        st.dayEdges[a][pe] = f;\n        st.dayEdges[b][pf] = e;\n        st.pos[f] = pe;\n        st.pos[e] = pf;\n\n        auto decEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]--;\n            st.inc[edges[x].v * D + d]--;\n            st.dayImp[d] -= impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]--;\n        };\n        auto incEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]++;\n            st.inc[edges[x].v * D + d]++;\n            st.dayImp[d] += impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]++;\n        };\n\n        decEdge(e, a); incEdge(e, b);\n        decEdge(f, b); incEdge(f, a);\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n        for (int g : cutAdj[f]) {\n            st.cutCnt[g * D + b]--;\n            st.cutCnt[g * D + a]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    void applyMove(State& st, int e, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e];\n        int last = st.dayEdges[a].back();\n        st.dayEdges[a][pe] = last;\n        st.pos[last] = pe;\n        st.dayEdges[a].pop_back();\n\n        st.pos[e] = (int)st.dayEdges[b].size();\n        st.dayEdges[b].push_back(e);\n\n        st.count[a]--;\n        st.count[b]++;\n\n        st.inc[edges[e].u * D + a]--;\n        st.inc[edges[e].v * D + a]--;\n        st.inc[edges[e].u * D + b]++;\n        st.inc[edges[e].v * D + b]++;\n\n        st.dayImp[a] -= impNorm[e];\n        st.dayImp[b] += impNorm[e];\n\n        st.cellCnt[a * C + edges[e].cell]--;\n        st.cellCnt[b * C + edges[e].cell]++;\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    bool trySwap(State& st, int e, int f) {\n        int a = st.assign[e];\n        int b = st.assign[f];\n        if (a == b) return false;\n\n        st.assign[e] = b;\n        st.assign[f] = a;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a], false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b], false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, false);\n\n        if (acc) {\n            applySwap(st, e, f, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            st.assign[f] = b;\n            return false;\n        }\n    }\n\n    bool tryMove(State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return false;\n        if (st.count[b] >= K) return false;\n\n        st.assign[e] = b;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a] - 1, false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b] + 1, false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, true);\n\n        if (acc) {\n            applyMove(st, e, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            return false;\n        }\n    }\n\n    void ensureLegal(vector<int>& assign) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) assign[e] = 0;\n            cnt[assign[e]]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            if (cnt[d] <= K) continue;\n            int b = -1;\n            for (int j = 0; j < D; j++) {\n                if (cnt[j] < K) {\n                    b = j;\n                    break;\n                }\n            }\n            if (b == -1) break;\n            cnt[d]--;\n            assign[e] = b;\n            cnt[b]++;\n        }\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        readInput();\n\n        computeOriginalAndLoad();\n        detectTwoEdgeCuts();\n        computeStretch();\n        computeImportance();\n\n        int P = 24;\n        if (D <= 10) P += 8;\n        else if (D <= 18) P += 4;\n        if (M <= 1200) P += 8;\n        else if (M <= 2000) P += 4;\n        if (N <= 700) P += 4;\n        P = min({P, N, 52});\n        optSources = selectSources(P);\n\n        vector<int> bestAssign;\n        long long bestScore = LLONG_MAX;\n\n        auto consider = [&](const vector<int>& assign) {\n            ScoreRes sc = scoreAll(assign, optSources);\n            if (sc.total < bestScore) {\n                bestScore = sc.total;\n                bestAssign = assign;\n            }\n        };\n\n        consider(buildHilbertLike(0));\n        consider(buildGreedy(0));\n\n        const double initDeadline = 2.25;\n        if (elapsed() < initDeadline) consider(buildGreedy(1));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(1));\n        if (elapsed() < initDeadline) consider(buildGreedy(2));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(2));\n        if (elapsed() < initDeadline) consider(buildGreedy(4));\n        if (elapsed() < initDeadline) consider(buildRandomBalanced());\n\n        if (bestAssign.empty()) bestAssign = buildRandomBalanced();\n\n        State st = buildState(bestAssign, optSources);\n        vector<int> bestLocal = st.assign;\n        long long bestLocalScore = st.totalScore;\n\n        localEndTime = 5.65;\n        while (elapsed() < localEndTime) {\n            Cand cand;\n            if (rng.nextInt(100) < 18) cand = proposeMove(st);\n            if (cand.type == 0) cand = proposeSwap(st);\n\n            bool accepted = false;\n            if (cand.type == 1) {\n                accepted = tryMove(st, cand.e, cand.f);\n            } else if (cand.type == 2) {\n                accepted = trySwap(st, cand.e, cand.f);\n            }\n\n            if (accepted && st.totalScore < bestLocalScore) {\n                bestLocalScore = st.totalScore;\n                bestLocal = st.assign;\n            }\n        }\n\n        ensureLegal(bestLocal);\n\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << bestLocal[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    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct I3 {\n        short x, y, z;\n    };\n    struct Rot {\n        int perm[3];\n        int sign[3];\n    };\n    struct AlignCand {\n        long long key;\n        int ori, tid, cnt, w;\n    };\n    struct AlignMinCmp {\n        bool operator()(const AlignCand& a, const AlignCand& b) const {\n            return a.key > b.key;\n        }\n    };\n    struct CompCand {\n        bool valid = false;\n        double score = -1e100;\n        int size = 0;\n        int cov = 0;\n        int ori = 0;\n        int tx = 0, ty = 0, tz = 0;\n        vector<int> cells;\n    };\n    struct Box {\n        int x = 0, y = 0, z = 0;\n        int lx = 0, ly = 0, lz = 0;\n        int cov = -1;\n        int vol = 0;\n        bool valid = false;\n    };\n    struct BoxCand {\n        bool valid = false;\n        Box b0, b1;\n        int vol = 0;\n        int cov = 0;\n        double score = -1;\n    };\n\n    int D, D2, N;\n    int rangeT, offsetT, Tcnt;\n    array<vector<string>, 2> F, Rt;\n\n    array<vector<char>, 2> allowed, rem, covF, covR;\n    array<vector<int>, 2> ans;\n    array<vector<unsigned char>, 2> aw;\n\n    vector<int> xs, ys, zs;\n    vector<array<int, 6>> neigh;\n\n    vector<Rot> rots;\n    vector<vector<I3>> rotp;\n\n    int unF[2][15];\n    int unR[2][15];\n\n    int allowedCount[2] = {0, 0};\n    int remCnt[2] = {0, 0};\n    int minAllowed = 0;\n    int totalUncov = 0;\n\n    int label = 0;\n    int commonVol = 0;\n    int uniqueVol[2] = {0, 0};\n    double commonCost = 0.0;\n\n    vector<int> cnt, wcnt;\n    vector<int> mark, vis, qmap;\n    int markToken = 1, visToken = 1;\n    array<vector<int>, 2> tmpF, tmpR;\n    int pixToken = 1;\n\n    vector<int> startTid, curTid, entries;\n\n    array<vector<vector<int>>, 2> blk;\n    vector<char> activeLab;\n\n    chrono::steady_clock::time_point startTime;\n\n    Solver(int D_, const array<vector<string>, 2>& F_, const array<vector<string>, 2>& Rt_)\n        : D(D_), F(F_), Rt(Rt_) {\n        D2 = D * D;\n        N = D * D * D;\n        rangeT = 3 * D - 2;\n        offsetT = D - 1;\n        Tcnt = rangeT * rangeT * rangeT;\n\n        memset(unF, 0, sizeof(unF));\n        memset(unR, 0, sizeof(unR));\n\n        for (int s = 0; s < 2; s++) {\n            allowed[s].assign(N, 0);\n            rem[s].assign(N, 0);\n            covF[s].assign(D2, 0);\n            covR[s].assign(D2, 0);\n            ans[s].assign(N, 0);\n            aw[s].assign(N, 0);\n            tmpF[s].assign(D2, 0);\n            tmpR[s].assign(D2, 0);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        zs.resize(N);\n        neigh.resize(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 v = id(x, y, z);\n                    xs[v] = x;\n                    ys[v] = y;\n                    zs[v] = z;\n                }\n            }\n        }\n\n        for (int v = 0; v < N; v++) {\n            int x = xs[v], y = ys[v], z = zs[v];\n            array<int, 6> nb;\n            nb.fill(-1);\n            if (x > 0) nb[0] = id(x - 1, y, z);\n            if (x + 1 < D) nb[1] = id(x + 1, y, z);\n            if (y > 0) nb[2] = id(x, y - 1, z);\n            if (y + 1 < D) nb[3] = id(x, y + 1, z);\n            if (z > 0) nb[4] = id(x, y, z - 1);\n            if (z + 1 < D) nb[5] = id(x, y, z + 1);\n            neigh[v] = nb;\n        }\n\n        for (int s = 0; s < 2; s++) {\n            for (int z = 0; z < D; z++) {\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1') {\n                        unF[s][z]++;\n                        totalUncov++;\n                    }\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1') {\n                        unR[s][z]++;\n                        totalUncov++;\n                    }\n                }\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                        if (F[s][z][x] == '1' && Rt[s][z][y] == '1') {\n                            int v = id(x, y, z);\n                            allowed[s][v] = 1;\n                            rem[s][v] = 1;\n                            allowedCount[s]++;\n                        }\n                    }\n                }\n            }\n            remCnt[s] = allowedCount[s];\n        }\n\n        minAllowed = min(allowedCount[0], allowedCount[1]);\n\n        generateRotations();\n        rotp.assign(rots.size(), vector<I3>(N));\n        for (int ri = 0; ri < (int)rots.size(); ri++) {\n            for (int v = 0; v < N; v++) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) {\n                    q[a] = rots[ri].sign[a] * p[rots[ri].perm[a]];\n                }\n                rotp[ri][v] = I3{(short)q[0], (short)q[1], (short)q[2]};\n            }\n        }\n\n        cnt.assign(Tcnt, 0);\n        wcnt.assign(Tcnt, 0);\n        startTid.assign(Tcnt, 0);\n        curTid.assign(Tcnt, 0);\n        mark.assign(N, 0);\n        vis.assign(N, 0);\n        qmap.assign(N, -1);\n    }\n\n    inline int id(int x, int y, int z) const {\n        return (x * D + y) * D + z;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void generateRotations() {\n        array<int, 3> p = {0, 1, 2};\n        sort(p.begin(), p.end());\n        do {\n            int inv = 0;\n            for (int i = 0; i < 3; i++) {\n                for (int j = i + 1; j < 3; j++) {\n                    if (p[i] > p[j]) inv++;\n                }\n            }\n            int parity = (inv % 2 == 0 ? 1 : -1);\n            for (int sx : {-1, 1}) {\n                for (int sy : {-1, 1}) {\n                    for (int sz : {-1, 1}) {\n                        if (parity * sx * sy * sz == 1) {\n                            Rot r;\n                            r.perm[0] = p[0];\n                            r.perm[1] = p[1];\n                            r.perm[2] = p[2];\n                            r.sign[0] = sx;\n                            r.sign[1] = sy;\n                            r.sign[2] = sz;\n                            rots.push_back(r);\n                        }\n                    }\n                }\n            }\n        } while (next_permutation(p.begin(), p.end()));\n    }\n\n    inline int activeWeight(int s, int v) const {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int w = 0;\n        if (!covF[s][z * D + x]) w++;\n        if (!covR[s][z * D + y]) w++;\n        return w;\n    }\n\n    void coverCell(int s, int v) {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int fid = z * D + x;\n        int rid = z * D + y;\n\n        if (F[s][z][x] == '1' && !covF[s][fid]) {\n            covF[s][fid] = 1;\n            unF[s][z]--;\n            totalUncov--;\n        }\n        if (Rt[s][z][y] == '1' && !covR[s][rid]) {\n            covR[s][rid] = 1;\n            unR[s][z]--;\n            totalUncov--;\n        }\n    }\n\n    int calcLBNow(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += max(unF[s][z], unR[s][z]);\n        return res;\n    }\n\n    int calcLBAfter(int s, const int* nf, const int* nr) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) {\n            int a = unF[s][z] - nf[z];\n            int b = unR[s][z] - nr[z];\n            if (a < 0) a = 0;\n            if (b < 0) b = 0;\n            res += max(a, b);\n        }\n        return res;\n    }\n\n    void decodeTid(int tid, int& tx, int& ty, int& tz) const {\n        tz = tid % rangeT;\n        tid /= rangeT;\n        ty = tid % rangeT;\n        tx = tid / rangeT;\n        tx -= offsetT;\n        ty -= offsetT;\n        tz -= offsetT;\n    }\n\n    void evalAlignment(int ori, int tid, const vector<int>& list0, CompCand& best) {\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        int inter = 0;\n\n        for (int p : list0) {\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            if (0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D) {\n                int q = id(qx, qy, qz);\n                if (rem[1][q]) {\n                    mark[p] = mt;\n                    qmap[p] = q;\n                    inter++;\n                }\n            }\n        }\n        if (inter == 0) return;\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(inter);\n        comp.reserve(inter);\n\n        for (int st : list0) {\n            if (mark[st] != mt || vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int v : comp) {\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n            }\n\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int remCap = min(remCnt[0], remCnt[1]) - sz;\n            int def = max(0, max(lb0, lb1) - remCap);\n\n            double score = (double)cov * sz;\n            score /= (1.0 + 0.05 * def);\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponent(int topK, double timeLimit) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if (list0.empty() || list1.empty()) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        priority_queue<AlignCand, vector<AlignCand>, AlignMinCmp> pq1, pq2;\n\n        auto consider = [&](auto& pq, const AlignCand& a) {\n            if ((int)pq.size() < topK) {\n                pq.push(a);\n            } else if (a.key > pq.top().key) {\n                pq.pop();\n                pq.push(a);\n            }\n        };\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int awp = aw[0][p];\n                for (int j = 0; j < n1; j++) {\n                    int tx = qx[j] - rp.x + offsetT;\n                    int ty = qy[j] - rp.y + offsetT;\n                    int tz = qz[j] - rp.z + offsetT;\n                    int tid = (tx * rangeT + ty) * rangeT + tz;\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            for (int tid = 0; tid < Tcnt; tid++) {\n                if (wcnt[tid] == 0) continue;\n                int c = cnt[tid];\n                int w = wcnt[tid];\n                consider(pq1, AlignCand{1LL * c * (w + 1), oi, tid, c, w});\n                consider(pq2, AlignCand{1LL * c * c, oi, tid, c, w});\n            }\n\n            if (elapsed() > timeLimit) break;\n        }\n\n        vector<AlignCand> aligns;\n        while (!pq1.empty()) {\n            aligns.push_back(pq1.top());\n            pq1.pop();\n        }\n        while (!pq2.empty()) {\n            aligns.push_back(pq2.top());\n            pq2.pop();\n        }\n\n        sort(aligns.begin(), aligns.end(), [](const AlignCand& a, const AlignCand& b) {\n            return a.key > b.key;\n        });\n\n        unordered_set<long long> seen;\n        seen.reserve(aligns.size() * 2 + 1);\n\n        int evalCnt = 0;\n        for (const auto& a : aligns) {\n            long long code = 1LL * a.ori * Tcnt + a.tid;\n            if (!seen.insert(code).second) continue;\n            evalAlignment(a.ori, a.tid, list0, best);\n            evalCnt++;\n            if (evalCnt >= topK) break;\n            if (elapsed() > timeLimit) break;\n        }\n\n        return best;\n    }\n\n    void evalBucketAlignment(int ori, int tid, int l, int r, int minSize, int oldNeed, CompCand& best) {\n        if (r - l < minSize) return;\n\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        for (int idx = l; idx < r; idx++) {\n            int p = entries[idx];\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            mark[p] = mt;\n            qmap[p] = id(qx, qy, qz);\n        }\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(r - l);\n        comp.reserve(r - l);\n\n        for (int idx = l; idx < r; idx++) {\n            int st = entries[idx];\n            if (vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            if (sz < minSize) continue;\n\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int v : comp) {\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n            }\n\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int newNeed = max(lb0, lb1);\n            int gainNeed = max(0, oldNeed - newNeed);\n            int cap = min(remCnt[0], remCnt[1]) - sz;\n            int def = max(0, newNeed - cap);\n\n            double score =\n                10.0 * gainNeed\n                + 1.0 * cov\n                + 0.7 * log((double)sz + 1.0)\n                + 0.3 * (1.0 - 1.0 / sz)\n                - 5.0 * def\n                + 0.0001 * sz;\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponentExhaustive(double deadline, int minSize) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if ((int)list0.size() < minSize || (int)list1.size() < minSize) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        int oldNeed = max(calcLBNow(0), calcLBNow(1));\n        vector<int> activeTids;\n        activeTids.reserve(Tcnt);\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            if (elapsed() > deadline) break;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n            activeTids.clear();\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n                int awp = aw[0][p];\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    if (cnt[tid] == 0) activeTids.push_back(tid);\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            int total = 0;\n            for (int tid : activeTids) {\n                startTid[tid] = total;\n                curTid[tid] = total;\n                total += cnt[tid];\n            }\n\n            entries.resize(total);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    entries[curTid[tid]++] = p;\n                }\n            }\n\n            for (int tid : activeTids) {\n                if (wcnt[tid] == 0 || cnt[tid] < minSize) continue;\n                evalBucketAlignment(oi, tid, startTid[tid], startTid[tid] + cnt[tid], minSize, oldNeed, best);\n                if (elapsed() > deadline) break;\n            }\n        }\n\n        return best;\n    }\n\n    void placeCommonMapped(const CompCand& c) {\n        int lab = ++label;\n        int sz = (int)c.cells.size();\n\n        for (int p : c.cells) {\n            I3 rp = rotp[c.ori][p];\n            int qx = rp.x + c.tx;\n            int qy = rp.y + c.ty;\n            int qz = rp.z + c.tz;\n            int q = id(qx, qy, qz);\n\n            ans[0][p] = lab;\n            rem[0][p] = 0;\n            coverCell(0, p);\n\n            ans[1][q] = lab;\n            rem[1][q] = 0;\n            coverCell(1, q);\n        }\n\n        remCnt[0] -= sz;\n        remCnt[1] -= sz;\n        commonVol += sz;\n        commonCost += 1.0 / sz;\n    }\n\n    inline int p3id(int x, int y, int z) const {\n        int P = D + 1;\n        return (x * P + y) * P + z;\n    }\n\n    inline int p2id(int a, int b) const {\n        int P = D + 1;\n        return a * P + b;\n    }\n\n    int query3(const vector<int>& ps, int x0, int x1, int y0, int y1, int z0, int z1) const {\n        return ps[p3id(x1, y1, z1)]\n             - ps[p3id(x0, y1, z1)]\n             - ps[p3id(x1, y0, z1)]\n             - ps[p3id(x1, y1, z0)]\n             + ps[p3id(x0, y0, z1)]\n             + ps[p3id(x0, y1, z0)]\n             + ps[p3id(x1, y0, z0)]\n             - ps[p3id(x0, y0, z0)];\n    }\n\n    int query2(const vector<int>& ps, int a0, int a1, int b0, int b1) const {\n        return ps[p2id(a1, b1)]\n             - ps[p2id(a0, b1)]\n             - ps[p2id(a1, b0)]\n             + ps[p2id(a0, b0)];\n    }\n\n    void buildPrefix3(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P * P, 0);\n        for (int x = 1; x <= D; x++) {\n            for (int y = 1; y <= D; y++) {\n                for (int z = 1; z <= D; z++) {\n                    int val = rem[s][id(x - 1, y - 1, z - 1)] ? 1 : 0;\n                    ps[p3id(x, y, z)] =\n                        val\n                        + ps[p3id(x - 1, y, z)]\n                        + ps[p3id(x, y - 1, z)]\n                        + ps[p3id(x, y, z - 1)]\n                        - ps[p3id(x - 1, y - 1, z)]\n                        - ps[p3id(x - 1, y, z - 1)]\n                        - ps[p3id(x, y - 1, z - 1)]\n                        + ps[p3id(x - 1, y - 1, z - 1)];\n                }\n            }\n        }\n    }\n\n    void buildPrefix2F(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int x = 1; x <= D; x++) {\n                int val = (F[s][z - 1][x - 1] == '1' && !covF[s][(z - 1) * D + (x - 1)]) ? 1 : 0;\n                ps[p2id(z, x)] =\n                    val + ps[p2id(z - 1, x)] + ps[p2id(z, x - 1)] - ps[p2id(z - 1, x - 1)];\n            }\n        }\n    }\n\n    void buildPrefix2R(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int y = 1; y <= D; y++) {\n                int val = (Rt[s][z - 1][y - 1] == '1' && !covR[s][(z - 1) * D + (y - 1)]) ? 1 : 0;\n                ps[p2id(z, y)] =\n                    val + ps[p2id(z - 1, y)] + ps[p2id(z, y - 1)] - ps[p2id(z - 1, y - 1)];\n            }\n        }\n    }\n\n    int shapeKey(int a, int b, int c) const {\n        if (a > b) swap(a, b);\n        if (b > c) swap(b, c);\n        if (a > b) swap(a, b);\n        return (a * 15 + b) * 15 + c;\n    }\n\n    void enumerateBoxesSide(int s, vector<Box>& best, double timeLimit) {\n        vector<int> ps3, psF, psR;\n        buildPrefix3(s, ps3);\n        buildPrefix2F(s, psF);\n        buildPrefix2R(s, psR);\n\n        for (int x0 = 0; x0 < D; x0++) {\n            if (elapsed() > timeLimit) return;\n            for (int x1 = x0 + 1; x1 <= D; x1++) {\n                int lx = x1 - x0;\n                for (int y0 = 0; y0 < D; y0++) {\n                    for (int y1 = y0 + 1; y1 <= D; y1++) {\n                        int ly = y1 - y0;\n                        for (int z0 = 0; z0 < D; z0++) {\n                            for (int z1 = z0 + 1; z1 <= D; z1++) {\n                                int lz = z1 - z0;\n                                int vol = lx * ly * lz;\n                                if (vol < 2) continue;\n\n                                if (query3(ps3, x0, x1, y0, y1, z0, z1) != vol) continue;\n\n                                int cov =\n                                    query2(psF, z0, z1, x0, x1)\n                                    + query2(psR, z0, z1, y0, y1);\n\n                                int key = shapeKey(lx, ly, lz);\n                                if (!best[key].valid || cov > best[key].cov) {\n                                    Box b;\n                                    b.x = x0;\n                                    b.y = y0;\n                                    b.z = z0;\n                                    b.lx = lx;\n                                    b.ly = ly;\n                                    b.lz = lz;\n                                    b.cov = cov;\n                                    b.vol = vol;\n                                    b.valid = true;\n                                    best[key] = b;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    BoxCand findBestCuboid(double timeLimit) {\n        const int KEY = 15 * 15 * 15;\n        vector<Box> best0(KEY), best1(KEY);\n\n        enumerateBoxesSide(0, best0, timeLimit);\n        if (elapsed() > timeLimit) return BoxCand();\n        enumerateBoxesSide(1, best1, timeLimit);\n\n        BoxCand res;\n        for (int k = 0; k < KEY; k++) {\n            if (!best0[k].valid || !best1[k].valid) continue;\n            int cov = best0[k].cov + best1[k].cov;\n            if (cov <= 0) continue;\n            int vol = best0[k].vol;\n            double score = (double)cov * vol;\n            if (!res.valid || score > res.score || (abs(score - res.score) < 1e-9 && vol > res.vol)) {\n                res.valid = true;\n                res.b0 = best0[k];\n                res.b1 = best1[k];\n                res.vol = vol;\n                res.cov = cov;\n                res.score = score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBox(const Box& b0, const Box& b1) {\n        int lab = ++label;\n        int vol = b0.vol;\n\n        auto put = [&](int s, const Box& b) {\n            for (int x = b.x; x < b.x + b.lx; x++) {\n                for (int y = b.y; y < b.y + b.ly; y++) {\n                    for (int z = b.z; z < b.z + b.lz; z++) {\n                        int v = id(x, y, z);\n                        ans[s][v] = lab;\n                        rem[s][v] = 0;\n                        coverCell(s, v);\n                    }\n                }\n            }\n        };\n\n        put(0, b0);\n        put(1, b1);\n\n        remCnt[0] -= vol;\n        remCnt[1] -= vol;\n        commonVol += vol;\n        commonCost += 1.0 / vol;\n    }\n\n    int findBestCell(int s, bool needActive) const {\n        int best = -1;\n        int bestW = needActive ? 0 : 100;\n        for (int v = 0; v < N; v++) {\n            if (!rem[s][v]) continue;\n            int w = activeWeight(s, v);\n            if (needActive) {\n                if (w > bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            } else {\n                if (best == -1 || w < bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            }\n        }\n        return best;\n    }\n\n    void placeCommonUnit(int a, int b) {\n        int lab = ++label;\n        ans[0][a] = lab;\n        rem[0][a] = 0;\n        coverCell(0, a);\n\n        ans[1][b] = lab;\n        rem[1][b] = 0;\n        coverCell(1, b);\n\n        remCnt[0]--;\n        remCnt[1]--;\n        commonVol += 1;\n        commonCost += 1.0;\n    }\n\n    bool placeUniqueCell(int s, int v) {\n        if (v < 0 || !rem[s][v]) return false;\n        int lab = ++label;\n        ans[s][v] = lab;\n        rem[s][v] = 0;\n        coverCell(s, v);\n        remCnt[s]--;\n        uniqueVol[s]++;\n        return true;\n    }\n\n    void placeCommonUnits() {\n        while (totalUncov > 0) {\n            int a0 = findBestCell(0, true);\n            int a1 = findBestCell(1, true);\n\n            if (a0 == -1 && a1 == -1) break;\n\n            if (a0 != -1 && a1 != -1) {\n                placeCommonUnit(a0, a1);\n            } else if (a0 != -1) {\n                int b = findBestCell(1, false);\n                if (b == -1) break;\n                placeCommonUnit(a0, b);\n            } else {\n                int a = findBestCell(0, false);\n                if (a == -1) break;\n                placeCommonUnit(a, a1);\n            }\n        }\n    }\n\n    int sideUncovered(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += unF[s][z] + unR[s][z];\n        return res;\n    }\n\n    int chooseCell(int s, int z, int x, int y) const {\n        if (x >= 0 && y >= 0) {\n            int v = id(x, y, z);\n            if (rem[s][v]) return v;\n        }\n        if (x >= 0) {\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] == '1') {\n                    int v = id(x, yy, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        if (y >= 0) {\n            for (int xx = 0; xx < D; xx++) {\n                if (F[s][z][xx] == '1') {\n                    int v = id(xx, y, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        for (int xx = 0; xx < D; xx++) {\n            if (F[s][z][xx] != '1') continue;\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] != '1') continue;\n                int v = id(xx, yy, z);\n                if (rem[s][v]) return v;\n            }\n        }\n        return -1;\n    }\n\n    void fillUnique(int s) {\n        int guard = 0;\n        while (sideUncovered(s) > 0 && guard++ < 1000) {\n            bool progress = false;\n\n            for (int z = 0; z < D; z++) {\n                vector<int> X, Y;\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1' && !covF[s][z * D + x]) X.push_back(x);\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) Y.push_back(y);\n                }\n\n                if (X.empty() && Y.empty()) continue;\n\n                if (!X.empty() && !Y.empty()) {\n                    int m = max((int)X.size(), (int)Y.size());\n                    for (int k = 0; k < m; k++) {\n                        int x = (k < (int)X.size() ? X[k] : X[0]);\n                        int y = (k < (int)Y.size() ? Y[k] : Y[0]);\n                        int v = chooseCell(s, z, x, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else if (!X.empty()) {\n                    for (int x : X) {\n                        int v = chooseCell(s, z, x, -1);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else {\n                    for (int y : Y) {\n                        int v = chooseCell(s, z, -1, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                }\n            }\n\n            if (!progress) {\n                int v = findBestCell(s, true);\n                if (!placeUniqueCell(s, v)) break;\n            }\n        }\n    }\n\n    void finalRepair() {\n        for (int s = 0; s < 2; s++) {\n            int guard = 0;\n            while (sideUncovered(s) > 0 && guard++ < 1000) {\n                bool progress = false;\n                for (int z = 0; z < D; z++) {\n                    for (int x = 0; x < D; x++) {\n                        if (F[s][z][x] == '1' && !covF[s][z * D + x]) {\n                            int v = chooseCell(s, z, x, -1);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                    for (int y = 0; y < D; y++) {\n                        if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) {\n                            int v = chooseCell(s, z, -1, y);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                }\n                if (!progress) break;\n            }\n        }\n    }\n\n    void buildBlockLists() {\n        for (int s = 0; s < 2; s++) {\n            blk[s].assign(label + 1, vector<int>());\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0) blk[s][a].push_back(v);\n            }\n        }\n\n        activeLab.assign(label + 1, 0);\n        for (int l = 1; l <= label; l++) {\n            if (!blk[0][l].empty() || !blk[1][l].empty()) activeLab[l] = 1;\n        }\n    }\n\n    bool isCommonLabel(int l) const {\n        return l > 0\n            && l < (int)activeLab.size()\n            && activeLab[l]\n            && !blk[0][l].empty()\n            && !blk[1][l].empty();\n    }\n\n    vector<int> canonicalShape(const vector<int>& cells) const {\n        vector<int> best;\n        bool first = true;\n        vector<array<int, 3>> tmp;\n        vector<int> enc;\n        tmp.reserve(cells.size());\n        enc.reserve(cells.size());\n\n        for (const Rot& rr : rots) {\n            tmp.clear();\n            int mn[3] = {INT_MAX, INT_MAX, INT_MAX};\n\n            for (int v : cells) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) {\n                    q[a] = rr.sign[a] * p[rr.perm[a]];\n                    mn[a] = min(mn[a], q[a]);\n                }\n                tmp.push_back({q[0], q[1], q[2]});\n            }\n\n            enc.clear();\n            for (auto t : tmp) {\n                int a = t[0] - mn[0];\n                int b = t[1] - mn[1];\n                int c = t[2] - mn[2];\n                enc.push_back((a * 64 + b) * 64 + c);\n            }\n            sort(enc.begin(), enc.end());\n\n            if (first || enc < best) {\n                first = false;\n                best = enc;\n            }\n        }\n\n        return best;\n    }\n\n    void pairUniqueUnits() {\n        vector<int> u0, u1;\n        for (int l = 1; l <= label; l++) {\n            if (!activeLab[l]) continue;\n            if (blk[0][l].size() == 1 && blk[1][l].empty()) u0.push_back(l);\n            if (blk[1][l].size() == 1 && blk[0][l].empty()) u1.push_back(l);\n        }\n\n        int m = min((int)u0.size(), (int)u1.size());\n        for (int i = 0; i < m; i++) {\n            int a = u0[i];\n            int b = u1[i];\n            if (!activeLab[a] || !activeLab[b]) continue;\n            if (blk[0][a].size() != 1 || !blk[1][a].empty()) continue;\n            if (blk[1][b].size() != 1 || !blk[0][b].empty()) continue;\n\n            int v = blk[1][b][0];\n            blk[1][a].push_back(v);\n            ans[1][v] = a;\n\n            blk[1][b].clear();\n            activeLab[b] = 0;\n        }\n    }\n\n    bool canMergeCommon(int a, int b) const {\n        if (!isCommonLabel(a) || !isCommonLabel(b)) return false;\n        if (blk[0][a].size() != blk[1][a].size()) return false;\n        if (blk[0][b].size() != blk[1][b].size()) return false;\n\n        vector<int> u0, u1;\n        u0.reserve(blk[0][a].size() + blk[0][b].size());\n        u1.reserve(blk[1][a].size() + blk[1][b].size());\n\n        u0.insert(u0.end(), blk[0][a].begin(), blk[0][a].end());\n        u0.insert(u0.end(), blk[0][b].begin(), blk[0][b].end());\n        u1.insert(u1.end(), blk[1][a].begin(), blk[1][a].end());\n        u1.insert(u1.end(), blk[1][b].begin(), blk[1][b].end());\n\n        if (u0.size() != u1.size()) return false;\n        return canonicalShape(u0) == canonicalShape(u1);\n    }\n\n    void mergeCommonLabels(int a, int b) {\n        if ((int)blk[0][a].size() < (int)blk[0][b].size()) swap(a, b);\n\n        for (int s = 0; s < 2; s++) {\n            for (int v : blk[s][b]) {\n                ans[s][v] = a;\n                blk[s][a].push_back(v);\n            }\n            blk[s][b].clear();\n        }\n        activeLab[b] = 0;\n    }\n\n    void postMergeCommon(double deadline) {\n        while (elapsed() < deadline) {\n            unordered_map<long long, int> flags;\n            flags.reserve(N * 4 + 10);\n\n            for (int s = 0; s < 2; s++) {\n                for (int v = 0; v < N; v++) {\n                    int a = ans[s][v];\n                    if (!isCommonLabel(a)) continue;\n\n                    for (int dir : {1, 3, 5}) {\n                        int nb = neigh[v][dir];\n                        if (nb < 0) continue;\n                        int b = ans[s][nb];\n                        if (a == b || !isCommonLabel(b)) continue;\n                        int x = a, y = b;\n                        if (x > y) swap(x, y);\n                        long long key = ((long long)x << 32) | (unsigned int)y;\n                        flags[key] |= (1 << s);\n                    }\n                }\n            }\n\n            int bestA = -1, bestB = -1;\n            double bestSave = 1e-12;\n            int bestVol = -1;\n\n            for (auto& kv : flags) {\n                if (elapsed() > deadline) return;\n                if (kv.second != 3) continue;\n\n                long long key = kv.first;\n                int a = (int)(key >> 32);\n                int b = (int)(key & 0xffffffffLL);\n                if (!isCommonLabel(a) || !isCommonLabel(b)) continue;\n\n                int va = (int)blk[0][a].size();\n                int vb = (int)blk[0][b].size();\n                if (va <= 0 || vb <= 0) continue;\n\n                double save = 1.0 / va + 1.0 / vb - 1.0 / (va + vb);\n                if (save + 1e-12 < bestSave) continue;\n\n                if (!canMergeCommon(a, b)) continue;\n\n                int vol = va + vb;\n                if (save > bestSave + 1e-12 || vol > bestVol) {\n                    bestSave = save;\n                    bestVol = vol;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n\n            if (bestA == -1) break;\n            mergeCommonLabels(bestA, bestB);\n        }\n    }\n\n    void postProcess(double deadline) {\n        buildBlockLists();\n        pairUniqueUnits();\n        if (elapsed() < deadline) {\n            postMergeCommon(deadline);\n        }\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        double compDeadline = 2.35;\n        for (int it = 0; it < 12 && totalUncov > 0 && elapsed() < compDeadline; it++) {\n            CompCand c = findBestComponent(90, compDeadline);\n            if (!c.valid || c.size < 3) break;\n            placeCommonMapped(c);\n        }\n\n        double cuboidDeadline = 4.85;\n        for (int it = 0; it < 180 && totalUncov > 0 && elapsed() < cuboidDeadline; it++) {\n            BoxCand b = findBestCuboid(cuboidDeadline);\n            if (!b.valid || b.vol < 2 || b.cov <= 0) break;\n            placeCommonBox(b.b0, b.b1);\n        }\n\n        double exhaustiveDeadline = 5.35;\n        for (int it = 0; it < 50 && totalUncov > 0 && elapsed() < exhaustiveDeadline; it++) {\n            CompCand c = findBestComponentExhaustive(exhaustiveDeadline, 2);\n            if (!c.valid || c.size < 2 || c.score <= 0.0) break;\n            placeCommonMapped(c);\n        }\n\n        placeCommonUnits();\n        fillUnique(0);\n        fillUnique(1);\n        finalRepair();\n\n        postProcess(5.78);\n    }\n\n    void print() const {\n        vector<int> mp(label + 1, 0);\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0) mp[a] = 1;\n            }\n        }\n\n        int n = 0;\n        for (int l = 1; l <= label; l++) {\n            if (mp[l]) mp[l] = ++n;\n        }\n\n        cout << n << '\\n';\n        for (int s = 0; s < 2; s++) {\n            for (int i = 0; i < N; i++) {\n                if (i) cout << ' ';\n                int a = ans[s][i];\n                cout << (a == 0 ? 0 : mp[a]);\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n\n    array<vector<string>, 2> F, R;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        R[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> R[i][z];\n    }\n\n    Solver solver(D, F, R);\n    solver.run();\n    solver.print();\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 105;\nstatic const int MAXM = 305;\nstatic const long long INFLL = (1LL << 62);\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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} gtimer;\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) {\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);\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 Edge {\n    int u, v;\n    long long w;\n};\n\nstruct RK {\n    unsigned short p;\n    int k;\n};\n\nstruct TreeResult {\n    long long cost = INFLL;\n    bitset<MAXM> mask;\n};\n\nstruct Solution {\n    vector<int> P;\n    TreeResult tree;\n    long long radCost = INFLL;\n    long long total = INFLL;\n};\n\nint N, M, K;\nvector<int> X, Y, RA, RB;\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj;\n\nvector<vector<int>> distSq;\nvector<vector<unsigned short>> ceilD;\nvector<RK> coverList[MAXN];\n\nlong long spDist[MAXN][MAXN];\nbitset<MAXM> pathE[MAXN][MAXN];\nbitset<MAXN> pathV[MAXN][MAXN];\n\nvector<int> edgeOrder;\nbitset<MAXM> globalMSTMask;\nbitset<MAXM> allEdgesMask;\n\nint ceil_sqrt_ll(long long v) {\n    int r = (int) sqrt((long double) v);\n    while (1LL * r * r < v) ++r;\n    while (r > 0 && 1LL * (r - 1) * (r - 1) >= v) --r;\n    return r;\n}\n\nlong long calcRadCost(const vector<int>& P) {\n    long long s = 0;\n    for (int p : P) s += 1LL * p * p;\n    return s;\n}\n\nint computeCovered(const vector<int>& P, vector<char>& covered) {\n    covered.assign(K, 0);\n    int rem = K;\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                if (rem == 0) return K;\n            }\n        }\n    }\n    return K - rem;\n}\n\nbool isFull(const vector<int>& P) {\n    vector<char> covered;\n    return computeCovered(P, covered) == K;\n}\n\nvector<int> makeOrder(const vector<int>& P, int mode, const vector<long long>* branch = nullptr) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            double p2 = 1.0 * P[i] * P[i];\n            double rd = (double) spDist[0][i];\n            if (mode == 0) sc = p2;\n            else if (mode == 1) sc = p2 + 0.7 * rd;\n            else if (mode == 2) sc = 0.2 * p2 + rd;\n            else {\n                long long b = (branch ? (*branch)[i] : 0LL);\n                sc = p2 + (double)b;\n            }\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvoid trimP(vector<int>& P, const vector<int>& order) {\n    vector<int> cnt(K, 0);\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            cnt[rk.k]++;\n        }\n    }\n\n    for (int i : order) {\n        if (P[i] <= 0) continue;\n        int old = P[i];\n        int need = 0;\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > old) break;\n            if (cnt[rk.k] == 1) need = max(need, (int)rk.p);\n        }\n        if (need < old) {\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > old) break;\n                if ((int)rk.p > need) cnt[rk.k]--;\n            }\n            P[i] = need;\n        }\n    }\n}\n\nTreeResult reduceMask(const bitset<MAXM>& mask, const vector<char>& terminal) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    DSU d(N);\n    bitset<MAXM> tree;\n    for (int eid : edgeOrder) {\n        if (mask.test(eid) && d.unite(edges[eid].u, edges[eid].v)) {\n            tree.set(eid);\n        }\n    }\n\n    vector<int> deg(N, 0);\n    vector<vector<int>> inc(N);\n    for (int e = 0; e < M; ++e) {\n        if (!tree.test(e)) continue;\n        int u = edges[e].u, v = edges[e].v;\n        deg[u]++;\n        deg[v]++;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n    }\n\n    queue<int> q;\n    for (int i = 0; i < N; ++i) {\n        if (!terminal[i] && deg[i] <= 1) q.push(i);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (terminal[v] || deg[v] != 1) continue;\n\n        int remEdge = -1;\n        for (int e : inc[v]) {\n            if (tree.test(e)) {\n                remEdge = e;\n                break;\n            }\n        }\n        if (remEdge == -1) {\n            deg[v] = 0;\n            continue;\n        }\n\n        int to = edges[remEdge].u ^ edges[remEdge].v ^ v;\n        tree.reset(remEdge);\n        deg[v]--;\n        deg[to]--;\n        if (!terminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    vector<char> vis(N, 0);\n    queue<int> qq;\n    vis[0] = 1;\n    qq.push(0);\n    while (!qq.empty()) {\n        int v = qq.front();\n        qq.pop();\n        for (auto [to, eid] : adj[v]) {\n            if (!tree.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            qq.push(to);\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (terminal[i] && !vis[i]) return res;\n    }\n\n    long long cost = 0;\n    for (int e = 0; e < M; ++e) {\n        if (tree.test(e)) cost += edges[e].w;\n    }\n    res.cost = cost;\n    res.mask = tree;\n    return res;\n}\n\nbitset<MAXM> buildMetricMSTMask(const vector<char>& terminal) {\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) terms.push_back(i);\n    }\n\n    int T = (int)terms.size();\n    bitset<MAXM> mask;\n    if (T <= 1) return mask;\n\n    vector<char> used(T, 0);\n    vector<long long> key(T, INFLL);\n    vector<int> parent(T, -1);\n    key[0] = 0;\n\n    for (int it = 0; it < T; ++it) {\n        int v = -1;\n        long long best = INFLL;\n        for (int i = 0; i < T; ++i) {\n            if (!used[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) {\n            mask |= pathE[terms[v]][terms[parent[v]]];\n        }\n\n        for (int u = 0; u < T; ++u) {\n            if (!used[u] && spDist[terms[v]][terms[u]] < key[u]) {\n                key[u] = spDist[terms[v]][terms[u]];\n                parent[u] = v;\n            }\n        }\n    }\n    return mask;\n}\n\nbitset<MAXM> buildSPTMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) mask |= pathE[0][i];\n    }\n    return mask;\n}\n\nbitset<MAXM> buildGreedyMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(0);\n\n    while (true) {\n        bool any = false;\n        for (int t = 1; t < N; ++t) {\n            if (terminal[t] && !treeV.test(t)) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n        for (int t = 1; t < N; ++t) {\n            if (!terminal[t] || treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult buildBestTree(const vector<int>& P) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    int termCnt = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminal[i] = 1;\n            termCnt++;\n        }\n    }\n    if (P[0] > 0 && !terminal[0]) {\n        terminal[0] = 1;\n        termCnt++;\n    }\n\n    TreeResult best;\n    best.cost = INFLL;\n    best.mask.reset();\n\n    if (termCnt <= 1) {\n        best.cost = 0;\n        return best;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    upd(buildMetricMSTMask(terminal));\n    upd(buildSPTMask(terminal));\n    upd(buildGreedyMask(terminal));\n    upd(globalMSTMask);\n    upd(allEdgesMask);\n\n    return best;\n}\n\nvector<char> getReachable(const bitset<MAXM>& mask) {\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] : adj[v]) {\n            if (!mask.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return vis;\n}\n\nvector<long long> computeBranch(const vector<int>& P, const TreeResult& tr) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terminal[i] = 1;\n    }\n\n    vector<long long> branch(N, 0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        vector<char> t2 = terminal;\n        t2[i] = 0;\n        t2[0] = 1;\n        TreeResult r = reduceMask(tr.mask, t2);\n        if (r.cost < INFLL / 2) {\n            branch[i] = max(0LL, tr.cost - r.cost);\n        }\n    }\n    return branch;\n}\n\nSolution evaluateSolution(const vector<int>& P) {\n    Solution s;\n    s.P = P;\n    if (!isFull(P)) {\n        s.total = INFLL;\n        return s;\n    }\n    s.radCost = calcRadCost(P);\n    s.tree = buildBestTree(P);\n    if (s.tree.cost >= INFLL / 2) {\n        s.total = INFLL;\n    } else {\n        s.total = s.radCost + s.tree.cost;\n    }\n    return s;\n}\n\nbool greedyRepair(\n    vector<int>& P,\n    const vector<char>& allowed,\n    double connWeight,\n    double exponent,\n    const vector<char>* freeVertices = nullptr,\n    double stopTime = 1e100\n) {\n    for (int i = 0; i < N; ++i) {\n        if (!allowed[i]) P[i] = 0;\n        P[i] = min(5000, max(0, P[i]));\n    }\n\n    vector<char> covered;\n    int cov = computeCovered(P, covered);\n    int rem = K - cov;\n    if (rem == 0) return true;\n\n    vector<long long> minConn(N);\n    for (int i = 0; i < N; ++i) minConn[i] = spDist[0][i];\n\n    for (int t = 0; t < N; ++t) {\n        if (P[t] > 0) {\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][t]);\n            }\n        }\n    }\n\n    vector<double> denom(K + 1, 1.0);\n    if (fabs(exponent - 1.0) < 1e-9) {\n        for (int i = 1; i <= K; ++i) denom[i] = (double)i;\n    } else {\n        for (int i = 1; i <= K; ++i) denom[i] = pow((double)i, exponent);\n    }\n\n    int iter = 0;\n    while (rem > 0) {\n        if ((iter & 7) == 0 && gtimer.elapsed() > stopTime) return false;\n        if (iter > 1000) {\n            // Safe fallback: cover one currently uncovered resident at a time.\n            for (int k = 0; k < K && rem > 0; ++k) {\n                if (covered[k]) continue;\n                int bestI = -1, bestP = 0;\n                double bestCost = 1e100;\n\n                for (int i = 0; i < N; ++i) {\n                    if (!allowed[i]) continue;\n                    int p = (int)ceilD[i][k];\n                    if (p > 5000) continue;\n                    int old = P[i];\n                    int np = max(old, p);\n                    double act = 0.0;\n                    if (old == 0 && connWeight != 0.0) {\n                        if (freeVertices && (*freeVertices)[i]) act = 0.0;\n                        else act = connWeight * (double)minConn[i];\n                    }\n                    double cost = (double)(1LL * np * np - 1LL * old * old) + act;\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestI = i;\n                        bestP = np;\n                    }\n                }\n\n                if (bestI == -1) return false;\n\n                int old = P[bestI];\n                P[bestI] = bestP;\n                if (old == 0) {\n                    for (int j = 0; j < N; ++j) {\n                        minConn[j] = min(minConn[j], spDist[j][bestI]);\n                    }\n                }\n\n                for (const auto& rk : coverList[bestI]) {\n                    if ((int)rk.p > bestP) break;\n                    if (!covered[rk.k]) {\n                        covered[rk.k] = 1;\n                        --rem;\n                    }\n                }\n\n                if (gtimer.elapsed() > stopTime) return false;\n            }\n            return rem == 0;\n        }\n\n        ++iter;\n\n        double bestScore = 1e100;\n        double bestAbsCost = 1e100;\n        int bestI = -1, bestP = -1, bestCnt = -1;\n\n        for (int i = 0; i < N; ++i) {\n            if (!allowed[i] || P[i] >= 5000 || coverList[i].empty()) continue;\n\n            int old = P[i];\n            double activation = 0.0;\n            if (old == 0 && connWeight != 0.0) {\n                if (freeVertices && (*freeVertices)[i]) activation = 0.0;\n                else activation = connWeight * (double)minConn[i];\n            }\n\n            int cnt = 0;\n            const auto& lst = coverList[i];\n            int idx = 0, sz = (int)lst.size();\n\n            while (idx < sz && (int)lst[idx].p <= old) idx++;\n\n            while (idx < sz) {\n                int p = (int)lst[idx].p;\n                int add = 0;\n                while (idx < sz && (int)lst[idx].p == p) {\n                    if (!covered[lst[idx].k]) add++;\n                    idx++;\n                }\n                if (add == 0) continue;\n\n                cnt += add;\n                double cost = (double)(1LL * p * p - 1LL * old * old) + activation;\n                double score = cost / denom[cnt];\n\n                if (score < bestScore - 1e-12 ||\n                    (fabs(score - bestScore) <= 1e-12 &&\n                     (cost < bestAbsCost || cnt > bestCnt))) {\n                    bestScore = score;\n                    bestAbsCost = cost;\n                    bestI = i;\n                    bestP = p;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestI == -1) return false;\n\n        int old = P[bestI];\n        P[bestI] = bestP;\n\n        int gained = 0;\n        for (const auto& rk : coverList[bestI]) {\n            if ((int)rk.p > bestP) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                gained++;\n            }\n        }\n\n        if (old == 0) {\n            for (int j = 0; j < N; ++j) {\n                minConn[j] = min(minConn[j], spDist[j][bestI]);\n            }\n        }\n\n        if (gained == 0) return false;\n    }\n\n    return true;\n}\n\nvoid computeShortestPaths() {\n    for (int s = 0; s < N; ++s) {\n        vector<long long> dist(N, INFLL);\n        vector<int> parNode(N, -1), parEdge(N, -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n\n        dist[s] = 0;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n\n            for (auto [to, eid] : adj[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parNode[to] = v;\n                    parEdge[to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        for (int t = 0; t < N; ++t) {\n            spDist[s][t] = dist[t];\n            pathE[s][t].reset();\n            pathV[s][t].reset();\n\n            if (dist[t] >= INFLL / 2) continue;\n\n            int cur = t;\n            pathV[s][t].set(cur);\n            while (cur != s) {\n                int e = parEdge[cur];\n                if (e < 0) break;\n                pathE[s][t].set(e);\n                cur = parNode[cur];\n                pathV[s][t].set(cur);\n            }\n        }\n    }\n}\n\nbitset<MAXM> buildGlobalMST() {\n    DSU d(N);\n    bitset<MAXM> m;\n    for (int eid : edgeOrder) {\n        if (d.unite(edges[eid].u, edges[eid].v)) {\n            m.set(eid);\n        }\n    }\n    return m;\n}\n\nvector<int> nearestSolution(double lambda) {\n    vector<int> P(N, 0);\n    for (int k = 0; k < K; ++k) {\n        double best = 1e100;\n        int bi = -1;\n        for (int i = 0; i < N; ++i) {\n            int p = (int)ceilD[i][k];\n            if (p > 5000) continue;\n            double val = (double)distSq[i][k] + lambda * (double)spDist[0][i];\n            if (val < best) {\n                best = val;\n                bi = i;\n            }\n        }\n\n        if (bi == -1) {\n            int bp = INT_MAX;\n            for (int i = 0; i < N; ++i) {\n                if ((int)ceilD[i][k] < bp) {\n                    bp = (int)ceilD[i][k];\n                    bi = i;\n                }\n            }\n        }\n\n        P[bi] = max(P[bi], (int)ceilD[bi][k]);\n    }\n    return P;\n}\n\nvoid considerCandidate(vector<int> P, vector<Solution>& sols, double stopTime) {\n    for (int& p : P) p = min(5000, max(0, p));\n\n    vector<char> allAllowed(N, 1);\n    if (!isFull(P)) {\n        greedyRepair(P, allAllowed, 0.6, 1.0, nullptr, stopTime);\n    }\n    if (!isFull(P)) return;\n\n    auto add = [&](const vector<int>& Q) {\n        Solution s = evaluateSolution(Q);\n        if (s.total < INFLL / 2) sols.push_back(s);\n    };\n\n    add(P);\n\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<int> q = P;\n        trimP(q, makeOrder(q, mode));\n        add(q);\n    }\n\n    vector<int> q = P;\n    trimP(q, makeOrder(q, 1));\n    trimP(q, makeOrder(q, 0));\n    add(q);\n}\n\nSolution localSearch(Solution cur, double deadline) {\n    vector<char> allAllowed(N, 1);\n\n    for (int pass = 0; pass < 6 && gtimer.elapsed() < deadline; ++pass) {\n        cur = evaluateSolution(cur.P);\n        bool improved = false;\n\n        // Strong reverse-delete using current branch costs.\n        if (gtimer.elapsed() < deadline) {\n            vector<long long> br = computeBranch(cur.P, cur.tree);\n            vector<int> p2 = cur.P;\n            trimP(p2, makeOrder(p2, 3, &br));\n            Solution ns = evaluateSolution(p2);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        // Re-optimize radii using only vertices already connected by the current tree.\n        if (gtimer.elapsed() < deadline) {\n            vector<char> avail = getReachable(cur.tree.mask);\n            double exps[2] = {1.0, 1.15};\n            for (double ex : exps) {\n                vector<int> p0(N, 0);\n                if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n                trimP(p0, makeOrder(p0, 0));\n                Solution ns = evaluateSolution(p0);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        vector<int> order = makeOrder(cur.P, 3, &br);\n\n        // Remove or shrink one expensive station, then repair.\n        int stationTried = 0;\n        int maxStations = (pass == 0 ? 50 : 30);\n\n        for (int id : order) {\n            if (cur.P[id] <= 0) continue;\n            if (gtimer.elapsed() > deadline) break;\n            if (stationTried++ >= maxStations) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            vector<int> uniqTargets;\n            for (int t : targets) {\n                if (t < 0 || t >= p) continue;\n                bool seen = false;\n                for (int u : uniqTargets) if (u == t) seen = true;\n                if (!seen) uniqTargets.push_back(t);\n            }\n\n            for (int np : uniqTargets) {\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                p2[id] = np;\n\n                double beta = (np == 0 ? 0.8 : 0.4);\n                if (!greedyRepair(p2, allAllowed, beta, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n        if (improved) continue;\n\n        // Destroy a whole subtree of the current cable tree.\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            struct CutCand {\n                long long score;\n                int e;\n                vector<int> terms;\n            };\n            vector<CutCand> cuts;\n\n            for (int e = 0; e < M; ++e) {\n                if (!cur.tree.mask.test(e)) continue;\n\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] : adj[v]) {\n                        if (eid == e || !cur.tree.mask.test(eid) || vis[to]) continue;\n                        vis[to] = 1;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> terms;\n                long long p2sum = 0;\n                for (int v = 0; v < N; ++v) {\n                    if (!vis[v] && cur.P[v] > 0) {\n                        terms.push_back(v);\n                        p2sum += 1LL * cur.P[v] * cur.P[v];\n                    }\n                }\n                if (terms.empty()) continue;\n\n                long long branchCost = edges[e].w;\n                for (int ee = 0; ee < M; ++ee) {\n                    if (ee == e || !cur.tree.mask.test(ee)) continue;\n                    int u = edges[ee].u, v = edges[ee].v;\n                    if (!vis[u] && !vis[v]) branchCost += edges[ee].w;\n                }\n\n                cuts.push_back({branchCost + p2sum, e, terms});\n            }\n\n            sort(cuts.begin(), cuts.end(), [](const CutCand& a, const CutCand& b) {\n                return a.score > b.score;\n            });\n\n            int tried = 0;\n            for (const auto& cc : cuts) {\n                if (tried++ >= 8) break;\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                for (int v : cc.terms) p2[v] = 0;\n\n                if (!greedyRepair(p2, allAllowed, 0.9, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        // Remove a pair among the most expensive terminals.\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            vector<int> top;\n            for (int id : order) {\n                if (cur.P[id] > 0) {\n                    top.push_back(id);\n                    if ((int)top.size() >= 8) break;\n                }\n            }\n\n            for (int a = 0; a < (int)top.size() && !improved; ++a) {\n                for (int b = a + 1; b < (int)top.size(); ++b) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> p2 = cur.P;\n                    p2[top[a]] = 0;\n                    p2[top[b]] = 0;\n\n                    if (!greedyRepair(p2, allAllowed, 0.85, 1.05, nullptr, deadline)) continue;\n\n                    trimP(p2, makeOrder(p2, 1));\n                    trimP(p2, makeOrder(p2, 0));\n\n                    Solution ns = evaluateSolution(p2);\n                    if (ns.total < cur.total) {\n                        cur = ns;\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gtimer.reset();\n\n    cin >> N >> M >> K;\n\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    adj.assign(N, {});\n    for (int j = 0; j < M; ++j) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n        adj[u].push_back({v, j});\n        adj[v].push_back({u, j});\n    }\n\n    RA.resize(K);\n    RB.resize(K);\n    for (int k = 0; k < K; ++k) cin >> RA[k] >> RB[k];\n\n    edgeOrder.resize(M);\n    iota(edgeOrder.begin(), edgeOrder.end(), 0);\n    sort(edgeOrder.begin(), edgeOrder.end(), [&](int a, int b) {\n        if (edges[a].w != edges[b].w) return edges[a].w < edges[b].w;\n        return a < b;\n    });\n\n    allEdgesMask.reset();\n    for (int e = 0; e < M; ++e) allEdgesMask.set(e);\n\n    computeShortestPaths();\n    globalMSTMask = buildGlobalMST();\n\n    distSq.assign(N, vector<int>(K));\n    ceilD.assign(N, vector<unsigned short>(K));\n\n    for (int i = 0; i < N; ++i) {\n        coverList[i].clear();\n        for (int k = 0; k < K; ++k) {\n            long long dx = (long long)X[i] - RA[k];\n            long long dy = (long long)Y[i] - RB[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            distSq[i][k] = (int)d2;\n            ceilD[i][k] = (unsigned short)p;\n            if (p <= 5000) coverList[i].push_back({(unsigned short)p, k});\n        }\n        sort(coverList[i].begin(), coverList[i].end(), [](const RK& a, const RK& b) {\n            if (a.p != b.p) return a.p < b.p;\n            return a.k < b.k;\n        });\n    }\n\n    vector<Solution> sols;\n    const double GEN_DEADLINE = 0.85;\n    const double LOCAL_DEADLINE = 1.90;\n\n    // Initial 1: nearest assignments with root-distance bias.\n    vector<double> lambdas = {0.0, 0.05, 0.2, 0.7, 1.5};\n    for (double l : lambdas) {\n        vector<int> P = nearestSolution(l);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    // Initial 2: reverse delete from all radius-5000 stations.\n    {\n        vector<int> P(N, 5000);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    // Initial 3: greedy set cover with several connection penalties.\n    vector<pair<double,double>> params = {\n        {0.0, 1.0}, {0.2, 1.0}, {0.5, 1.0}, {0.8, 1.0},\n        {1.2, 1.0}, {2.0, 1.0}, {0.3, 1.15}, {0.8, 1.15},\n        {1.5, 1.15}, {0.5, 0.9}\n    };\n\n    vector<char> allAllowed(N, 1);\n    for (auto [beta, ex] : params) {\n        if (gtimer.elapsed() > GEN_DEADLINE) break;\n        vector<int> P(N, 0);\n        if (greedyRepair(P, allAllowed, beta, ex, nullptr, GEN_DEADLINE)) {\n            considerCandidate(P, sols, GEN_DEADLINE);\n        }\n    }\n\n    // Emergency fallback.\n    if (sols.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        if (!isFull(P)) greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        sols.push_back(evaluateSolution(P));\n    }\n\n    sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b) {\n        return a.total < b.total;\n    });\n\n    vector<Solution> uniq;\n    for (const auto& s : sols) {\n        if (s.total >= INFLL / 2) continue;\n        bool dup = false;\n        for (const auto& u : uniq) {\n            if (u.P == s.P) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniq.push_back(s);\n        if ((int)uniq.size() >= 20) break;\n    }\n\n    if (uniq.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        uniq.push_back(evaluateSolution(P));\n    }\n\n    Solution best = uniq[0];\n\n    int optN = min(5, (int)uniq.size());\n    for (int i = 0; i < optN && gtimer.elapsed() < LOCAL_DEADLINE; ++i) {\n        Solution opt = localSearch(uniq[i], LOCAL_DEADLINE);\n        if (opt.total < best.total) best = opt;\n    }\n\n    // Final safe trim.\n    best = evaluateSolution(best.P);\n    if (gtimer.elapsed() < 1.95) {\n        vector<long long> br = computeBranch(best.P, best.tree);\n        vector<int> p2 = best.P;\n        trimP(p2, makeOrder(p2, 3, &br));\n        Solution ns = evaluateSolution(p2);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (!isFull(best.P)) {\n        greedyRepair(best.P, allAllowed, 0.0, 1.0);\n        best = evaluateSolution(best.P);\n    } else {\n        best = evaluateSolution(best.P);\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 e = 0; e < M; ++e) {\n        if (e) cout << ' ';\n        cout << (best.tree.mask.test(e) ? 1 : 0);\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 int M = N * (N + 1) / 2;\nstatic constexpr int INTERNAL = M - N;\n\nint ID[N][N], Xc[M], Yc[M];\nvector<int> G[M], PAR[M], CH[M];\nvector<pair<int,int>> EDGES;\nvector<pair<int,int>> ADJ;\nvector<int> INCIDENT[M];\n\nbool validXY(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y <= x;\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 FastRand {\n    uint64_t x;\n    FastRand(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nvoid precompute() {\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) ID[i][j] = -1;\n\n    int idx = 0;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            ID[x][y] = idx;\n            Xc[idx] = x;\n            Yc[idx] = y;\n            idx++;\n        }\n    }\n\n    int dx[6] = {0, 0, -1, -1, 1, 1};\n    int dy[6] = {-1, 1, -1, 0, 0, 1};\n\n    for (int p = 0; p < M; p++) {\n        int x = Xc[p], y = Yc[p];\n\n        for (int k = 0; k < 6; k++) {\n            int nx = x + dx[k], ny = y + dy[k];\n            if (validXY(nx, ny)) G[p].push_back(ID[nx][ny]);\n        }\n\n        if (x + 1 < N) {\n            CH[p].push_back(ID[x + 1][y]);\n            CH[p].push_back(ID[x + 1][y + 1]);\n        }\n        if (x > 0) {\n            if (y > 0) PAR[p].push_back(ID[x - 1][y - 1]);\n            if (y < x) PAR[p].push_back(ID[x - 1][y]);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int c : CH[p]) {\n            int ei = (int)EDGES.size();\n            EDGES.emplace_back(p, c);\n            INCIDENT[p].push_back(ei);\n            INCIDENT[c].push_back(ei);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int q : G[p]) {\n            if (p < q) ADJ.emplace_back(p, q);\n        }\n    }\n}\n\nstruct Work {\n    array<int, M> a;\n    array<int, M> pos;\n    vector<pair<int,int>> ops;\n\n    Work() {}\n\n    Work(const array<int, M>& init) {\n        a = init;\n        for (int i = 0; i < M; i++) pos[a[i]] = i;\n        ops.clear();\n    }\n};\n\ninline void doSwap(Work& w, int u, int v) {\n    int lu = w.a[u], lv = w.a[v];\n    swap(w.a[u], w.a[v]);\n    w.pos[lu] = v;\n    w.pos[lv] = u;\n    w.ops.emplace_back(u, v);\n}\n\nint countViol(const array<int, M>& a) {\n    int e = 0;\n    for (auto [p, c] : EDGES) {\n        if (a[p] > a[c]) e++;\n    }\n    return e;\n}\n\narray<int, M> simulateOps(const array<int, M>& init, const vector<pair<int,int>>& ops) {\n    array<int, M> a = init;\n    for (auto [u, v] : ops) swap(a[u], a[v]);\n    return a;\n}\n\nint centerVal(int p) {\n    return abs(2 * Yc[p] - Xc[p]);\n}\n\nint chooseCand(const vector<int>& cand, int choice, const Work& w) {\n    int best = cand[0];\n    for (int q : cand) {\n        bool take = false;\n        if (choice == 0) {\n            if (w.a[q] > w.a[best]) take = true;\n        } else if (choice == 1) {\n            if (w.a[q] < w.a[best]) take = true;\n        } else if (choice == 2) {\n            if (Yc[q] < Yc[best]) take = true;\n        } else if (choice == 3) {\n            if (Yc[q] > Yc[best]) take = true;\n        } else {\n            int cq = centerVal(q), cb = centerVal(best);\n            if (cq < cb || (cq == cb && w.a[q] > w.a[best])) take = true;\n        }\n        if (take) best = q;\n    }\n    return best;\n}\n\nint chooseCandRand(const vector<int>& cand, int mode, const Work& w, FastRand& rng, int dir) {\n    if ((int)cand.size() == 1) return cand[0];\n\n    if (mode == 0) return cand[rng.nextInt((int)cand.size())];\n\n    if (1 <= mode && mode <= 5) {\n        int base = chooseCand(cand, mode - 1, w);\n        if (rng.nextInt(100) < 75) return base;\n        vector<int> other;\n        for (int q : cand) if (q != base) other.push_back(q);\n        if (other.empty()) return base;\n        return other[rng.nextInt((int)other.size())];\n    }\n\n    int best = cand[0];\n    long long bestSc = LLONG_MIN;\n    for (int q : cand) {\n        long long sc = 0;\n        if (mode == 6) {\n            sc = 100LL * w.a[q] - 15LL * centerVal(q);\n        } else {\n            sc = -100LL * w.a[q] - 15LL * centerVal(q);\n        }\n        if (dir == 0) sc -= 3LL * Xc[q];\n        else sc += 3LL * Xc[q];\n        sc += (long long)(rng.nextInt(301) - 150);\n        if (sc > bestSc) {\n            bestSc = sc;\n            best = q;\n        }\n    }\n    return best;\n}\n\n// Guaranteed finisher.\nbool appendCone(Work& w, int yOrder, int pathMode, int limit) {\n    if (countViol(w.a) == 0) return true;\n\n    for (int x = 0; x <= N - 2; x++) {\n        for (int yi = 0; yi <= x; yi++) {\n            int y = (yOrder == 0 ? yi : x - yi);\n\n            int best = ID[x][y];\n            int bv = w.a[best];\n\n            for (int r = x; r < N; r++) {\n                int c0 = y;\n                int c1 = y + (r - x);\n                for (int c = c0; c <= c1; c++) {\n                    int p = ID[r][c];\n                    if (w.a[p] < bv) {\n                        bv = w.a[p];\n                        best = p;\n                    }\n                }\n            }\n\n            int cur = best;\n            while (Xc[cur] > x) {\n                int cx = Xc[cur], cy = Yc[cur];\n                bool goLeft = false;\n\n                if (pathMode == 0) {\n                    goLeft = (cy > y);\n                } else if (pathMode == 1) {\n                    goLeft = !(cx - cy > x - y);\n                } else {\n                    int rem = cx - x;\n                    int needLeft = cy - y;\n                    if (needLeft <= 0) goLeft = false;\n                    else if (needLeft >= rem) goLeft = true;\n                    else goLeft = (needLeft * 2 >= rem);\n                }\n\n                int np = goLeft ? ID[cx - 1][cy - 1] : ID[cx - 1][cy];\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, cur, np);\n                cur = np;\n            }\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n    return countViol(w.a) == 0;\n}\n\nbool appendSift(Work& w, int dir, int choice, int limit) {\n    if (countViol(w.a) == 0) return true;\n    if ((int)w.ops.size() > limit) return false;\n\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    } else {\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool appendSiftRandom(Work& w, int dir, int mode, uint64_t seed, int limit) {\n    if (countViol(w.a) == 0) return true;\n    if ((int)w.ops.size() > limit) return false;\n\n    FastRand rng(seed);\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    } else {\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool solveSift(const array<int, M>& init, int dir, int choice, int limit, Work& out) {\n    Work w(init);\n    if (appendSift(w, dir, choice, limit)) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool parentsFixed(int p, const vector<char>& fixed) {\n    for (int q : PAR[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nbool childrenFixed(int p, const vector<char>& fixed) {\n    for (int q : CH[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nint openInc(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (fixed[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openDec(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (fixed[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nstruct Strat {\n    int w;\n    int row;\n    int center;\n    int open;\n    int randAmp;\n    uint64_t seed;\n};\n\nbool solveBFS(const array<int, M>& init, int dir, const Strat& st, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<char> fixed(M, 0), avail(M, 0);\n\n    if (dir == 0) {\n        avail[ID[0][0]] = 1;\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openInc(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(v + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] < N - 1) internalFixed++;\n\n            for (int ch : CH[best]) {\n                if (!fixed[ch] && parentsFixed(ch, fixed)) avail[ch] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    } else {\n        for (int y = 0; y < N; y++) avail[ID[N - 1][y]] = 1;\n\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n            int step = M - 1 - v;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openDec(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] > 0) nonTopFixed++;\n\n            for (int pr : PAR[best]) {\n                if (!fixed[pr] && childrenFixed(pr, fixed)) avail[pr] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Bidirectional BFS construction.\nbool parentsTop(int p, const vector<unsigned char>& type) {\n    for (int q : PAR[p]) if (type[q] != 1) return false;\n    return true;\n}\n\nbool childrenBottom(int p, const vector<unsigned char>& type) {\n    for (int q : CH[p]) if (type[q] != 2) return false;\n    return true;\n}\n\nint openTopCnt(int p, const vector<unsigned char>& type) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (type[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && type[q] != 1) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openBottomCnt(int p, const vector<unsigned char>& type) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (type[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && type[q] != 2) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nstruct BiOpt {\n    bool ok = false;\n    int target = -1;\n    int dist = 0;\n    long long score = 0;\n};\n\nBiOpt getBiOption(\n    const Work& w,\n    const vector<unsigned char>& type,\n    const vector<char>& avail,\n    int label,\n    bool topSide,\n    const Strat& st,\n    int step,\n    array<int, M>& dist,\n    array<int, M>& prv\n) {\n    BiOpt opt;\n    int start = w.pos[label];\n    if (type[start]) return opt;\n\n    dist.fill(-1);\n    prv.fill(-1);\n\n    int que[M], head = 0, tail = 0;\n    dist[start] = 0;\n    que[tail++] = start;\n\n    while (head < tail) {\n        int u = que[head++];\n        for (int nb : G[u]) {\n            if (type[nb]) continue;\n            if (dist[nb] != -1) continue;\n            dist[nb] = dist[u] + 1;\n            prv[nb] = u;\n            que[tail++] = nb;\n        }\n    }\n\n    long long bestSc = LLONG_MAX;\n    int best = -1;\n\n    for (int p = 0; p < M; p++) {\n        if (!avail[p] || type[p] || dist[p] < 0) continue;\n\n        int opn = topSide ? openTopCnt(p, type) : openBottomCnt(p, type);\n        long long sc = 1LL * dist[p] * st.w\n                     + 1LL * st.row * Xc[p]\n                     + 1LL * st.center * centerVal(p)\n                     + 1LL * st.open * opn;\n\n        if (st.randAmp > 0) {\n            uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n            sc += (long long)(h % (uint64_t)st.randAmp);\n        }\n\n        if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n            best = p;\n            bestSc = sc;\n        }\n    }\n\n    if (best == -1) return opt;\n\n    opt.ok = true;\n    opt.target = best;\n    opt.dist = dist[best];\n    opt.score = bestSc;\n    return opt;\n}\n\nbool solveBiBFS(const array<int, M>& init, const Strat& topSt, const Strat& botSt, int sideBias, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<unsigned char> type(M, 0); // 0 free, 1 top-small fixed, 2 bottom-large fixed\n    vector<char> topAvail(M, 0), botAvail(M, 0);\n\n    topAvail[ID[0][0]] = 1;\n    for (int y = 0; y < N; y++) botAvail[ID[N - 1][y]] = 1;\n\n    int lo = 0, hi = M - 1;\n    int step = 0;\n\n    while (lo <= hi) {\n        array<int, M> distTop, prvTop, distBot, prvBot;\n\n        BiOpt ot = getBiOption(w, type, topAvail, lo, true, topSt, step, distTop, prvTop);\n        BiOpt ob = getBiOption(w, type, botAvail, hi, false, botSt, step, distBot, prvBot);\n\n        if (!ot.ok && !ob.ok) return false;\n\n        bool chooseTop;\n        if (!ob.ok) chooseTop = true;\n        else if (!ot.ok) chooseTop = false;\n        else chooseTop = (ot.score + sideBias <= ob.score);\n\n        int target;\n        array<int, M>* prv;\n\n        if (chooseTop) {\n            target = ot.target;\n            prv = &prvTop;\n            if ((int)w.ops.size() + ot.dist > limit) return false;\n        } else {\n            target = ob.target;\n            prv = &prvBot;\n            if ((int)w.ops.size() + ob.dist > limit) return false;\n        }\n\n        vector<int> path;\n        for (int cur = target; cur != -1; cur = (*prv)[cur]) path.push_back(cur);\n        reverse(path.begin(), path.end());\n\n        for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n        if (chooseTop) {\n            type[target] = 1;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            lo++;\n\n            for (int ch : CH[target]) {\n                if (!type[ch] && parentsTop(ch, type)) topAvail[ch] = 1;\n            }\n        } else {\n            type[target] = 2;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            hi--;\n\n            for (int pr : PAR[target]) {\n                if (!type[pr] && childrenBottom(pr, type)) botAvail[pr] = 1;\n            }\n        }\n\n        step++;\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint localDelta(const Work& w, int p, int c) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[c]) add(e);\n\n    int before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        if (w.a[u] > w.a[v]) before++;\n\n        int au = (u == p ? w.a[c] : (u == c ? w.a[p] : w.a[u]));\n        int av = (v == p ? w.a[c] : (v == c ? w.a[p] : w.a[v]));\n        if (au > av) after++;\n    }\n\n    return before - after;\n}\n\nint chooseViolationEdge(const Work& w, int variant) {\n    long long bestKey = LLONG_MIN;\n    int best = -1;\n\n    for (int ei = 0; ei < (int)EDGES.size(); ei++) {\n        auto [p, c] = EDGES[ei];\n        if (w.a[p] <= w.a[c]) continue;\n\n        int diff = w.a[p] - w.a[c];\n        int delta = 0;\n        if (variant >= 6) delta = localDelta(w, p, c);\n\n        long long key = 0;\n        if (variant == 0) {\n            key = diff;\n        } else if (variant == 1) {\n            key = 1LL * (M - w.a[c]) * 1000 + diff;\n        } else if (variant == 2) {\n            key = 1LL * w.a[p] * 1000 + diff;\n        } else if (variant == 3) {\n            key = 1LL * (N - Xc[p]) * 100000 + diff;\n        } else if (variant == 4) {\n            key = 1LL * Xc[p] * 100000 + diff;\n        } else if (variant == 5) {\n            key = 1LL * diff * 1000 + (N - Xc[p]) * 20 + (M - w.a[c]);\n        } else if (variant == 6) {\n            key = 1LL * delta * 1000000 + 1LL * diff * 1000 + (M - w.a[c]);\n        } else if (variant == 7) {\n            key = 1LL * delta * 1000000 + 1LL * (N - Xc[p]) * 1000 + diff;\n        } else {\n            key = 1LL * delta * 1000000 + 1LL * Xc[p] * 1000 + diff;\n        }\n\n        if (key > bestKey) {\n            bestKey = key;\n            best = ei;\n        }\n    }\n\n    return best;\n}\n\nbool runLocalSteps(Work& w, int variant, int steps, int limit) {\n    for (int s = 0; s < steps; s++) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) return true;\n\n        if ((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n    return true;\n}\n\nbool solveLocal(const array<int, M>& init, int variant, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) {\n            out = move(w);\n            return true;\n        }\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool solveSweep(const array<int, M>& init, int xdir, int ydir, int choice, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        bool changed = false;\n\n        for (int xi = 0; xi < N - 1; xi++) {\n            int x = (xdir == 0 ? N - 2 - xi : xi);\n\n            for (int yi = 0; yi <= x; yi++) {\n                int y = (ydir == 0 ? yi : x - yi);\n                int cur = ID[x][y];\n\n                while (Xc[cur] < N - 1) {\n                    vector<int> cand;\n                    for (int q : CH[cur]) {\n                        if (w.a[cur] > w.a[q]) cand.push_back(q);\n                    }\n                    if (cand.empty()) break;\n\n                    int q = chooseCand(cand, choice, w);\n                    if ((int)w.ops.size() + 1 > limit) return false;\n\n                    doSwap(w, cur, q);\n                    cur = q;\n                    changed = true;\n                }\n            }\n        }\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n        if (!changed) break;\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Greedy all-adjacent local energy prefix.\nlong long edgeCostVal(int ap, int ac, int W, bool quad) {\n    if (ap <= ac) return 0;\n    long long d = ap - ac;\n    if (quad) return (long long)W + d * d;\n    return (long long)W + d;\n}\n\nlong long swapGainCost(const array<int, M>& a, int p, int q, int W, bool quad) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[q]) add(e);\n\n    long long before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        before += edgeCostVal(a[u], a[v], W, quad);\n\n        int au = (u == p ? a[q] : (u == q ? a[p] : a[u]));\n        int av = (v == p ? a[q] : (v == q ? a[p] : a[v]));\n        after += edgeCostVal(au, av, W, quad);\n    }\n\n    return before - after;\n}\n\nbool runGreedyCost(Work& w, int W, bool quad, int maxSteps, int limit) {\n    for (int s = 0; s < maxSteps; s++) {\n        if ((int)w.ops.size() >= limit) return countViol(w.a) == 0;\n\n        long long bestGain = 0;\n        long long bestTie = LLONG_MIN;\n        int bu = -1, bv = -1;\n\n        for (auto [u, v] : ADJ) {\n            long long gain = swapGainCost(w.a, u, v, W, quad);\n            if (gain <= 0) continue;\n\n            long long deltaP = 1LL * (w.a[u] - w.a[v]) * (Xc[v] - Xc[u]);\n            long long rowGain = -deltaP;\n\n            if (gain > bestGain || (gain == bestGain && rowGain > bestTie)) {\n                bestGain = gain;\n                bestTie = rowGain;\n                bu = u;\n                bv = v;\n            }\n        }\n\n        if (bu == -1) break;\n\n        doSwap(w, bu, bv);\n        if (countViol(w.a) == 0) return true;\n    }\n\n    return countViol(w.a) == 0;\n}\n\n// Fast reverse pruning of a valid operation sequence.\nbool canSwapKeepValid(const array<int, M>& a, int p, int q) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[q]) add(e);\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n\n        int au = a[u], av = a[v];\n        if (u == p) au = a[q];\n        else if (u == q) au = a[p];\n\n        if (v == p) av = a[q];\n        else if (v == q) av = a[p];\n\n        if (au > av) return false;\n    }\n\n    return true;\n}\n\nvector<pair<int,int>> pruneOpsFast(const array<int, M>& init, const vector<pair<int,int>>& ops, int passes = 3) {\n    vector<pair<int,int>> cur = ops;\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (cur.empty()) break;\n\n        array<int, M> a = simulateOps(init, cur);\n        if (countViol(a) != 0) return cur;\n\n        array<int, M> suff;\n        for (int i = 0; i < M; i++) suff[i] = i;\n\n        vector<unsigned char> keep(cur.size(), 1);\n        int deleted = 0;\n\n        for (int ii = (int)cur.size(); ii-- > 0; ) {\n            int u = cur[ii].first;\n            int v = cur[ii].second;\n\n            int p = suff[u];\n            int q = suff[v];\n\n            if (canSwapKeepValid(a, p, q)) {\n                swap(a[p], a[q]);\n                keep[ii] = 0;\n                deleted++;\n            } else {\n                swap(suff[u], suff[v]);\n            }\n        }\n\n        if (deleted == 0) break;\n\n        vector<pair<int,int>> nxt;\n        nxt.reserve(cur.size() - deleted);\n        for (int i = 0; i < (int)cur.size(); i++) {\n            if (keep[i]) nxt.push_back(cur[i]);\n        }\n        cur.swap(nxt);\n    }\n\n    return cur;\n}\n\nbool validSkipping(const array<int, M>& init, const vector<pair<int,int>>& ops, int s1, int s2 = -1) {\n    array<int, M> a = init;\n    for (int i = 0; i < (int)ops.size(); i++) {\n        if (i == s1 || i == s2) continue;\n        swap(a[ops[i].first], a[ops[i].second]);\n    }\n    return countViol(a) == 0;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    array<int, M> init;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            cin >> init[ID[x][y]];\n        }\n    }\n\n    uint64_t inputHash = 0;\n    for (int i = 0; i < M; i++) {\n        inputHash = splitmix64(inputHash ^ (uint64_t)(init[i] + 1) * 1000003ULL ^ (uint64_t)i);\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto searchOK = [&]() {\n        return elapsed() < 1.78;\n    };\n    auto finalOK = [&]() {\n        return elapsed() < 1.93;\n    };\n\n    vector<pair<int,int>> bestOps;\n    int bestK = 10001;\n    const int PRUNE_MARGIN = 1600;\n\n    auto consider = [&](Work&& w) {\n        int raw = (int)w.ops.size();\n        if (raw > 10000) return;\n        if (countViol(w.a) != 0) return;\n\n        if (bestK <= 10000 && raw >= bestK + PRUNE_MARGIN) return;\n\n        vector<pair<int,int>> pruned = pruneOpsFast(init, w.ops, 3);\n        if ((int)pruned.size() > 10000) return;\n\n        array<int, M> aa = simulateOps(init, pruned);\n        if (countViol(aa) != 0) return;\n\n        int k = (int)pruned.size();\n        if (k < bestK) {\n            bestK = k;\n            bestOps = move(pruned);\n        }\n    };\n\n    auto limitGen = [&]() {\n        if (bestK > 10000) return 10000;\n        return min(10000, bestK + PRUNE_MARGIN);\n    };\n\n    // Guaranteed candidates first.\n    for (int yo = 0; yo < 2; yo++) {\n        for (int pm = 0; pm < 3; pm++) {\n            Work w(init);\n            if (appendCone(w, yo, pm, 10000)) consider(move(w));\n        }\n    }\n\n    // Deterministic sifts.\n    for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n        for (int ch = 0; ch < 5 && searchOK() && bestK > 0; ch++) {\n            Work w;\n            if (solveSift(init, dir, ch, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    // Randomized sifts.\n    for (int t = 0; t < 90 && searchOK() && bestK > 0; t++) {\n        int dir = t & 1;\n        int mode = (t / 2) % 8;\n        uint64_t seed = inputHash ^ (uint64_t)(t + 1) * 0x9e3779b97f4a7c15ULL;\n\n        Work w(init);\n        if (appendSiftRandom(w, dir, mode, seed, limitGen())) consider(move(w));\n    }\n\n    // Bidirectional BFS candidates.\n    vector<tuple<Strat, Strat, int>> biStrats;\n    auto addBi = [&](Strat a, Strat b, int bias) {\n        biStrats.emplace_back(a, b, bias);\n    };\n\n    addBi({1000, 5, 0, -20, 0, 0}, {1000, -5, 0, -20, 0, 0}, 0);\n    addBi({1000, 10, 0, -20, 0, 0}, {1000, -10, 0, -20, 0, 0}, 0);\n    addBi({1000, 0, 0, -20, 0, 0}, {1000, 0, 0, -20, 0, 0}, 0);\n    addBi({1000, 5, -3, -20, 0, 0}, {1000, -5, -3, -20, 0, 0}, 0);\n    addBi({1000, 5, 3, -20, 0, 0}, {1000, -5, 3, -20, 0, 0}, 0);\n    addBi({300, 20, 0, -30, 0, 0}, {300, -20, 0, -30, 0, 0}, 0);\n    addBi({500, 10, -5, -30, 80, inputHash ^ 111}, {500, -10, -5, -30, 80, inputHash ^ 222}, 0);\n    addBi({500, 10, 5, -30, 80, inputHash ^ 333}, {500, -10, 5, -30, 80, inputHash ^ 444}, 0);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 555}, {1000, -5, 0, -20, 100, inputHash ^ 666}, -200);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 777}, {1000, -5, 0, -20, 100, inputHash ^ 888}, 200);\n\n    for (auto [ts, bs, bias] : biStrats) {\n        if (!searchOK() || bestK == 0) break;\n        Work w;\n        if (solveBiBFS(init, ts, bs, bias, limitGen(), w)) consider(move(w));\n    }\n\n    // Greedy energy prefixes + sift finishers.\n    vector<tuple<int,bool,int>> gparams = {\n        {10000, false, 120},\n        {10000, false, 300},\n        {3000, false, 300},\n        {1000, false, 500},\n        {300, false, 500},\n        {20000, true, 250}\n    };\n\n    for (auto [W, quad, steps] : gparams) {\n        if (!searchOK() || bestK == 0) break;\n\n        Work pref(init);\n        runGreedyCost(pref, W, quad, steps, limitGen());\n\n        if (countViol(pref.a) == 0) consider(Work(pref));\n\n        for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n            for (int ch : {0, 1, 4}) {\n                if (!searchOK() || bestK == 0) break;\n                Work w = pref;\n                if (appendSift(w, dir, ch, limitGen())) consider(move(w));\n            }\n        }\n    }\n\n    // Local violation prefixes + sift/cone finishers.\n    vector<int> prefVars = {0, 1, 6, 7};\n    vector<int> prefSteps = {80, 180, 350, 700};\n\n    for (int var : prefVars) {\n        for (int stp : prefSteps) {\n            if (!searchOK() || bestK == 0) break;\n\n            Work pref(init);\n            if (!runLocalSteps(pref, var, stp, limitGen())) continue;\n\n            if (countViol(pref.a) == 0) {\n                consider(Work(pref));\n                continue;\n            }\n\n            for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n                for (int ch : {0, 1, 4}) {\n                    if (!searchOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendSift(w, dir, ch, limitGen())) consider(move(w));\n                }\n            }\n\n            for (int yo = 0; yo < 2 && searchOK() && bestK > 0; yo++) {\n                for (int pm = 0; pm < 3; pm++) {\n                    if (!searchOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendCone(w, yo, pm, limitGen())) consider(move(w));\n                }\n            }\n        }\n    }\n\n    // BFS topological constructions.\n    vector<Strat> strats;\n    auto addStrat = [&](int w, int r, int c, int o, int ra = 0, uint64_t seed = 0) {\n        strats.push_back({w, r, c, o, ra, seed});\n    };\n\n    addStrat(1000, 0, 0, 0);\n    addStrat(1000, 1, 0, 0);\n    addStrat(1000, -1, 0, 0);\n    addStrat(1000, 0, 1, 0);\n    addStrat(1000, 0, -1, 0);\n    addStrat(1000, 0, 0, -10);\n    addStrat(200, 10, 0, 0);\n    addStrat(200, -10, 0, 0);\n    addStrat(200, 30, 0, 0);\n    addStrat(200, -30, 0, 0);\n    addStrat(200, 0, 10, 0);\n    addStrat(200, 0, -10, 0);\n    addStrat(200, 10, -5, -20);\n    addStrat(200, -10, 5, -20);\n    addStrat(100, 10, 0, -30);\n    addStrat(100, -10, 0, -30);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 1234567);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 9876543);\n    addStrat(700, 5, -3, -15, 150, inputHash ^ 5555555);\n    addStrat(700, -5, 3, -15, 150, inputHash ^ 3141592);\n\n    for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n        for (const auto& st : strats) {\n            if (!searchOK() || bestK == 0) break;\n            Work w;\n            if (solveBFS(init, dir, st, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    // Sweep heapification variants.\n    for (int xd = 0; xd < 2 && searchOK() && bestK > 0; xd++) {\n        for (int yd = 0; yd < 2 && searchOK() && bestK > 0; yd++) {\n            for (int ch = 0; ch < 4 && searchOK() && bestK > 0; ch++) {\n                Work w;\n                if (solveSweep(init, xd, yd, ch, limitGen(), w)) consider(move(w));\n            }\n        }\n    }\n\n    // Pure local violation swapping variants.\n    for (int var = 0; var < 9 && searchOK() && bestK > 0; var++) {\n        Work w;\n        if (solveLocal(init, var, limitGen(), w)) consider(move(w));\n    }\n\n    // Safety fallback.\n    if (bestK > 10000) {\n        Work w(init);\n        appendCone(w, 0, 0, 10000);\n        bestOps = move(w.ops);\n        bestK = (int)bestOps.size();\n    }\n\n    // More exact final pruning on the best sequence.\n    bestOps = pruneOpsFast(init, bestOps, 5);\n\n    auto slowSingle = [&](bool rev) {\n        if (rev) {\n            for (int i = (int)bestOps.size() - 1; i >= 0 && finalOK(); i--) {\n                if (validSkipping(init, bestOps, i)) {\n                    bestOps.erase(bestOps.begin() + i);\n                }\n            }\n        } else {\n            for (int i = 0; i < (int)bestOps.size() && finalOK(); ) {\n                if (validSkipping(init, bestOps, i)) {\n                    bestOps.erase(bestOps.begin() + i);\n                } else {\n                    i++;\n                }\n            }\n        }\n    };\n\n    auto slowPairs = [&]() {\n        for (int i = 0; i + 1 < (int)bestOps.size() && finalOK(); ) {\n            if (validSkipping(init, bestOps, i, i + 1)) {\n                bestOps.erase(bestOps.begin() + i, bestOps.begin() + i + 2);\n            } else {\n                i++;\n            }\n        }\n    };\n\n    if (finalOK()) slowSingle(false);\n    if (finalOK()) slowSingle(true);\n    if (finalOK()) slowPairs();\n    if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n\n    // Last safety check.\n    {\n        array<int, M> aa = simulateOps(init, bestOps);\n        if (countViol(aa) != 0 || (int)bestOps.size() > 10000) {\n            Work w(init);\n            appendCone(w, 0, 0, 10000);\n            bestOps = move(w.ops);\n        }\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto [u, v] : bestOps) {\n        cout << Xc[u] << ' ' << Yc[u] << ' ' << Xc[v] << ' ' << Yc[v] << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nint D, N, M;\nint rootR, rootC;\nbool obs[9][9];\nint gid[9][9];\n\nvector<pair<int,int>> posi;\nvector<vector<int>> adjList;\nvector<int> rootAdjCells;\nvector<char> isRootAdj;\n\nvector<uint64_t> adjLo, adjHi;\nvector<int> orderP, pIndex;\n\nvector<int> assignedLabel;\nvector<char> unseenLabel;\nint emptyCnt;\n\nstatic inline bool inside(int r, int c) {\n    return 0 <= r && r < D && 0 <= c && c < D;\n}\n\nstatic inline bool hasBit(uint64_t lo, uint64_t hi, int i) {\n    if (i < 64) return (lo >> i) & 1ULL;\n    return (hi >> (i - 64)) & 1ULL;\n}\n\nstatic inline void setBit(uint64_t &lo, uint64_t &hi, int i) {\n    if (i < 64) lo |= 1ULL << i;\n    else hi |= 1ULL << (i - 64);\n}\n\nstatic inline bool intersects(uint64_t aLo, uint64_t aHi, uint64_t bLo, uint64_t bHi) {\n    return ((aLo & bLo) | (aHi & bHi)) != 0;\n}\n\nstatic inline int countLessMask(uint64_t lo, uint64_t hi, int x) {\n    if (x <= 0) return 0;\n    if (x < 64) {\n        return __builtin_popcountll(lo & ((1ULL << x) - 1));\n    }\n    if (x == 64) return __builtin_popcountll(lo);\n    int h = x - 64;\n    uint64_t mask = (1ULL << h) - 1;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n}\n\n// Checks whether all current empty cells except a,b are reachable from entrance.\nbool connectedAvoid(int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (assignedLabel[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (assignedLabel[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validPlacementCandidates() {\n    vector<int> cand;\n    for (int c = 0; c < M; c++) {\n        if (assignedLabel[c] != -1) continue;\n        if (connectedAvoid(c, -1, emptyCnt - 1)) cand.push_back(c);\n    }\n\n    // Should never happen if the invariant is maintained.\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (assignedLabel[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nint countNextValidAfter(int c) {\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return 0;\n    if (rem == 1) return 1;\n\n    int cnt = 0;\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (connectedAvoid(c, e, rem - 1)) cnt++;\n    }\n    return cnt;\n}\n\nint invOfValues(const int *seq) {\n    int inv = 0;\n    for (int i = 0; i < M; i++) {\n        for (int j = i + 1; j < M; j++) {\n            if (seq[i] > seq[j]) inv++;\n        }\n    }\n    return inv;\n}\n\nint greedyCostLabels(const vector<int> &lab) {\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            bool acc = isRootAdj[i] || intersects(adjLo[i], adjHi[i], rlo, rhi);\n            if (acc && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) return 1000000000;\n\n        int x = lab[best];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nint sequenceCost(const vector<int> &seq, const vector<int> &lab) {\n    if ((int)seq.size() != M) return 1000000000;\n\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int x = lab[seq[step]];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nvector<int> greedySequenceMinLabel(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            bool acc = isRootAdj[i] || intersects(adjLo[i], adjHi[i], rlo, rhi);\n            if (acc && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) break;\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n    }\n\n    return seq;\n}\n\nvector<int> greedySequenceLookahead2(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestScore = INT_MAX;\n        int bestCostInc = INT_MAX;\n        int bestLab = INT_MAX;\n\n        for (int c = 0; c < M; c++) {\n            if (hasBit(rlo, rhi, c)) continue;\n            bool acc = isRootAdj[c] || intersects(adjLo[c], adjHi[c], rlo, rhi);\n            if (!acc) continue;\n\n            int x = lab[c];\n            int less = countLessMask(llo, lhi, x);\n            int inc1 = x - less;\n            int costInc = step - less;\n\n            uint64_t nrlo = rlo, nrhi = rhi;\n            uint64_t nllo = llo, nlhi = lhi;\n            setBit(nrlo, nrhi, c);\n            setBit(nllo, nlhi, x);\n\n            int inc2 = 0;\n            if (step + 1 < M) {\n                inc2 = INT_MAX / 4;\n                for (int d = 0; d < M; d++) {\n                    if (hasBit(nrlo, nrhi, d)) continue;\n                    bool acc2 = isRootAdj[d] || intersects(adjLo[d], adjHi[d], nrlo, nrhi);\n                    if (!acc2) continue;\n\n                    int y = lab[d];\n                    int less2 = countLessMask(nllo, nlhi, y);\n                    inc2 = min(inc2, y - less2);\n                }\n            }\n\n            int score = inc1 + inc2;\n\n            if (score < bestScore ||\n                (score == bestScore && costInc < bestCostInc) ||\n                (score == bestScore && costInc == bestCostInc && x < bestLab)) {\n                bestScore = score;\n                bestCostInc = costInc;\n                bestLab = x;\n                best = c;\n            }\n        }\n\n        if (best == -1) break;\n\n        int x = lab[best];\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return seq;\n}\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key &o) const {\n        return lo == o.lo && hi == o.hi;\n    }\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\nstruct KeyHash {\n    size_t operator()(const Key &k) const {\n        return splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1);\n    }\n};\n\nstruct Node {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nstruct Temp {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nvector<int> beamSearchRemoval(const vector<int> &lab, int upperBound) {\n    const int BEAM = 5000;\n\n    vector<Node> nodes;\n    nodes.reserve((M + 1) * BEAM + 1);\n    nodes.push_back(Node{0, 0, 0, 0, 0, 0, -1, -1});\n\n    vector<int> cur;\n    cur.push_back(0);\n\n    auto betterTemp = [](const Temp &a, const Temp &b) {\n        if (a.forced != b.forced) return a.forced < b.forced;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.lo != b.lo) return a.lo < b.lo;\n        return a.hi < b.hi;\n    };\n\n    for (int depth = 0; depth < M; depth++) {\n        vector<Temp> temps;\n        size_t reserveSize = min<size_t>((size_t)cur.size() * 32 + 100, 300000);\n        temps.reserve(reserveSize);\n\n        unordered_map<Key, int, KeyHash> mp;\n        mp.reserve(reserveSize * 2);\n\n        for (int idx : cur) {\n            const Node &s = nodes[idx];\n\n            for (int i = 0; i < M; i++) {\n                if (hasBit(s.lo, s.hi, i)) continue;\n\n                bool acc = isRootAdj[i] || intersects(adjLo[i], adjHi[i], s.lo, s.hi);\n                if (!acc) continue;\n\n                int x = lab[i];\n                int less = countLessMask(s.llo, s.lhi, x);\n\n                int cost2 = s.cost + (depth - less);\n                int forced2 = s.forced + (x - less);\n\n                if (forced2 > upperBound) continue;\n\n                uint64_t nlo = s.lo, nhi = s.hi;\n                uint64_t nllo = s.llo, nlhi = s.lhi;\n                setBit(nlo, nhi, i);\n                setBit(nllo, nlhi, x);\n\n                Temp t{nlo, nhi, nllo, nlhi, cost2, forced2, idx, i};\n                Key key{nlo, nhi};\n\n                auto it = mp.find(key);\n                if (it == mp.end()) {\n                    int id = (int)temps.size();\n                    temps.push_back(t);\n                    mp.emplace(key, id);\n                } else {\n                    int id = it->second;\n                    if (t.cost < temps[id].cost ||\n                        (t.cost == temps[id].cost && t.forced < temps[id].forced)) {\n                        temps[id] = t;\n                    }\n                }\n            }\n        }\n\n        if (temps.empty()) return {};\n\n        if ((int)temps.size() > BEAM) {\n            nth_element(temps.begin(), temps.begin() + BEAM, temps.end(), betterTemp);\n            temps.resize(BEAM);\n        }\n\n        vector<int> nxt;\n        nxt.reserve(temps.size());\n\n        for (const Temp &t : temps) {\n            int id = (int)nodes.size();\n            nodes.push_back(Node{t.lo, t.hi, t.llo, t.lhi, t.cost, t.forced, t.parent, t.cell});\n            nxt.push_back(id);\n        }\n\n        cur.swap(nxt);\n    }\n\n    int bestNode = -1;\n    int bestCost = INT_MAX;\n\n    for (int idx : cur) {\n        if (nodes[idx].cost < bestCost) {\n            bestCost = nodes[idx].cost;\n            bestNode = idx;\n        }\n    }\n\n    if (bestNode == -1) return {};\n\n    vector<int> seq;\n    while (bestNode != 0 && bestNode != -1) {\n        seq.push_back(nodes[bestNode].cell);\n        bestNode = nodes[bestNode].parent;\n    }\n\n    reverse(seq.begin(), seq.end());\n    if ((int)seq.size() != M) return {};\n    return seq;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D >> N;\n    rootR = 0;\n    rootC = (D - 1) / 2;\n\n    memset(obs, 0, sizeof(obs));\n    memset(gid, -1, sizeof(gid));\n\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = true;\n    }\n\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (r == rootR && c == rootC) continue;\n            if (obs[r][c]) continue;\n            gid[r][c] = (int)posi.size();\n            posi.push_back({r, c});\n        }\n    }\n\n    M = (int)posi.size();\n\n    adjList.assign(M, {});\n    isRootAdj.assign(M, 0);\n    adjLo.assign(M, 0);\n    adjHi.assign(M, 0);\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    for (int id = 0; id < M; id++) {\n        auto [r, c] = posi[id];\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n            if (!inside(nr, nc)) continue;\n\n            if (nr == rootR && nc == rootC) {\n                isRootAdj[id] = 1;\n            } else if (!obs[nr][nc]) {\n                int to = gid[nr][nc];\n                if (to >= 0) adjList[id].push_back(to);\n            }\n        }\n\n        if (isRootAdj[id]) rootAdjCells.push_back(id);\n    }\n\n    for (int i = 0; i < M; i++) {\n        for (int to : adjList[i]) {\n            if (to < 64) adjLo[i] |= 1ULL << to;\n            else adjHi[i] |= 1ULL << (to - 64);\n        }\n    }\n\n    // BFS order from entrance, prioritizing downward/central expansion.\n    int dist[9][9];\n    int disc[9][9];\n    for (int r = 0; r < 9; r++) {\n        for (int c = 0; c < 9; c++) {\n            dist[r][c] = 1e9;\n            disc[r][c] = 1e9;\n        }\n    }\n\n    int bfsDirs[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};\n    queue<pair<int,int>> q;\n    dist[rootR][rootC] = 0;\n    disc[rootR][rootC] = 0;\n    int dcnt = 1;\n    q.push({rootR, rootC});\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : bfsDirs) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != (int)1e9) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            disc[nr][nc] = dcnt++;\n            q.push({nr, nc});\n        }\n    }\n\n    orderP.resize(M);\n    iota(orderP.begin(), orderP.end(), 0);\n\n    sort(orderP.begin(), orderP.end(), [&](int a, int b) {\n        auto [ra, ca] = posi[a];\n        auto [rb, cb] = posi[b];\n        if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n        if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n        return a < b;\n    });\n\n    pIndex.assign(M, 0);\n    for (int i = 0; i < M; i++) pIndex[orderP[i]] = i;\n\n    assignedLabel.assign(M, -1);\n    unseenLabel.assign(M, 1);\n    emptyCnt = M;\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<int> cand = validPlacementCandidates();\n\n        vector<int> futureLabels;\n        futureLabels.reserve(emptyCnt - 1);\n\n        int rankLabel = 0;\n        for (int x = 0; x < M; x++) {\n            if (!unseenLabel[x]) continue;\n            if (x < t) rankLabel++;\n            if (x != t) futureLabels.push_back(x);\n        }\n\n        int bestCell = -1;\n        int bestHyp = INT_MAX;\n        int bestInv = INT_MAX;\n        int bestAbs = INT_MAX;\n        int bestNext = -1;\n        int bestPDiff = INT_MAX;\n\n        vector<int> lab(M);\n        int seqVals[85];\n\n        for (int c : cand) {\n            int ptr = 0;\n            int si = 0;\n\n            for (int cell : orderP) {\n                int v;\n                if (assignedLabel[cell] != -1) {\n                    v = assignedLabel[cell];\n                } else if (cell == c) {\n                    v = t;\n                } else {\n                    v = futureLabels[ptr++];\n                }\n\n                lab[cell] = v;\n                seqVals[si++] = v;\n            }\n\n            int fixedInv = invOfValues(seqVals);\n            int greedyInv = greedyCostLabels(lab);\n            int hyp = min(fixedInv, greedyInv);\n\n            int rankCell = 0;\n            for (int e = 0; e < M; e++) {\n                if (assignedLabel[e] == -1 && pIndex[e] < pIndex[c]) rankCell++;\n            }\n\n            int absDiff = abs(rankCell - rankLabel);\n            int nextValid = countNextValidAfter(c);\n            int pDiff = abs(pIndex[c] - t);\n\n            bool better = false;\n            if (hyp != bestHyp) better = hyp < bestHyp;\n            else if (fixedInv != bestInv) better = fixedInv < bestInv;\n            else if (absDiff != bestAbs) better = absDiff < bestAbs;\n            else if (nextValid != bestNext) better = nextValid > bestNext;\n            else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n\n            if (better) {\n                bestHyp = hyp;\n                bestInv = fixedInv;\n                bestAbs = absDiff;\n                bestNext = nextValid;\n                bestPDiff = pDiff;\n                bestCell = c;\n            }\n        }\n\n        if (bestCell == -1) bestCell = cand[0];\n\n        assignedLabel[bestCell] = t;\n        unseenLabel[t] = 0;\n        emptyCnt--;\n\n        cout << posi[bestCell].first << ' ' << posi[bestCell].second << endl;\n    }\n\n    vector<int> bestSeq = orderP;\n    int bestCost = sequenceCost(bestSeq, assignedLabel);\n\n    vector<int> gseq = greedySequenceMinLabel(assignedLabel);\n    int gcost = sequenceCost(gseq, assignedLabel);\n    if (gcost < bestCost) {\n        bestCost = gcost;\n        bestSeq = gseq;\n    }\n\n    vector<int> lseq = greedySequenceLookahead2(assignedLabel);\n    int lcost = sequenceCost(lseq, assignedLabel);\n    if (lcost < bestCost) {\n        bestCost = lcost;\n        bestSeq = lseq;\n    }\n\n    vector<int> bseq = beamSearchRemoval(assignedLabel, bestCost);\n    int bcost = sequenceCost(bseq, assignedLabel);\n    if (bcost < bestCost) {\n        bestSeq = bseq;\n        bestCost = bcost;\n    }\n\n    if ((int)bestSeq.size() != M) bestSeq = orderP;\n\n    for (int cell : bestSeq) {\n        cout << posi[cell].first << ' ' << posi[cell].second << '\\n';\n    }\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 50;\nstatic const int MAXV = MAXN * MAXN;\nstatic const int MAXC = 105;\n\nint N, M, V;\nbool REQ[MAXC][MAXC];\nint GDEP[MAXC], DEGREQ[MAXC], NEED[MAXC];\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\n\nint visArr[MAXV];\nint bfsQ[MAXV];\nint visStamp = 1;\n\ninline int newStamp() {\n    ++visStamp;\n    if (visStamp == INT_MAX) {\n        memset(visArr, 0, sizeof(visArr));\n        visStamp = 1;\n    }\n    return visStamp;\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 RNG {\n    uint64_t s;\n    RNG(uint64_t seed = 1) : s(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (s += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    template<class T>\n    void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            swap(v[i], v[nextInt(i + 1)]);\n        }\n    }\n};\n\nstruct State {\n    array<unsigned char, MAXV> g;\n    int cnt[MAXC];\n    int edge[MAXC][MAXC];\n    int zeros;\n\n    void clear() {\n        g.fill(0);\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n        zeros = 0;\n    }\n\n    inline void addEdgeCnt(int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        edge[a][b] += d;\n        edge[b][a] += d;\n    }\n\n    void rebuild() {\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n\n        for (int p = 0; p < V; ++p) {\n            int a = g[p];\n            cnt[a]++;\n        }\n        zeros = cnt[0];\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int p = r * N + c;\n                int a = g[p];\n\n                if (r + 1 < N) addEdgeCnt(a, g[(r + 1) * N + c], 1);\n                if (c + 1 < N) addEdgeCnt(a, g[r * N + (c + 1)], 1);\n\n                if (r == 0) addEdgeCnt(0, a, 1);\n                if (r == N - 1) addEdgeCnt(0, a, 1);\n                if (c == 0) addEdgeCnt(0, a, 1);\n                if (c == N - 1) addEdgeCnt(0, a, 1);\n            }\n        }\n    }\n\n    inline bool hasZeroAdj(int p) const {\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return true;\n            int q = nr * N + nc;\n            if (g[q] == 0) return true;\n        }\n        return false;\n    }\n\n    bool connectedAfterRemoveColor(int p, int col) const {\n        if (cnt[col] <= 1) return false;\n\n        int r = p / N, c = p % N;\n        int nb[4], k = 0;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (g[q] == col) nb[k++] = q;\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        bool reached[4] = {};\n        reached[0] = true;\n        int found = 1;\n\n        visArr[nb[0]] = stamp;\n        bfsQ[tail++] = nb[0];\n\n        while (head < tail && found < k) {\n            int v = bfsQ[head++];\n            int vr = v / N, vc = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = vr + DR[d], nc = vc + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n\n                visArr[q] = stamp;\n\n                for (int i = 1; i < k; ++i) {\n                    if (!reached[i] && q == nb[i]) {\n                        reached[i] = true;\n                        ++found;\n                        break;\n                    }\n                }\n\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return found == k;\n    }\n\n    bool zeroConnectedAfterRemove(int p) const {\n        if (cnt[0] <= 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int q = r * N + c;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0] - 1;\n    }\n\n    bool tryChange(int p, int to) {\n        int from = g[p];\n        if (from == to) return false;\n        if (to < 0 || to > M) return false;\n\n        if (from > 0 && cnt[from] <= 1) return false;\n\n        if (to == 0) {\n            if (from == 0) return false;\n            if (!hasZeroAdj(p)) return false;\n        } else {\n            bool adjTarget = false;\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] == to) {\n                    adjTarget = true;\n                    break;\n                }\n            }\n            if (!adjTarget) return false;\n        }\n\n        int du[16], dv[16], dd[16], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            int nbcol = 0;\n            if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                nbcol = g[nr * N + nc];\n            }\n\n            addDelta(from, nbcol, -1);\n            addDelta(to, nbcol, +1);\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        if (from == 0) {\n            if (!zeroConnectedAfterRemove(p)) return false;\n        } else {\n            if (!connectedAfterRemoveColor(p, from)) return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        cnt[from]--;\n        cnt[to]++;\n\n        if (from == 0) zeros--;\n        if (to == 0) zeros++;\n\n        g[p] = (unsigned char)to;\n        return true;\n    }\n};\n\nvoid computeGraphInfo() {\n    for (int i = 0; i <= M; ++i) {\n        DEGREQ[i] = 0;\n        for (int j = 0; j <= M; ++j) {\n            if (i != j && REQ[i][j]) DEGREQ[i]++;\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        NEED[i] = max(1, (DEGREQ[i] - 1) / 2);\n    }\n    NEED[0] = 0;\n\n    fill(GDEP, GDEP + MAXC, 1000000);\n    queue<int> q;\n    GDEP[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u = 0; u <= M; ++u) {\n            if (!REQ[v][u]) continue;\n            if (GDEP[u] > GDEP[v] + 1) {\n                GDEP[u] = GDEP[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        if (GDEP[i] > 100000) GDEP[i] = 50;\n    }\n}\n\nvoid computeDist(const State& st, vector<int>& dist) {\n    const int INF = 1e9;\n    dist.assign(V, INF);\n\n    int head = 0, tail = 0;\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] == 0) {\n            dist[p] = 0;\n            bfsQ[tail++] = p;\n        }\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n            int p = r * N + c;\n            if (dist[p] > 1) {\n                dist[p] = 1;\n                bfsQ[tail++] = p;\n            }\n        }\n    }\n\n    while (head < tail) {\n        int v = bfsQ[head++];\n        int r = v / N, c = v % N;\n        int nd = dist[v] + 1;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (dist[q] > nd) {\n                dist[q] = nd;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n}\n\nint greedyDelete(State& st, RNG& rng, int mode = 0) {\n    vector<int> cand;\n    cand.reserve(V * 5);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0 && st.hasZeroAdj(p)) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    if (mode == 1) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            int sa = st.cnt[ca] - NEED[ca];\n            int sb = st.cnt[cb] - NEED[cb];\n            if (sa != sb) return sa > sb;\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 2) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (st.cnt[ca] != st.cnt[cb]) return st.cnt[ca] > st.cnt[cb];\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 3) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return st.cnt[ca] > st.cnt[cb];\n        });\n    }\n\n    int deleted = 0;\n\n    for (size_t idx = 0; idx < cand.size(); ++idx) {\n        int p = cand[idx];\n        if (st.g[p] == 0) continue;\n        if (!st.hasZeroAdj(p)) continue;\n\n        if (st.tryChange(p, 0)) {\n            ++deleted;\n\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) cand.push_back(q);\n            }\n        }\n    }\n\n    return deleted;\n}\n\nint greedyDeleteMulti(State& st, RNG& rng, int repeats, int modeBase) {\n    int old = st.zeros;\n    if (repeats <= 1) {\n        greedyDelete(st, rng, modeBase & 3);\n        return st.zeros - old;\n    }\n\n    State base = st;\n    State best = st;\n\n    for (int r = 0; r < repeats; ++r) {\n        State tmp = base;\n        greedyDelete(tmp, rng, (modeBase + r) & 3);\n        if (tmp.zeros > best.zeros) best = tmp;\n    }\n\n    st = best;\n    return st.zeros - old;\n}\n\nstruct Params {\n    int strategy;       // 0: grid distance, 1: graph depth, 2: random, 3: mixed, 4: surplus\n    int orderMode;      // 0: near, 1: random, 2: far, 3: graph-depth desc, 4: graph-depth asc\n    int eqProb;\n    bool useLayer;\n    bool targetRandom;\n    bool preDelete;\n    int delRepeats;\n    int delMode;\n};\n\nParams getParams(int run) {\n    switch (run % 20) {\n        case 0:  return {0, 0,  0, false, false, true,  1, 0};\n        case 1:  return {0, 0, 10, true,  false, true,  1, 1};\n        case 2:  return {1, 0, 15, false, false, true,  1, 0};\n        case 3:  return {1, 3, 20, true,  false, true,  1, 1};\n        case 4:  return {3, 0, 15, false, false, true,  1, 2};\n        case 5:  return {4, 0, 10, false, false, true,  1, 1};\n        case 6:  return {2, 1,  0, false, true,  true,  1, 0};\n        case 7:  return {0, 1, 30, false, true,  true,  1, 2};\n        case 8:  return {1, 4, 25, false, false, false, 1, 3};\n        case 9:  return {3, 3, 20, true,  false, false, 1, 1};\n        case 10: return {0, 2,  0, false, true,  true,  1, 0};\n        case 11: return {4, 1, 20, false, true,  true,  1, 2};\n        case 12: return {1, 0,  0, true,  false, true,  2, 0};\n        case 13: return {3, 0, 30, false, false, true,  2, 1};\n        case 14: return {2, 1,  0, false, true,  false, 1, 0};\n        case 15: return {0, 0, 50, false, true,  false, 1, 1};\n        case 16: return {1, 3, 40, false, true,  false, 1, 2};\n        case 17: return {4, 3, 30, true,  false, true,  1, 3};\n        case 18: return {3, 1, 10, false, true,  true,  2, 0};\n        default: return {0, 0, 20, true,  false, true,  1, 0};\n    }\n}\n\nint recolorPass(State& st, const vector<int>& dist, RNG& rng, const Params& par) {\n    const int INF = 1e9;\n\n    int layer[MAXC];\n    for (int i = 0; i < MAXC; ++i) layer[i] = INF;\n    layer[0] = 0;\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a > 0) layer[a] = min(layer[a], dist[p]);\n    }\n\n    vector<int> order;\n    order.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) order.push_back(p);\n    }\n\n    rng.shuffleVec(order);\n\n    if (par.orderMode == 0) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 2) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n    } else if (par.orderMode == 3) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] > GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 4) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    }\n\n    struct Target {\n        int col;\n        int score;\n        int td;\n        int gd;\n        int rnd;\n    };\n\n    int changed = 0;\n\n    for (int p : order) {\n        int a = st.g[p];\n        if (a == 0) continue;\n        if (st.cnt[a] <= 1) continue;\n\n        int dp = dist[p];\n        int r = p / N, c = p % N;\n\n        Target ts[4];\n        int tn = 0;\n\n        auto addTarget = [&](int b, int dq, int score) {\n            int pos = -1;\n            for (int i = 0; i < tn; ++i) {\n                if (ts[i].col == b) {\n                    pos = i;\n                    break;\n                }\n            }\n\n            if (pos == -1) {\n                ts[tn++] = {b, score, dq, GDEP[b], (int)(rng.next() & 0x7fffffff)};\n            } else {\n                if (score > ts[pos].score) {\n                    ts[pos].score = score;\n                    ts[pos].td = min(ts[pos].td, dq);\n                }\n            }\n        };\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int q = nr * N + nc;\n            int b = st.g[q];\n            if (b == 0 || b == a) continue;\n\n            int dq = dist[q];\n            bool ok = false;\n            int score = 0;\n\n            if (par.strategy == 0) {\n                ok = (dq < dp) || (dq == dp && par.eqProb > 0 && rng.nextInt(100) < par.eqProb);\n                if (par.useLayer && layer[b] > layer[a]) ok = false;\n                score = (dp - dq) * 20 + (layer[a] - layer[b]) * 3 + (GDEP[a] - GDEP[b]);\n            } else if (par.strategy == 1) {\n                int da = GDEP[a], db = GDEP[b];\n                ok = (db < da) ||\n                     (db == da && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (dq < dp && db <= da + 1);\n\n                if (par.useLayer && layer[b] > layer[a] + 1) ok = false;\n                score = (da - db) * 30 + (dp - dq) * 5 + (layer[a] - layer[b]);\n            } else if (par.strategy == 2) {\n                ok = true;\n                score = (int)(rng.next() & 0xffff);\n            } else if (par.strategy == 3) {\n                int val =\n                    (GDEP[a] - GDEP[b]) * 18 +\n                    (dp - dq) * 7 +\n                    (layer[a] - layer[b]) * 4 +\n                    ((st.cnt[a] - NEED[a]) - (st.cnt[b] - NEED[b]));\n\n                ok = (val > 0) ||\n                     (val == 0 && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (rng.nextInt(100) < 4);\n\n                score = val;\n            } else {\n                int surplusA = st.cnt[a] - NEED[a];\n                int surplusB = st.cnt[b] - NEED[b];\n                int val =\n                    (surplusA - surplusB) * 5 +\n                    (GDEP[a] - GDEP[b]) * 8 +\n                    (dp - dq) * 3;\n\n                ok = (val > 0) ||\n                     (par.eqProb > 0 && rng.nextInt(100) < par.eqProb / 2);\n\n                score = val;\n            }\n\n            if (!ok) continue;\n            addTarget(b, dq, score);\n        }\n\n        if (tn == 0) continue;\n\n        if (par.targetRandom || par.strategy == 2) {\n            for (int i = tn - 1; i > 0; --i) {\n                swap(ts[i], ts[rng.nextInt(i + 1)]);\n            }\n        } else {\n            for (int i = 0; i < tn; ++i) {\n                for (int j = i + 1; j < tn; ++j) {\n                    bool better = false;\n                    if (ts[j].score != ts[i].score) {\n                        better = ts[j].score > ts[i].score;\n                    } else if (ts[j].td != ts[i].td) {\n                        better = ts[j].td < ts[i].td;\n                    } else if (ts[j].gd != ts[i].gd) {\n                        better = ts[j].gd < ts[i].gd;\n                    } else {\n                        better = ts[j].rnd < ts[i].rnd;\n                    }\n                    if (better) swap(ts[i], ts[j]);\n                }\n            }\n        }\n\n        for (int i = 0; i < tn; ++i) {\n            if (st.tryChange(p, ts[i].col)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid improve(State& st, State& best, RNG& rng, const Params& par, const Timer& timer, double limit) {\n    vector<int> dist;\n    int lastZeros = st.zeros;\n    int stagnant = 0;\n\n    for (int cycle = 0; cycle < 80; ++cycle) {\n        if (timer.elapsed() > limit) break;\n\n        int del = 0;\n\n        if (par.preDelete) {\n            del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode);\n            if (st.zeros > best.zeros) best = st;\n        }\n\n        computeDist(st, dist);\n        int rec = recolorPass(st, dist, rng, par);\n\n        del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode + cycle);\n        if (st.zeros > best.zeros) best = st;\n\n        if (st.zeros > lastZeros) {\n            lastZeros = st.zeros;\n            stagnant = 0;\n        } else {\n            ++stagnant;\n        }\n\n        if (rec + del == 0) break;\n\n        int maxStag = 4;\n        if (par.strategy == 2) maxStag = 3;\n        if (par.eqProb >= 30) maxStag++;\n        if (par.delRepeats >= 2) maxStag++;\n\n        if (stagnant >= maxStag) break;\n    }\n}\n\nint randomInterfaceRecolorPass(State& st, RNG& rng, int limitChanges) {\n    vector<int> cells;\n    cells.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b > 0 && b != a) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cells.push_back(p);\n    }\n\n    rng.shuffleVec(cells);\n\n    int changed = 0;\n\n    for (int p : cells) {\n        if (changed >= limitChanges) break;\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b == 0 || b == a) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint randomExpandPass(State& st, RNG& rng, int quota) {\n    vector<int> cand;\n    cand.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            if (st.g[nr * N + nc] > 0) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n\n    for (int p : cand) {\n        if (changed >= quota) break;\n        if (st.g[p] != 0) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b <= 0) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid shakeSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    while (timer.elapsed() < limit) {\n        State st = best;\n\n        int rounds = 3 + rng.nextInt(4);\n\n        for (int rd = 0; rd < rounds; ++rd) {\n            if (timer.elapsed() >= limit) break;\n\n            if (st.zeros > best.zeros - 25) {\n                randomExpandPass(st, rng, 2 + rng.nextInt(7));\n            }\n\n            randomInterfaceRecolorPass(st, rng, 80 + rng.nextInt(160));\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n\n            if (st.zeros > best.zeros) {\n                best = st;\n            }\n\n            if (st.zeros + 30 < best.zeros) break;\n        }\n    }\n}\n\nbool validateState(const State& st) {\n    static int cnt2[MAXC];\n    static int ed2[MAXC][MAXC];\n\n    memset(cnt2, 0, sizeof(cnt2));\n    memset(ed2, 0, sizeof(ed2));\n\n    auto add = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        ed2[a][b]++;\n        ed2[b][a]++;\n    };\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a < 0 || a > M) return false;\n        cnt2[a]++;\n    }\n\n    for (int c = 1; c <= M; ++c) {\n        if (cnt2[c] == 0) return false;\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n            int a = st.g[p];\n\n            if (r + 1 < N) add(a, st.g[(r + 1) * N + c]);\n            if (c + 1 < N) add(a, st.g[r * N + (c + 1)]);\n\n            if (r == 0) add(0, a);\n            if (r == N - 1) add(0, a);\n            if (c == 0) add(0, a);\n            if (c == N - 1) add(0, a);\n        }\n    }\n\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if ((ed2[i][j] > 0) != REQ[i][j]) return false;\n        }\n    }\n\n    for (int col = 1; col <= M; ++col) {\n        int start = -1;\n\n        for (int p = 0; p < V; ++p) {\n            if (st.g[p] == col) {\n                start = p;\n                break;\n            }\n        }\n\n        if (start == -1) return false;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        visArr[start] = stamp;\n        bfsQ[tail++] = start;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != cnt2[col]) return false;\n    }\n\n    if (cnt2[0] > 0) {\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (st.g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != cnt2[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    V = N * N;\n\n    State init;\n    init.clear();\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int x;\n            cin >> x;\n            init.g[i * N + j] = (unsigned char)x;\n\n            seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    init.rebuild();\n\n    memset(REQ, 0, sizeof(REQ));\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if (init.edge[i][j] > 0) {\n                REQ[i][j] = REQ[j][i] = true;\n            }\n        }\n    }\n\n    computeGraphInfo();\n\n    Timer timer;\n\n    const double MAIN_LIMIT = 1.58;\n    const double SHAKE_LIMIT = 1.84;\n    const double POLISH_LIMIT = 1.91;\n\n    State best = init;\n\n    int run = 0;\n    while (timer.elapsed() < MAIN_LIMIT) {\n        State st;\n\n        if (run >= 4 && run % 3 == 2) {\n            st = best;\n        } else {\n            st = init;\n        }\n\n        uint64_t rseed =\n            seed\n            + 0x9e3779b97f4a7c15ULL * (uint64_t)(run + 1)\n            + 0xbf58476d1ce4e5b9ULL * (uint64_t)(best.zeros + 1);\n\n        RNG rng(rseed);\n        Params par = getParams(run);\n\n        improve(st, best, rng, par, timer, MAIN_LIMIT);\n        ++run;\n    }\n\n    RNG shakeRng(seed ^ 0xd1b54a32d192ed03ULL ^ (uint64_t)best.zeros);\n    shakeSearch(best, shakeRng, timer, SHAKE_LIMIT);\n\n    RNG finalRng(seed ^ 0x94d049bb133111ebULL);\n    while (timer.elapsed() < POLISH_LIMIT) {\n        int before = best.zeros;\n\n        for (int mode = 0; mode < 4; ++mode) {\n            if (timer.elapsed() >= POLISH_LIMIT) break;\n            greedyDelete(best, finalRng, mode);\n        }\n\n        if (best.zeros == before) break;\n    }\n\n    if (!validateState(best)) {\n        best = init;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (j) cout << ' ';\n            cout << (int)best.g[i * N + j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, D, Q;\nint qUsed = 0;\nmt19937_64 rng;\nvector<vector<char>> itemCmp;\n\nconstexpr int DP_SCALE_BASE = 500;\nconstexpr int DP_SUM_LIMIT = 80000;\n\nstruct Solution {\n    vector<int> assign;\n    vector<vector<int>> bins;\n    vector<double> load;\n    double obj = 1e100;\n};\n\nchar invCmp(char c) {\n    if (c == '>') return '<';\n    if (c == '<') return '>';\n    return c;\n}\n\nchar ask(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    if (!(cin >> s)) exit(0);\n    qUsed++;\n    return s[0];\n}\n\nchar compareItems(int a, int b) {\n    if (a == b) return '=';\n    if (itemCmp[a][b] != '?') return itemCmp[a][b];\n    if (qUsed >= Q) return '?';\n\n    vector<int> L{a}, R{b};\n    char c = ask(L, R);\n    itemCmp[a][b] = c;\n    itemCmp[b][a] = invCmp(c);\n    return c;\n}\n\ndouble norm_pdf(double x) {\n    static const double INV_SQRT_2PI = 1.0 / sqrt(2.0 * acos(-1.0));\n    if (abs(x) > 40) return 0.0;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble norm_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble truncatedNormalMean(double mu, double sd, double lo, double hi) {\n    if (sd < 1e-12) return clamp(mu, lo, hi);\n\n    double a = (lo - mu) / sd;\n    double b = (hi - mu) / sd;\n    double A = norm_cdf(a);\n    double B = norm_cdf(b);\n    double Z = B - A;\n\n    if (Z < 1e-14) {\n        if (mu < lo) return lo;\n        if (mu > hi) return hi;\n        return clamp(mu, lo, hi);\n    }\n\n    double mean = mu + sd * (norm_pdf(a) - norm_pdf(b)) / Z;\n    return clamp(mean, lo, hi);\n}\n\nvector<double> estimateWeights(const vector<double>& score, int qRand) {\n    vector<double> est(N, 1.0);\n    if (qRand <= 0) return est;\n\n    const double PI = acos(-1.0);\n    const double c = sqrt(2.0 / PI);\n\n    int K = N / 2;\n    double pNonZero = 2.0 * K / N;\n    double lambda = 2.0 * K / (N - 1.0);\n    double ce = c * sqrt(lambda);\n\n    double sigmaZ = sqrt(pNonZero * N) / (ce * sqrt((double)qRand));\n\n    // Prior: Exp(1), truncated at b=N/D, then normalized to mean 1.\n    double cap = (double)N / D;\n    double e = exp(-cap);\n    double Z = 1.0 - e;\n    double meanX = (1.0 - (cap + 1.0) * e) / Z;\n    double secondX = (2.0 - (cap * cap + 2.0 * cap + 2.0) * e) / Z;\n    double varX = max(1e-12, secondX - meanX * meanX);\n    double cv = sqrt(varX) / meanX;\n    double rMax = cap / meanX;\n\n    double tau = max(1e-6, cv * sigmaZ);\n    double rate = meanX;\n\n    for (int i = 0; i < N; i++) {\n        double zObs = score[i] * sqrt((double)N) / (ce * qRand);\n        double obsR = 1.0 + cv * zObs;\n\n        // Posterior with exponential prior:\n        // exp(-rate*r) * Normal(obsR | r, tau^2)\n        double mu = obsR - rate * tau * tau;\n        est[i] = truncatedNormalMean(mu, tau, 0.0, rMax);\n        est[i] = max(est[i], 1e-6);\n    }\n\n    return est;\n}\n\ndouble calcObjLoad(const vector<double>& load, double target) {\n    double res = 0.0;\n    for (double x : load) {\n        double d = x - target;\n        res += d * d;\n    }\n    return res;\n}\n\ndouble totalWeight(const vector<double>& w) {\n    return accumulate(w.begin(), w.end(), 0.0);\n}\n\nSolution buildSolution(const vector<int>& assign, const vector<double>& w) {\n    Solution sol;\n    sol.assign = assign;\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    for (int i = 0; i < N; i++) {\n        int b = sol.assign[i];\n        sol.bins[b].push_back(i);\n        sol.load[b] += w[i];\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nvoid eraseItem(vector<int>& v, int x) {\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (v[i] == x) {\n            v[i] = v.back();\n            v.pop_back();\n            return;\n        }\n    }\n}\n\nvoid moveItemSol(Solution& sol, int item, int from, int to, const vector<double>& w) {\n    eraseItem(sol.bins[from], item);\n    sol.bins[to].push_back(item);\n    sol.assign[item] = to;\n    sol.load[from] -= w[item];\n    sol.load[to] += w[item];\n}\n\nvoid swapItemsSol(Solution& sol, int x, int y, int bx, int by, const vector<double>& w) {\n    for (int& v : sol.bins[bx]) {\n        if (v == x) {\n            v = y;\n            break;\n        }\n    }\n    for (int& v : sol.bins[by]) {\n        if (v == y) {\n            v = x;\n            break;\n        }\n    }\n\n    sol.assign[x] = by;\n    sol.assign[y] = bx;\n\n    sol.load[bx] += w[y] - w[x];\n    sol.load[by] += w[x] - w[y];\n}\n\nvoid localImprove(Solution& sol, const vector<double>& w, double target) {\n    for (int iter = 0; iter < 2000; iter++) {\n        double bestDelta = -1e-12;\n        int bestType = 0;\n        int bestI = -1, bestJ = -1;\n        int bestA = -1, bestB = -1;\n\n        // Single-item move\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            if ((int)sol.bins[a].size() <= 1) continue;\n\n            for (int b = 0; b < D; b++) {\n                if (a == b) continue;\n\n                double oldVal =\n                    pow(sol.load[a] - target, 2) +\n                    pow(sol.load[b] - target, 2);\n\n                double newVal =\n                    pow(sol.load[a] - w[i] - target, 2) +\n                    pow(sol.load[b] + w[i] - target, 2);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        // Swap\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            for (int j = i + 1; j < N; j++) {\n                int b = sol.assign[j];\n                if (a == b) continue;\n\n                double oldVal =\n                    pow(sol.load[a] - target, 2) +\n                    pow(sol.load[b] - target, 2);\n\n                double newVal =\n                    pow(sol.load[a] - w[i] + w[j] - target, 2) +\n                    pow(sol.load[b] - w[j] + w[i] - target, 2);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestI = i;\n                    bestJ = j;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        if (bestType == 0) break;\n\n        if (bestType == 1) {\n            moveItemSol(sol, bestI, bestA, bestB, w);\n        } else {\n            swapItemsSol(sol, bestI, bestJ, bestA, bestB, w);\n        }\n\n        sol.obj += bestDelta;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nbool pairBalanceDP(Solution& sol, int a, int b, const vector<double>& w, double target) {\n    vector<int> items = sol.bins[a];\n    for (int x : sol.bins[b]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 1) return false;\n\n    double pairSum = sol.load[a] + sol.load[b];\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(w[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1);\n    vector<int> parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    int bestS = -1;\n    int bestDiff = INT_MAX;\n    for (int s = 0; s <= total; s++) {\n        if (!dp[s]) continue;\n        int diff = abs(total - 2 * s);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestS = s;\n        }\n    }\n\n    if (bestS < 0) return false;\n\n    vector<char> inA(M, 0);\n    int cur = bestS;\n    while (cur > 0) {\n        int idx = parItem[cur];\n        if (idx < 0) return false;\n        inA[idx] = 1;\n        cur = parPrev[cur];\n    }\n\n    int cntA = 0;\n    double loadA = 0.0;\n    for (int i = 0; i < M; i++) {\n        if (inA[i]) {\n            cntA++;\n            loadA += w[items[i]];\n        }\n    }\n\n    if (cntA == 0 || cntA == M) return false;\n\n    double loadB = pairSum - loadA;\n\n    // Keep orientation closer to the previous one.\n    double keepCost = abs(loadA - sol.load[a]) + abs(loadB - sol.load[b]);\n    double flipCost = abs(loadB - sol.load[a]) + abs(loadA - sol.load[b]);\n    if (flipCost < keepCost) {\n        for (char& x : inA) x ^= 1;\n        swap(loadA, loadB);\n        cntA = M - cntA;\n    }\n\n    double oldPair =\n        pow(sol.load[a] - target, 2) +\n        pow(sol.load[b] - target, 2);\n\n    double newPair =\n        pow(loadA - target, 2) +\n        pow(loadB - target, 2);\n\n    if (newPair >= oldPair - 1e-12) return false;\n\n    sol.bins[a].clear();\n    sol.bins[b].clear();\n    sol.load[a] = 0.0;\n    sol.load[b] = 0.0;\n\n    for (int i = 0; i < M; i++) {\n        int item = items[i];\n        if (inA[i]) {\n            sol.assign[item] = a;\n            sol.bins[a].push_back(item);\n            sol.load[a] += w[item];\n        } else {\n            sol.assign[item] = b;\n            sol.bins[b].push_back(item);\n            sol.load[b] += w[item];\n        }\n    }\n\n    sol.obj += newPair - oldPair;\n    return true;\n}\n\nvoid improveSolution(Solution& sol, const vector<double>& w, int sweeps) {\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n\n    localImprove(sol, w, target);\n\n    for (int sw = 0; sw < sweeps; sw++) {\n        double before = sol.obj;\n        vector<tuple<double, int, int>> pairs;\n\n        for (int a = 0; a < D; a++) {\n            for (int b = a + 1; b < D; b++) {\n                pairs.emplace_back(abs(sol.load[a] - sol.load[b]), a, b);\n            }\n        }\n\n        sort(pairs.rbegin(), pairs.rend());\n\n        bool changed = false;\n        for (auto [_, a, b] : pairs) {\n            changed |= pairBalanceDP(sol, a, b, w, target);\n        }\n\n        localImprove(sol, w, target);\n\n        if (!changed || sol.obj >= before - 1e-12) break;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nSolution makeGreedyOrder(const vector<int>& order, const vector<double>& w) {\n    Solution sol;\n    sol.assign.assign(N, -1);\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    vector<int> cnt(D, 0);\n\n    for (int item : order) {\n        int best = 0;\n        for (int b = 1; b < D; b++) {\n            if (sol.load[b] < sol.load[best] - 1e-12 ||\n                (abs(sol.load[b] - sol.load[best]) <= 1e-12 && cnt[b] < cnt[best])) {\n                best = b;\n            }\n        }\n\n        sol.assign[item] = best;\n        sol.bins[best].push_back(item);\n        sol.load[best] += w[item];\n        cnt[best]++;\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nSolution makeSnake(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        int block = i / D;\n        int pos = i % D;\n        int b = (block % 2 == 0) ? pos : (D - 1 - pos);\n        assign[order[i]] = b;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution makeRoundRobin(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        assign[order[i]] = i % D;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution partitionEstimated(const vector<double>& w) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return w[a] > w[b];\n    });\n\n    Solution best;\n    auto consider = [&](Solution sol) {\n        improveSolution(sol, w, 2);\n        if (sol.obj < best.obj) best = sol;\n    };\n\n    consider(makeGreedyOrder(order, w));\n    consider(makeSnake(order, w));\n    consider(makeRoundRobin(order, w));\n\n    normal_distribution<double> nd(0.0, 0.35);\n\n    for (int rep = 0; rep < 3; rep++) {\n        vector<pair<double, int>> keys;\n        keys.reserve(N);\n\n        for (int i = 0; i < N; i++) {\n            double key = log(max(1e-9, w[i])) + nd(rng);\n            keys.emplace_back(-key, i);\n        }\n\n        sort(keys.begin(), keys.end());\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto [_, id] : keys) ord.push_back(id);\n\n        consider(makeGreedyOrder(ord, w));\n    }\n\n    improveSolution(best, w, 2);\n    return best;\n}\n\nvector<int> withoutItem(const vector<int>& v, int x) {\n    vector<int> res;\n    res.reserve(v.size());\n    for (int y : v) {\n        if (y != x) res.push_back(y);\n    }\n    return res;\n}\n\nint minMaxCost() {\n    int pairs = D / 2;\n    int sz = pairs + (D % 2);\n    return pairs + max(0, sz - 1) + max(0, sz - 1);\n}\n\nbool findActualMinMax(const vector<vector<int>>& bins, int& mn, int& mx) {\n    vector<int> winners, losers;\n\n    for (int i = 0; i + 1 < D; i += 2) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[i], bins[i + 1]);\n        if (c == '>') {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        } else if (c == '<') {\n            winners.push_back(i + 1);\n            losers.push_back(i);\n        } else {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        }\n    }\n\n    if (D % 2 == 1) {\n        winners.push_back(D - 1);\n        losers.push_back(D - 1);\n    }\n\n    mx = winners[0];\n    for (int i = 1; i < (int)winners.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[winners[i]], bins[mx]);\n        if (c == '>') mx = winners[i];\n    }\n\n    mn = losers[0];\n    for (int i = 1; i < (int)losers.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[losers[i]], bins[mn]);\n        if (c == '<') mn = losers[i];\n    }\n\n    return true;\n}\n\nint actualRefine(Solution& sol, const vector<double>& est) {\n    int successes = 0;\n\n    while (qUsed < Q) {\n        int cost = minMaxCost();\n        if (Q - qUsed < cost + 1) break;\n\n        int mn = -1, mx = -1;\n        if (!findActualMinMax(sol.bins, mn, mx)) break;\n\n        int H = mx;\n        int L = mn;\n        if (H == L) break;\n\n        bool success = false;\n\n        // Try moving a small item from the actual heaviest bin to the actual lightest bin.\n        if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n            vector<int> items = sol.bins[H];\n            sort(items.begin(), items.end(), [&](int a, int b) {\n                return est[a] < est[b];\n            });\n\n            int rem = Q - qUsed;\n            int moveLimit = min((int)items.size(), min(6, max(1, rem / 3)));\n            if (rem <= 3) moveLimit = min((int)items.size(), rem);\n\n            int bestMove = -1;\n            int tried = 0;\n\n            for (int x : items) {\n                if (tried >= moveLimit || qUsed >= Q) break;\n\n                vector<int> left = withoutItem(sol.bins[H], x);\n                if (left.empty()) break;\n\n                char c = ask(left, sol.bins[L]);\n                tried++;\n\n                if (c == '>') {\n                    bestMove = x;\n                } else if (bestMove != -1) {\n                    break;\n                }\n            }\n\n            if (bestMove != -1) {\n                moveItemSol(sol, bestMove, H, L, est);\n                success = true;\n            }\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        // Try swaps that are provably improving.\n        if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n            vector<tuple<double, int, int>> cand;\n\n            for (int x : sol.bins[H]) {\n                for (int y : sol.bins[L]) {\n                    double diff = est[x] - est[y];\n                    double key = (diff >= 0.0) ? diff : (2.0 + (-diff));\n                    cand.emplace_back(key, x, y);\n                }\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int tried = 0;\n            for (auto [_, x, y] : cand) {\n                if (tried >= 20 || qUsed >= Q) break;\n                tried++;\n\n                char xy = compareItems(x, y);\n                if (xy == '?') break;\n                if (xy != '>') continue;\n\n                // If L consists only of y, then H\\{x} has positive weight,\n                // so the condition H\\{x} > L\\{y}=0 is automatically true.\n                if ((int)sol.bins[L].size() == 1) {\n                    swapItemsSol(sol, x, y, H, L, est);\n                    success = true;\n                    break;\n                }\n\n                vector<int> left = withoutItem(sol.bins[H], x);\n                vector<int> right = withoutItem(sol.bins[L], y);\n\n                if (left.empty()) continue;\n                if (right.empty()) {\n                    swapItemsSol(sol, x, y, H, L, est);\n                    success = true;\n                    break;\n                }\n\n                if (qUsed >= Q) break;\n\n                char c = ask(left, right);\n                if (c == '>') {\n                    swapItemsSol(sol, x, y, H, L, est);\n                    success = true;\n                    break;\n                }\n            }\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        break;\n    }\n\n    return successes;\n}\n\nvoid randomBalancedQueries(int cnt, vector<double>& score) {\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n\n    int K = N / 2;\n\n    for (int q = 0; q < cnt && qUsed < Q; q++) {\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L, R;\n        L.reserve(K);\n        R.reserve(K);\n\n        for (int i = 0; i < K; i++) L.push_back(perm[i]);\n        for (int i = 0; i < K; i++) R.push_back(perm[K + i]);\n\n        char c = ask(L, R);\n        int y = 0;\n        if (c == '>') y = 1;\n        else if (c == '<') y = -1;\n\n        if (y != 0) {\n            for (int x : L) score[x] += y;\n            for (int x : R) score[x] -= y;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)N * 1000003ULL;\n    seed ^= (uint64_t)D * 10007ULL;\n    seed ^= (uint64_t)Q * 998244353ULL;\n    rng.seed(seed);\n\n    itemCmp.assign(N, vector<char>(N, '?'));\n    for (int i = 0; i < N; i++) itemCmp[i][i] = '=';\n\n    vector<double> score(N, 0.0);\n\n    int qRefine = min(Q / 5, 2 * N);\n    int qRandom = Q - qRefine;\n\n    randomBalancedQueries(qRandom, score);\n\n    vector<double> est = estimateWeights(score, qRandom);\n\n    Solution sol = partitionEstimated(est);\n\n    actualRefine(sol, est);\n\n    // Remaining queries are consumed safely.\n    while (qUsed < Q) {\n        vector<int> L{0}, R{1};\n        ask(L, R);\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << sol.assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MMAX = 10;\nstatic const int INF = 1000000000;\n\nint nG, mG;\nusing StackArray = array<vector<int>, MMAX>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (double)(next() >> 11) * (1.0 / (double)(1ULL << 53));\n    }\n};\n\nstruct Params {\n    int mode = 2;\n    int badMode = 0;\n    int goodMode = 0;\n    int thresholdMode = 0;\n    int destMode = 0;\n\n    double noise = 0.0;\n\n    double lenW = 0.06;\n    double dirtyW = 1.5;\n    double badW = 3.0;\n    double amountW = 0.05;\n    double slackW = 0.02;\n    double heightW = 0.0;\n    double gW = 0.05;\n\n    int initA = -1, initB = -1;\n};\n\nstruct Result {\n    vector<pair<int,int>> ops;\n    int cost = INF;\n    bool ok = false;\n};\n\nstruct Stats {\n    int len = 0;\n    int maxv = -1;\n    int minv = INF;\n    int internalBad = 0;\n};\n\nResult invalidResult() {\n    return Result{{}, INF, false};\n}\n\npair<int,int> findBox(const StackArray& st, int v) {\n    for (int i = 0; i < mG; 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\nint minStackValue(const StackArray& st, int s) {\n    if (st[s].empty()) return INF;\n    int mn = INF;\n    for (int x : st[s]) mn = min(mn, x);\n    return mn;\n}\n\nint thresholdValue(const StackArray& st, int s, int mode) {\n    if (st[s].empty()) return INF;\n    if (mode == 1) return st[s].back();\n    return minStackValue(st, s);\n}\n\nint aboveMinCountOne(const vector<int>& a) {\n    if (a.empty()) return 0;\n    int mn = INF, pos = -1;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i] < mn) {\n            mn = a[i];\n            pos = i;\n        }\n    }\n    return (int)a.size() - pos - 1;\n}\n\nStats blockStats(const vector<int>& a, int cut) {\n    Stats s;\n    s.len = (int)a.size() - cut;\n    for (int i = cut; i < (int)a.size(); i++) {\n        s.maxv = max(s.maxv, a[i]);\n        s.minv = min(s.minv, a[i]);\n        if (i + 1 < (int)a.size() && a[i] < a[i + 1]) s.internalBad++;\n    }\n    return s;\n}\n\nint countGreaterThan(const vector<int>& a, int cut, int g) {\n    int c = 0;\n    for (int i = cut; i < (int)a.size(); i++) {\n        if (a[i] > g) c++;\n    }\n    return c;\n}\n\nint topCleanStart(const vector<int>& a, int targetPos) {\n    int c = (int)a.size() - 1;\n    while (c - 1 > targetPos && a[c - 1] > a[c]) c--;\n    return c;\n}\n\nbool existsGoodDest(const StackArray& st, int src, const Stats& bs, const Params& p) {\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int g = thresholdValue(st, d, p.thresholdMode);\n        if (bs.maxv < g) return true;\n    }\n    return false;\n}\n\nint chooseDest(const StackArray& st, int src, int cut, const Params& p, XorShift& rng) {\n    Stats bs = blockStats(st[src], cut);\n    int bestDst = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        int g = thresholdValue(st, d, p.thresholdMode);\n        double normG = (g >= INF / 2 ? 1000.0 : (double)g);\n        bool good = (bs.maxv < g);\n        int badCnt = countGreaterThan(st[src], cut, g);\n        int h = (int)st[d].size();\n        int aboveMin = aboveMinCountOne(st[d]);\n\n        double score = 0.0;\n        if (p.destMode == 0) {\n            if (good) {\n                score = normG * 10.0 + h * 0.01;\n            } else {\n                score = 100000.0 - normG * 10.0 + badCnt * 100.0 + h * 0.01;\n            }\n        } else if (p.destMode == 1) {\n            if (good) {\n                score = normG * 10.0 - h * 0.05;\n            } else {\n                score = 100000.0 - normG * 10.0 - aboveMin * 5.0 + h * 0.01;\n            }\n        } else if (p.destMode == 2) {\n            if (good) {\n                score = (g >= INF / 2 ? 0.0 : normG * 10.0) + h * 0.02;\n            } else {\n                score = 100000.0 + badCnt * 1000.0 - normG * 20.0 - aboveMin * 5.0;\n            }\n        } else {\n            if (good) {\n                score = (normG - bs.maxv) * 10.0 + h * 0.1;\n            } else {\n                score = 100000.0 + badCnt * 500.0\n                      + max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g)) * 5.0\n                      - normG * 10.0 + h * 0.1;\n            }\n        }\n\n        if (p.noise > 0.0) {\n            score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestDst = d;\n        }\n    }\n\n    if (bestDst == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return bestDst;\n}\n\nbool applyMove(StackArray& st, vector<pair<int,int>>& ops, int& cost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    int label = st[src][cut];\n\n    ops.push_back({label, dst + 1});\n    cost += len + 1;\n\n    if (cost >= cutoff) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    if ((int)ops.size() > 5000) return false;\n    return true;\n}\n\nstruct Choice {\n    int cut = -1;\n    int dst = -1;\n};\n\nChoice chooseEnumMove(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    int blockers = h - pos - 1;\n\n    vector<int> cuts;\n    auto addCut = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    addCut(h - 1);\n    addCut(pos + 1);\n    int c0 = topCleanStart(a, pos);\n    addCut(c0);\n\n    for (int c = c0; c < h; c++) addCut(c);\n\n    int cur = h - 1;\n    int added = 0;\n    while (cur > pos && added < 12) {\n        int r = cur;\n        while (r - 1 > pos && a[r - 1] > a[r]) r--;\n        addCut(r);\n        cur = r - 1;\n        added++;\n    }\n\n    if (blockers <= 25) {\n        for (int c = pos + 1; c < h; c++) addCut(c);\n    } else {\n        for (int t = 1; t <= 10; t++) {\n            int c = pos + 1 + (int)((long long)(blockers - 1) * t / 11);\n            addCut(c);\n        }\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    Choice best;\n    double bestScore = 1e100;\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(a, cut);\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            int g = thresholdValue(st, d, p.thresholdMode);\n            int badCnt = countGreaterThan(a, cut, g);\n            double normG = (g >= INF / 2 ? 250.0 : (double)g);\n\n            double score = 1.0 - p.lenW * bs.len + p.dirtyW * bs.internalBad;\n\n            if (badCnt == 0) {\n                score += p.slackW * (normG - bs.maxv);\n                score += p.heightW * (int)st[d].size();\n            } else {\n                score += p.badW * badCnt;\n                score += p.amountW * max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g));\n                score -= p.gW * normG;\n                score += p.heightW * (int)st[d].size();\n            }\n\n            if (p.noise > 0.0) {\n                score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best.cut = cut;\n                best.dst = d;\n            }\n        }\n    }\n\n    if (best.cut == -1) {\n        best.cut = h - 1;\n        best.dst = (src == 0 ? 1 : 0);\n    }\n    return best;\n}\n\nResult simulateGreedy(const StackArray& init, Params p, uint64_t seed, int cutoff) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n    XorShift rng(seed);\n\n    if (p.initA >= 0 && p.initA < mG && p.initB >= 0 && p.initB < mG &&\n        p.initA != p.initB && !st[p.initA].empty()) {\n        if (!applyMove(st, ops, cost, p.initA, 0, p.initB, cutoff)) {\n            return invalidResult();\n        }\n    }\n\n    for (int v = 1; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            if (p.mode == 3) {\n                Choice ch = chooseEnumMove(st, src, pos, p, rng);\n                if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                    return invalidResult();\n                }\n                continue;\n            }\n\n            int cut = -1;\n\n            if (p.mode == 0) {\n                cut = pos + 1;\n            } else if (p.mode == 1) {\n                cut = h - 1;\n            } else {\n                int c0 = topCleanStart(st[src], pos);\n                bool selected = false;\n\n                if (p.goodMode == 0) {\n                    for (int c = c0; c < h; c++) {\n                        Stats bs = blockStats(st[src], c);\n                        if (existsGoodDest(st, src, bs, p)) {\n                            cut = c;\n                            selected = true;\n                            break;\n                        }\n                    }\n                } else if (p.goodMode == 1) {\n                    Stats bs = blockStats(st[src], c0);\n                    if (existsGoodDest(st, src, bs, p)) {\n                        cut = c0;\n                        selected = true;\n                    }\n                } else {\n                    cut = c0;\n                    selected = true;\n                }\n\n                if (!selected) {\n                    if (p.badMode == 3) {\n                        Choice ch = chooseEnumMove(st, src, pos, p, rng);\n                        if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                            return invalidResult();\n                        }\n                        continue;\n                    } else if (p.badMode == 0) {\n                        cut = c0;\n                    } else if (p.badMode == 1) {\n                        cut = pos + 1;\n                    } else {\n                        cut = h - 1;\n                    }\n                }\n            }\n\n            int dst = chooseDest(st, src, cut, p, rng);\n            if (!applyMove(st, ops, cost, src, cut, dst, cutoff)) {\n                return invalidResult();\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    for (int i = 0; i < mG; i++) {\n        if (!st[i].empty()) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint stateBadCount(const StackArray& st) {\n    int cnt = 0;\n    for (int i = 0; i < mG; i++) {\n        int mn = INF;\n        for (int x : st[i]) {\n            if (x > mn) cnt++;\n            mn = min(mn, x);\n        }\n    }\n    return cnt;\n}\n\nint aboveMinTotal(const StackArray& st) {\n    int s = 0;\n    for (int i = 0; i < mG; i++) s += aboveMinCountOne(st[i]);\n    return s;\n}\n\ndouble beamEval(const StackArray& st, int cost, double alpha) {\n    return cost + alpha * stateBadCount(st) + 0.30 * alpha * aboveMinTotal(st);\n}\n\nstruct BeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateBeamWhole(const StackArray& init, int W, double alpha, int cutoff) {\n    BeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(6000);\n    first.eval = beamEval(first.st, first.cost, alpha);\n\n    vector<BeamState> beam;\n    beam.push_back(first);\n\n    for (int v = 1; v <= nG; v++) {\n        vector<BeamState> cand;\n        cand.reserve(beam.size() * mG);\n\n        for (const auto& bs : beam) {\n            if (bs.cost >= cutoff) continue;\n\n            auto [src, pos] = findBox(bs.st, v);\n            if (src < 0) continue;\n\n            int h = (int)bs.st[src].size();\n\n            if (pos == h - 1) {\n                BeamState ns = bs;\n                ns.ops.push_back({v, 0});\n                ns.st[src].pop_back();\n                if ((int)ns.ops.size() > 5000) continue;\n                ns.eval = beamEval(ns.st, ns.cost, alpha);\n                cand.push_back(std::move(ns));\n            } else {\n                int cut = pos + 1;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n\n                    BeamState ns = bs;\n                    if (!applyMove(ns.st, ns.ops, ns.cost, src, cut, d, cutoff)) continue;\n\n                    if (ns.st[src].empty() || ns.st[src].back() != v) continue;\n                    ns.ops.push_back({v, 0});\n                    ns.st[src].pop_back();\n                    if ((int)ns.ops.size() > 5000) continue;\n\n                    ns.eval = beamEval(ns.st, ns.cost, alpha);\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const BeamState& a, const BeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)cand.size() > W) cand.resize(W);\n        beam = std::move(cand);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nint validateCost(const StackArray& init, const vector<pair<int,int>>& ops) {\n    if ((int)ops.size() > 5000) return -1;\n\n    StackArray st = init;\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (auto [v, to] : ops) {\n        if (v < 1 || v > nG) return -1;\n\n        if (to == 0) {\n            if (v != nextRemove) return -1;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!st[s].empty() && st[s].back() == v) {\n                    st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return -1;\n            int dst = to - 1;\n\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)st[s].size(); j++) {\n                    if (st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n            if (src == -1) return -1;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n\n            if (src != dst) {\n                st[dst].insert(st[dst].end(), st[src].begin() + pos, st[src].end());\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return -1;\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return -1;\n    return cost;\n}\n\nParams randomParams(XorShift& rng) {\n    Params p;\n\n    int r = rng.nextInt(100);\n    if (r < 12) p.mode = 0;\n    else if (r < 30) p.mode = 1;\n    else if (r < 82) p.mode = 2;\n    else p.mode = 3;\n\n    p.badMode = rng.nextInt(4);\n    p.goodMode = rng.nextInt(3);\n    p.thresholdMode = (rng.nextInt(100) < 85 ? 0 : 1);\n    p.destMode = rng.nextInt(4);\n\n    p.noise = rng.nextDouble() * 4.0;\n\n    p.lenW = 0.02 + rng.nextDouble() * 0.18;\n    p.dirtyW = 0.5 + rng.nextDouble() * 4.0;\n    p.badW = 1.0 + rng.nextDouble() * 6.0;\n    p.amountW = rng.nextDouble() * 0.25;\n    p.slackW = rng.nextDouble() * 0.08;\n    p.heightW = (rng.nextDouble() - 0.5) * 0.06;\n    p.gW = rng.nextDouble() * 0.20;\n\n    if (mG >= 2 && rng.nextInt(100) < 12) {\n        p.initA = rng.nextInt(mG);\n        p.initB = rng.nextInt(mG - 1);\n        if (p.initB >= p.initA) p.initB++;\n    }\n\n    return p;\n}\n\n/* ---------- Feature-based macro beam search ---------- */\n\nstruct Feature {\n    int bad = 0;\n    int above = 0;\n    int runs = 0;\n    int inc = 0;\n    int empty = 0;\n};\n\nFeature& operator+=(Feature& a, const Feature& b) {\n    a.bad += b.bad;\n    a.above += b.above;\n    a.runs += b.runs;\n    a.inc += b.inc;\n    a.empty += b.empty;\n    return a;\n}\n\nFeature& operator-=(Feature& a, const Feature& b) {\n    a.bad -= b.bad;\n    a.above -= b.above;\n    a.runs -= b.runs;\n    a.inc -= b.inc;\n    a.empty -= b.empty;\n    return a;\n}\n\nFeature calcFeatureParts(const vector<int>& A, int l1, int r1,\n                         const vector<int>& B, int l2, int r2) {\n    Feature f;\n    int len = (r1 - l1) + (r2 - l2);\n    if (len == 0) {\n        f.empty = 1;\n        return f;\n    }\n\n    int idx = 0;\n    int mnBelow = INF;\n    int minVal = INF, minPos = -1;\n    int prevVal = -1;\n    bool hasPrev = false;\n    bool prevBad = false;\n\n    auto process = [&](int x) {\n        if (hasPrev && prevVal < x) f.inc++;\n\n        bool isBad = (x > mnBelow);\n        if (isBad) {\n            f.bad++;\n            if (!prevBad) f.runs++;\n        }\n        prevBad = isBad;\n\n        if (x < minVal) {\n            minVal = x;\n            minPos = idx;\n        }\n        mnBelow = min(mnBelow, x);\n\n        prevVal = x;\n        hasPrev = true;\n        idx++;\n    };\n\n    for (int i = l1; i < r1; i++) process(A[i]);\n    for (int i = l2; i < r2; i++) process(B[i]);\n\n    f.above = len - minPos - 1;\n    return f;\n}\n\nFeature totalFeatures(const StackArray& st, array<Feature, MMAX>* per = nullptr) {\n    Feature total;\n    for (int i = 0; i < mG; i++) {\n        Feature fi = calcFeatureParts(st[i], 0, (int)st[i].size(), st[i], 0, 0);\n        if (per) (*per)[i] = fi;\n        total += fi;\n    }\n    return total;\n}\n\nstruct EvalParam {\n    double A = 2.7;     // bad boxes\n    double B = 0.9;     // above stack minimum\n    double C = 1.2;     // bad runs\n    double D = 0.25;    // adjacent increasing violations\n    double E = 2.0;     // empty stack bonus\n    double F = 1.5;     // next target blockers\n    double beta = 0.75; // local action heuristic weight\n};\n\ndouble heuristicFeature(const Feature& f, const EvalParam& ep) {\n    return ep.A * f.bad + ep.B * f.above + ep.C * f.runs\n         + ep.D * f.inc - ep.E * f.empty;\n}\n\nint aboveBoxCount(const StackArray& st, int v) {\n    if (v > nG) return 0;\n    auto [s, p] = findBox(st, v);\n    if (s < 0) return 0;\n    return (int)st[s].size() - p - 1;\n}\n\ndouble heuristicState(const StackArray& st, int nextv, const EvalParam& ep) {\n    Feature f = totalFeatures(st, nullptr);\n    double h = heuristicFeature(f, ep);\n    if (nextv <= nG) h += ep.F * aboveBoxCount(st, nextv);\n    return h;\n}\n\nFeature featureAfterMoveContext(const StackArray& st,\n                                const array<Feature, MMAX>& sf,\n                                const Feature& total,\n                                int src, int pos, int cut, int dst,\n                                bool popIfExpose) {\n    int h = (int)st[src].size();\n\n    int srcEnd = cut;\n    if (popIfExpose && cut == pos + 1) srcEnd = pos;\n\n    Feature fsrc = calcFeatureParts(st[src], 0, srcEnd, st[src], 0, 0);\n    Feature fdst = calcFeatureParts(st[dst], 0, (int)st[dst].size(), st[src], cut, h);\n\n    Feature nf = total;\n    nf -= sf[src];\n    nf -= sf[dst];\n    nf += fsrc;\n    nf += fdst;\n    return nf;\n}\n\nuint64_t hashState(const StackArray& st) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < mG; i++) {\n        h ^= (uint64_t)(239 + i);\n        h *= 1099511628211ULL;\n        for (int x : st[i]) {\n            h ^= (uint64_t)(x + 1009);\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nstruct Macro {\n    StackArray st;\n    int addCost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n    bool ok = false;\n};\n\nMacro invalidMacro() {\n    Macro m;\n    m.ok = false;\n    m.addCost = INF;\n    return m;\n}\n\nbool macroMove(StackArray& st, vector<pair<int,int>>& ops, int& addCost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    if (addCost + len + 1 >= cutoff) return false;\n\n    int label = st[src][cut];\n    ops.push_back({label, dst + 1});\n    addCost += len + 1;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    return (int)ops.size() <= 5000;\n}\n\nbool macroRemove(StackArray& st, vector<pair<int,int>>& ops, int v) {\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return false;\n    if (pos != (int)st[src].size() - 1) return false;\n    ops.push_back({v, 0});\n    st[src].pop_back();\n    return (int)ops.size() <= 5000;\n}\n\nint bestDestByFeature(const StackArray& st, int src, int pos, int cut, const EvalParam& ep) {\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n    Stats bs = blockStats(st[src], cut);\n\n    int best = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n        double score = heuristicFeature(nf, ep);\n\n        int thr = minStackValue(st, d);\n        double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n\n        if (bs.maxv < thr) score += 0.0005 * thrNorm;\n        else score -= 0.0005 * thrNorm;\n\n        score += 0.00001 * (int)st[d].size();\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = d;\n        }\n    }\n\n    if (best == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return best;\n}\n\nvector<int> generateCutsForAction(const StackArray& st, int src, int pos, int maxCuts = 16) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    vector<int> cuts;\n\n    auto add = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    int c0 = topCleanStart(a, pos);\n    add(pos + 1);\n    add(h - 1);\n    add(c0);\n\n    int runLen = h - c0;\n    if (runLen <= 16) {\n        for (int c = c0; c < h; c++) add(c);\n    } else {\n        for (int t = 0; t < 10; t++) {\n            int c = c0 + (int)((long long)(runLen - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    int end = h;\n    int cnt = 0;\n    while (end > pos + 1 && cnt < 12) {\n        int start = end - 1;\n        while (start - 1 > pos && a[start - 1] > a[start]) start--;\n        add(start);\n        end = start;\n        cnt++;\n    }\n\n    int r = h - pos - 1;\n    if (r <= 18) {\n        for (int c = pos + 1; c < h; c++) add(c);\n    } else {\n        for (int t = 1; t <= 8; t++) {\n            int c = pos + 1 + (int)((long long)(r - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int thr = minStackValue(st, d);\n        int mx = -1;\n        int best = -1;\n        for (int c = h - 1; c > pos; c--) {\n            mx = max(mx, a[c]);\n            if (mx < thr) best = c;\n            else break;\n        }\n        if (best != -1) add(best);\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    if ((int)cuts.size() > maxCuts) {\n        vector<int> old = cuts;\n        vector<int> nc;\n        auto add2 = [&](int c) {\n            if (c > pos && c < h) nc.push_back(c);\n        };\n        add2(pos + 1);\n        add2(h - 1);\n        add2(c0);\n\n        int samples = max(1, maxCuts - 3);\n        for (int t = 0; t < samples; t++) {\n            int idx = (int)((long long)(old.size() - 1) * t / max(1, samples - 1));\n            add2(old[idx]);\n        }\n\n        sort(nc.begin(), nc.end());\n        nc.erase(unique(nc.begin(), nc.end()), nc.end());\n        cuts = nc;\n    }\n\n    return cuts;\n}\n\nstruct Action {\n    int cut = -1;\n    int dst = -1;\n    double score = 1e100;\n};\n\nvector<Action> getTopActions(const StackArray& st, int src, int pos,\n                             const EvalParam& ep, double beta, int limit) {\n    vector<Action> actions;\n    if (limit <= 0) return actions;\n\n    auto cuts = generateCutsForAction(st, src, pos, 16);\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n\n    int h = (int)st[src].size();\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(st[src], cut);\n        int len = h - cut;\n\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n            double sc = (len + 1) + beta * heuristicFeature(nf, ep);\n\n            int thr = minStackValue(st, d);\n            double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n            int badCnt = countGreaterThan(st[src], cut, thr);\n\n            if (bs.maxv < thr) {\n                sc += 0.0002 * thrNorm;\n                if (bs.internalBad == 0) sc -= 0.05 * bs.len;\n            } else {\n                sc += 0.20 * badCnt;\n                sc -= 0.0002 * thrNorm;\n            }\n            sc += 0.10 * bs.internalBad;\n\n            actions.push_back({cut, d, sc});\n        }\n    }\n\n    sort(actions.begin(), actions.end(), [](const Action& a, const Action& b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.cut != b.cut) return a.cut < b.cut;\n        return a.dst < b.dst;\n    });\n\n    if ((int)actions.size() > limit) actions.resize(limit);\n    return actions;\n}\n\nMacro completePolicy(const StackArray& input, int v, int policy,\n                     const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        int cut = -1, dst = -1;\n\n        if (policy == 0) { // longest compatible clean suffix if possible\n            int c0 = topCleanStart(mo.st[src], pos);\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(mo.st[src], c);\n                bool good = false;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n                    if (bs.maxv < minStackValue(mo.st, d)) {\n                        good = true;\n                        break;\n                    }\n                }\n                if (good) {\n                    cut = c;\n                    break;\n                }\n            }\n            if (cut == -1) cut = c0;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 1) { // maximal top clean run\n            cut = topCleanStart(mo.st[src], pos);\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 2) { // single top box\n            cut = h - 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 3) { // whole suffix\n            cut = pos + 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else { // one-step feature greedy\n            auto acts = getTopActions(mo.st, src, pos, ep, ep.beta, 1);\n            if (acts.empty()) return invalidMacro();\n            cut = acts[0].cut;\n            dst = acts[0].dst;\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, cut, dst, cutoff)) {\n            return invalidMacro();\n        }\n    }\n}\n\nvector<Macro> generateMacros(const StackArray& st, int v,\n                             const EvalParam& ep, int cutoff, int limit) {\n    vector<Macro> res;\n\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return res;\n\n    int h = (int)st[src].size();\n\n    auto pushMacro = [&](Macro&& mo) {\n        if (!mo.ok) return;\n        if (mo.addCost >= cutoff) return;\n        if ((int)mo.ops.size() > 5000) return;\n        mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n        res.push_back(std::move(mo));\n    };\n\n    if (pos == h - 1) {\n        Macro mo;\n        mo.st = st;\n        mo.addCost = 0;\n        mo.ops.reserve(1);\n        if (macroRemove(mo.st, mo.ops, v)) {\n            mo.ok = true;\n            pushMacro(std::move(mo));\n        }\n        return res;\n    }\n\n    int r = h - pos - 1;\n\n    // Direct deterministic macro policies.\n    pushMacro(completePolicy(st, v, 0, ep, cutoff));\n    pushMacro(completePolicy(st, v, 1, ep, cutoff));\n    pushMacro(completePolicy(st, v, 2, ep, cutoff));\n    if (r <= 60) pushMacro(completePolicy(st, v, 4, ep, cutoff));\n\n    auto addFirstFinish = [&](int cut, int dst, int finishPolicy) {\n        StackArray tmp = st;\n        vector<pair<int,int>> ops;\n        ops.reserve(256);\n        int cst = 0;\n        if (!macroMove(tmp, ops, cst, src, cut, dst, cutoff)) return;\n\n        Macro rest = completePolicy(tmp, v, finishPolicy, ep, cutoff - cst);\n        if (!rest.ok) return;\n\n        Macro mo;\n        mo.st = rest.st;\n        mo.addCost = cst + rest.addCost;\n        mo.ops = std::move(ops);\n        mo.ops.insert(mo.ops.end(), rest.ops.begin(), rest.ops.end());\n        mo.ok = true;\n        pushMacro(std::move(mo));\n    };\n\n    // Whole suffix to every destination.\n    int wholeCut = pos + 1;\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        addFirstFinish(wholeCut, d, 0);\n    }\n\n    // Top clean run to every destination.\n    int cleanCut = topCleanStart(st[src], pos);\n    if (cleanCut != wholeCut) {\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n            addFirstFinish(cleanCut, d, 0);\n        }\n    }\n\n    // Feature-scored first moves, then complete by clean policy.\n    int firstLimit = (r <= 8 ? 8 : 6);\n    auto acts = getTopActions(st, src, pos, ep, ep.beta, firstLimit);\n    for (const auto& ac : acts) {\n        addFirstFinish(ac.cut, ac.dst, 0);\n    }\n\n    sort(res.begin(), res.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        if (a.addCost != b.addCost) return a.addCost < b.addCost;\n        return a.ops.size() < b.ops.size();\n    });\n\n    vector<Macro> out;\n    out.reserve(min(limit, (int)res.size()));\n    unordered_set<uint64_t> seen;\n    seen.reserve(res.size() * 2 + 10);\n\n    for (auto& mo : res) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= limit) break;\n        }\n    }\n\n    return out;\n}\n\nstruct MacroBeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateMacroBeam(const StackArray& init, int W, const EvalParam& ep,\n                         int cutoff,\n                         chrono::steady_clock::time_point deadline) {\n    MacroBeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(6000);\n    first.eval = heuristicState(first.st, 1, ep);\n\n    vector<MacroBeamState> beam;\n    beam.push_back(std::move(first));\n\n    const int perStateLimit = 18;\n\n    for (int v = 1; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) return invalidResult();\n\n        vector<MacroBeamState> cand;\n        cand.reserve(beam.size() * perStateLimit);\n\n        for (const auto& bs : beam) {\n            if (chrono::steady_clock::now() > deadline) return invalidResult();\n            if (bs.cost >= cutoff) continue;\n\n            auto macros = generateMacros(bs.st, v, ep, cutoff - bs.cost, perStateLimit);\n\n            for (auto& mo : macros) {\n                int nc = bs.cost + mo.addCost;\n                if (nc >= cutoff) continue;\n\n                MacroBeamState ns;\n                ns.st = std::move(mo.st);\n                ns.cost = nc;\n                ns.ops = bs.ops;\n                ns.ops.insert(ns.ops.end(), mo.ops.begin(), mo.ops.end());\n                if ((int)ns.ops.size() > 5000) continue;\n\n                ns.eval = ns.cost + heuristicState(ns.st, v + 1, ep);\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const MacroBeamState& a, const MacroBeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.ops.size() < b.ops.size();\n        });\n\n        vector<MacroBeamState> nb;\n        nb.reserve(W);\n        unordered_set<uint64_t> seen;\n        seen.reserve(cand.size() * 2 + 10);\n\n        for (auto& c : cand) {\n            uint64_t hs = hashState(c.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(c));\n                if ((int)nb.size() >= W) break;\n            }\n        }\n\n        if (nb.empty()) return invalidResult();\n        beam = std::move(nb);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> nG >> mG;\n\n    StackArray init;\n    for (int i = 0; i < mG; i++) {\n        init[i].reserve(nG);\n        for (int j = 0; j < nG / mG; j++) {\n            int x;\n            cin >> x;\n            init[i].push_back(x);\n        }\n    }\n\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < mG; i++) {\n        for (int x : init[i]) {\n            seed = seed * 1000003ULL + (uint64_t)x + 97ULL;\n        }\n    }\n    XorShift master(seed);\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto timeUp = [&]() -> bool {\n        return elapsed() > 1.82;\n    };\n\n    Result best;\n\n    auto consider = [&](Result r) {\n        if (!r.ok) return;\n        if ((int)r.ops.size() > 5000) return;\n        if (best.ok && r.cost >= best.cost) return;\n\n        int vc = validateCost(init, r.ops);\n        if (vc < 0 || vc != r.cost) return;\n\n        best = std::move(r);\n    };\n\n    // Guaranteed valid fallback.\n    {\n        Params p;\n        p.mode = 0;\n        p.thresholdMode = 0;\n        p.destMode = 0;\n        consider(simulateGreedy(init, p, master.next(), INF));\n    }\n\n    auto runParam = [&](Params p) {\n        if (timeUp()) return;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    // Deterministic greedy variants.\n    for (int th = 0; th <= 1; th++) {\n        for (int dm = 0; dm < 4; dm++) {\n            Params p;\n\n            p = Params();\n            p.mode = 0;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            p = Params();\n            p.mode = 1;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            for (int bad = 0; bad <= 2; bad++) {\n                for (int good = 0; good <= 2; good++) {\n                    p = Params();\n                    p.mode = 2;\n                    p.badMode = bad;\n                    p.goodMode = good;\n                    p.thresholdMode = th;\n                    p.destMode = dm;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Scored-enumeration presets.\n    for (int th = 0; th <= 1; th++) {\n        for (double lw : {0.03, 0.07, 0.13}) {\n            for (double dw : {0.8, 1.8, 3.0}) {\n                Params p;\n                p.mode = 3;\n                p.thresholdMode = th;\n                p.lenW = lw;\n                p.dirtyW = dw;\n                p.badW = 3.0;\n                p.gW = 0.08;\n                p.slackW = 0.02;\n                runParam(p);\n            }\n        }\n    }\n\n    // Whole-suffix beam from the previous solver.\n    for (double alpha : {0.0, 1.0, 2.0, 4.0, 6.0}) {\n        if (timeUp()) break;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateBeamWhole(init, 60, alpha, cutoff));\n    }\n\n    // New macro beam search.\n    {\n        auto macroEnd = startTime + chrono::milliseconds(1250);\n        vector<pair<int, EvalParam>> cfgs = {\n            {30, EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75}},\n            {26, EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65}},\n            {24, EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85}},\n            {22, EvalParam{4.5, 0.25, 2.4, 0.05, 3.0, 1.0, 0.55}}\n        };\n\n        for (auto [W, ep] : cfgs) {\n            if (timeUp()) break;\n            if (chrono::steady_clock::now() > macroEnd) break;\n            int cutoff = best.ok ? best.cost : INF;\n            consider(simulateMacroBeam(init, W, ep, cutoff, macroEnd));\n        }\n    }\n\n    // Initial one-stack merge variants.\n    if (!timeUp()) {\n        for (int bad = 0; bad <= 1 && !timeUp(); bad++) {\n            for (int a = 0; a < mG && !timeUp(); a++) {\n                for (int b = 0; b < mG && !timeUp(); b++) {\n                    if (a == b) continue;\n                    Params p;\n                    p.mode = 2;\n                    p.goodMode = 0;\n                    p.badMode = bad;\n                    p.thresholdMode = 0;\n                    p.destMode = 0;\n                    p.initA = a;\n                    p.initB = b;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Random multi-start until time limit.\n    while (!timeUp()) {\n        Params p = randomParams(master);\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    }\n\n    // Final safety.\n    if (!best.ok || validateCost(init, best.ops) < 0) {\n        Params p;\n        p.mode = 0;\n        p.thresholdMode = 0;\n        p.destMode = 0;\n        best = simulateGreedy(init, p, seed, INF);\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIMIT_LEN = 100000;\nstatic const unsigned short INF_DIST = 30000;\n\nint N, V;\nvector<string> hwall, vwall;\nvector<int> dirtv;\n\nstruct Edge {\n    int to;\n    char ch;\n};\nvector<vector<Edge>> adjg;\nvector<unsigned short> distAll;\nvector<int> dist0;\n\ninline int D(int a, int b) {\n    return distAll[a * V + b];\n}\n\ninline char moveChar(int from, int to) {\n    int diff = to - from;\n    if (diff == 1) return 'R';\n    if (diff == -1) return 'L';\n    if (diff == N) return 'D';\n    return 'U';\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 RouteBuilder {\n    int cur = 0;\n    int t = 0;\n    vector<int> seq;\n    string moves;\n    vector<int> last;\n    vector<char> seen;\n    int unseen = 0;\n\n    void init() {\n        cur = 0;\n        t = 0;\n        seq.clear();\n        moves.clear();\n        last.assign(V, 0);\n        seen.assign(V, 0);\n        seen[0] = 1;\n        unseen = V - 1;\n    }\n\n    void addMove(int nb) {\n        moves.push_back(moveChar(cur, nb));\n        cur = nb;\n        ++t;\n        seq.push_back(nb);\n        last[nb] = t;\n        if (!seen[nb]) {\n            seen[nb] = 1;\n            --unseen;\n        }\n    }\n};\n\nvoid computeAllPairsDistances() {\n    distAll.assign(V * V, INF_DIST);\n    vector<int> q(V);\n\n    for (int s = 0; s < V; ++s) {\n        unsigned short* ds = &distAll[s * V];\n        int head = 0, tail = 0;\n        ds[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int x = q[head++];\n            unsigned short nd = ds[x] + 1;\n            for (const auto& e : adjg[x]) {\n                if (ds[e.to] == INF_DIST) {\n                    ds[e.to] = nd;\n                    q[tail++] = e.to;\n                }\n            }\n        }\n    }\n\n    dist0.assign(V, 0);\n    for (int i = 0; i < V; ++i) dist0[i] = D(i, 0);\n}\n\nint chooseNextOnShortestPath(const RouteBuilder& b, int target, bool preferUnseen) {\n    int cur = b.cur;\n    int cd = D(target, cur);\n    int best = -1;\n    long double bestVal = -1e100L;\n\n    for (const auto& e : adjg[cur]) {\n        int nb = e.to;\n        if (D(target, nb) + 1 != cd) continue;\n\n        long long age = (long long)b.t + 1 - b.last[nb];\n        long double val = (long double)dirtv[nb] * age * age;\n\n        if (preferUnseen && !b.seen[nb]) val += 1e30L;\n        val += (long double)(nb % 19) * 1e-9L;\n\n        if (val > bestVal) {\n            bestVal = val;\n            best = nb;\n        }\n    }\n\n    if (best == -1) {\n        for (const auto& e : adjg[cur]) {\n            if (D(target, e.to) + 1 == cd) return e.to;\n        }\n    }\n    return best;\n}\n\nvoid appendPath(RouteBuilder& b, int target, bool preferUnseen) {\n    while (b.cur != target) {\n        int nb = chooseNextOnShortestPath(b, target, preferUnseen);\n        if (nb < 0) break;\n        b.addMove(nb);\n        if (b.t > LIMIT_LEN + 5000) break;\n    }\n}\n\nlong double evaluateSeq(const vector<int>& seq, int L) {\n    if (L <= 0 || L > LIMIT_LEN) return 1e100L;\n    if ((int)seq.size() < L) return 1e100L;\n    if (seq[L - 1] != 0) return 1e100L;\n\n    vector<int> first(V, -1), prev(V, -1);\n    vector<long long> gapSum(V, 0);\n\n    for (int t = 1; t <= L; ++t) {\n        int id = seq[t - 1];\n        if (first[id] == -1) {\n            first[id] = t;\n        } else {\n            long long g = t - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = t;\n    }\n\n    long double total = 0;\n    for (int id = 0; id < V; ++id) {\n        if (first[id] == -1) return 1e100L;\n        long long g = (long long)L - prev[id] + first[id];\n        gapSum[id] += g * (g - 1) / 2;\n        total += (long double)gapSum[id] * dirtv[id];\n    }\n\n    return total / L;\n}\n\nvector<int> rowOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        } else {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> rowOrderBottom() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int ii = 0; ii < N; ++ii) {\n        int i = N - 1 - ii;\n        if (ii % 2 == 0) {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        } else {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int j = 0; j < N; ++j) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        } else {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrderRight() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int jj = 0; jj < N; ++jj) {\n        int j = N - 1 - jj;\n        if (jj % 2 == 0) {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        } else {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvoid rotHilbert(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\nlong long hilbertIndex(int x, int y) {\n    int S = 1;\n    while (S < N) S <<= 1;\n\n    long long d = 0;\n    for (int s = S / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += 1LL * s * s * ((3 * rx) ^ ry);\n        rotHilbert(s, x, y, rx, ry);\n    }\n    return d;\n}\n\nvector<int> hilbertOrder() {\n    vector<pair<long long, int>> a;\n    a.reserve(V);\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            a.push_back({hilbertIndex(j, i), i * N + j});\n        }\n    }\n\n    sort(a.begin(), a.end());\n    vector<int> ord;\n    ord.reserve(V);\n    for (auto [_, id] : a) ord.push_back(id);\n    return ord;\n}\n\nRouteBuilder makeRouteByOrder(const vector<int>& ord) {\n    RouteBuilder b;\n    b.init();\n\n    for (int id : ord) {\n        if (!b.seen[id]) appendPath(b, id, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeNearestCover(int variant) {\n    RouteBuilder b;\n    b.init();\n\n    while (b.unseen > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n\n            int r = D(b.cur, id);\n            double key;\n\n            if (variant == 0) {\n                key = r * 1000000.0 + dist0[id];\n            } else if (variant == 1) {\n                key = r * 1000000.0 - dirtv[id] * 200.0;\n            } else if (variant == 2) {\n                key = (r + 0.20 * dist0[id]) * 1000000.0 - dirtv[id] * 10.0;\n            } else if (variant == 3) {\n                unsigned x = (unsigned)(id * 1103515245u + 12345u);\n                key = r * 1000000.0 + (x % 10000) * 0.01;\n            } else {\n                int degUnseen = 0;\n                for (auto& e : adjg[id]) if (!b.seen[e.to]) ++degUnseen;\n                key = r * 1000000.0 + degUnseen * 1000.0 - dirtv[id] * 0.05;\n            }\n\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best == -1) break;\n        appendPath(b, best, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeDFSRoute(const string& dirOrder, int sortMode) {\n    RouteBuilder b;\n    b.init();\n\n    vector<int> rankDir(256, 0);\n    for (int i = 0; i < 4; ++i) rankDir[(unsigned char)dirOrder[i]] = i;\n\n    vector<char> vis(V, 0);\n\n    function<void(int)> dfs = [&](int u) {\n        vis[u] = 1;\n        vector<Edge> es = adjg[u];\n\n        sort(es.begin(), es.end(), [&](const Edge& a, const Edge& c) {\n            if (sortMode == 1 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] > dirtv[c.to];\n            }\n            if (sortMode == 2 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] < dirtv[c.to];\n            }\n            return rankDir[(unsigned char)a.ch] < rankDir[(unsigned char)c.ch];\n        });\n\n        for (auto& e : es) {\n            if (!vis[e.to]) {\n                b.addMove(e.to);\n                dfs(e.to);\n                b.addMove(u);\n            }\n        }\n    };\n\n    dfs(0);\n    return b;\n}\n\nvector<int> firstVisitOrder(const RouteBuilder& b) {\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int id : b.seq) {\n        if (!used[id]) {\n            used[id] = 1;\n            ord.push_back(id);\n        }\n    }\n\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) ord.push_back(id);\n    }\n\n    return ord;\n}\n\nvector<int> makeCounts(const vector<double>& weight, double scale, int& M) {\n    vector<int> cnt(V);\n    M = 1;\n    for (int id = 0; id < V; ++id) {\n        int c = max(1, (int)(scale * weight[id] + 0.5));\n        cnt[id] = c;\n        M = max(M, c);\n    }\n    return cnt;\n}\n\nint initialAccumulator(int pos, int M, int mode) {\n    if (M <= 1) return 0;\n    if (mode == 0) return 0;\n\n    int desired = 0;\n\n    if (mode == 1) {\n        desired = (int)((long long)pos * M / V);\n    } else if (mode == 2) {\n        desired = (int)((long long)(V - 1 - pos) * M / V);\n    } else {\n        unsigned x = (unsigned)(pos * 2654435761u + 1013904223u);\n        desired = x % M;\n    }\n\n    int a = M - 1 - desired;\n    a %= M;\n    if (a < 0) a += M;\n    return a;\n}\n\nvector<vector<int>> buildEvents(const vector<int>& ord, const vector<int>& cnt, int M, int mode) {\n    vector<vector<int>> events(M);\n\n    for (int k = 0; k < V; ++k) {\n        int id = ord[k];\n        int c = cnt[id];\n        int a = initialAccumulator(k, M, mode);\n\n        for (int m = 1; m <= c; ++m) {\n            long long num = 1LL * m * M - a;\n            int p = (int)((num + c - 1) / c - 1);\n            if (p < 0) p = 0;\n            if (p >= M) p = M - 1;\n            events[p].push_back(id);\n        }\n    }\n\n    return events;\n}\n\nlong long phaseLength(const vector<int>& ord, const vector<double>& weight,\n                      double scale, int mode, long long cap) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    long long len = 0;\n    int cur = 0;\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) {\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                int id = ev[idx];\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        }\n    }\n\n    len += D(cur, 0);\n    return len;\n}\n\nRouteBuilder buildPhaseRoute(const vector<int>& ord, const vector<double>& weight,\n                             double scale, int mode) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    RouteBuilder b;\n    b.init();\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) appendPath(b, id, true);\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                appendPath(b, ev[idx], true);\n            }\n        }\n\n        if (b.t > LIMIT_LEN + 1000) break;\n    }\n\n    appendPath(b, 0, true);\n    return b;\n}\n\ndouble findPhaseScale(const vector<int>& ord, const vector<double>& weight, int mode) {\n    double lo = 0.0, hi = 1.0;\n\n    while (hi < 2048.0 && phaseLength(ord, weight, hi, mode, LIMIT_LEN + 1) <= LIMIT_LEN) {\n        lo = hi;\n        hi *= 2.0;\n    }\n\n    for (int it = 0; it < 13; ++it) {\n        double mid = (lo + hi) * 0.5;\n        if (phaseLength(ord, weight, mid, mode, LIMIT_LEN + 1) <= LIMIT_LEN) lo = mid;\n        else hi = mid;\n    }\n\n    return lo;\n}\n\nRouteBuilder buildChunkGreedy(RouteBuilder prefix, double offset, int minTargetDist,\n                              int chunk, int maxLen, const Timer& timer, double timeLimit) {\n    RouteBuilder b = std::move(prefix);\n\n    auto selectTarget = [&](int md) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (b.t + r + dist0[id] > maxLen) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n\n    while (b.t + D(b.cur, 0) < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        int target = selectTarget(minTargetDist);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n        }\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n    return b;\n}\n\nuint64_t hashOrder(const vector<int>& ord) {\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\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n\n    cin >> N;\n    V = N * N;\n\n    hwall.resize(N - 1);\n    for (int i = 0; i < N - 1; ++i) cin >> hwall[i];\n\n    vwall.resize(N);\n    for (int i = 0; i < N; ++i) cin >> vwall[i];\n\n    dirtv.assign(V, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> dirtv[i * N + j];\n        }\n    }\n\n    adjg.assign(V, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = i * N + j;\n\n            if (i + 1 < N && hwall[i][j] == '0') {\n                int to = (i + 1) * N + j;\n                adjg[id].push_back({to, 'D'});\n                adjg[to].push_back({id, 'U'});\n            }\n\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int to = i * N + (j + 1);\n                adjg[id].push_back({to, 'R'});\n                adjg[to].push_back({id, 'L'});\n            }\n        }\n    }\n\n    computeAllPairsDistances();\n\n    long double bestScore = 1e100L;\n    string bestMoves;\n\n    RouteBuilder bestShort;\n    long double bestShortScore = 1e100L;\n\n    auto consider = [&](const RouteBuilder& b, int L) {\n        if (L <= 0 || L > LIMIT_LEN || L > b.t) return;\n        long double sc = evaluateSeq(b.seq, L);\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestMoves = b.moves.substr(0, L);\n        }\n    };\n\n    auto considerFull = [&](const RouteBuilder& b) {\n        consider(b, b.t);\n    };\n\n    auto considerShort = [&](const RouteBuilder& b) {\n        if (b.t <= LIMIT_LEN && b.cur == 0 && b.unseen == 0) {\n            long double sc = evaluateSeq(b.seq, b.t);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = b.moves;\n            }\n\n            if (sc < bestShortScore) {\n                bestShortScore = sc;\n                bestShort = b;\n            }\n        }\n    };\n\n    vector<RouteBuilder> shortCandidates;\n\n    vector<string> dirs = {\"RDLU\", \"DRUL\", \"LURD\", \"ULDR\", \"RULD\", \"DLUR\"};\n    for (int i = 0; i < (int)dirs.size(); ++i) {\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 0));\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 1));\n        if (i < 2) shortCandidates.push_back(makeDFSRoute(dirs[i], 2));\n    }\n\n    shortCandidates.push_back(makeRouteByOrder(rowOrder()));\n    shortCandidates.push_back(makeRouteByOrder(colOrder()));\n    shortCandidates.push_back(makeRouteByOrder(rowOrderBottom()));\n    shortCandidates.push_back(makeRouteByOrder(colOrderRight()));\n\n    for (int v = 0; v < 5; ++v) {\n        shortCandidates.push_back(makeNearestCover(v));\n    }\n\n    for (auto& b : shortCandidates) considerShort(b);\n\n    if (bestShort.t == 0) {\n        bestShort = shortCandidates[0];\n        considerFull(bestShort);\n    }\n\n    vector<vector<int>> orders;\n    unordered_set<uint64_t> orderHashes;\n\n    auto addOrder = [&](vector<int> ord) {\n        if ((int)ord.size() != V) return;\n\n        vector<char> seen(V, 0);\n        for (int x : ord) {\n            if (x < 0 || x >= V || seen[x]) return;\n            seen[x] = 1;\n        }\n\n        uint64_t h = hashOrder(ord);\n        if (orderHashes.insert(h).second) orders.push_back(ord);\n    };\n\n    addOrder(firstVisitOrder(bestShort));\n    addOrder(rowOrder());\n    addOrder(colOrder());\n    addOrder(rowOrderBottom());\n    addOrder(colOrderRight());\n    addOrder(hilbertOrder());\n\n    for (auto& b : shortCandidates) {\n        addOrder(firstVisitOrder(b));\n    }\n\n    int initialOrderCount = orders.size();\n    for (int i = 0; i < initialOrderCount; ++i) {\n        vector<int> rev = orders[i];\n        reverse(rev.begin(), rev.end());\n        addOrder(rev);\n    }\n\n    vector<double> baseExps = {0.42, 0.50, 0.60};\n    vector<double> richExps = {0.35, 0.42, 0.50, 0.58, 0.67};\n    vector<double> muls = {1.00, 0.88, 0.75, 0.65, 0.50, 1.08};\n\n    for (int oi = 0; oi < (int)orders.size(); ++oi) {\n        if (timer.elapsed() > 1.50) break;\n\n        const vector<int>& ord = orders[oi];\n        const vector<double>& exps = (oi < 8 ? richExps : baseExps);\n\n        vector<int> modes;\n        if (oi < 8) modes = {0, 1, 2};\n        else modes = {0, 1};\n\n        for (double ep : exps) {\n            if (timer.elapsed() > 1.55) break;\n\n            vector<double> weight(V);\n            for (int id = 0; id < V; ++id) {\n                weight[id] = pow((double)dirtv[id], ep);\n            }\n\n            for (int mode : modes) {\n                if (timer.elapsed() > 1.58) break;\n\n                double scale = findPhaseScale(ord, weight, mode);\n\n                for (double m : muls) {\n                    double sca = scale * m;\n                    if (sca < 0.0) continue;\n\n                    long long len = phaseLength(ord, weight, sca, mode, LIMIT_LEN + 1);\n                    if (len <= LIMIT_LEN) {\n                        RouteBuilder b = buildPhaseRoute(ord, weight, sca, mode);\n                        if (b.t <= LIMIT_LEN && b.cur == 0) {\n                            considerFull(b);\n                        }\n                    }\n\n                    if (timer.elapsed() > 1.60) break;\n                }\n            }\n        }\n    }\n\n    auto considerZeroPrefixes = [&](const RouteBuilder& b, int minGap) {\n        int last = 0;\n        for (int t = 1; t <= b.t; ++t) {\n            if (b.seq[t - 1] == 0 && t - last >= minGap) {\n                consider(b, t);\n                last = t;\n                if (timer.elapsed() > 1.90) break;\n            }\n        }\n    };\n\n    if (timer.elapsed() < 1.70) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 20.0, 1, 1000000, LIMIT_LEN, timer, 1.76);\n        if (g.t <= LIMIT_LEN && g.cur == 0) {\n            considerFull(g);\n            considerZeroPrefixes(g, 12000);\n        }\n    }\n\n    if (timer.elapsed() < 1.80) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 35.0, 1, 4, LIMIT_LEN, timer, 1.87);\n        if (g.t <= LIMIT_LEN && g.cur == 0) {\n            considerFull(g);\n            considerZeroPrefixes(g, 12000);\n        }\n    }\n\n    if (timer.elapsed() < 1.88) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 70.0, 3, 5, 75000, timer, 1.93);\n        if (g.t <= LIMIT_LEN && g.cur == 0) {\n            considerFull(g);\n            considerZeroPrefixes(g, 9000);\n        }\n    }\n\n    if (bestMoves.empty()) {\n        bestMoves = shortCandidates[0].moves;\n    }\n\n    cout << bestMoves << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x = 88172645463325252ull;\n    uint32_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n    double nextDouble() { return (next() >> 8) * (1.0 / 16777216.0); }\n};\n\nstruct Solver {\n    static constexpr unsigned short USINF = 30000;\n\n    int N, M;\n    int si, sj, startId;\n    vector<string> grid;\n    vector<string> words;\n    vector<array<int, 5>> wch;\n\n    vector<int> letterPos[26];\n    unsigned char distCell[225][225];\n\n    vector<int> lastChar;\n    vector<unsigned char> overlap;\n\n    vector<int> initOff;\n    vector<unsigned short> initData;\n    vector<int> startMinCost, startMin10, startAvg10;\n\n    vector<int> edgeOff;\n    vector<unsigned short> edgeData;\n    vector<int> edgeMin10, edgeAvg10;\n\n    int maxOcc = 0;\n\n    struct Mode {\n        vector<int> edge;\n        vector<int> start;\n    };\n    vector<Mode> modes;\n\n    struct Move {\n        int type; // 0 relocate, 1 swap, 2 reverse, 3 block relocate\n        int a, b;\n        long long delta;\n        int c;\n    };\n\n    struct Candidate {\n        int cost;\n        vector<int> order;\n    };\n\n    struct ExactCtx {\n        int n;\n        vector<int> cnt;\n        vector<int> foff, roff;\n        vector<unsigned short> fdata, rdata;\n        vector<int> prefOff, suffOff;\n        vector<unsigned short> prefData, suffData;\n        int current = 0;\n    };\n\n    Timer timer;\n    XorShift rng;\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    unordered_map<int, int> targetMap;\n    int pow4 = 456976; // 26^4\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        startId = si * N + sj;\n\n        grid.resize(N);\n        for (int c = 0; c < 26; c++) letterPos[c].clear();\n\n        for (int i = 0; i < N; i++) {\n            cin >> grid[i];\n            for (int j = 0; j < N; j++) {\n                int c = grid[i][j] - 'A';\n                letterPos[c].push_back(i * N + j);\n            }\n        }\n\n        words.resize(M);\n        wch.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) wch[i][k] = words[i][k] - 'A';\n        }\n    }\n\n    int encodeWord(const string& s) const {\n        int code = 0;\n        for (char ch : s) code = code * 26 + (ch - 'A');\n        return code;\n    }\n\n    int calcOverlap(int a, int b) const {\n        for (int k = 4; k >= 1; k--) {\n            bool ok = true;\n            for (int p = 0; p < k; p++) {\n                if (words[a][5 - k + p] != words[b][p]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    inline int wordCnt(int w) const {\n        return (int)letterPos[lastChar[w]].size();\n    }\n\n    void precompute() {\n        int V = N * N;\n        for (int a = 0; a < V; a++) {\n            int ai = a / N, aj = a % N;\n            for (int b = 0; b < V; b++) {\n                int bi = b / N, bj = b % N;\n                distCell[a][b] = (unsigned char)(abs(ai - bi) + abs(aj - bj));\n            }\n        }\n\n        maxOcc = 0;\n        for (int c = 0; c < 26; c++) {\n            maxOcc = max(maxOcc, (int)letterPos[c].size());\n        }\n\n        lastChar.assign(M, 0);\n        for (int i = 0; i < M; i++) lastChar[i] = wch[i][4];\n\n        overlap.assign(M * M, 0);\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                overlap[i * M + j] = (unsigned char)calcOverlap(i, j);\n            }\n        }\n\n        targetMap.clear();\n        targetMap.reserve(512);\n        for (int i = 0; i < M; i++) targetMap[encodeWord(words[i])] = i;\n\n        long long sumOccLast = 0;\n        for (int i = 0; i < M; i++) {\n            sumOccLast += (int)letterPos[lastChar[i]].size();\n        }\n\n        initOff.assign(M, 0);\n        startMinCost.assign(M, 0);\n        startMin10.assign(M, 0);\n        startAvg10.assign(M, 0);\n        initData.clear();\n        initData.reserve((size_t)sumOccLast);\n\n        vector<int> cur(maxOcc), nxt(maxOcc);\n        const int INF = 1e9;\n\n        for (int i = 0; i < M; i++) {\n            int c0 = wch[i][0];\n            int cnt = (int)letterPos[c0].size();\n\n            for (int p = 0; p < cnt; p++) {\n                cur[p] = (int)distCell[startId][letterPos[c0][p]] + 1;\n            }\n\n            int prevC = c0;\n            int prevCnt = cnt;\n            for (int h = 1; h < 5; h++) {\n                int nc = wch[i][h];\n                int nextCnt = (int)letterPos[nc].size();\n\n                for (int q = 0; q < nextCnt; q++) {\n                    int best = INF;\n                    int qid = letterPos[nc][q];\n                    for (int p = 0; p < prevCnt; p++) {\n                        int v = cur[p] + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                        if (v < best) best = v;\n                    }\n                    nxt[q] = best;\n                }\n\n                for (int q = 0; q < nextCnt; q++) cur[q] = nxt[q];\n                prevC = nc;\n                prevCnt = nextCnt;\n            }\n\n            initOff[i] = (int)initData.size();\n            int mn = INF;\n            long long sum = 0;\n            for (int p = 0; p < prevCnt; p++) {\n                mn = min(mn, cur[p]);\n                sum += cur[p];\n                initData.push_back((unsigned short)cur[p]);\n            }\n            startMinCost[i] = mn;\n            startMin10[i] = 10 * mn;\n            startAvg10[i] = (int)((10 * sum + prevCnt / 2) / prevCnt);\n        }\n\n        edgeOff.assign(M * M, 0);\n        edgeAvg10.assign(M * M, 0);\n        edgeMin10.assign(M * M, 0);\n        edgeData.clear();\n\n        long long totalMat = sumOccLast * sumOccLast;\n        if (totalMat < 100000000LL) edgeData.reserve((size_t)totalMat);\n\n        vector<int> mat(maxOcc * maxOcc), mat2(maxOcc * maxOcc);\n\n        for (int i = 0; i < M; i++) {\n            int cStart = lastChar[i];\n            int rows = (int)letterPos[cStart].size();\n\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int k = overlap[idx];\n\n                int prevC = cStart;\n                int prevCnt = rows;\n\n                fill(mat.begin(), mat.begin() + rows * prevCnt, INF);\n                for (int r = 0; r < rows; r++) mat[r * prevCnt + r] = 0;\n\n                for (int h = k; h < 5; h++) {\n                    int nc = wch[j][h];\n                    int nextCnt = (int)letterPos[nc].size();\n\n                    for (int r = 0; r < rows; r++) {\n                        int baseIdx = r * prevCnt;\n                        int outIdx = r * nextCnt;\n                        for (int q = 0; q < nextCnt; q++) {\n                            int best = INF;\n                            int qid = letterPos[nc][q];\n                            for (int p = 0; p < prevCnt; p++) {\n                                int v = mat[baseIdx + p]\n                                      + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                                if (v < best) best = v;\n                            }\n                            mat2[outIdx + q] = best;\n                        }\n                    }\n\n                    mat.swap(mat2);\n                    prevC = nc;\n                    prevCnt = nextCnt;\n                }\n\n                int cols = (int)letterPos[lastChar[j]].size();\n                edgeOff[idx] = (int)edgeData.size();\n                edgeData.resize(edgeData.size() + rows * cols);\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                int off = edgeOff[idx];\n\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    for (int q = 0; q < cols; q++) {\n                        int v = mat[r * cols + q];\n                        edgeData[off + r * cols + q] = (unsigned short)v;\n                        rowMin = min(rowMin, v);\n                        globalMin = min(globalMin, v);\n                    }\n                    sumRowMin += rowMin;\n                }\n\n                edgeMin10[idx] = 10 * globalMin;\n                edgeAvg10[idx] = (int)((10 * sumRowMin + rows / 2) / rows);\n            }\n        }\n    }\n\n    void buildModes() {\n        modes.clear();\n        modes.resize(4);\n\n        for (auto& mo : modes) {\n            mo.edge.assign(M * M, 0);\n            mo.start.assign(M, 0);\n        }\n\n        for (int i = 0; i < M; i++) {\n            modes[0].start[i] = startAvg10[i];\n            modes[1].start[i] = startMin10[i];\n            modes[2].start[i] = startAvg10[i];\n            modes[3].start[i] = startAvg10[i];\n        }\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int len = 5 - (int)overlap[idx];\n\n                modes[0].edge[idx] = edgeAvg10[idx];\n                modes[1].edge[idx] = edgeMin10[idx];\n                modes[2].edge[idx] = len * 1000 + edgeAvg10[idx];\n                modes[3].edge[idx] = len * 10000 + edgeAvg10[idx];\n            }\n        }\n    }\n\n    inline long long arc(const Mode& mode, int u, int v) const {\n        if (u < 0 && v < 0) return 0;\n        if (u < 0) return mode.start[v];\n        if (v < 0) return 0;\n        return mode.edge[u * M + v];\n    }\n\n    int exactCost(const vector<int>& ord) const {\n        if (ord.empty()) return 0;\n\n        const int INF = 1e9;\n        int dp[225], ndp[225];\n\n        int first = ord[0];\n        int cnt = (int)letterPos[lastChar[first]].size();\n        int off0 = initOff[first];\n\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off0 + i];\n\n        for (int idx = 1; idx < (int)ord.size(); idx++) {\n            int a = ord[idx - 1];\n            int b = ord[idx];\n\n            int rows = (int)letterPos[lastChar[a]].size();\n            int cols = (int)letterPos[lastChar[b]].size();\n\n            fill(ndp, ndp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[a * M + b]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)mr[c];\n                    if (v < ndp[c]) ndp[c] = v;\n                }\n            }\n\n            for (int c = 0; c < cols; c++) dp[c] = ndp[c];\n        }\n\n        int last = ord.back();\n        int lastCnt = (int)letterPos[lastChar[last]].size();\n        int ans = INF;\n        for (int i = 0; i < lastCnt; i++) ans = min(ans, dp[i]);\n        return ans;\n    }\n\n    vector<int> hungarian(const vector<vector<int>>& a) const {\n        int n = (int)a.size();\n        const long long INF = (1LL << 60);\n\n        vector<long long> u(n + 1), v(n + 1);\n        vector<int> p(n + 1), way(n + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<long long> minv(n + 1, INF);\n            vector<char> used(n + 1, false);\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0];\n                int j1 = 0;\n                long long delta = INF;\n\n                for (int j = 1; j <= n; j++) {\n                    if (used[j]) continue;\n                    long long cur = (long long)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\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\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);\n        for (int j = 1; j <= n; j++) ans[p[j] - 1] = j - 1;\n        return ans;\n    }\n\n    vector<int> patchAssignment(const vector<int>& succ, const Mode& mode) const {\n        int D = M;\n        int n = M + 1;\n\n        vector<char> visited(n, false);\n        vector<int> path;\n\n        int cur = succ[D];\n        visited[D] = true;\n        while (cur != D && !visited[cur]) {\n            visited[cur] = true;\n            path.push_back(cur);\n            cur = succ[cur];\n        }\n\n        vector<vector<int>> cycles;\n        for (int i = 0; i < M; i++) {\n            if (visited[i]) continue;\n\n            vector<int> cyc;\n            cur = i;\n            while (!visited[cur]) {\n                visited[cur] = true;\n                cyc.push_back(cur);\n                cur = succ[cur];\n            }\n            if (!cyc.empty()) cycles.push_back(cyc);\n        }\n\n        auto costArc = [&](int u, int v) -> long long {\n            if (u == D && v == D) return 0;\n            if (u == D) return mode.start[v];\n            if (v == D) return 0;\n            return mode.edge[u * M + v];\n        };\n\n        while (!cycles.empty()) {\n            long long bestDelta = (1LL << 60);\n            int bestC = -1, bestE = -1, bestBreak = -1;\n\n            for (int ci = 0; ci < (int)cycles.size(); ci++) {\n                const auto& C = cycles[ci];\n                int k = (int)C.size();\n\n                for (int e = 0; e <= (int)path.size(); e++) {\n                    int u = (e == 0 ? D : path[e - 1]);\n                    int v = (e == (int)path.size() ? D : path[e]);\n                    long long oldCost = costArc(u, v);\n\n                    for (int bidx = 0; bidx < k; bidx++) {\n                        int a = C[bidx];\n                        int b = C[(bidx + 1) % k];\n\n                        long long delta = costArc(u, b) + costArc(a, v)\n                                        - oldCost - costArc(a, b);\n\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestC = ci;\n                            bestE = e;\n                            bestBreak = bidx;\n                        }\n                    }\n                }\n            }\n\n            const auto& C = cycles[bestC];\n            int k = (int)C.size();\n            vector<int> seg;\n            seg.reserve(k);\n            for (int t = 0; t < k; t++) {\n                seg.push_back(C[(bestBreak + 1 + t) % k]);\n            }\n\n            path.insert(path.begin() + bestE, seg.begin(), seg.end());\n            cycles.erase(cycles.begin() + bestC);\n        }\n\n        return path;\n    }\n\n    vector<int> hungarianPatch(const Mode& mode) const {\n        int n = M + 1;\n        int D = M;\n        const int INF = 100000000;\n\n        vector<vector<int>> cost(n, vector<int>(n, INF));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                cost[i][j] = (i == j ? INF : mode.edge[i * M + j]);\n            }\n            cost[i][D] = 0;\n        }\n\n        for (int j = 0; j < M; j++) cost[D][j] = mode.start[j];\n        cost[D][D] = INF;\n\n        vector<int> assign = hungarian(cost);\n        return patchAssignment(assign, mode);\n    }\n\n    vector<int> cheapestInsertion(const Mode& mode) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestDelta = (1LL << 60);\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> nearestNeighborBest(const Mode& mode) const {\n        vector<int> bestPath;\n        long long bestScore = (1LL << 60);\n\n        for (int s = 0; s < M; s++) {\n            vector<char> used(M, false);\n            vector<int> path;\n            path.reserve(M);\n\n            path.push_back(s);\n            used[s] = true;\n\n            long long score = mode.start[s];\n            int last = s;\n\n            for (int step = 1; step < M; step++) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (used[j]) continue;\n                    int c = mode.edge[last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                path.push_back(bestJ);\n                used[bestJ] = true;\n                score += bestC;\n                last = bestJ;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestPath = path;\n            }\n        }\n\n        return bestPath;\n    }\n\n    struct DSU {\n        vector<int> p;\n        DSU(int n = 0) { init(n); }\n        void init(int n) {\n            p.resize(n);\n            iota(p.begin(), p.end(), 0);\n        }\n        int find(int x) {\n            return p[x] == x ? x : p[x] = find(p[x]);\n        }\n        bool unite(int a, int b) {\n            a = find(a);\n            b = find(b);\n            if (a == b) return false;\n            p[b] = a;\n            return true;\n        }\n    };\n\n    vector<int> greedyPathCover(const Mode& mode, bool overlapKey) const {\n        struct E {\n            int u, v, ov, cost;\n        };\n\n        vector<E> es;\n        es.reserve(M * (M - 1));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                es.push_back({i, j, (int)overlap[i * M + j], mode.edge[i * M + j]});\n            }\n        }\n\n        if (overlapKey) {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                if (a.ov != b.ov) return a.ov > b.ov;\n                return a.cost < b.cost;\n            });\n        } else {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                return a.cost < b.cost;\n            });\n        }\n\n        vector<int> out(M, -1), in(M, -1);\n        DSU dsu(M);\n        int added = 0;\n\n        for (const auto& e : es) {\n            if (out[e.u] != -1 || in[e.v] != -1) continue;\n            if (dsu.find(e.u) == dsu.find(e.v)) continue;\n\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n\n            added++;\n            if (added == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) {\n            if (in[i] == -1) {\n                head = i;\n                break;\n            }\n        }\n\n        vector<int> path;\n        while (head != -1) {\n            path.push_back(head);\n            head = out[head];\n        }\n\n        if ((int)path.size() != M) {\n            path.resize(M);\n            iota(path.begin(), path.end(), 0);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedy(int startWord) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = (int)letterPos[lastChar[curWord]].size();\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            int bestScore = INF;\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = (int)letterPos[lastChar[j]].size();\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                if (minv < bestScore) {\n                    bestScore = minv;\n                    bestJ = j;\n                }\n            }\n\n            int cols = (int)letterPos[lastChar[bestJ]].size();\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    long long relocateDelta(const vector<int>& ord, int i, int p, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (p == i) return 0;\n\n        int x = ord[i];\n\n        int L = (i > 0 ? ord[i - 1] : -1);\n        int R = (i + 1 < n ? ord[i + 1] : -1);\n\n        long long rem = arc(mode, L, R) - arc(mode, L, x) - arc(mode, x, R);\n\n        auto getRemoved = [&](int idx) -> int {\n            return ord[idx < i ? idx : idx + 1];\n        };\n\n        int left = (p > 0 ? getRemoved(p - 1) : -1);\n        int right = (p < n - 1 ? getRemoved(p) : -1);\n\n        long long ins = arc(mode, left, x) + arc(mode, x, right) - arc(mode, left, right);\n        return rem + ins;\n    }\n\n    long long blockRelocateDelta(const vector<int>& ord, int l, int r, int q, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (q >= l && q <= r + 1) return 0;\n\n        int A = ord[l];\n        int B = ord[r];\n\n        int L = (l > 0 ? ord[l - 1] : -1);\n        int R = (r + 1 < n ? ord[r + 1] : -1);\n\n        int P = (q > 0 ? ord[q - 1] : -1);\n        int Q = (q < n ? ord[q] : -1);\n\n        long long oldCost = arc(mode, L, A) + arc(mode, B, R) + arc(mode, P, Q);\n        long long newCost = arc(mode, L, R) + arc(mode, P, A) + arc(mode, B, Q);\n        return newCost - oldCost;\n    }\n\n    long long swapDelta(const vector<int>& ord, int i, int j, const Mode& mode) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int n = (int)ord.size();\n        vector<int> ks;\n        int arr[4] = {i - 1, i, j - 1, j};\n\n        for (int t = 0; t < 4; t++) {\n            int k = arr[t];\n            if (k < -1 || k > n - 1) continue;\n            if (find(ks.begin(), ks.end(), k) == ks.end()) ks.push_back(k);\n        }\n\n        auto nodeNew = [&](int idx) -> int {\n            if (idx == i) return ord[j];\n            if (idx == j) return ord[i];\n            return ord[idx];\n        };\n\n        auto edgeOld = [&](int k) -> long long {\n            if (k == -1) return mode.start[ord[0]];\n            if (k >= n - 1) return 0;\n            return mode.edge[ord[k] * M + ord[k + 1]];\n        };\n\n        auto edgeNew = [&](int k) -> long long {\n            if (k == -1) return mode.start[nodeNew(0)];\n            if (k >= n - 1) return 0;\n            return mode.edge[nodeNew(k) * M + nodeNew(k + 1)];\n        };\n\n        long long oldSum = 0, newSum = 0;\n        for (int k : ks) {\n            oldSum += edgeOld(k);\n            newSum += edgeNew(k);\n        }\n        return newSum - oldSum;\n    }\n\n    long long reverseDeltaSlow(const vector<int>& ord, int l, int r, const Mode& mode) const {\n        int n = (int)ord.size();\n        long long oldCost = 0, newCost = 0;\n\n        if (l == 0) {\n            oldCost += mode.start[ord[l]];\n            newCost += mode.start[ord[r]];\n        } else {\n            oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n            newCost += mode.edge[ord[l - 1] * M + ord[r]];\n        }\n\n        if (r + 1 < n) {\n            oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n            newCost += mode.edge[ord[l] * M + ord[r + 1]];\n        }\n\n        for (int k = l; k < r; k++) {\n            oldCost += mode.edge[ord[k] * M + ord[k + 1]];\n            newCost += mode.edge[ord[k + 1] * M + ord[k]];\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyMove(vector<int>& ord, const Move& mv) const {\n        if (mv.type == 0) {\n            int x = ord[mv.a];\n            ord.erase(ord.begin() + mv.a);\n            ord.insert(ord.begin() + mv.b, x);\n        } else if (mv.type == 1) {\n            swap(ord[mv.a], ord[mv.b]);\n        } else if (mv.type == 2) {\n            reverse(ord.begin() + mv.a, ord.begin() + mv.b + 1);\n        } else if (mv.type == 3) {\n            int l = mv.a;\n            int r = mv.b;\n            int q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos;\n            if (q < l) pos = q;\n            else pos = q - len;\n\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        }\n    }\n\n    void improveAdditive(vector<int>& ord, const Mode& mode, int maxIter = 40, int maxBlockLen = 3) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if ((iter & 1) == 0 && timer.elapsed() > 1.48) break;\n\n            long long bestDelta = 0;\n            Move bestMove{-1, 0, 0, 0};\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {0, i, p, d};\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {1, i, j, d};\n                    }\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    long long d = newCost - oldCost;\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {2, l, r, d};\n                    }\n                }\n            }\n\n            bool stopBlock = false;\n            int limLen = min(maxBlockLen, n - 1);\n            for (int len = 2; len <= limLen && !stopBlock; len++) {\n                for (int l = 0; l + len <= n && !stopBlock; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        if (d < bestDelta) {\n                            bestDelta = d;\n                            bestMove = {3, l, r, d, q};\n                        }\n                    }\n                    if ((l & 15) == 0 && timer.elapsed() > 1.48) stopBlock = true;\n                }\n            }\n\n            if (bestDelta < 0) {\n                applyMove(ord, bestMove);\n            } else {\n                break;\n            }\n        }\n    }\n\n    Candidate exactRefine(vector<int> ord, double deadline, int rounds, int K) {\n        int cur = exactCost(ord);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestOrder = ord;\n        }\n\n        const Mode& mode = modes[0];\n        int n = (int)ord.size();\n\n        for (int round = 0; round < rounds; round++) {\n            if (timer.elapsed() > deadline) break;\n\n            vector<Move> moves;\n            moves.reserve(n * n * 2);\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    moves.push_back({0, i, p, d});\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    moves.push_back({1, i, j, d});\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    moves.push_back({2, l, r, newCost - oldCost});\n                }\n            }\n\n            int limLen = min(4, n - 1);\n            for (int len = 2; len <= limLen; len++) {\n                for (int l = 0; l + len <= n; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        moves.push_back({3, l, r, d, q});\n                    }\n                }\n            }\n\n            sort(moves.begin(), moves.end(), [](const Move& a, const Move& b) {\n                return a.delta < b.delta;\n            });\n\n            int bestLocal = cur;\n            Move bestMv{-1, 0, 0, 0};\n            int lim = min(K, (int)moves.size());\n\n            for (int i = 0; i < lim; i++) {\n                if ((i & 31) == 0 && timer.elapsed() > deadline) break;\n\n                vector<int> cand = ord;\n                applyMove(cand, moves[i]);\n                int nc = exactCost(cand);\n\n                if (nc < bestLocal) {\n                    bestLocal = nc;\n                    bestMv = moves[i];\n                }\n            }\n\n            if (bestMv.type != -1) {\n                applyMove(ord, bestMv);\n                cur = bestLocal;\n\n                if (cur < bestCost) {\n                    bestCost = cur;\n                    bestOrder = ord;\n                }\n            } else {\n                break;\n            }\n        }\n\n        return {cur, ord};\n    }\n\n    void buildExactCtx(const vector<int>& ord, ExactCtx& ctx, bool needRev) const {\n        int n = (int)ord.size();\n        ctx.n = n;\n        ctx.cnt.assign(n, 0);\n        for (int i = 0; i < n; i++) ctx.cnt[i] = wordCnt(ord[i]);\n\n        ctx.foff.assign(n * n, -1);\n        ctx.fdata.clear();\n        ctx.fdata.reserve((size_t)n * n * 90);\n\n        vector<unsigned short> prev, cur;\n\n        for (int l = 0; l < n; l++) {\n            int rows = ctx.cnt[l];\n            prev.assign(rows * rows, USINF);\n            for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n            ctx.foff[l * n + l] = (int)ctx.fdata.size();\n            ctx.fdata.insert(ctx.fdata.end(), prev.begin(), prev.end());\n\n            for (int r = l + 1; r < n; r++) {\n                int mid = ctx.cnt[r - 1];\n                int cols = ctx.cnt[r];\n                cur.assign(rows * cols, USINF);\n\n                const unsigned short* e = &edgeData[edgeOff[ord[r - 1] * M + ord[r]]];\n\n                for (int i = 0; i < rows; i++) {\n                    for (int k = 0; k < mid; k++) {\n                        int base = prev[i * mid + k];\n                        if (base >= USINF) continue;\n                        const unsigned short* er = e + k * cols;\n                        int outBase = i * cols;\n                        for (int j = 0; j < cols; j++) {\n                            int v = base + (int)er[j];\n                            if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                        }\n                    }\n                }\n\n                ctx.foff[l * n + r] = (int)ctx.fdata.size();\n                ctx.fdata.insert(ctx.fdata.end(), cur.begin(), cur.end());\n                prev.swap(cur);\n            }\n        }\n\n        ctx.roff.assign(n * n, -1);\n        ctx.rdata.clear();\n        if (needRev) {\n            ctx.rdata.reserve((size_t)n * n * 90);\n\n            for (int r = 0; r < n; r++) {\n                int rows = ctx.cnt[r];\n                prev.assign(rows * rows, USINF);\n                for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n                ctx.roff[r * n + r] = (int)ctx.rdata.size();\n                ctx.rdata.insert(ctx.rdata.end(), prev.begin(), prev.end());\n\n                for (int l = r - 1; l >= 0; l--) {\n                    int mid = ctx.cnt[l + 1];\n                    int cols = ctx.cnt[l];\n                    cur.assign(rows * cols, USINF);\n\n                    const unsigned short* e = &edgeData[edgeOff[ord[l + 1] * M + ord[l]]];\n\n                    for (int i = 0; i < rows; i++) {\n                        for (int k = 0; k < mid; k++) {\n                            int base = prev[i * mid + k];\n                            if (base >= USINF) continue;\n                            const unsigned short* er = e + k * cols;\n                            int outBase = i * cols;\n                            for (int j = 0; j < cols; j++) {\n                                int v = base + (int)er[j];\n                                if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                            }\n                        }\n                    }\n\n                    ctx.roff[l * n + r] = (int)ctx.rdata.size();\n                    ctx.rdata.insert(ctx.rdata.end(), cur.begin(), cur.end());\n                    prev.swap(cur);\n                }\n            }\n        }\n\n        ctx.prefOff.assign(n, 0);\n        ctx.prefData.clear();\n        ctx.prefData.reserve(n * maxOcc);\n\n        vector<unsigned short> dp, ndp;\n\n        {\n            int w = ord[0];\n            int cnt = ctx.cnt[0];\n            dp.resize(cnt);\n            int off = initOff[w];\n            for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n            ctx.prefOff[0] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        for (int pos = 1; pos < n; pos++) {\n            int rows = ctx.cnt[pos - 1];\n            int cols = ctx.cnt[pos];\n            ndp.assign(cols, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos - 1] * M + ord[pos]]];\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)er[c];\n                    if (v < ndp[c]) ndp[c] = (unsigned short)v;\n                }\n            }\n\n            dp.swap(ndp);\n            ctx.prefOff[pos] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        ctx.current = USINF;\n        for (unsigned short v : dp) ctx.current = min(ctx.current, (int)v);\n\n        vector<vector<unsigned short>> sv(n);\n        sv[n - 1].assign(ctx.cnt[n - 1], 0);\n\n        for (int pos = n - 2; pos >= 0; pos--) {\n            int rows = ctx.cnt[pos];\n            int cols = ctx.cnt[pos + 1];\n            sv[pos].assign(rows, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos] * M + ord[pos + 1]]];\n\n            for (int r = 0; r < rows; r++) {\n                int best = USINF;\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = (int)er[c] + (int)sv[pos + 1][c];\n                    if (v < best) best = v;\n                }\n                sv[pos][r] = (unsigned short)best;\n            }\n        }\n\n        ctx.suffOff.assign(n, 0);\n        ctx.suffData.clear();\n        ctx.suffData.reserve(n * maxOcc);\n        for (int pos = 0; pos < n; pos++) {\n            ctx.suffOff[pos] = (int)ctx.suffData.size();\n            ctx.suffData.insert(ctx.suffData.end(), sv[pos].begin(), sv[pos].end());\n        }\n    }\n\n    inline void loadInitWord(int w, int* a, int& cnt) const {\n        cnt = wordCnt(w);\n        const unsigned short* p = &initData[initOff[w]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void loadPrefPos(const ExactCtx& ctx, int pos, int* a, int& cnt) const {\n        cnt = ctx.cnt[pos];\n        const unsigned short* p = &ctx.prefData[ctx.prefOff[pos]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void applyEdgeArr(int* a, int& cnt, int u, int v, int* tmp) const {\n        const int INF = 1e9;\n        int rows = cnt;\n        int cols = wordCnt(v);\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n        for (int r = 0; r < rows; r++) {\n            int base = a[r];\n            const unsigned short* mr = mat + r * cols;\n            for (int c = 0; c < cols; c++) {\n                int val = base + (int)mr[c];\n                if (val < tmp[c]) tmp[c] = val;\n            }\n        }\n\n        for (int c = 0; c < cols; c++) a[c] = tmp[c];\n        cnt = cols;\n    }\n\n    inline void applyFInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[r];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[l];\n        int cols = ctx.cnt[r];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.fdata[ctx.foff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline void applyRInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[l];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[r];\n        int cols = ctx.cnt[l];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.rdata[ctx.roff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline int finishAt(const ExactCtx& ctx, int pos, int* a, int cnt) const {\n        const unsigned short* s = &ctx.suffData[ctx.suffOff[pos]];\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) {\n            int v = a[i] + (int)s[i];\n            if (v < ans) ans = v;\n        }\n        return ans;\n    }\n\n    inline int minArr(int* a, int cnt) const {\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) ans = min(ans, a[i]);\n        return ans;\n    }\n\n    int evalBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[l], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            }\n\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n\n            applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n\n            applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    int evalRelocateExact(const vector<int>& ord, const ExactCtx& ctx, int i, int p) const {\n        if (i == p) return ctx.current;\n        int q = (p < i ? p : p + 1);\n        return evalBlockExact(ord, ctx, i, i, q);\n    }\n\n    int evalSwapExact(const vector<int>& ord, const ExactCtx& ctx, int i, int j) const {\n        if (i > j) swap(i, j);\n        int n = ctx.n;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (i == 0) {\n            loadInitWord(ord[j], a, cnt);\n        } else {\n            loadPrefPos(ctx, i - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[i - 1], ord[j], tmp);\n        }\n\n        if (j == i + 1) {\n            applyEdgeArr(a, cnt, ord[j], ord[i], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[j], ord[i + 1], tmp);\n            applyFInterval(ctx, i + 1, j - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[j - 1], ord[i], tmp);\n        }\n\n        if (j + 1 < n) {\n            applyEdgeArr(a, cnt, ord[i], ord[j + 1], tmp);\n            return finishAt(ctx, j + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalReverseExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r) const {\n        int n = ctx.n;\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l == 0) {\n            loadInitWord(ord[r], a, cnt);\n        } else {\n            loadPrefPos(ctx, l - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l - 1], ord[r], tmp);\n        }\n\n        applyRInterval(ctx, l, r, a, cnt, tmp);\n\n        if (r + 1 < n) {\n            applyEdgeArr(a, cnt, ord[l], ord[r + 1], tmp);\n            return finishAt(ctx, r + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    void improveExactInterval(vector<int>& ord, double deadline, int maxIter) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if (timer.elapsed() > deadline - 0.07) break;\n\n            ExactCtx ctx;\n            buildExactCtx(ord, ctx, true);\n\n            int cur = ctx.current;\n            if (cur < bestCost) {\n                bestCost = cur;\n                bestOrder = ord;\n            }\n\n            int bestVal = cur;\n            Move bestMv{-1, 0, 0, 0};\n\n            int checks = 0;\n            bool timeout = false;\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    int val = evalRelocateExact(ord, ctx, i, p);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {0, i, p, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    int val = evalSwapExact(ord, ctx, i, j);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {1, i, j, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    int val = evalReverseExact(ord, ctx, l, r);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {2, l, r, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(6, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {3, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n        ENUM_DONE:\n            if (bestMv.type != -1 && bestVal < cur) {\n                applyMove(ord, bestMv);\n                int real = exactCost(ord);\n                if (real < bestCost) {\n                    bestCost = real;\n                    bestOrder = ord;\n                }\n                if (real >= cur) break;\n            } else {\n                break;\n            }\n\n            if (timeout || timer.elapsed() > deadline) break;\n        }\n    }\n\n    void simulatedAnnealing(double deadline) {\n        if (timer.elapsed() > deadline) return;\n\n        vector<int> curOrd = bestOrder;\n        int curCost = bestCost;\n        const Mode& mode = modes[0];\n\n        double st = timer.elapsed();\n        int n = (int)curOrd.size();\n        if (n <= 1) return;\n\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            Move mv{-1, 0, 0, 0};\n\n            int typ = rng.nextInt(100);\n            if (typ < 35) {\n                int i = rng.nextInt(n);\n                int p = rng.nextInt(n);\n                if (p == i) continue;\n                long long d = relocateDelta(curOrd, i, p, mode);\n                mv = {0, i, p, d};\n            } else if (typ < 60) {\n                int i = rng.nextInt(n);\n                int j = rng.nextInt(n);\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                long long d = swapDelta(curOrd, i, j, mode);\n                mv = {1, i, j, d};\n            } else if (typ < 82) {\n                int l = rng.nextInt(n);\n                int r = rng.nextInt(n);\n                if (l == r) continue;\n                if (l > r) swap(l, r);\n                long long d = reverseDeltaSlow(curOrd, l, r, mode);\n                mv = {2, l, r, d};\n            } else {\n                if (n <= 3) continue;\n                int len = 2 + rng.nextInt(min(6, n - 1) - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                long long d = blockRelocateDelta(curOrd, l, r, q, mode);\n                mv = {3, l, r, d, q};\n            }\n\n            if (mv.delta > 3000) continue;\n            if (mv.delta > 800 && rng.nextInt(100) < 95) continue;\n\n            vector<int> cand = curOrd;\n            applyMove(cand, mv);\n            int nc = exactCost(cand);\n\n            int diff = nc - curCost;\n            double progress = (timer.elapsed() - st) / max(1e-9, deadline - st);\n            double temp = 18.0 * pow(0.05, progress) + 0.4;\n\n            if (diff <= 0 || rng.nextDouble() < exp(-diff / temp)) {\n                curOrd.swap(cand);\n                curCost = nc;\n\n                if (curCost < bestCost) {\n                    bestCost = curCost;\n                    bestOrder = curOrd;\n                }\n            }\n\n            iter++;\n            if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    string buildString(const vector<int>& ord) const {\n        if (ord.empty()) return \"\";\n\n        string s = words[ord[0]];\n        for (int i = 1; i < (int)ord.size(); i++) {\n            int a = ord[i - 1];\n            int b = ord[i];\n            int k = overlap[a * M + b];\n            s += words[b].substr(k);\n        }\n        return s;\n    }\n\n    bool containsAll(const string& s) const {\n        if ((int)s.size() < 5) return false;\n\n        vector<char> seen(M, false);\n        int got = 0;\n\n        int code = 0;\n        for (int i = 0; i < 5; i++) code = code * 26 + (s[i] - 'A');\n\n        auto mark = [&](int cd) {\n            auto it = targetMap.find(cd);\n            if (it != targetMap.end()) {\n                int id = it->second;\n                if (!seen[id]) {\n                    seen[id] = true;\n                    got++;\n                }\n            }\n        };\n\n        mark(code);\n\n        for (int i = 5; i < (int)s.size(); i++) {\n            code = (code % pow4) * 26 + (s[i] - 'A');\n            mark(code);\n        }\n\n        return got == M;\n    }\n\n    void tryRemoveRedundant(double deadline) {\n        bool improved = true;\n\n        while (improved && timer.elapsed() < deadline) {\n            improved = false;\n\n            for (int p = 0; p < (int)bestOrder.size(); p++) {\n                if (timer.elapsed() > deadline) break;\n                if ((int)bestOrder.size() <= 1) break;\n\n                vector<int> cand = bestOrder;\n                cand.erase(cand.begin() + p);\n\n                string s = buildString(cand);\n                if (!containsAll(s)) continue;\n\n                int c = exactCost(cand);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestOrder = cand;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    void outputStringPath(const string& s) const {\n        int L = (int)s.size();\n        const int INF = 1e9;\n\n        vector<vector<int>> pred(L);\n        vector<int> dpPrev, dpCur;\n\n        for (int idx = 0; idx < L; idx++) {\n            int c = s[idx] - 'A';\n            int cnt = (int)letterPos[c].size();\n\n            dpCur.assign(cnt, INF);\n            pred[idx].assign(cnt, -1);\n\n            if (idx == 0) {\n                for (int q = 0; q < cnt; q++) {\n                    int id = letterPos[c][q];\n                    dpCur[q] = (int)distCell[startId][id] + 1;\n                }\n            } else {\n                int pc = s[idx - 1] - 'A';\n                int pcnt = (int)letterPos[pc].size();\n\n                for (int q = 0; q < cnt; q++) {\n                    int qid = letterPos[c][q];\n                    int best = INF;\n                    int bestP = -1;\n\n                    for (int p = 0; p < pcnt; p++) {\n                        int pid = letterPos[pc][p];\n                        int v = dpPrev[p] + (int)distCell[pid][qid] + 1;\n                        if (v < best) {\n                            best = v;\n                            bestP = p;\n                        }\n                    }\n\n                    dpCur[q] = best;\n                    pred[idx][q] = bestP;\n                }\n            }\n\n            dpPrev.swap(dpCur);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < dpPrev[bestIdx]) bestIdx = i;\n        }\n\n        vector<int> outIds(L);\n        for (int idx = L - 1; idx >= 0; idx--) {\n            int c = s[idx] - 'A';\n            outIds[idx] = letterPos[c][bestIdx];\n            bestIdx = pred[idx][bestIdx];\n        }\n\n        for (int id : outIds) {\n            cout << id / N << ' ' << id % N << '\\n';\n        }\n    }\n\n    void solve() {\n        timer.reset();\n\n        precompute();\n        buildModes();\n\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = exactCost(bestOrder);\n\n        vector<Candidate> candidates;\n\n        auto consider = [&](const vector<int>& ord) {\n            int c = exactCost(ord);\n            candidates.push_back({c, ord});\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = ord;\n            }\n        };\n\n        consider(bestOrder);\n\n        for (int mi = 0; mi < (int)modes.size(); mi++) {\n            if (timer.elapsed() > 1.25) break;\n\n            {\n                vector<int> ord = hungarianPatch(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = cheapestInsertion(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = nearestNeighborBest(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes[0], false);\n            improveAdditive(ord, modes[0], 35, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes.back(), true);\n            improveAdditive(ord, modes.back(), 35, 3);\n            consider(ord);\n        }\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return startMinCost[a] < startMinCost[b];\n        });\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<int> starts;\n        for (int i = 0; i < min(M, 10); i++) starts.push_back(ids[i]);\n        for (int i = 0; i < min((int)candidates.size(), 8); i++) {\n            if (!candidates[i].order.empty()) starts.push_back(candidates[i].order[0]);\n        }\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        int greedyRuns = 0;\n        for (int stWord : starts) {\n            if (greedyRuns >= 14 || timer.elapsed() > 1.45) break;\n\n            vector<int> ord = coordinateGreedy(stWord);\n            consider(ord);\n\n            improveAdditive(ord, modes[0], 25, 3);\n            consider(ord);\n\n            greedyRuns++;\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<vector<int>> refineList;\n        for (const auto& cand : candidates) {\n            bool dup = false;\n            for (const auto& v : refineList) {\n                if (v == cand.order) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) refineList.push_back(cand.order);\n            if ((int)refineList.size() >= 3) break;\n        }\n\n        for (auto& ord : refineList) {\n            if (timer.elapsed() > 1.60) break;\n            Candidate r = exactRefine(ord, 1.60, 3, 350);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.64) {\n            Candidate r = exactRefine(bestOrder, 1.64, 3, 500);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.84) {\n            improveExactInterval(bestOrder, 1.84, 3);\n        }\n\n        simulatedAnnealing(1.875);\n        tryRemoveRedundant(1.89);\n\n        string finalS = buildString(bestOrder);\n        if (!containsAll(finalS) || (int)finalS.size() > 5000) {\n            bestOrder.resize(M);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n            finalS = buildString(bestOrder);\n        }\n\n        outputStringPath(finalS);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXC = 400;\nstatic constexpr double EXACT_W = 1e7;\nstatic constexpr double BAN_W = 1e8;\n\nstruct Placement {\n    int di, dj;\n    vector<int> cells;\n    bitset<MAXC> bits;\n};\n\nstruct Field {\n    int area = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> placements;\n    vector<uint16_t> contrib; // flattened: placement * Q + q\n};\n\nstruct Observation {\n    vector<int> cells;\n    int k;\n    int y;\n};\n\nstruct State {\n    bool valid = false;\n    vector<int> pos;\n    vector<int> pred;\n    vector<int> cnt;\n    double score = -1e300;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n    int totalArea = 0;\n    int Q = 0;\n    int stride = 0;\n\n    vector<Field> fields;\n    vector<Observation> obs;\n\n    vector<double> scoreFlat;\n    vector<double> tHat, invVarT;\n\n    vector<unsigned char> drilled;\n    vector<int> drillVal;\n    vector<int> drilledCells;\n    int drilledCount = 0;\n\n    vector<vector<unsigned char>> bannedEqMasks;\n    vector<vector<unsigned char>> subsetMasks;\n\n    int opCount = 0;\n    int maxInitialQueries = 0;\n\n    mt19937 rng{123456789};\n\n    chrono::steady_clock::time_point startTime;\n\n    double elapsedMs() const {\n        return chrono::duration<double, std::milli>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    }\n\n    double normalCDF(double x) {\n        return 0.5 * erfc(-x / sqrt(2.0));\n    }\n\n    void readInput() {\n        cin >> N >> M >> eps;\n        C = N * N;\n        alpha = 1.0 - 2.0 * eps;\n        fields.resize(M);\n\n        for (int m = 0; m < M; m++) {\n            int d;\n            cin >> d;\n            fields[m].area = d;\n            fields[m].rel.resize(d);\n            int mx_i = 0, mx_j = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[m].rel[t] = {i, j};\n                mx_i = max(mx_i, i);\n                mx_j = max(mx_j, j);\n            }\n            fields[m].h = mx_i + 1;\n            fields[m].w = mx_j + 1;\n            totalArea += d;\n        }\n\n        generatePlacements();\n\n        drilled.assign(C, 0);\n        drillVal.assign(C, 0);\n    }\n\n    void generatePlacements() {\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            for (int di = 0; di + f.h <= N; di++) {\n                for (int dj = 0; dj + f.w <= N; dj++) {\n                    Placement p;\n                    p.di = di;\n                    p.dj = dj;\n                    p.bits.reset();\n                    for (auto [ri, rj] : f.rel) {\n                        int c = (di + ri) * N + (dj + rj);\n                        p.cells.push_back(c);\n                        p.bits.set(c);\n                    }\n                    f.placements.push_back(std::move(p));\n                }\n            }\n        }\n    }\n\n    void maybeAskDiv(vector<int> cells) {\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        if ((int)cells.size() < 2) return;\n        if ((int)obs.size() >= maxInitialQueries) return;\n\n        cout << \"q \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int y;\n        if (!(cin >> y)) exit(0);\n        if (y < 0) exit(0);\n\n        opCount++;\n        obs.push_back({cells, (int)cells.size(), y});\n    }\n\n    void askInitialQueries() {\n        maxInitialQueries = max(0, C - 10);\n\n        // Rows\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            maybeAskDiv(cells);\n        }\n\n        // Columns\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            maybeAskDiv(cells);\n        }\n\n        // Coarse blocks\n        int B = max(3, (N + 4) / 5);\n        for (int r = 0; r < N; r += B) {\n            for (int c = 0; c < N; c += B) {\n                vector<int> cells;\n                for (int i = r; i < min(N, r + B); i++) {\n                    for (int j = c; j < min(N, c + B); j++) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                maybeAskDiv(cells);\n            }\n        }\n\n        // Shifted full blocks\n        int off = B / 2;\n        if (off > 0) {\n            for (int r = off; r + B <= N; r += B) {\n                for (int c = off; c + B <= N; c += B) {\n                    vector<int> cells;\n                    for (int i = r; i < r + B; i++) {\n                        for (int j = c; j < c + B; j++) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        }\n\n        // Modulo patterns\n        auto addModQueries = [&](int mod) {\n            for (int a = 0; a < mod; a++) {\n                for (int b = 0; b < mod; b++) {\n                    vector<int> cells;\n                    for (int i = 0; i < N; i++) {\n                        for (int j = 0; j < N; j++) {\n                            if (i % mod == a && j % mod == b) {\n                                cells.push_back(i * N + j);\n                            }\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        };\n        addModQueries(2);\n        if (N >= 13) addModQueries(3);\n\n        // Random masks\n        int R = (N <= 12 ? N : 2 * N);\n        for (int r = 0; r < R; r++) {\n            vector<int> cells;\n            for (int attempt = 0; attempt < 100; attempt++) {\n                cells.clear();\n                for (int c = 0; c < C; c++) {\n                    if ((int)(rng() % 10000) < 2500) cells.push_back(c);\n                }\n                if ((int)cells.size() >= 2) break;\n            }\n            if ((int)cells.size() < 2) {\n                cells = {0, C - 1};\n            }\n            maybeAskDiv(cells);\n        }\n    }\n\n    int drillCell(int c) {\n        if (drilled[c]) return drillVal[c];\n\n        cout << \"q 1 \" << c / N << ' ' << c % N << '\\n';\n        cout.flush();\n\n        int v;\n        if (!(cin >> v)) exit(0);\n        if (v < 0) exit(0);\n\n        opCount++;\n        drilled[c] = 1;\n        drillVal[c] = v;\n        drilledCount++;\n        drilledCells.push_back(c);\n        return v;\n    }\n\n    bool submitAnswer(vector<unsigned char> mask) {\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        vector<int> cells;\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) cells.push_back(c);\n        }\n\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int res;\n        if (!(cin >> res)) exit(0);\n        opCount++;\n\n        if (res == 1) exit(0);\n        if (res < 0) exit(0);\n        return false;\n    }\n\n    bool canFallback() const {\n        return opCount + (C - drilledCount) + 1 <= 2 * C;\n    }\n\n    bool canWrongGuessAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    void fallback() {\n        for (int c = 0; c < C; c++) {\n            if (!drilled[c]) drillCell(c);\n        }\n\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (drillVal[c] > 0) mask[c] = 1;\n        }\n\n        submitAnswer(mask);\n        exit(0);\n    }\n\n    void buildContrib() {\n        Q = (int)obs.size();\n        vector<vector<int>> obsOfCell(C);\n\n        for (int q = 0; q < Q; q++) {\n            for (int c : obs[q].cells) obsOfCell[c].push_back(q);\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            int P = (int)f.placements.size();\n            f.contrib.assign(P * Q, 0);\n\n            for (int p = 0; p < P; p++) {\n                uint16_t *arr = Q ? &f.contrib[p * Q] : nullptr;\n                for (int c : f.placements[p].cells) {\n                    for (int q : obsOfCell[c]) {\n                        arr[q]++;\n                    }\n                }\n            }\n        }\n    }\n\n    void buildScoreTables() {\n        stride = totalArea + 1;\n        scoreFlat.assign(Q * stride, 0.0);\n        tHat.assign(Q, 0.0);\n        invVarT.assign(Q, 1.0);\n\n        for (int q = 0; q < Q; q++) {\n            int k = obs[q].k;\n            int y = obs[q].y;\n\n            double sigma = sqrt(k * eps * (1.0 - eps));\n            double varT = k * eps * (1.0 - eps) / (alpha * alpha)\n                        + 0.25 / (alpha * alpha);\n            invVarT[q] = 1.0 / max(1e-9, varT);\n\n            double th = (y - eps * k) / alpha;\n            th = min<double>(totalArea, max<double>(0.0, th));\n            tHat[q] = th;\n\n            for (int t = 0; t <= totalArea; t++) {\n                double mu = eps * k + alpha * t;\n                double prob;\n\n                if (y == 0) {\n                    prob = normalCDF((0.5 - mu) / sigma);\n                } else {\n                    double lo = (y - 0.5 - mu) / sigma;\n                    double hi = (y + 0.5 - mu) / sigma;\n                    prob = normalCDF(hi) - normalCDF(lo);\n                }\n\n                if (!(prob > 1e-300)) prob = 1e-300;\n                scoreFlat[q * stride + t] = log(prob);\n            }\n        }\n    }\n\n    void addToState(State &s, int m, int p, int sign) {\n        if (Q) {\n            const uint16_t *arr = &fields[m].contrib[p * Q];\n            for (int q = 0; q < Q; q++) s.pred[q] += sign * (int)arr[q];\n        }\n\n        for (int c : fields[m].placements[p].cells) {\n            s.cnt[c] += sign;\n        }\n    }\n\n    double computeExactScore(const vector<int> &cnt) const {\n        long long sq = 0;\n        for (int c : drilledCells) {\n            int diff = cnt[c] - drillVal[c];\n            sq += 1LL * diff * diff;\n        }\n        return -EXACT_W * (double)sq;\n    }\n\n    double computeBanPenalty(const vector<int> &cnt) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = cnt[c] > 0;\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (cnt[c] > 0 && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeBanPenaltyBits(const bitset<MAXC> &uni) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = uni.test(c);\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (uni.test(c) && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeScore(const State &s) const {\n        double sc = 0.0;\n\n        for (int q = 0; q < Q; q++) {\n            sc += scoreFlat[q * stride + s.pred[q]];\n        }\n\n        sc += computeExactScore(s.cnt);\n        sc += computeBanPenalty(s.cnt);\n        return sc;\n    }\n\n    State buildState(const vector<int> &pos) {\n        State s;\n        s.valid = true;\n        s.pos = pos;\n        s.pred.assign(Q, 0);\n        s.cnt.assign(C, 0);\n\n        for (int m = 0; m < M; m++) {\n            addToState(s, m, s.pos[m], +1);\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    bool placementCoversKnownZero(int m, int p) const {\n        for (int c : fields[m].placements[p].cells) {\n            if (drilled[c] && drillVal[c] == 0) return true;\n        }\n        return false;\n    }\n\n    int randomPlacement(int m) {\n        int P = (int)fields[m].placements.size();\n\n        for (int t = 0; t < 50; t++) {\n            int p = (int)(rng() % P);\n            if (!placementCoversKnownZero(m, p)) return p;\n        }\n\n        vector<int> valid;\n        for (int p = 0; p < P; p++) {\n            if (!placementCoversKnownZero(m, p)) valid.push_back(p);\n        }\n\n        if (!valid.empty()) {\n            return valid[(int)(rng() % valid.size())];\n        }\n        return (int)(rng() % P);\n    }\n\n    State makeRandomState() {\n        vector<int> pos(M);\n        for (int m = 0; m < M; m++) {\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makePerturbedState(const State &base, int changes) {\n        vector<int> pos = base.pos;\n        for (int t = 0; t < changes; t++) {\n            int m = (int)(rng() % M);\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makeGreedyState() {\n        vector<int> pos(M, -1);\n        vector<int> pred(Q, 0);\n        vector<int> cnt(C, 0);\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].area > fields[b].area;\n        });\n\n        int placedArea = 0;\n\n        for (int m : order) {\n            int P = (int)fields[m].placements.size();\n            int newArea = placedArea + fields[m].area;\n\n            double bestVal = 1e300;\n            int bestP = 0;\n\n            for (int p = 0; p < P; p++) {\n                double val = 0.0;\n                const uint16_t *arr = Q ? &fields[m].contrib[p * Q] : nullptr;\n\n                for (int q = 0; q < Q; q++) {\n                    double target = tHat[q] * (double)newArea / (double)totalArea;\n                    double diff = (double)(pred[q] + arr[q]) - target;\n                    val += diff * diff * invVarT[q];\n                }\n\n                for (int c : fields[m].placements[p].cells) {\n                    if (drilled[c]) {\n                        if (drillVal[c] == 0) val += 1e9;\n                        if (cnt[c] + 1 > drillVal[c]) val += 1e9;\n                    }\n                }\n\n                if (val < bestVal - 1e-9 ||\n                    (fabs(val - bestVal) <= 1e-9 && (rng() & 1))) {\n                    bestVal = val;\n                    bestP = p;\n                }\n            }\n\n            pos[m] = bestP;\n            if (Q) {\n                const uint16_t *arr = &fields[m].contrib[bestP * Q];\n                for (int q = 0; q < Q; q++) pred[q] += arr[q];\n            }\n            for (int c : fields[m].placements[bestP].cells) cnt[c]++;\n            placedArea = newArea;\n        }\n\n        return buildState(pos);\n    }\n\n    State optimizeExactSmall() {\n        State invalid;\n\n        if (M == 2) {\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n\n            double bestSc = -1e300;\n            vector<int> bestPos(2, 0);\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    double sc = 0.0;\n                    for (int q = 0; q < Q; q++) {\n                        int t = a0[q] + a1[q];\n                        sc += scoreFlat[q * stride + t];\n                    }\n\n                    if (drilledCount > 0) {\n                        long long sq = 0;\n                        for (int c : drilledCells) {\n                            int cnt = (b0.test(c) ? 1 : 0) + (b1.test(c) ? 1 : 0);\n                            int diff = cnt - drillVal[c];\n                            sq += 1LL * diff * diff;\n                        }\n                        sc -= EXACT_W * (double)sq;\n                    }\n\n                    if (hasBan) {\n                        bitset<MAXC> uni = b0 | b1;\n                        sc += computeBanPenaltyBits(uni);\n                    }\n\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestPos[0] = p0;\n                        bestPos[1] = p1;\n                    }\n                }\n            }\n\n            return buildState(bestPos);\n        }\n\n        if (M == 3) {\n            long long prod = 1;\n            for (int m = 0; m < 3; m++) {\n                prod *= (long long)fields[m].placements.size();\n            }\n            if (prod > 250000) return invalid;\n\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n            int P2 = (int)fields[2].placements.size();\n\n            double bestSc = -1e300;\n            vector<int> bestPos(3, 0);\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            vector<int> pred01(Q);\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    for (int q = 0; q < Q; q++) pred01[q] = a0[q] + a1[q];\n\n                    bitset<MAXC> bits01;\n                    if (hasBan) bits01 = b0 | b1;\n\n                    for (int p2 = 0; p2 < P2; p2++) {\n                        const uint16_t *a2 = Q ? &fields[2].contrib[p2 * Q] : nullptr;\n                        const auto &b2 = fields[2].placements[p2].bits;\n\n                        double sc = 0.0;\n                        for (int q = 0; q < Q; q++) {\n                            int t = pred01[q] + a2[q];\n                            sc += scoreFlat[q * stride + t];\n                        }\n\n                        if (drilledCount > 0) {\n                            long long sq = 0;\n                            for (int c : drilledCells) {\n                                int cnt = (b0.test(c) ? 1 : 0)\n                                        + (b1.test(c) ? 1 : 0)\n                                        + (b2.test(c) ? 1 : 0);\n                                int diff = cnt - drillVal[c];\n                                sq += 1LL * diff * diff;\n                            }\n                            sc -= EXACT_W * (double)sq;\n                        }\n\n                        if (hasBan) {\n                            bitset<MAXC> uni = bits01 | b2;\n                            sc += computeBanPenaltyBits(uni);\n                        }\n\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bestPos[0] = p0;\n                            bestPos[1] = p1;\n                            bestPos[2] = p2;\n                        }\n                    }\n                }\n            }\n\n            return buildState(bestPos);\n        }\n\n        return invalid;\n    }\n\n    State coordinateDescent(State s, int sweeps, double deadlineMs) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            shuffle(order.begin(), order.end(), rng);\n            bool changed = false;\n\n            for (int m : order) {\n                if (elapsedMs() > deadlineMs) {\n                    s.score = computeScore(s);\n                    return s;\n                }\n\n                int oldP = s.pos[m];\n                addToState(s, m, oldP, -1);\n\n                double baseExact = computeExactScore(s.cnt);\n\n                vector<int> baseDiff(bannedEqMasks.size(), 0);\n                vector<int> baseOut(subsetMasks.size(), 0);\n\n                for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                    const auto &mask = bannedEqMasks[f];\n                    int diff = 0;\n                    for (int c = 0; c < C; c++) {\n                        bool cov = s.cnt[c] > 0;\n                        if (cov != (bool)mask[c]) diff++;\n                    }\n                    baseDiff[f] = diff;\n                }\n\n                for (size_t f = 0; f < subsetMasks.size(); f++) {\n                    const auto &mask = subsetMasks[f];\n                    int out = 0;\n                    for (int c = 0; c < C; c++) {\n                        if (s.cnt[c] > 0 && !mask[c]) out++;\n                    }\n                    baseOut[f] = out;\n                }\n\n                int P = (int)fields[m].placements.size();\n                int bestP = oldP;\n                double bestSc = -1e300;\n\n                for (int p = 0; p < P; p++) {\n                    const auto &pl = fields[m].placements[p];\n                    double total = baseExact;\n\n                    if (Q) {\n                        const uint16_t *arr = &fields[m].contrib[p * Q];\n                        for (int q = 0; q < Q; q++) {\n                            int t = s.pred[q] + arr[q];\n                            total += scoreFlat[q * stride + t];\n                        }\n                    }\n\n                    if (drilledCount > 0) {\n                        for (int c : pl.cells) {\n                            if (drilled[c]) {\n                                int diff = s.cnt[c] - drillVal[c];\n                                total += -EXACT_W *\n                                    (double)((diff + 1) * (diff + 1) - diff * diff);\n                            }\n                        }\n                    }\n\n                    for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                        int diff = baseDiff[f];\n                        const auto &mask = bannedEqMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0) {\n                                if (mask[c]) diff--;\n                                else diff++;\n                            }\n                        }\n\n                        if (diff == 0) total -= BAN_W;\n                    }\n\n                    for (size_t f = 0; f < subsetMasks.size(); f++) {\n                        int out = baseOut[f];\n                        const auto &mask = subsetMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0 && !mask[c]) out++;\n                        }\n\n                        if (out == 0) total -= BAN_W;\n                    }\n\n                    if (total > bestSc + 1e-9 ||\n                        (fabs(total - bestSc) <= 1e-9 && (rng() & 1))) {\n                        bestSc = total;\n                        bestP = p;\n                    }\n                }\n\n                addToState(s, m, bestP, +1);\n                s.pos[m] = bestP;\n                s.score = bestSc;\n                if (bestP != oldP) changed = true;\n            }\n\n            if (!changed) break;\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    State optimize(const State *prev, bool first) {\n        State exact = optimizeExactSmall();\n        if (exact.valid) return exact;\n\n        double now = elapsedMs();\n        double req = first ? 1200.0 : 450.0;\n        double deadline = min(2450.0, now + req);\n        if (deadline < now + 30.0) deadline = now + 30.0;\n\n        int maxRestarts;\n        if (first) {\n            if (M <= 4) maxRestarts = 80;\n            else if (M <= 10) maxRestarts = 50;\n            else maxRestarts = 35;\n        } else {\n            if (M <= 4) maxRestarts = 40;\n            else if (M <= 10) maxRestarts = 25;\n            else maxRestarts = 18;\n        }\n\n        int sweeps = first ? 7 : 5;\n\n        State best;\n\n        for (int r = 0; r < maxRestarts && elapsedMs() < deadline; r++) {\n            State s;\n\n            if (r == 0 && prev && prev->valid) {\n                s = buildState(prev->pos);\n            } else if ((r == 0 && (!prev || !prev->valid)) ||\n                       (r == 1 && prev && prev->valid)) {\n                s = makeGreedyState();\n            } else if (prev && prev->valid && r < 6) {\n                int changes = 1 + (r % max(1, M / 2));\n                s = makePerturbedState(*prev, changes);\n            } else {\n                s = makeRandomState();\n            }\n\n            s = coordinateDescent(s, sweeps, deadline);\n\n            if (!best.valid || s.score > best.score) {\n                best = std::move(s);\n            }\n        }\n\n        if (!best.valid) {\n            if (prev && prev->valid) best = buildState(prev->pos);\n            else best = makeGreedyState();\n        }\n\n        return best;\n    }\n\n    int countExactMismatch(const State &s) const {\n        int mism = 0;\n        for (int c : drilledCells) {\n            if (s.cnt[c] != drillVal[c]) mism++;\n        }\n        return mism;\n    }\n\n    vector<unsigned char> unionMask(const State &s) const {\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) mask[c] = 1;\n        }\n        return mask;\n    }\n\n    bool allVerifiedPositive(const vector<unsigned char> &mask) const {\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) {\n                if (!drilled[c]) return false;\n                if (drillVal[c] <= 0) return false;\n            }\n        }\n        return true;\n    }\n\n    bool sameMask(const vector<unsigned char> &a,\n                  const vector<unsigned char> &b) const {\n        return a == b;\n    }\n\n    bool isBannedEq(const vector<unsigned char> &mask) const {\n        for (const auto &x : bannedEqMasks) {\n            if (sameMask(x, mask)) return true;\n        }\n        return false;\n    }\n\n    void addBannedEq(const vector<unsigned char> &mask) {\n        if (!isBannedEq(mask)) bannedEqMasks.push_back(mask);\n    }\n\n    void addSubsetMask(const vector<unsigned char> &mask) {\n        for (const auto &x : subsetMasks) {\n            if (sameMask(x, mask)) return;\n        }\n        subsetMasks.push_back(mask);\n    }\n\n    int boundaryScore(int c, const vector<unsigned char> &mask) const {\n        int i = c / N;\n        int j = c % N;\n        int score = 0;\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                score++;\n            } else {\n                int nc = ni * N + nj;\n                if (!mask[nc]) score++;\n            }\n        }\n\n        return score;\n    }\n\n    vector<int> cellsToDrillInUnion(const vector<unsigned char> &U) {\n        vector<pair<int,int>> order;\n\n        for (int c = 0; c < C; c++) {\n            if (U[c] && !drilled[c]) {\n                int key = boundaryScore(c, U) * 1000000 + (int)(rng() % 1000000);\n                order.push_back({-key, c});\n            }\n        }\n\n        sort(order.begin(), order.end());\n\n        vector<int> res;\n        for (auto [_, c] : order) res.push_back(c);\n        return res;\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        askInitialQueries();\n        buildContrib();\n        buildScoreTables();\n\n        State best = optimize(nullptr, true);\n\n        int maxUnverifiedGuesses = (N >= 15 ? 3 : 2);\n        int unverifiedUsed = 0;\n        int mismatchRetries = 0;\n\n        while (true) {\n            if (!canFallback()) {\n                fallback();\n            }\n\n            if (elapsedMs() > 2600.0) {\n                fallback();\n            }\n\n            if (drilledCount == C) {\n                fallback();\n            }\n\n            int mism = countExactMismatch(best);\n            if (mism > 0) {\n                if (mismatchRetries < 3 && elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    mismatchRetries++;\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n            mismatchRetries = 0;\n\n            vector<unsigned char> U = unionMask(best);\n            vector<unsigned char> A = U;\n            for (int c = 0; c < C; c++) {\n                if (drilled[c] && drillVal[c] > 0) A[c] = 1;\n            }\n\n            bool verified = allVerifiedPositive(A);\n\n            if (verified && isBannedEq(A)) {\n                addSubsetMask(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            // A few cheap speculative guesses before paying drilling cost.\n            if (!verified &&\n                unverifiedUsed < maxUnverifiedGuesses &&\n                canWrongGuessAndFallback() &&\n                !isBannedEq(A)) {\n                submitAnswer(A);\n                addBannedEq(A);\n                unverifiedUsed++;\n                best = optimize(&best, false);\n                continue;\n            }\n\n            if (!verified) {\n                vector<int> todo = cellsToDrillInUnion(U);\n\n                if (todo.empty()) {\n                    if (elapsedMs() < 2400.0) {\n                        best = optimize(&best, false);\n                        continue;\n                    } else {\n                        fallback();\n                    }\n                }\n\n                bool contradiction = false;\n\n                for (int c : todo) {\n                    if (!canFallback()) fallback();\n\n                    int v = drillCell(c);\n                    if (v != best.cnt[c]) {\n                        contradiction = true;\n                        break;\n                    }\n                }\n\n                if (contradiction) {\n                    best = optimize(&best, false);\n                    continue;\n                } else {\n                    continue;\n                }\n            } else {\n                if (!canWrongGuessAndFallback()) {\n                    fallback();\n                }\n\n                submitAnswer(A);\n\n                // If all cells in A were confirmed positive and the answer is wrong,\n                // then the true union has at least one additional outside cell.\n                addSubsetMask(A);\n                addBannedEq(A);\n\n                best = optimize(&best, false);\n                continue;\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int W = 1000;\nstatic const int AREA = W * W;\nstatic const unsigned short INF = 30000;\nenum { VERT = 0, HOR = 1 };\nenum { POLICY_STATIC_ABS = 0, POLICY_STATIC_RATIO = 1, POLICY_PREV = 2 };\n\nstruct Rect {\n    int y0, x0, y1, x1;\n};\n\nint D, N;\nvector<vector<int>> A;\nvector<int> globalMaxDemand, meanDemand, medDemand, p75Demand, p90Demand;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nint clamp_int(int v, int lo, int hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\n/* ---------- exact evaluator ---------- */\n\nstruct Bound {\n    array<vector<pair<int,int>>, W + 1> H, V;\n    void clear() {\n        for (int i = 0; i <= W; i++) {\n            H[i].clear();\n            V[i].clear();\n        }\n    }\n};\n\nvoid merge_intervals(vector<pair<int,int>>& v) {\n    if (v.empty()) return;\n    sort(v.begin(), v.end());\n    int m = 0;\n    for (auto p : v) {\n        if (m == 0 || p.first > v[m-1].second) {\n            v[m++] = p;\n        } else {\n            v[m-1].second = max(v[m-1].second, p.second);\n        }\n    }\n    v.resize(m);\n}\n\nvoid build_bound(const vector<Rect>& rs, Bound& b) {\n    b.clear();\n    for (const auto& r : rs) {\n        if (r.y0 > 0 && r.y0 < W) b.H[r.y0].push_back({r.x0, r.x1});\n        if (r.y1 > 0 && r.y1 < W) b.H[r.y1].push_back({r.x0, r.x1});\n        if (r.x0 > 0 && r.x0 < W) b.V[r.x0].push_back({r.y0, r.y1});\n        if (r.x1 > 0 && r.x1 < W) b.V[r.x1].push_back({r.y0, r.y1});\n    }\n    for (int i = 1; i < W; i++) {\n        merge_intervals(b.H[i]);\n        merge_intervals(b.V[i]);\n    }\n}\n\nlong long symdiff_line(const vector<pair<int,int>>& a, const vector<pair<int,int>>& b) {\n    long long la = 0, lb = 0, inter = 0;\n    for (auto [l, r] : a) la += r - l;\n    for (auto [l, r] : b) lb += r - l;\n\n    int i = 0, j = 0;\n    while (i < (int)a.size() && j < (int)b.size()) {\n        int l = max(a[i].first, b[j].first);\n        int r = min(a[i].second, b[j].second);\n        if (l < r) inter += r - l;\n        if (a[i].second < b[j].second) i++;\n        else j++;\n    }\n    return la + lb - 2 * inter;\n}\n\nlong long diff_bound(const Bound& a, const Bound& b) {\n    long long res = 0;\n    for (int i = 1; i < W; i++) {\n        res += symdiff_line(a.H[i], b.H[i]);\n        res += symdiff_line(a.V[i], b.V[i]);\n    }\n    return res;\n}\n\nlong long transition_cost(const vector<Rect>& x, const vector<Rect>& y) {\n    Bound bx, by;\n    build_bound(x, bx);\n    build_bound(y, by);\n    return diff_bound(bx, by);\n}\n\nlong long shortage_day(const vector<Rect>& rs, int d) {\n    long long res = 0;\n    for (int k = 0; k < N; k++) {\n        long long area = 1LL * (rs[k].y1 - rs[k].y0) * (rs[k].x1 - rs[k].x0);\n        if (area < A[d][k]) res += 100LL * (A[d][k] - area);\n    }\n    return res;\n}\n\nlong long evaluate_solution(const vector<vector<Rect>>& sol, long long limit = LLONG_MAX) {\n    long long total = 0;\n    Bound prev, cur;\n    for (int d = 0; d < D; d++) {\n        total += shortage_day(sol[d], d);\n        if (total > limit) return total;\n        build_bound(sol[d], cur);\n        if (d > 0) {\n            total += diff_bound(prev, cur);\n            if (total > limit) return total;\n        }\n        swap(prev, cur);\n    }\n    return total;\n}\n\n/* ---------- slicing tree ---------- */\n\nstruct Node {\n    int l = 0, r = 0;\n    int left = -1, right = -1;\n    int orient = VERT;\n    double ratio = 0.5;\n    int target = 1;\n    int targetCoord = -1;\n\n    bool leaf() const { return left == -1; }\n};\n\nstruct Tree {\n    vector<Node> nodes;\n    int root = 0;\n    vector<int> order;\n};\n\nvoid build_order(Tree& t) {\n    t.order.clear();\n    function<void(int)> dfs = [&](int v) {\n        if (!t.nodes[v].leaf()) {\n            dfs(t.nodes[v].left);\n            dfs(t.nodes[v].right);\n        }\n        t.order.push_back(v);\n    };\n    dfs(t.root);\n}\n\nint choose_split(int l, int r, int mode, const vector<double>& pref) {\n    if (r - l <= 1) return l + 1;\n    if (mode == 1) return (l + r) / 2;\n\n    double total = pref[r] - pref[l];\n    int best = l + 1;\n    double bestScore = 1e100;\n\n    for (int m = l + 1; m <= r - 1; m++) {\n        double af = (pref[m] - pref[l]) / total;\n        double cf = double(m - l) / double(r - l);\n        double score;\n        if (mode == 0) {\n            score = fabs(af - 0.5);\n        } else {\n            score = fabs(af - 0.5) + 0.35 * fabs(cf - 0.5);\n        }\n        if (score < bestScore) {\n            bestScore = score;\n            best = m;\n        }\n    }\n    return best;\n}\n\nTree build_aspect_tree(const vector<int>& base, int splitMode, int orientMode) {\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    Tree t;\n    function<int(int,int,int,int,int)> rec = [&](int l, int r, int h, int w, int depth) -> int {\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].l = l;\n        t.nodes[idx].r = r;\n\n        if (r - l == 1) return idx;\n\n        int orient;\n        if (orientMode == 0) orient = (w >= h ? VERT : HOR);\n        else if (orientMode == 1) orient = (depth % 2 == 0 ? VERT : HOR);\n        else orient = (depth % 2 == 0 ? HOR : VERT);\n\n        int m = choose_split(l, r, splitMode, pref);\n        double sL = pref[m] - pref[l];\n        double sT = pref[r] - pref[l];\n        double ratio = sL / sT;\n\n        t.nodes[idx].orient = orient;\n        t.nodes[idx].ratio = ratio;\n\n        int hL = h, hR = h, wL = w, wR = w;\n        if (orient == VERT) {\n            int c = (w >= 2 ? clamp_int((int)llround(w * ratio), 1, w - 1) : 1);\n            wL = max(1, c);\n            wR = max(1, w - c);\n        } else {\n            int c = (h >= 2 ? clamp_int((int)llround(h * ratio), 1, h - 1) : 1);\n            hL = max(1, c);\n            hR = max(1, h - c);\n        }\n\n        int li = rec(l, m, hL, wL, depth + 1);\n        int ri = rec(m, r, hR, wR, depth + 1);\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        return idx;\n    };\n\n    t.root = rec(0, N, W, W, 0);\n    build_order(t);\n    return t;\n}\n\nint build_fixed_rec(Tree& t, int l, int r, int orient, int splitMode, const vector<double>& pref) {\n    int idx = (int)t.nodes.size();\n    t.nodes.push_back(Node());\n    t.nodes[idx].l = l;\n    t.nodes[idx].r = r;\n    t.nodes[idx].orient = orient;\n\n    if (r - l == 1) return idx;\n\n    int m = choose_split(l, r, splitMode, pref);\n    double sL = pref[m] - pref[l];\n    double sT = pref[r] - pref[l];\n    t.nodes[idx].ratio = sL / sT;\n\n    int li = build_fixed_rec(t, l, m, orient, splitMode, pref);\n    int ri = build_fixed_rec(t, m, r, orient, splitMode, pref);\n    t.nodes[idx].left = li;\n    t.nodes[idx].right = ri;\n    return idx;\n}\n\nTree build_shelf_tree(const vector<int>& base, int R, int groupMode, int itemSplitMode) {\n    R = clamp_int(R, 1, N);\n\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> groups;\n    int prev = 0;\n    for (int g = 0; g < R; g++) {\n        int en;\n        if (g == R - 1) {\n            en = N;\n        } else {\n            int minEnd = prev + 1;\n            int maxEnd = N - (R - g - 1);\n            if (groupMode == 0) {\n                double target = pref[N] * double(g + 1) / double(R);\n                en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            } else {\n                en = (int)llround(double(N) * double(g + 1) / double(R));\n            }\n            en = clamp_int(en, minEnd, maxEnd);\n        }\n        groups.push_back({prev, en});\n        prev = en;\n    }\n\n    Tree t;\n    vector<int> rowRoot;\n    vector<double> rowPref(R + 1, 0);\n\n    for (int i = 0; i < R; i++) {\n        auto [l, r] = groups[i];\n        rowRoot.push_back(build_fixed_rec(t, l, r, VERT, itemSplitMode, pref));\n        rowPref[i+1] = rowPref[i] + (pref[r] - pref[l]);\n    }\n\n    function<int(int,int)> combine = [&](int lo, int hi) -> int {\n        if (hi - lo == 1) return rowRoot[lo];\n\n        int mid = lo + 1;\n        double total = rowPref[hi] - rowPref[lo];\n        double best = 1e100;\n        for (int m = lo + 1; m <= hi - 1; m++) {\n            double d = fabs((rowPref[m] - rowPref[lo]) - total * 0.5);\n            if (d < best) {\n                best = d;\n                mid = m;\n            }\n        }\n\n        int li = combine(lo, mid);\n        int ri = combine(mid, hi);\n\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        t.nodes[idx].l = t.nodes[li].l;\n        t.nodes[idx].r = t.nodes[ri].r;\n        t.nodes[idx].orient = HOR;\n        t.nodes[idx].ratio = (rowPref[mid] - rowPref[lo]) / (rowPref[hi] - rowPref[lo]);\n        return idx;\n    };\n\n    t.root = combine(0, R);\n    build_order(t);\n    return t;\n}\n\n/* ---------- DP for slicing tree ---------- */\n\nstruct DPComputer {\n    const Tree* tr;\n    bool freeOrient;\n    vector<array<unsigned short, W + 1>> dp;\n    vector<array<unsigned short, W + 1>> mh;\n\n    DPComputer(const Tree& t, bool f) : tr(&t), freeOrient(f) {\n        dp.resize(t.nodes.size());\n        mh.resize(t.nodes.size());\n    }\n\n    void compute_mh_from_dp(int idx) {\n        auto& P = dp[idx];\n        auto& M = mh[idx];\n        for (int i = 0; i <= W; i++) M[i] = INF;\n\n        int prev = W + 1;\n        for (int h = 1; h <= W; h++) {\n            int v = P[h];\n            if (v <= W && v < prev) {\n                for (int w = v; w < prev; w++) M[w] = h;\n                prev = v;\n            }\n        }\n    }\n\n    void horizontal_merge(int L, int R, array<unsigned short, W + 1>& out) {\n        for (int i = 0; i <= W; i++) out[i] = INF;\n        int prev = W + 1;\n        for (int w = 1; w <= W; w++) {\n            int hL = mh[L][w], hR = mh[R][w];\n            int req = (hL >= INF || hR >= INF ? INF : hL + hR);\n            if (req <= W && req < prev) {\n                for (int h = req; h < prev; h++) out[h] = w;\n                prev = req;\n            }\n        }\n    }\n\n    void compute(const vector<int>& demand) {\n        for (int idx : tr->order) {\n            const Node& nd = tr->nodes[idx];\n            auto& P = dp[idx];\n            auto& M = mh[idx];\n\n            if (nd.leaf()) {\n                long long a = demand[nd.l];\n                P[0] = M[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    long long v = (a + h - 1) / h;\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                for (int w = 1; w <= W; w++) {\n                    long long v = (a + w - 1) / w;\n                    M[w] = (v <= W ? (unsigned short)v : INF);\n                }\n                continue;\n            }\n\n            int L = nd.left, R = nd.right;\n\n            if (!freeOrient && nd.orient == VERT) {\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                compute_mh_from_dp(idx);\n            } else if (!freeOrient && nd.orient == HOR) {\n                horizontal_merge(L, R, P);\n                compute_mh_from_dp(idx);\n            } else {\n                array<unsigned short, W + 1> HP;\n                horizontal_merge(L, R, HP);\n\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    if (v > W) v = INF;\n                    P[h] = (unsigned short)min(v, (int)HP[h]);\n                }\n                compute_mh_from_dp(idx);\n            }\n        }\n    }\n};\n\n/* ---------- target assignment and reconstruction ---------- */\n\nbool assign_targets_dp_rec(Tree& t, int idx, int y, int x, int h, int w, const DPComputer& comp) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return true;\n\n    int L = nd.left, R = nd.right;\n\n    if (nd.orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(w * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        nd.target = c;\n        nd.targetCoord = x + c;\n        return assign_targets_dp_rec(t, L, y, x, h, c, comp) &&\n               assign_targets_dp_rec(t, R, y, x + c, h, w - c, comp);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(h * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        nd.target = c;\n        nd.targetCoord = y + c;\n        return assign_targets_dp_rec(t, L, y, x, c, w, comp) &&\n               assign_targets_dp_rec(t, R, y + c, x, h - c, w, comp);\n    }\n}\n\nvoid assign_targets_ratio_rec(Tree& t, int idx, int y, int x, int h, int w) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return;\n\n    if (nd.orient == VERT) {\n        int c = (w >= 2 ? clamp_int((int)llround(w * nd.ratio), 1, w - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = x + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, h, max(1, c));\n        assign_targets_ratio_rec(t, nd.right, y, x + c, h, max(1, w - c));\n    } else {\n        int c = (h >= 2 ? clamp_int((int)llround(h * nd.ratio), 1, h - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = y + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, max(1, c), w);\n        assign_targets_ratio_rec(t, nd.right, y + c, x, max(1, h - c), w);\n    }\n}\n\nvoid assign_targets(Tree& t, const vector<int>& demand) {\n    for (auto& nd : t.nodes) {\n        nd.target = 1;\n        nd.targetCoord = -1;\n    }\n\n    DPComputer comp(t, false);\n    comp.compute(demand);\n\n    bool ok = (comp.dp[t.root][W] <= W);\n    if (ok) ok = assign_targets_dp_rec(t, t.root, 0, 0, W, W, comp);\n\n    if (!ok) assign_targets_ratio_rec(t, t.root, 0, 0, W, W);\n}\n\nbool feasible_vert(const DPComputer& comp, int L, int R, int h, int w) {\n    if (w < 2) return false;\n    int a = comp.dp[L][h], b = comp.dp[R][h];\n    return a < INF && b < INF && a + b <= w;\n}\n\nbool feasible_hor(const DPComputer& comp, int L, int R, int h, int w) {\n    if (h < 2) return false;\n    int a = comp.mh[L][w], b = comp.mh[R][w];\n    return a < INF && b < INF && a + b <= h;\n}\n\nint target_size_for(\n    const Tree& t,\n    int idx,\n    int orient,\n    int dim,\n    int originCoord,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (policy == POLICY_PREV && prevOrient[idx] == orient && prevCoord[idx] >= 0) {\n        return prevCoord[idx] - originCoord;\n    }\n\n    if (policy == POLICY_STATIC_RATIO || orient != nd.orient || nd.targetCoord < 0) {\n        return (int)llround(dim * nd.ratio);\n    }\n\n    return nd.targetCoord - originCoord;\n}\n\nbool reconstruct_rec(\n    const Tree& t,\n    int idx,\n    int y,\n    int x,\n    int h,\n    int w,\n    const DPComputer& comp,\n    vector<Rect>& rects,\n    bool freeOrient,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord,\n    vector<int>& curOrient,\n    vector<int>& curCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (nd.leaf()) {\n        if (h <= 0 || w <= 0) return false;\n        rects[nd.l] = {y, x, y + h, x + w};\n        return true;\n    }\n\n    int L = nd.left, R = nd.right;\n    bool canV = feasible_vert(comp, L, R, h, w);\n    bool canH = feasible_hor(comp, L, R, h, w);\n\n    int orient = nd.orient;\n    if (freeOrient) {\n        int po = (policy == POLICY_PREV ? prevOrient[idx] : -1);\n        if (po == VERT && canV) orient = VERT;\n        else if (po == HOR && canH) orient = HOR;\n        else if (nd.orient == VERT && canV) orient = VERT;\n        else if (nd.orient == HOR && canH) orient = HOR;\n        else if (canV) orient = VERT;\n        else if (canH) orient = HOR;\n        else return false;\n    } else {\n        if (orient == VERT && !canV) return false;\n        if (orient == HOR && !canH) return false;\n    }\n\n    if (orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, VERT, w, x, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        curOrient[idx] = VERT;\n        curCoord[idx] = x + c;\n\n        return reconstruct_rec(t, L, y, x, h, c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y, x + c, h, w - c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, HOR, h, y, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        curOrient[idx] = HOR;\n        curCoord[idx] = y + c;\n\n        return reconstruct_rec(t, L, y, x, c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y + c, x, h - c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    }\n}\n\nbool make_solution(const Tree& t, bool freeOrient, int policy, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n\n    DPComputer comp(t, freeOrient);\n    int M = (int)t.nodes.size();\n\n    vector<int> prevOrient(M, -1), prevCoord(M, -1);\n    for (int i = 0; i < M; i++) {\n        if (!t.nodes[i].leaf()) {\n            prevOrient[i] = t.nodes[i].orient;\n            prevCoord[i] = t.nodes[i].targetCoord;\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        comp.compute(A[d]);\n        if (comp.dp[t.root][W] > W) return false;\n\n        vector<int> curOrient(M, -1), curCoord(M, -1);\n        bool ok = reconstruct_rec(\n            t, t.root, 0, 0, W, W, comp, sol[d],\n            freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord\n        );\n        if (!ok) return false;\n\n        if (policy == POLICY_PREV) {\n            prevOrient.swap(curOrient);\n            prevCoord.swap(curCoord);\n        }\n    }\n    return true;\n}\n\nbool make_static_solution(const Tree& t, const vector<int>& demand, bool freeOrient, vector<vector<Rect>>& sol) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][W] > W) return false;\n\n    vector<Rect> one(N);\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    bool ok = reconstruct_rec(\n        t, t.root, 0, 0, W, W, comp, one,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n    if (!ok) return false;\n\n    sol.assign(D, one);\n    return true;\n}\n\n/* ---------- candidates and postprocessing ---------- */\n\nvector<int> scale_to_limit(const vector<int>& v) {\n    long long s = 0;\n    for (int x : v) s += x;\n    if (s <= AREA) return v;\n\n    vector<int> r(N);\n    double f = double(AREA) / double(s);\n    long long sr = 0;\n    for (int i = 0; i < N; i++) {\n        r[i] = max(1, (int)floor(v[i] * f));\n        sr += r[i];\n    }\n\n    while (sr > AREA) {\n        int id = -1;\n        for (int i = 0; i < N; i++) {\n            if (r[i] > 1 && (id == -1 || r[i] > r[id])) id = i;\n        }\n        if (id == -1) break;\n        r[id]--;\n        sr--;\n    }\n    return r;\n}\n\nvector<vector<Rect>> make_fallback() {\n    vector<vector<Rect>> sol(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; d++) {\n        vector<int> h(N, 1);\n        int rem = W - N;\n\n        auto gain = [&](int k) -> int {\n            long long covered = 1LL * h[k] * W;\n            if (covered >= A[d][k]) return 0;\n            return (int)min<long long>(W, A[d][k] - covered);\n        };\n\n        priority_queue<pair<int,int>> pq;\n        for (int k = 0; k < N; k++) pq.push({gain(k), k});\n\n        while (rem > 0 && !pq.empty()) {\n            auto [g, k] = pq.top();\n            pq.pop();\n            int cg = gain(k);\n            if (cg != g) {\n                pq.push({cg, k});\n                continue;\n            }\n            if (cg <= 0) break;\n            h[k]++;\n            rem--;\n            pq.push({gain(k), k});\n        }\n\n        h[N-1] += rem;\n\n        int y = 0;\n        for (int k = 0; k < N; k++) {\n            sol[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    return sol;\n}\n\nvector<vector<Rect>> bestSol;\nlong long bestScore = LLONG_MAX;\n\nvoid consider_solution(const vector<vector<Rect>>& sol) {\n    long long sc = evaluate_solution(sol, bestScore);\n    if (sc < bestScore) {\n        bestScore = sc;\n        bestSol = sol;\n    }\n}\n\n/* ---------- new fixed-shelf improvement ---------- */\n\nstatic const int SEG_INF = 1'000'000'000;\nstatic const int MAX_SEG_OPT = 4;\n\nint hMinSeg[55][55], hStaticSeg[55][55];\nint segOptCnt[55][55];\nint segOptH[55][55][MAX_SEG_OPT];\nlong long segOptCost[55][55][MAX_SEG_OPT];\nint segOptTarget[55][55][MAX_SEG_OPT];\nbool segOptSoft[55][55][MAX_SEG_OPT];\n\nint ceil_div_int(int a, int b) {\n    return (a + b - 1) / b;\n}\n\nbool check_segment_h(int l, int r, int h) {\n    for (int d = 0; d < D; d++) {\n        int s = 0;\n        for (int k = l; k < r; k++) {\n            s += ceil_div_int(A[d][k], h);\n            if (s > W) return false;\n        }\n    }\n    return true;\n}\n\nint compute_hmin_segment(int l, int r) {\n    if (!check_segment_h(l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_segment_h(l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nbool check_static_h(int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(globalMaxDemand[k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_hstatic_segment(int l, int r) {\n    if (!check_static_h(l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_static_h(l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nint base_value_for_target(int type, int k) {\n    if (type == 0) return globalMaxDemand[k];\n    if (type == 1) return p90Demand[k];\n    if (type == 2) return p75Demand[k];\n    if (type == 3) return meanDemand[k];\n    return medDemand[k];\n}\n\nvector<int> normalize_widths(vector<int> w) {\n    int m = (int)w.size();\n    int s = accumulate(w.begin(), w.end(), 0);\n    while (s < W) {\n        w[m - 1]++;\n        s++;\n    }\n    while (s > W) {\n        bool done = false;\n        for (int i = m - 1; i >= 0 && s > W; i--) {\n            if (w[i] > 1) {\n                w[i]--;\n                s--;\n                done = true;\n            }\n        }\n        if (!done) break;\n    }\n    return w;\n}\n\nvector<int> allocate_by_weights(const vector<int>& lower, const vector<double>& weights) {\n    int m = (int)lower.size();\n    int sumL = accumulate(lower.begin(), lower.end(), 0);\n    if (sumL > W) {\n        vector<int> w(m, 1);\n        int rem = W - m;\n        for (int i = 0; i < m && rem > 0; i++, rem--) w[i]++;\n        if (rem > 0) w[m-1] += rem;\n        return w;\n    }\n\n    vector<int> w = lower;\n    int rem = W - sumL;\n    if (rem == 0) return w;\n\n    double sw = 0;\n    for (double x : weights) sw += max(1e-9, x);\n    if (sw <= 0) sw = m;\n\n    vector<pair<double,int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; i++) {\n        double ideal = rem * max(1e-9, weights[i]) / sw;\n        int add = (int)floor(ideal);\n        w[i] += add;\n        used += add;\n        frac.push_back({ideal - add, i});\n    }\n    int left = rem - used;\n    sort(frac.rbegin(), frac.rend());\n    for (int i = 0; i < left; i++) w[frac[i % m].second]++;\n    return normalize_widths(w);\n}\n\nvector<int> make_target_widths(int l, int r, int h, int targetType) {\n    int m = r - l;\n    vector<int> lower(m, 1);\n    long long sumL = 0;\n    for (int i = 0; i < m; i++) {\n        int b = base_value_for_target(targetType, l + i);\n        lower[i] = max(1, ceil_div_int(b, h));\n        sumL += lower[i];\n    }\n    if (sumL > W) {\n        fill(lower.begin(), lower.end(), 1);\n    }\n\n    vector<double> weights(m);\n    for (int i = 0; i < m; i++) {\n        weights[i] = max(1, base_value_for_target(targetType, l + i));\n    }\n    return allocate_by_weights(lower, weights);\n}\n\nvector<int> project_near(vector<int> ref, const vector<int>& lb) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    vector<int> w = ref;\n    for (int i = 0; i < m; i++) {\n        if (w[i] >= lb[i]) continue;\n        int need = lb[i] - w[i];\n        w[i] = lb[i];\n\n        while (need > 0) {\n            int best = -1;\n            for (int j = 0; j < m; j++) {\n                if (w[j] <= lb[j]) continue;\n                if (best == -1 ||\n                    abs(j - i) < abs(best - i) ||\n                    (abs(j - i) == abs(best - i) && w[j] - lb[j] > w[best] - lb[best])) {\n                    best = j;\n                }\n            }\n            if (best == -1) break;\n            int x = min(need, w[best] - lb[best]);\n            w[best] -= x;\n            need -= x;\n        }\n    }\n    return normalize_widths(w);\n}\n\nvoid make_day_lb(int l, int r, int h, int d, const vector<int>& ref, bool soft, vector<int>& lb) {\n    int m = r - l;\n    lb.assign(m, 1);\n    for (int i = 0; i < m; i++) {\n        int a = A[d][l + i];\n        int q = ceil_div_int(a, h);\n        if (soft && (int)ref.size() == m && ref[i] < q && q > 1) {\n            int rem = a - h * (q - 1);\n            if (100LL * rem < 2LL * h) q--;\n        }\n        lb[i] = max(1, q);\n    }\n}\n\nvector<int> shortage_widths(const vector<int>& refIn, int l, int r, int h, int d) {\n    int m = r - l;\n    vector<int> ref = normalize_widths(refIn);\n    vector<int> w(m);\n    long long sum = 0;\n    for (int i = 0; i < m; i++) {\n        w[i] = max(1, ceil_div_int(A[d][l + i], h));\n        sum += w[i];\n    }\n    if (sum <= W) return project_near(ref, w);\n\n    auto loss_remove = [&](int i) -> int {\n        if (w[i] <= 1) return INT_MAX / 4;\n        long long a = A[d][l + i];\n        long long before = min<long long>(a, 1LL * h * w[i]);\n        long long after = min<long long>(a, 1LL * h * (w[i] - 1));\n        return (int)(before - after);\n    };\n\n    using Tup = tuple<int,int,int,int>;\n    priority_queue<Tup, vector<Tup>, greater<Tup>> pq;\n    for (int i = 0; i < m; i++) {\n        if (w[i] > 1) {\n            int loss = loss_remove(i);\n            int pen = abs((w[i] - 1) - ref[i]) - abs(w[i] - ref[i]);\n            pq.push({loss, pen, i, w[i]});\n        }\n    }\n\n    while (sum > W && !pq.empty()) {\n        auto [loss, pen, i, oldw] = pq.top();\n        pq.pop();\n        if (oldw != w[i]) continue;\n        if (w[i] <= 1) continue;\n\n        w[i]--;\n        sum--;\n\n        if (w[i] > 1) {\n            int nl = loss_remove(i);\n            int np = abs((w[i] - 1) - ref[i]) - abs(w[i] - ref[i]);\n            pq.push({nl, np, i, w[i]});\n        }\n    }\n\n    return normalize_widths(w);\n}\n\nint symdiff_cut_count(const vector<int>& a, const vector<int>& b) {\n    int m = (int)a.size();\n    vector<int> ca, cb;\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += a[i];\n        ca.push_back(s);\n    }\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += b[i];\n        cb.push_back(s);\n    }\n    int i = 0, j = 0, common = 0;\n    while (i < (int)ca.size() && j < (int)cb.size()) {\n        if (ca[i] == cb[j]) {\n            common++;\n            i++;\n            j++;\n        } else if (ca[i] < cb[j]) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n    return (int)ca.size() + (int)cb.size() - 2 * common;\n}\n\nlong long row_shortage_cost(int l, int r, int h, int d, const vector<int>& w) {\n    long long res = 0;\n    for (int i = 0; i < r - l; i++) {\n        long long area = 1LL * h * w[i];\n        if (area < A[d][l + i]) res += 100LL * (A[d][l + i] - area);\n    }\n    return res;\n}\n\nlong long simulate_row_fast(int l, int r, int h, int targetType, bool soft) {\n    vector<int> target = make_target_widths(l, r, h, targetType);\n    vector<int> prev;\n    long long cost = 0;\n\n    for (int d = 0; d < D; d++) {\n        vector<int> ref = (d == 0 ? target : prev);\n        vector<int> lb;\n        make_day_lb(l, r, h, d, ref, soft, lb);\n        int sumLB = accumulate(lb.begin(), lb.end(), 0);\n\n        vector<int> w;\n        if (sumLB <= W) w = project_near(ref, lb);\n        else w = shortage_widths(ref, l, r, h, d);\n\n        cost += row_shortage_cost(l, r, h, d, w);\n        if (d > 0) cost += 1LL * h * symdiff_cut_count(prev, w);\n        prev = w;\n    }\n    return cost;\n}\n\nvoid best_row_option(int l, int r, int h, long long& best, int& bestT, bool& bestS) {\n    if (hStaticSeg[l][r] < SEG_INF && h >= hStaticSeg[l][r]) {\n        best = 0;\n        bestT = 0;\n        bestS = false;\n        return;\n    }\n\n    best = (1LL << 62);\n    bestT = 0;\n    bestS = false;\n\n    for (int t = 0; t < 4; t++) {\n        for (int s = 0; s <= 1; s++) {\n            long long c = simulate_row_fast(l, r, h, t, s);\n            if (c < best) {\n                best = c;\n                bestT = t;\n                bestS = (bool)s;\n            }\n        }\n    }\n}\n\nvector<int> choose_widths_overlap(vector<int> ref, const vector<int>& lb, vector<int> target) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n    target = normalize_widths(target);\n\n    if (m == 1) return vector<int>{W};\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    vector<int> oldSet(W + 1, 0);\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += ref[i];\n        if (0 <= s && s <= W) oldSet[s] = 1;\n    }\n\n    vector<int> targetCut(m - 1);\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += target[i];\n        targetCut[i] = s;\n    }\n\n    const int NEG = -1'000'000'000;\n    const int MATCH = 1'000'000;\n\n    vector<int> prev(W + 1, NEG), cur(W + 1, NEG);\n    vector<int> prefVal(W + 1), prefPos(W + 1);\n    vector<vector<short>> par(m, vector<short>(W + 1, -1));\n\n    prev[0] = 0;\n\n    vector<int> prefLB(m + 1, 0), suffLB(m + 1, 0);\n    for (int i = 0; i < m; i++) prefLB[i+1] = prefLB[i] + lb[i];\n    for (int i = m - 1; i >= 0; i--) suffLB[i] = suffLB[i+1] + lb[i];\n\n    for (int i = 1; i <= m - 1; i++) {\n        prefVal[0] = prev[0];\n        prefPos[0] = 0;\n        for (int x = 1; x <= W; x++) {\n            if (prev[x] > prefVal[x-1]) {\n                prefVal[x] = prev[x];\n                prefPos[x] = x;\n            } else {\n                prefVal[x] = prefVal[x-1];\n                prefPos[x] = prefPos[x-1];\n            }\n        }\n\n        fill(cur.begin(), cur.end(), NEG);\n\n        int minX = prefLB[i];\n        int maxX = W - suffLB[i];\n        for (int x = minX; x <= maxX; x++) {\n            int lim = x - lb[i-1];\n            if (lim < 0) continue;\n            int val = prefVal[lim];\n            if (val <= NEG / 2) continue;\n            int p = prefPos[lim];\n\n            int bonus = (oldSet[x] ? MATCH : 0) - abs(x - targetCut[i-1]);\n            int nv = val + bonus;\n            if (nv > cur[x]) {\n                cur[x] = nv;\n                par[i][x] = (short)p;\n            }\n        }\n        prev.swap(cur);\n    }\n\n    int bestP = -1, bestVal = NEG;\n    int maxP = W - lb[m-1];\n    for (int p = 0; p <= maxP; p++) {\n        if (prev[p] > bestVal) {\n            bestVal = prev[p];\n            bestP = p;\n        }\n    }\n\n    if (bestP < 0) return project_near(ref, lb);\n\n    vector<int> cuts(m + 1);\n    cuts[0] = 0;\n    cuts[m] = W;\n    cuts[m-1] = bestP;\n\n    for (int i = m - 1; i >= 1; i--) {\n        int p = par[i][cuts[i]];\n        if (p < 0) return project_near(ref, lb);\n        cuts[i-1] = p;\n    }\n\n    vector<int> w(m);\n    for (int i = 0; i < m; i++) {\n        w[i] = cuts[i+1] - cuts[i];\n        if (w[i] < lb[i] || w[i] <= 0) return project_near(ref, lb);\n    }\n    return normalize_widths(w);\n}\n\nstruct ShelfRowChoice {\n    int l, r, h;\n    int targetType;\n    bool soft;\n};\n\nbool build_fixed_shelf_solution(const vector<ShelfRowChoice>& rows, vector<vector<Rect>>& sol, bool overlap) {\n    sol.assign(D, vector<Rect>(N));\n    int y = 0;\n\n    for (const auto& row : rows) {\n        if (y + row.h > W) return false;\n\n        vector<int> target = make_target_widths(row.l, row.r, row.h, row.targetType);\n        vector<int> prev;\n\n        for (int d = 0; d < D; d++) {\n            vector<int> ref = (d == 0 ? target : prev);\n            vector<int> lb;\n            make_day_lb(row.l, row.r, row.h, d, ref, row.soft, lb);\n\n            int sumLB = accumulate(lb.begin(), lb.end(), 0);\n            vector<int> w;\n            if (sumLB <= W) {\n                if (overlap) w = choose_widths_overlap(ref, lb, target);\n                else w = project_near(ref, lb);\n            } else {\n                w = shortage_widths(ref, row.l, row.r, row.h, d);\n            }\n\n            int x = 0;\n            for (int i = 0; i < row.r - row.l; i++) {\n                int k = row.l + i;\n                if (w[i] <= 0) return false;\n                sol[d][k] = {y, x, y + row.h, x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            prev = w;\n        }\n        y += row.h;\n    }\n\n    return y <= W;\n}\n\nvoid consider_static_horizontal_knapsack() {\n    const long long BIG = (1LL << 62);\n\n    vector<vector<long long>> cost(N, vector<long long>(W + 1, 0));\n    for (int k = 0; k < N; k++) {\n        for (int h = 1; h <= W; h++) {\n            long long c = 0;\n            for (int d = 0; d < D; d++) {\n                long long area = 1LL * h * W;\n                if (area < A[d][k]) c += 100LL * (A[d][k] - area);\n            }\n            cost[k][h] = c;\n        }\n    }\n\n    vector<long long> dp(W + 1, BIG), ndp(W + 1, BIG);\n    vector<vector<short>> par(N + 1, vector<short>(W + 1, -1));\n    dp[0] = 0;\n\n    for (int k = 0; k < N; k++) {\n        fill(ndp.begin(), ndp.end(), BIG);\n        int remainItems = N - k - 1;\n        for (int used = 0; used <= W; used++) {\n            if (dp[used] >= BIG / 2) continue;\n            int maxh = W - used - remainItems;\n            for (int h = 1; h <= maxh; h++) {\n                long long nv = dp[used] + cost[k][h];\n                int nu = used + h;\n                if (nv < ndp[nu]) {\n                    ndp[nu] = nv;\n                    par[k+1][nu] = (short)h;\n                }\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    long long best = BIG;\n    int bestUsed = -1;\n    for (int used = 0; used <= W; used++) {\n        if (dp[used] < best) {\n            best = dp[used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0) return;\n\n    vector<int> h(N);\n    int used = bestUsed;\n    for (int k = N; k >= 1; k--) {\n        int x = par[k][used];\n        if (x <= 0) return;\n        h[k-1] = x;\n        used -= x;\n    }\n\n    vector<Rect> one(N);\n    int y = 0;\n    for (int k = 0; k < N; k++) {\n        one[k] = {y, 0, y + h[k], W};\n        y += h[k];\n    }\n\n    vector<vector<Rect>> sol(D, one);\n    consider_solution(sol);\n}\n\nvoid run_fixed_shelf_dp() {\n    for (int l = 0; l <= N; l++) {\n        for (int r = 0; r <= N; r++) {\n            hMinSeg[l][r] = hStaticSeg[l][r] = SEG_INF;\n            segOptCnt[l][r] = 0;\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            hMinSeg[l][r] = compute_hmin_segment(l, r);\n            hStaticSeg[l][r] = compute_hstatic_segment(l, r);\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            int hm = hMinSeg[l][r];\n            if (hm >= SEG_INF) continue;\n\n            vector<int> hs;\n            auto addH = [&](int h) {\n                if (h < 1 || h > W) return;\n                if (find(hs.begin(), hs.end(), h) == hs.end()) hs.push_back(h);\n            };\n\n            addH(hm);\n\n            int hsStatic = hStaticSeg[l][r];\n            if (hsStatic < SEG_INF) {\n                addH(hsStatic);\n                if (hsStatic - hm >= 2) addH((hm + hsStatic) / 2);\n            } else {\n                if (hm < W) addH((hm + W) / 2);\n            }\n\n            sort(hs.begin(), hs.end());\n            if ((int)hs.size() > MAX_SEG_OPT) hs.resize(MAX_SEG_OPT);\n\n            for (int h : hs) {\n                int idx = segOptCnt[l][r]++;\n                segOptH[l][r][idx] = h;\n\n                long long c;\n                int t;\n                bool s;\n                best_row_option(l, r, h, c, t, s);\n\n                segOptCost[l][r][idx] = c;\n                segOptTarget[l][r][idx] = t;\n                segOptSoft[l][r][idx] = s;\n            }\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, BIG));\n    vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> parUsed(N + 1, vector<short>(W + 1, -1));\n    vector<vector<signed char>> parOpt(N + 1, vector<signed char>(W + 1, -1));\n\n    dp[0][0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        for (int used = 0; used <= W; used++) {\n            if (dp[i][used] >= BIG / 2) continue;\n\n            for (int j = i + 1; j <= N; j++) {\n                for (int oi = 0; oi < segOptCnt[i][j]; oi++) {\n                    int h = segOptH[i][j][oi];\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    long long nv = dp[i][used] + segOptCost[i][j][oi];\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parUsed[j][nu] = (short)used;\n                        parOpt[j][nu] = (signed char)oi;\n                    }\n                }\n            }\n        }\n    }\n\n    long long best = BIG;\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 < 0) return;\n\n    vector<ShelfRowChoice> rows;\n    int curI = N, curH = bestH;\n    while (curI > 0) {\n        int pi = parI[curI][curH];\n        int pu = parUsed[curI][curH];\n        int oi = parOpt[curI][curH];\n        if (pi < 0 || pu < 0 || oi < 0) return;\n\n        rows.push_back({\n            pi,\n            curI,\n            segOptH[pi][curI][oi],\n            segOptTarget[pi][curI][oi],\n            segOptSoft[pi][curI][oi]\n        });\n\n        curI = pi;\n        curH = pu;\n    }\n    reverse(rows.begin(), rows.end());\n\n    vector<vector<Rect>> sol;\n    if (build_fixed_shelf_solution(rows, sol, false)) consider_solution(sol);\n    if (bestScore == 0) return;\n    if (build_fixed_shelf_solution(rows, sol, true)) consider_solution(sol);\n}\n\n/* ---------- old slicing candidate handling ---------- */\n\nconst double TL_CAND = 2.65;\nconst double TL_POST = 2.85;\n\nvoid process_tree(Tree t, const vector<int>& base, int level) {\n    if (elapsed_sec() > TL_CAND || bestScore == 0) return;\n\n    vector<int> target = scale_to_limit(base);\n    assign_targets(t, target);\n\n    vector<vector<Rect>> sol;\n\n    if (elapsed_sec() < TL_CAND && make_static_solution(t, target, false, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, globalMaxDemand, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_PREV, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 1 && elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_STATIC_ABS, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, target, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_solution(t, true, POLICY_PREV, sol)) {\n        consider_solution(sol);\n    }\n}\n\nvoid try_all_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto orig = bestSol;\n    for (int t = 0; t < D && elapsed_sec() < TL_POST; t++) {\n        vector<vector<Rect>> sol(D, orig[t]);\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n}\n\nvoid smooth_by_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto sol = bestSol;\n    long long curScore = evaluate_solution(sol);\n\n    auto local_cost = [&](int d, const vector<Rect>& cand) -> long long {\n        long long c = shortage_day(cand, d);\n        if (d > 0) c += transition_cost(sol[d-1], cand);\n        if (d + 1 < D) c += transition_cost(cand, sol[d+1]);\n        return c;\n    };\n\n    for (int pass = 0; pass < 5 && elapsed_sec() < TL_POST; pass++) {\n        bool improved = false;\n\n        for (int d = 0; d < D && elapsed_sec() < TL_POST; d++) {\n            long long old = local_cost(d, sol[d]);\n\n            if (d > 0) {\n                long long nw = local_cost(d, sol[d-1]);\n                if (nw < old) {\n                    sol[d] = sol[d-1];\n                    curScore += nw - old;\n                    old = nw;\n                    improved = true;\n                }\n            }\n\n            if (d + 1 < D) {\n                long long nw = local_cost(d, sol[d+1]);\n                if (nw < old) {\n                    sol[d] = sol[d+1];\n                    curScore += nw - old;\n                    old = nw;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    curScore = evaluate_solution(sol);\n    if (curScore < bestScore) {\n        bestScore = curScore;\n        bestSol = sol;\n    }\n}\n\n/* ---------- main ---------- */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int inputW;\n    cin >> inputW >> 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    globalMaxDemand.assign(N, 1);\n    meanDemand.assign(N, 1);\n    medDemand.assign(N, 1);\n    p75Demand.assign(N, 1);\n    p90Demand.assign(N, 1);\n\n    for (int k = 0; k < N; k++) {\n        long long s = 0;\n        vector<int> vals;\n        for (int d = 0; d < D; d++) {\n            s += A[d][k];\n            vals.push_back(A[d][k]);\n            globalMaxDemand[k] = max(globalMaxDemand[k], A[d][k]);\n        }\n        sort(vals.begin(), vals.end());\n        meanDemand[k] = max(1, (int)(s / D));\n        medDemand[k] = vals[D / 2];\n        p75Demand[k] = vals[min(D - 1, (int)llround(0.75 * (D - 1)))];\n        p90Demand[k] = vals[min(D - 1, (int)llround(0.90 * (D - 1)))];\n    }\n\n    bestSol = make_fallback();\n    bestScore = evaluate_solution(bestSol);\n\n    consider_static_horizontal_knapsack();\n\n    if (bestScore != 0) {\n        run_fixed_shelf_dp();\n    }\n\n    if (bestScore != 0) {\n        vector<vector<int>> bases;\n        bases.push_back(globalMaxDemand);\n        bases.push_back(p90Demand);\n        bases.push_back(p75Demand);\n        bases.push_back(meanDemand);\n        bases.push_back(medDemand);\n\n        vector<pair<int,int>> combos = {\n            {0, 0},\n            {2, 0},\n            {1, 0},\n            {0, 1},\n            {0, 2}\n        };\n\n        for (int bi = 0; bi < (int)bases.size(); bi++) {\n            for (int ci = 0; ci < (int)combos.size(); ci++) {\n                if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n\n                int splitMode = combos[ci].first;\n                int orientMode = combos[ci].second;\n                Tree t = build_aspect_tree(bases[bi], splitMode, orientMode);\n\n                int level = 1;\n                if (ci == 0 && bi <= 3) level = 2;\n                process_tree(t, bases[bi], level);\n            }\n            if (bestScore == 0) break;\n        }\n\n        vector<int> Rs;\n        auto addR = [&](int r) {\n            r = clamp_int(r, 1, N);\n            if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n        };\n\n        int sq = max(1, (int)llround(sqrt((double)N)));\n        addR(sq);\n        addR(sq + 1);\n        addR(sq - 1);\n        addR(N / 4);\n        addR(N / 3);\n        addR(N / 2);\n        addR(2 * sq);\n        addR(5);\n        addR(8);\n        addR(10);\n        addR(15);\n        addR(20);\n        addR(N);\n        addR(1);\n\n        vector<int> shelfBaseIds = {0, 1, 3, 2};\n        for (int bi : shelfBaseIds) {\n            for (int groupMode = 0; groupMode <= 1; groupMode++) {\n                for (int r : Rs) {\n                    if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n                    Tree t = build_shelf_tree(bases[bi], r, groupMode, 0);\n                    int level = (groupMode == 0 ? 1 : 0);\n                    process_tree(t, bases[bi], level);\n                }\n                if (bestScore == 0) break;\n            }\n            if (bestScore == 0) break;\n        }\n    }\n\n    try_all_copy();\n    smooth_by_copy();\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            const Rect& r = bestSol[d][k];\n            cout << r.y0 << ' ' << r.x0 << ' ' << r.y1 << ' ' << r.x1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int BN = 9;\nstatic const int AP = 7;\nstatic const int KMAX = 81;\nstatic const int MOD = 998244353;\nstatic const int MAX_MULTI = 5;\n\nint N, M, K;\narray<int, KMAX> initBoard;\nlong long initScore = 0;\nint stampVal[20][9];\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\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} timer;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n} rng(123456789);\n\nstruct Action {\n    int m, p, q;\n    int anchor;\n    int idx[9];\n    int val[9];\n};\n\nstruct Option {\n    unsigned char cnt;\n    unsigned char s1, s2;\n    int val[9];\n};\n\nstruct MultiOption {\n    unsigned char cnt;\n    unsigned char st[MAX_MULTI];\n    int val[9];\n};\n\nstruct PairInfo {\n    unsigned short a, b;\n    unsigned char len;\n    unsigned char idx[18];\n    int val[18];\n};\n\nvector<Action> actions;\narray<array<int, 9>, 49> anchorCells;\nvector<int> cellCovers[81];\nvector<Option> options;\nvector<MultiOption> multiOpts[MAX_MULTI + 1];\nbool anchorOverlap[49][49];\nvector<PairInfo> overlapPairs;\n\ninline long long evalAdd(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalSub(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applyAdd(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applySub(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalPairInfo(const array<int, KMAX>& b, const PairInfo& pi) {\n    long long delta = 0;\n    for (int t = 0; t < pi.len; t++) {\n        int idx = pi.idx[t];\n        int old = b[idx];\n        int nv = old + pi.val[t];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalMultiAtAnchor(const array<int, KMAX>& b, int anc, const MultiOption& op) {\n    long long delta = 0;\n    const auto& cells = anchorCells[anc];\n    for (int k = 0; k < 9; k++) {\n        int old = b[cells[k]];\n        int nv = old + op.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\nvoid genMultiRec(int target, int start, vector<int>& chosen, array<int, 9>& vals) {\n    if ((int)chosen.size() == target) {\n        MultiOption op{};\n        op.cnt = (unsigned char)target;\n        for (int i = 0; i < MAX_MULTI; i++) op.st[i] = 0;\n        for (int i = 0; i < target; i++) op.st[i] = (unsigned char)chosen[i];\n        for (int k = 0; k < 9; k++) op.val[k] = vals[k];\n        multiOpts[target].push_back(op);\n        return;\n    }\n\n    for (int m = start; m < M; m++) {\n        auto oldVals = vals;\n        chosen.push_back(m);\n        for (int k = 0; k < 9; k++) {\n            int v = vals[k] + stampVal[m][k];\n            if (v >= MOD) v -= MOD;\n            vals[k] = v;\n        }\n        genMultiRec(target, m, chosen, vals);\n        chosen.pop_back();\n        vals = oldVals;\n    }\n}\n\nvoid precomputeMultiOptions() {\n    for (int c = 0; c <= MAX_MULTI; c++) multiOpts[c].clear();\n\n    MultiOption zero{};\n    zero.cnt = 0;\n    for (int i = 0; i < MAX_MULTI; i++) zero.st[i] = 0;\n    for (int k = 0; k < 9; k++) zero.val[k] = 0;\n    multiOpts[0].push_back(zero);\n\n    for (int target = 1; target <= MAX_MULTI; target++) {\n        vector<int> chosen;\n        array<int, 9> vals{};\n        genMultiRec(target, 0, chosen, vals);\n    }\n}\n\nvoid precomputeOverlapPairs() {\n    overlapPairs.clear();\n    overlapPairs.reserve(170000);\n\n    int A = (int)actions.size();\n\n    for (int a = 0; a < A; a++) {\n        for (int b = a; b < A; b++) {\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) continue;\n\n            PairInfo pi{};\n            pi.a = (unsigned short)a;\n            pi.b = (unsigned short)b;\n            pi.len = 0;\n\n            auto addCell = [&](int idx, int val) {\n                for (int t = 0; t < pi.len; t++) {\n                    if (pi.idx[t] == idx) {\n                        int nv = pi.val[t] + val;\n                        if (nv >= MOD) nv -= MOD;\n                        pi.val[t] = nv;\n                        return;\n                    }\n                }\n                pi.idx[pi.len] = (unsigned char)idx;\n                pi.val[pi.len] = val;\n                pi.len++;\n            };\n\n            for (int k = 0; k < 9; k++) addCell(actions[a].idx[k], actions[a].val[k]);\n            for (int k = 0; k < 9; k++) addCell(actions[b].idx[k], actions[b].val[k]);\n\n            overlapPairs.push_back(pi);\n        }\n    }\n}\n\nvoid precompute() {\n    actions.reserve(49 * M);\n\n    for (int p = 0; p < AP; p++) {\n        for (int q = 0; q < AP; q++) {\n            int aid = p * AP + q;\n            int t = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    anchorCells[aid][t++] = (p + di) * BN + (q + dj);\n                }\n            }\n        }\n    }\n\n    for (int a = 0; a < 49; a++) {\n        int p1 = a / AP, q1 = a % AP;\n        for (int b = 0; b < 49; b++) {\n            int p2 = b / AP, q2 = b % AP;\n            anchorOverlap[a][b] = (abs(p1 - p2) <= 2 && abs(q1 - q2) <= 2);\n        }\n    }\n\n    for (int anc = 0; anc < 49; anc++) {\n        int p = anc / AP;\n        int q = anc % AP;\n        for (int m = 0; m < M; m++) {\n            Action a;\n            a.m = m;\n            a.p = p;\n            a.q = q;\n            a.anchor = anc;\n            for (int k = 0; k < 9; k++) {\n                a.idx[k] = anchorCells[anc][k];\n                a.val[k] = stampVal[m][k];\n            }\n            actions.push_back(a);\n        }\n    }\n\n    for (int r = 0; r < BN; r++) {\n        for (int c = 0; c < BN; c++) {\n            int cell = r * BN + c;\n            for (int p = max(0, r - 2); p <= min(AP - 1, r); p++) {\n                for (int q = max(0, c - 2); q <= min(AP - 1, c); q++) {\n                    cellCovers[cell].push_back(p * AP + q);\n                }\n            }\n        }\n    }\n\n    Option none{};\n    none.cnt = 0;\n    none.s1 = none.s2 = 0;\n    for (int k = 0; k < 9; k++) none.val[k] = 0;\n    options.push_back(none);\n\n    for (int m = 0; m < M; m++) {\n        Option op{};\n        op.cnt = 1;\n        op.s1 = m;\n        op.s2 = 0;\n        for (int k = 0; k < 9; k++) op.val[k] = stampVal[m][k];\n        options.push_back(op);\n    }\n\n    for (int a = 0; a < M; a++) {\n        for (int b = a; b < M; b++) {\n            Option op{};\n            op.cnt = 2;\n            op.s1 = a;\n            op.s2 = b;\n            for (int k = 0; k < 9; k++) {\n                int v = stampVal[a][k] + stampVal[b][k];\n                if (v >= MOD) v -= MOD;\n                op.val[k] = v;\n            }\n            options.push_back(op);\n        }\n    }\n\n    precomputeMultiOptions();\n    precomputeOverlapPairs();\n}\n\nstruct Solution {\n    array<int, KMAX> board;\n    array<int, KMAX> slot;\n    long long score;\n};\n\nvoid rebuild(Solution& sol) {\n    sol.board = initBoard;\n    sol.score = initScore;\n    for (int i = 0; i < K; i++) {\n        if (sol.slot[i] >= 0) {\n            sol.score += applyAdd(sol.board, sol.slot[i]);\n        }\n    }\n}\n\nSolution makeSolutionFromOps(const vector<int>& ops) {\n    Solution sol;\n    sol.slot.fill(-1);\n    int L = min((int)ops.size(), K);\n    for (int i = 0; i < L; i++) sol.slot[i] = ops[i];\n    rebuild(sol);\n    return sol;\n}\n\nSolution greedySolution() {\n    Solution sol;\n    sol.board = initBoard;\n    sol.slot.fill(-1);\n    sol.score = initScore;\n\n    for (int step = 0; step < K; step++) {\n        long long bestDelta = 0;\n        int best = -1;\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long d = evalAdd(sol.board, aid);\n            if (d > bestDelta) {\n                bestDelta = d;\n                best = aid;\n            }\n        }\n        if (best == -1) break;\n        sol.slot[step] = best;\n        sol.score += applyAdd(sol.board, best);\n    }\n\n    return sol;\n}\n\nvoid coordinateDescent(Solution& sol, int maxSweeps, double timeLimit) {\n    array<int, KMAX> ord;\n    for (int i = 0; i < K; i++) ord[i] = i;\n\n    for (int sweep = 0; sweep < maxSweeps; sweep++) {\n        if (timer.elapsed() > timeLimit) break;\n\n        for (int i = K - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int oi = 0; oi < K; oi++) {\n            int pos = ord[oi];\n            int old = sol.slot[pos];\n            long long oldScore = sol.score;\n\n            if (old >= 0) {\n                sol.score += applySub(sol.board, old);\n            }\n            long long base = sol.score;\n\n            int best = old;\n            long long bestScore = oldScore;\n\n            if (base > bestScore) {\n                bestScore = base;\n                best = -1;\n            }\n\n            for (int aid = 0; aid < (int)actions.size(); aid++) {\n                long long cand = base + evalAdd(sol.board, aid);\n                if (cand > bestScore) {\n                    bestScore = cand;\n                    best = aid;\n                }\n            }\n\n            sol.score = base;\n            if (best >= 0) {\n                sol.score += applyAdd(sol.board, best);\n            }\n            sol.slot[pos] = best;\n\n            if (sol.score > oldScore) improved = true;\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid anchorGroupOptimize(Solution& sol, int maxPasses, double timeLimit) {\n    for (int pass = 0; pass < maxPasses; pass++) {\n        bool improved = false;\n\n        for (int ii = 0; ii < 49; ii++) {\n            if (timer.elapsed() > timeLimit) return;\n\n            int anc = (pass & 1) ? (48 - ii) : ii;\n\n            vector<int> slots;\n            for (int i = 0; i < K; i++) {\n                int a = sol.slot[i];\n                if (a >= 0 && actions[a].anchor == anc) slots.push_back(i);\n            }\n\n            int c = (int)slots.size();\n            if (c <= 1 || c > MAX_MULTI) continue;\n\n            vector<int> oldActs(c);\n            long long oldScore = sol.score;\n\n            for (int t = 0; t < c; t++) {\n                oldActs[t] = sol.slot[slots[t]];\n                sol.score += applySub(sol.board, oldActs[t]);\n                sol.slot[slots[t]] = -1;\n            }\n\n            long long base = sol.score;\n            long long bestScore = oldScore;\n            int bestCnt = -1;\n            int bestIdx = -1;\n\n            for (int cnt = 0; cnt <= c; cnt++) {\n                const auto& vec = multiOpts[cnt];\n                for (int oi = 0; oi < (int)vec.size(); oi++) {\n                    long long cand = base + evalMultiAtAnchor(sol.board, anc, vec[oi]);\n                    if (cand > bestScore) {\n                        bestScore = cand;\n                        bestCnt = cnt;\n                        bestIdx = oi;\n                    }\n                }\n            }\n\n            sol.score = base;\n\n            if (bestCnt >= 0) {\n                const MultiOption& op = multiOpts[bestCnt][bestIdx];\n                for (int t = 0; t < bestCnt; t++) {\n                    int aid = anc * M + (int)op.st[t];\n                    sol.slot[slots[t]] = aid;\n                    sol.score += applyAdd(sol.board, aid);\n                }\n                improved = true;\n            } else {\n                for (int t = 0; t < c; t++) {\n                    sol.slot[slots[t]] = oldActs[t];\n                    sol.score += applyAdd(sol.board, oldActs[t]);\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nlong long orderCost(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    int cnt[49] = {};\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        cnt[br]++;\n    }\n\n    int maxc = 0;\n    int sumsq = 0;\n    int zero = 0;\n    for (int i = 0; i < 49; i++) {\n        maxc = max(maxc, cnt[i]);\n        sumsq += cnt[i] * cnt[i];\n        if (cnt[i] == 0) zero++;\n    }\n\n    return (long long)maxc * 1000000LL + (long long)sumsq * 1000LL + zero;\n}\n\nvector<int> findBalancedOrder() {\n    vector<int> base(49);\n    iota(base.begin(), base.end(), 0);\n\n    vector<int> best = base;\n    long long bestCost = orderCost(best);\n\n    const int REPS = 10;\n    const int ITERS = 1300;\n\n    for (int rep = 0; rep < REPS; rep++) {\n        vector<int> perm = base;\n        for (int i = 48; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(perm[i], perm[j]);\n        }\n\n        long long cur = orderCost(perm);\n\n        for (int it = 0; it < ITERS; it++) {\n            int a = rng.nextInt(49);\n            int b = rng.nextInt(49);\n            if (a == b) continue;\n\n            swap(perm[a], perm[b]);\n            long long nc = orderCost(perm);\n\n            if (nc <= cur) {\n                cur = nc;\n            } else {\n                swap(perm[a], perm[b]);\n            }\n        }\n\n        if (cur < bestCost) {\n            bestCost = cur;\n            best = perm;\n        }\n    }\n\n    return best;\n}\n\nvector<vector<int>> computeFinalCells(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    vector<vector<int>> finalCells(49);\n\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            if (rank[aid] > br) br = rank[aid];\n        }\n        finalCells[br].push_back(cell);\n    }\n\n    return finalCells;\n}\n\nstruct BeamState {\n    array<int, KMAX> cell;\n    long long fin;\n    long long total;\n    long long key;\n    int parent;\n    short opt;\n    unsigned char used;\n};\n\nvector<int> beamSearch(const vector<int>& order, int perWidth, long long finalWeight) {\n    vector<vector<int>> finalCells = computeFinalCells(order);\n\n    vector<vector<BeamState>> layers;\n    layers.reserve(50);\n\n    BeamState init{};\n    init.cell = initBoard;\n    init.fin = 0;\n    init.total = initScore;\n    init.key = initScore;\n    init.parent = -1;\n    init.opt = -1;\n    init.used = 0;\n\n    layers.push_back(vector<BeamState>{init});\n\n    vector<vector<BeamState>> buckets(K + 1);\n    int reserveEach = perWidth * (int)options.size() + 8;\n    for (auto& b : buckets) b.reserve(reserveEach);\n\n    auto cmpState = [](const BeamState& a, const BeamState& b) {\n        if (a.key != b.key) return a.key > b.key;\n        if (a.fin != b.fin) return a.fin > b.fin;\n        return a.total > b.total;\n    };\n\n    for (int step = 0; step < 49; step++) {\n        for (auto& b : buckets) b.clear();\n\n        const vector<BeamState>& cur = layers.back();\n        int anc = order[step];\n        const auto& cells = anchorCells[anc];\n        const vector<int>& fins = finalCells[step];\n\n        for (int si = 0; si < (int)cur.size(); si++) {\n            const BeamState& st = cur[si];\n\n            for (int oid = 0; oid < (int)options.size(); oid++) {\n                const Option& op = options[oid];\n                int nu = (int)st.used + (int)op.cnt;\n                if (nu > K) continue;\n\n                BeamState ns;\n                ns.cell = st.cell;\n                ns.fin = st.fin;\n                ns.total = st.total;\n                ns.parent = si;\n                ns.opt = (short)oid;\n                ns.used = (unsigned char)nu;\n\n                if (op.cnt) {\n                    for (int k = 0; k < 9; k++) {\n                        int v = op.val[k];\n                        int idx = cells[k];\n                        int old = ns.cell[idx];\n                        int nv = old + v;\n                        if (nv >= MOD) nv -= MOD;\n                        ns.cell[idx] = nv;\n                        ns.total += (long long)nv - old;\n                    }\n                }\n\n                for (int idx : fins) {\n                    ns.fin += ns.cell[idx];\n                }\n\n                ns.key = ns.fin * finalWeight + (ns.total - ns.fin);\n                buckets[nu].push_back(std::move(ns));\n            }\n        }\n\n        vector<BeamState> next;\n        next.reserve((K + 1) * perWidth);\n\n        for (int u = 0; u <= K; u++) {\n            auto& v = buckets[u];\n            if ((int)v.size() > perWidth) {\n                nth_element(v.begin(), v.begin() + perWidth, v.end(), cmpState);\n                v.resize(perWidth);\n            }\n            for (auto& s : v) next.push_back(std::move(s));\n        }\n\n        layers.push_back(std::move(next));\n    }\n\n    const vector<BeamState>& last = layers.back();\n    int bestIdx = 0;\n    for (int i = 1; i < (int)last.size(); i++) {\n        if (last[i].fin > last[bestIdx].fin) bestIdx = i;\n    }\n\n    vector<int> optAt(49);\n    int idx = bestIdx;\n    for (int step = 48; step >= 0; step--) {\n        const BeamState& st = layers[step + 1][idx];\n        optAt[step] = st.opt;\n        idx = st.parent;\n    }\n\n    vector<int> ops;\n    ops.reserve(K);\n\n    for (int step = 0; step < 49; step++) {\n        int anc = order[step];\n        const Option& op = options[optAt[step]];\n\n        if (op.cnt >= 1) ops.push_back(anc * M + (int)op.s1);\n        if (op.cnt >= 2) ops.push_back(anc * M + (int)op.s2);\n    }\n\n    if ((int)ops.size() > K) ops.resize(K);\n    return ops;\n}\n\nbool optimizePairExact(Solution& sol, int i, int j) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n    sol.slot[i] = sol.slot[j] = -1;\n\n    long long base = sol.score;\n    long long oldDelta = oldScore - base;\n    long long bestDelta = oldDelta;\n    int bestA = old1;\n    int bestB = old2;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n        if (d[a] > bestDelta) {\n            bestDelta = d[a];\n            bestA = a;\n            bestB = -1;\n        }\n    }\n\n    if (0 > bestDelta) {\n        bestDelta = 0;\n        bestA = bestB = -1;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    for (int ia = 0; ia < A; ia++) {\n        int a = ord[ia];\n        if (d[a] + d[ord[0]] <= bestDelta) break;\n\n        for (int ib = 0; ib < A; ib++) {\n            int b = ord[ib];\n            long long ub = d[a] + d[b];\n            if (ub <= bestDelta) break;\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                bestDelta = ub;\n                bestA = a;\n                bestB = b;\n                break;\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        if (delta > bestDelta) {\n            bestDelta = delta;\n            bestA = pi.a;\n            bestB = pi.b;\n        }\n    }\n\n    sol.score = base;\n\n    if (bestDelta > oldDelta) {\n        sol.slot[i] = bestA;\n        sol.slot[j] = bestB;\n        if (bestA >= 0) sol.score += applyAdd(sol.board, bestA);\n        if (bestB >= 0) sol.score += applyAdd(sol.board, bestB);\n        return true;\n    } else {\n        sol.slot[i] = old1;\n        sol.slot[j] = old2;\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n        return false;\n    }\n}\n\nvoid exactPairSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 18);\n        vector<pair<int, int>> pairs;\n        pairs.reserve(R * R);\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                pairs.push_back({loss[a].second, loss[b].second});\n            }\n        }\n\n        for (int i = (int)pairs.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n        int maxTries = stagnant == 0 ? 36 : 24;\n\n        for (auto [a, b] : pairs) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizePairExact(sol, a, b)) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= maxTries) break;\n        }\n\n        if (!improved) {\n            int randomTries = 10;\n            for (int t = 0; t < randomTries && timer.elapsed() < timeLimit; t++) {\n                int a, b;\n\n                if (rng.nextInt(100) < 75) {\n                    a = loss[rng.nextInt(R)].second;\n                } else {\n                    a = rng.nextInt(K);\n                }\n\n                do {\n                    if (rng.nextInt(100) < 75) {\n                        b = loss[rng.nextInt(R)].second;\n                    } else {\n                        b = rng.nextInt(K);\n                    }\n                } while (a == b);\n\n                if (optimizePairExact(sol, a, b)) {\n                    coordinateDescent(sol, 3, timeLimit);\n                    anchorGroupOptimize(sol, 1, timeLimit);\n                    improved = true;\n                    break;\n                }\n            }\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 3) break;\n        }\n    }\n}\n\nstruct PairCand {\n    long long delta;\n    int a, b;\n};\n\nstruct PairCandMinCmp {\n    bool operator()(const PairCand& x, const PairCand& y) const {\n        return x.delta > y.delta;\n    }\n};\n\nbool optimizeTripleApprox(Solution& sol, int i, int j, int k) {\n    if (i == j || i == k || j == k) return false;\n\n    int old[3] = {sol.slot[i], sol.slot[j], sol.slot[k]};\n    int pos[3] = {i, j, k};\n    long long oldScore = sol.score;\n\n    for (int t = 0; t < 3; t++) {\n        if (old[t] >= 0) sol.score += applySub(sol.board, old[t]);\n        sol.slot[pos[t]] = -1;\n    }\n\n    long long base = sol.score;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    const int CAND = 80;\n    priority_queue<PairCand, vector<PairCand>, PairCandMinCmp> pq;\n\n    auto pushCand = [&](long long delta, int a, int b) {\n        PairCand pc{delta, a, b};\n        if ((int)pq.size() < CAND) {\n            pq.push(pc);\n        } else if (delta > pq.top().delta) {\n            pq.pop();\n            pq.push(pc);\n        }\n    };\n\n    pushCand(0, -1, -1);\n\n    int singleT = min(A, 120);\n    for (int t = 0; t < singleT; t++) {\n        int a = ord[t];\n        pushCand(d[a], a, -1);\n    }\n\n    int topT = min(A, 80);\n    for (int x = 0; x < topT; x++) {\n        int a = ord[x];\n        for (int y = x + 1; y < topT; y++) {\n            int b = ord[y];\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                pushCand(d[a] + d[b], a, b);\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        pushCand(delta, pi.a, pi.b);\n    }\n\n    vector<PairCand> cands;\n    while (!pq.empty()) {\n        cands.push_back(pq.top());\n        pq.pop();\n    }\n\n    long long bestScore = oldScore;\n    int best[3] = {old[0], old[1], old[2]};\n\n    for (const PairCand& pc : cands) {\n        long long curScore = base;\n\n        if (pc.a >= 0) curScore += applyAdd(sol.board, pc.a);\n        if (pc.b >= 0) curScore += applyAdd(sol.board, pc.b);\n\n        int third = -1;\n        long long localBest = curScore;\n\n        for (int a = 0; a < A; a++) {\n            long long cand = curScore + evalAdd(sol.board, a);\n            if (cand > localBest) {\n                localBest = cand;\n                third = a;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best[0] = pc.a;\n            best[1] = pc.b;\n            best[2] = third;\n        }\n\n        if (pc.b >= 0) applySub(sol.board, pc.b);\n        if (pc.a >= 0) applySub(sol.board, pc.a);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = best[t];\n            if (best[t] >= 0) sol.score += applyAdd(sol.board, best[t]);\n        }\n        return true;\n    } else {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = old[t];\n            if (old[t] >= 0) sol.score += applyAdd(sol.board, old[t]);\n        }\n        return false;\n    }\n}\n\nvoid tripleSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 12);\n        vector<array<int, 3>> triples;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                for (int c = b + 1; c < R; c++) {\n                    triples.push_back({loss[a].second, loss[b].second, loss[c].second});\n                }\n            }\n        }\n\n        for (int i = (int)triples.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(triples[i], triples[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n\n        for (auto tr : triples) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizeTripleApprox(sol, tr[0], tr[1], tr[2])) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= 7) break;\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 2) break;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> K;\n\n    for (int i = 0; i < BN; i++) {\n        for (int j = 0; j < BN; j++) {\n            int x;\n            cin >> x;\n            initBoard[i * BN + j] = x;\n            initScore += x;\n        }\n    }\n\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                cin >> stampVal[m][i * 3 + j];\n            }\n        }\n    }\n\n    timer.reset();\n\n    precompute();\n\n    Solution best = greedySolution();\n    coordinateDescent(best, 25, 0.80);\n    anchorGroupOptimize(best, 2, 0.95);\n    coordinateDescent(best, 8, 1.05);\n\n    vector<int> order = findBalancedOrder();\n\n    if (timer.elapsed() < 1.15) {\n        vector<int> ops = beamSearch(order, 6, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 18, 1.45);\n        anchorGroupOptimize(sol, 2, 1.52);\n        coordinateDescent(sol, 6, 1.58);\n        if (sol.score > best.score) best = sol;\n    }\n\n    vector<int> revOrder = order;\n    reverse(revOrder.begin(), revOrder.end());\n\n    if (timer.elapsed() < 1.38) {\n        vector<int> ops = beamSearch(revOrder, 4, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 14, 1.66);\n        anchorGroupOptimize(sol, 2, 1.72);\n        coordinateDescent(sol, 5, 1.76);\n        if (sol.score > best.score) best = sol;\n    }\n\n    coordinateDescent(best, 8, 1.78);\n    anchorGroupOptimize(best, 2, 1.81);\n\n    exactPairSearch(best, 1.84);\n    tripleSearch(best, 1.88);\n\n    anchorGroupOptimize(best, 1, 1.90);\n    coordinateDescent(best, 3, 1.92);\n\n    vector<int> out;\n    for (int i = 0; i < K; i++) {\n        if (best.slot[i] >= 0) out.push_back(best.slot[i]);\n    }\n\n    cout << out.size() << '\\n';\n    for (int id : out) {\n        const Action& a = actions[id];\n        cout << a.m << ' ' << a.p << ' ' << a.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 TOT = 25;\nstatic constexpr int BASE = 6;\nstatic constexpr int PBASE = 7776; // 6^5\nstatic constexpr int TOTAL_STATES = PBASE * PBASE;\nstatic constexpr int INF = 1e9;\n\nint A[N][N];\nint srcOf[TOT], idxOf[TOT];\nint pow6_[N + 1];\n\nuint8_t dig[PBASE][N];\nuint8_t sumCode[PBASE];\nuint8_t exhCode[PBASE];\n\nvector<signed char> memoBlock;\n\ninline int manhattan(int r1, int c1, int r2, int c2) {\n    return abs(r1 - r2) + abs(c1 - c2);\n}\n\nstruct TransCode {\n    int npcode, nqcode, code, k;\n};\n\nbool makeTransCodes(int pcode, int qcode, int d, TransCode &tr) {\n    int qd = dig[qcode][d];\n    if (qd >= N) return false;\n\n    int x = N * d + qd;\n    int s = srcOf[x];\n    int idx = idxOf[x];\n    int ps = dig[pcode][s];\n\n    int nq = qcode + pow6_[d];\n    int np = pcode;\n    int k = 0;\n\n    if (idx < ps) {\n        k = 0;\n    } else {\n        k = idx - ps;\n        int buffer = (int)sumCode[pcode] - (int)sumCode[qcode];\n        int capacity = 15 + (int)exhCode[pcode]; // cols 1..3 + exhausted receiving gates\n        if (buffer + k > capacity) return false;\n        np = pcode + (idx + 1 - ps) * pow6_[s];\n    }\n\n    tr = {np, nq, np * PBASE + nq, k};\n    return true;\n}\n\nint dfsBlock(int code) {\n    signed char m = memoBlock[code];\n    if (m != -1) {\n        if (m >= 100) return INF;\n        return (int)m;\n    }\n\n    int pcode = code / PBASE;\n    int qcode = code % PBASE;\n\n    if (sumCode[qcode] == TOT) {\n        memoBlock[code] = 0;\n        return 0;\n    }\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(pcode, qcode, d, tr)) continue;\n        int sub = dfsBlock(tr.code);\n        if (sub >= INF) continue;\n        best = min(best, tr.k + sub);\n    }\n\n    memoBlock[code] = (best >= INF ? 100 : (signed char)best);\n    return best;\n}\n\nstruct RowOption {\n    vector<int> cols;\n    string act;\n    int len = 0;\n    int finalCol = 0;\n};\n\nvector<RowOption> rowOpts;\n\nRowOption makeRowOption(vector<int> cols) {\n    RowOption ro;\n    ro.cols = cols;\n\n    int pos = 0;\n    for (int t = 0; t < (int)cols.size(); t++) {\n        if (t > 0) {\n            while (pos > 0) {\n                ro.act.push_back('L');\n                pos--;\n            }\n        }\n\n        ro.act.push_back('P');\n\n        while (pos < cols[t]) {\n            ro.act.push_back('R');\n            pos++;\n        }\n\n        ro.act.push_back('Q');\n    }\n\n    ro.len = (int)ro.act.size();\n    ro.finalCol = cols.empty() ? 0 : cols.back();\n    return ro;\n}\n\nvoid initRowOptions() {\n    vector<vector<int>> defs = {\n        {},\n        {1},\n        {2},\n        {3},\n        {2, 1},\n        {3, 1},\n        {3, 2},\n        {3, 2, 1},\n    };\n    for (auto &v : defs) rowOpts.push_back(makeRowOption(v));\n}\n\nstruct State {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) occ[i][j] = -1;\n        }\n        r = c = 0;\n        act.clear();\n        eval = 0;\n    }\n\n    int code() const {\n        return pcode * PBASE + qcode;\n    }\n\n    int delivered() const {\n        return sumCode[qcode];\n    }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveTo(int tr, int tc) {\n        while (r < tr) add('D');\n        while (r > tr) add('U');\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    vector<pair<int, int>> storageOptions(int b, int srcRow, double storageW, int maxOpt) const {\n        vector<tuple<double, int, int, int>> cand;\n        int bd = b / N;\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n                cand.emplace_back(sc, tie, rr, cc);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        vector<pair<int, int>> res;\n        for (int i = 0; i < (int)cand.size() && i < maxOpt; i++) {\n            res.push_back({get<2>(cand[i]), get<3>(cand[i])});\n        }\n        return res;\n    }\n};\n\nbool doDispatchBuffered(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int rr = ns.lr[x], cc = ns.lc[x];\n    if (rr < 0 || ns.occ[rr][cc] != x) return false;\n\n    ns.moveTo(rr, cc);\n    ns.add('P');\n    ns.occ[rr][cc] = -1;\n    ns.lr[x] = ns.lc[x] = -1;\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nbool doDispatchSource(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int s = srcOf[x];\n\n    if (ns.p[s] >= N) return false;\n    if (A[s][ns.p[s]] != x) return false;\n    if (ns.occ[s][0] != x) return false;\n\n    ns.moveTo(s, 0);\n    ns.add('P');\n    ns.occ[s][0] = -1;\n    ns.incP(s);\n    if (ns.p[s] < N) ns.occ[s][0] = A[s][ns.p[s]];\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nvoid expandBlockers(\n    const State &cur,\n    int s,\n    int idx,\n    int d,\n    double storageW,\n    int optLimit,\n    vector<State> &out\n) {\n    if (cur.p[s] == idx) {\n        State ns = cur;\n        if (doDispatchSource(ns, d)) out.push_back(std::move(ns));\n        return;\n    }\n\n    if (cur.p[s] > idx) return;\n\n    int b = A[s][cur.p[s]];\n    if (cur.occ[s][0] != b) return;\n\n    State base = cur;\n    base.moveTo(s, 0);\n    base.add('P');\n    base.occ[s][0] = -1;\n    base.incP(s);\n    if (base.p[s] < N) base.occ[s][0] = A[s][base.p[s]];\n\n    auto opts = base.storageOptions(b, s, storageW, optLimit);\n    for (auto [rr, cc] : opts) {\n        if (base.occ[rr][cc] != -1) continue;\n\n        State ns = base;\n        ns.moveTo(rr, cc);\n        ns.add('Q');\n        ns.occ[rr][cc] = b;\n        ns.lr[b] = rr;\n        ns.lc[b] = cc;\n\n        expandBlockers(ns, s, idx, d, storageW, optLimit, out);\n    }\n}\n\nvector<State> expandExecuteTarget(\n    const State &st,\n    int d,\n    double storageW,\n    int optLimit,\n    int perTransLimit\n) {\n    vector<State> res;\n\n    int x = N * d + st.q[d];\n    int s = srcOf[x];\n    int idx = idxOf[x];\n\n    if (idx < st.p[s]) {\n        State ns = st;\n        if (doDispatchBuffered(ns, d)) res.push_back(std::move(ns));\n    } else {\n        expandBlockers(st, s, idx, d, storageW, optLimit, res);\n    }\n\n    if ((int)res.size() > perTransLimit) {\n        sort(res.begin(), res.end(), [](const State &a, const State &b) {\n            return a.act.size() < b.act.size();\n        });\n        res.resize(perTransLimit);\n    }\n\n    return res;\n}\n\nint nearestHeuristic(const State &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct PlanResult {\n    bool ok = false;\n    string act;\n};\n\nPlanResult buildBeam(const State &init, double storageW, int width, int hcoef, int optLimit) {\n    if (dfsBlock(init.code()) >= INF) return {false, \"\"};\n\n    vector<State> beam;\n    beam.push_back(init);\n\n    auto comp = [](const State &a, const State &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.act.size() < b.act.size();\n    };\n\n    int perTransLimit = (optLimit <= 1 ? 1 : 10);\n\n    for (int step = init.delivered(); step < TOT; step++) {\n        vector<State> cand;\n        cand.reserve((size_t)width * N * perTransLimit);\n\n        for (const State &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                vector<State> nsList = expandExecuteTarget(st, d, storageW, optLimit, perTransLimit);\n                for (State &ns : nsList) {\n                    if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n                    int near = nearestHeuristic(ns);\n                    ns.eval = (int)ns.act.size() + hcoef * remAfter + near;\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return {false, \"\"};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    string best;\n    int bestLen = INF;\n    for (const State &st : beam) {\n        if (st.delivered() == TOT && (int)st.act.size() < bestLen) {\n            bestLen = (int)st.act.size();\n            best = st.act;\n        }\n    }\n\n    if (best.empty()) return {false, \"\"};\n    return {true, best};\n}\n\nstruct Pattern {\n    array<int, N> opt{};\n    int T = 0;\n};\n\nPattern makePattern(const array<int, N> &arr) {\n    Pattern p;\n    p.opt = arr;\n    p.T = 0;\n    for (int i = 0; i < N; i++) {\n        p.T = max(p.T, rowOpts[arr[i]].len);\n    }\n    return p;\n}\n\nvector<Pattern> generatePatterns() {\n    vector<Pattern> patterns;\n    set<array<int, N>> seen;\n\n    auto add = [&](array<int, N> arr) {\n        if (seen.insert(arr).second) {\n            patterns.push_back(makePattern(arr));\n        }\n    };\n\n    for (int o = 0; o < (int)rowOpts.size(); o++) {\n        array<int, N> arr;\n        arr.fill(o);\n        add(arr);\n    }\n\n    vector<pair<int, int>> pairs = {\n        {7, 6}, {7, 5}, {7, 4}, {7, 3}, {7, 1}, {7, 0},\n        {6, 5}, {6, 4}, {6, 3},\n        {5, 1}, {4, 1}, {4, 0}, {3, 1}, {3, 0}\n    };\n\n    for (auto [hi, lo] : pairs) {\n        for (int mask = 0; mask < (1 << N); mask++) {\n            array<int, N> arr;\n            for (int i = 0; i < N; i++) {\n                arr[i] = ((mask >> i) & 1) ? hi : lo;\n            }\n            add(arr);\n        }\n    }\n\n    return patterns;\n}\n\nState makeInitialState(const Pattern &pat) {\n    State st;\n    st.clear();\n\n    for (int i = 0; i < N; i++) {\n        const RowOption &ro = rowOpts[pat.opt[i]];\n        int k = (int)ro.cols.size();\n\n        st.p[i] = k;\n        st.pcode += k * pow6_[i];\n\n        for (int t = 0; t < k; t++) {\n            int b = A[i][t];\n            int cc = ro.cols[t];\n            st.occ[i][cc] = b;\n            st.lr[b] = i;\n            st.lc[b] = cc;\n        }\n\n        if (k < N) {\n            st.occ[i][0] = A[i][k];\n        }\n    }\n\n    st.r = 0;\n    st.c = rowOpts[pat.opt[0]].finalCol;\n    return st;\n}\n\nstring makeBigString(const Pattern &pat, const string &cont) {\n    string big = rowOpts[pat.opt[0]].act;\n    if ((int)big.size() < pat.T) {\n        big += string(pat.T - (int)big.size(), '.');\n    }\n    big += cont;\n    return big;\n}\n\narray<string, N> makeSortedOutput(const Pattern &pat, const string &cont) {\n    array<string, N> out;\n    out[0] = makeBigString(pat, cont);\n\n    for (int i = 1; i < N; i++) {\n        out[i] = rowOpts[pat.opt[i]].act;\n        out[i].push_back('B');\n    }\n\n    return out;\n}\n\nstring buildDirectPlan() {\n    State st;\n    st.clear();\n    for (int i = 0; i < N; i++) st.occ[i][0] = A[i][0];\n\n    for (int s = 0; s < N; s++) {\n        while (st.p[s] < N) {\n            int x = A[s][st.p[s]];\n            int d = x / N;\n\n            st.moveTo(s, 0);\n            st.add('P');\n            st.occ[s][0] = -1;\n            st.incP(s);\n            if (st.p[s] < N) st.occ[s][0] = A[s][st.p[s]];\n\n            st.moveTo(d, N - 1);\n            st.add('Q');\n        }\n    }\n\n    return st.act;\n}\n\nint directInversions() {\n    vector<int> seq[N];\n    int inv = 0;\n\n    for (int s = 0; s < N; s++) {\n        for (int k = 0; k < N; k++) {\n            int x = A[s][k];\n            int d = x / N;\n            for (int y : seq[d]) {\n                if (y > x) inv++;\n            }\n            seq[d].push_back(x);\n        }\n    }\n\n    return inv;\n}\n\nvoid initTables() {\n    pow6_[0] = 1;\n    for (int i = 0; i < N; i++) pow6_[i + 1] = pow6_[i] * BASE;\n\n    for (int code = 0; code < PBASE; code++) {\n        int tmp = code;\n        int sm = 0, ex = 0;\n        for (int i = 0; i < N; i++) {\n            int v = tmp % BASE;\n            tmp /= BASE;\n            dig[code][i] = (uint8_t)v;\n            sm += v;\n            if (v == N) ex++;\n        }\n        sumCode[code] = (uint8_t)sm;\n        exhCode[code] = (uint8_t)ex;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initTables();\n    initRowOptions();\n\n    int Nin;\n    cin >> Nin;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> A[i][j];\n            srcOf[A[i][j]] = i;\n            idxOf[A[i][j]] = j;\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsedMs = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    };\n\n    memoBlock.assign(TOTAL_STATES, -1);\n\n    array<string, N> bestOut;\n    long long bestScore = (long long)4e18;\n\n    {\n        string directAct = buildDirectPlan();\n        int inv = directInversions();\n        long long directScore = (long long)directAct.size() + 100LL * inv;\n\n        bestOut[0] = directAct.empty() ? \".\" : directAct;\n        for (int i = 1; i < N; i++) bestOut[i] = \"B\";\n        bestScore = directScore;\n    }\n\n    auto tryUpdateSorted = [&](const Pattern &pat, const string &cont) {\n        if (cont.empty()) return;\n\n        auto out = makeSortedOutput(pat, cont);\n        int m0 = 0;\n        for (int i = 0; i < N; i++) m0 = max(m0, (int)out[i].size());\n        if (m0 <= 0 || m0 > 10000) return;\n\n        long long sc = m0;\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestOut = out;\n        }\n    };\n\n    vector<Pattern> patterns = generatePatterns();\n\n    vector<pair<int, int>> estimates; // estimated total length, pattern index\n\n    for (int idx = 0; idx < (int)patterns.size(); idx++) {\n        if (idx >= 8 && elapsedMs() > 1200) break;\n\n        State init = makeInitialState(patterns[idx]);\n        if (dfsBlock(init.code()) >= INF) continue;\n\n        PlanResult pr = buildBeam(init, 1.0, 1, 8, 1);\n        if (!pr.ok) continue;\n\n        int totalLen = patterns[idx].T + (int)pr.act.size();\n        estimates.push_back({totalLen, idx});\n        tryUpdateSorted(patterns[idx], pr.act);\n    }\n\n    sort(estimates.begin(), estimates.end());\n\n    vector<int> selected;\n    vector<char> used(patterns.size(), 0);\n\n    auto addSelected = [&](int idx) {\n        if (0 <= idx && idx < (int)patterns.size() && !used[idx]) {\n            used[idx] = 1;\n            selected.push_back(idx);\n        }\n    };\n\n    for (int i = 0; i < (int)estimates.size() && i < 10; i++) {\n        addSelected(estimates[i].second);\n    }\n    for (int i = 0; i < 8 && i < (int)patterns.size(); i++) {\n        addSelected(i); // uniform patterns, including no preprocessing\n    }\n\n    vector<double> weights = {0.0, 0.3, 0.7, 1.2, 2.5, 5.0};\n    vector<int> hcoefs = {0, 8};\n\n    bool stop = false;\n    for (int rank = 0; rank < (int)selected.size() && !stop; rank++) {\n        int idx = selected[rank];\n        State init = makeInitialState(patterns[idx]);\n\n        int width = (rank < 3 ? 220 : 140);\n\n        for (int h : hcoefs) {\n            for (double w : weights) {\n                if (elapsedMs() > 2700) {\n                    stop = true;\n                    break;\n                }\n\n                PlanResult pr = buildBeam(init, w, width, h, 1);\n                if (pr.ok) {\n                    tryUpdateSorted(patterns[idx], pr.act);\n                }\n            }\n            if (stop) break;\n        }\n    }\n\n    // Small additional branching over storage cells for the most promising patterns.\n    for (int rank = 0; rank < (int)selected.size() && rank < 3; rank++) {\n        if (elapsedMs() > 2450) break;\n\n        int idx = selected[rank];\n        State init = makeInitialState(patterns[idx]);\n\n        for (double w : {0.7, 1.5, 3.0}) {\n            if (elapsedMs() > 2750) break;\n\n            PlanResult pr = buildBeam(init, w, 70, 8, 2);\n            if (pr.ok) {\n                tryUpdateSorted(patterns[idx], pr.act);\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (bestOut[i].empty()) bestOut[i] = \".\";\n        if ((int)bestOut[i].size() > 10000) bestOut[i].resize(10000);\n        cout << bestOut[i] << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 20;\nstatic const int V = N * N;\nstatic const long long INFLL = (1LL << 60);\nstatic const int INF = 1e9;\n\nint H[V];\nint DIST[V][V];\nlong long BASE_COST = 0;\n\nint cell_id(int r, int c) {\n    return r * N + c;\n}\n\nstruct Solution {\n    vector<string> ops;\n    long long cost = 0;\n    long long load = 0;\n    int pos = 0;\n    bool valid = true;\n\n    void moveOne(char ch) {\n        ops.emplace_back(1, ch);\n        cost += 100 + load;\n\n        int r = pos / N;\n        int c = pos % N;\n        if (ch == 'U') --r;\n        if (ch == 'D') ++r;\n        if (ch == 'L') --c;\n        if (ch == 'R') ++c;\n        if (r < 0 || r >= N || c < 0 || c >= N) valid = false;\n        pos = cell_id(r, c);\n    }\n\n    void moveTo(int target) {\n        int tr = target / N;\n        int tc = target % N;\n        while (pos / N < tr) moveOne('D');\n        while (pos / N > tr) moveOne('U');\n        while (pos % N < tc) moveOne('R');\n        while (pos % N > tc) moveOne('L');\n    }\n\n    void addLoad(long long d) {\n        if (d <= 0) return;\n        ops.push_back(string(\"+\") + to_string(d));\n        cost += d;\n        load += d;\n    }\n\n    void addUnload(long long d) {\n        if (d <= 0) return;\n        if (load < d) valid = false;\n        ops.push_back(string(\"-\") + to_string(d));\n        cost += d;\n        load -= d;\n    }\n};\n\narray<int, V> nearestDist(const vector<int>& rem, bool positive, bool& has) {\n    array<int, V> dist;\n    dist.fill(INF);\n    queue<int> q;\n    has = false;\n\n    for (int i = 0; i < V; ++i) {\n        if ((positive && rem[i] > 0) || (!positive && rem[i] < 0)) {\n            dist[i] = 0;\n            q.push(i);\n            has = true;\n        }\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        int r = v / N;\n        int c = v % N;\n        const int dr[4] = {-1, 1, 0, 0};\n        const int dc[4] = {0, 0, -1, 1};\n\n        for (int k = 0; k < 4; ++k) {\n            int nr = r + dr[k];\n            int nc = c + dc[k];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int to = cell_id(nr, nc);\n            if (dist[to] > dist[v] + 1) {\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n    }\n\n    return dist;\n}\n\nint selectSource(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearNeg,\n    int mode,\n    int maxAmount\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] <= 0) continue;\n        if (maxAmount >= 0 && rem[i] > maxAmount) continue;\n\n        int d = DIST[cur][i];\n        int nd = nearNeg[i] >= INF ? 0 : nearNeg[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * rem[i];\n        } else if (mode == 1) {\n            score = 10000LL * d - 200LL * rem[i];\n        } else {\n            score = 8000LL * d + 3000LL * nd - 50LL * rem[i];\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nint selectDemand(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearPos,\n    bool hasPos,\n    long long load,\n    int mode\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] >= 0) continue;\n\n        int demand = -rem[i];\n        int del = (int)min<long long>(load, demand);\n        if (del <= 0) continue;\n\n        int d = DIST[cur][i];\n        int future = 0;\n        if (load == del && hasPos && nearPos[i] < INF) future = nearPos[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * del + 1000LL * future;\n        } else if (mode == 1) {\n            score = 1000LL * d * (100 + load) / (del + 10) + 500LL * future;\n        } else {\n            score = 10000LL * d - 200LL * del + 1000LL * future;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nSolution makeGreedySolution(int maxLoad, int ratioNum, int ratioDen, int sourceMode, int demandMode) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 10000; ++iter) {\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            sol.moveTo(p);\n            int a = rem[p];\n            sol.addLoad(a);\n            rem[p] = 0;\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (maxLoad > 0 && hasPos) {\n                int maxAmount = maxLoad - (int)sol.load;\n                if (maxAmount > 0) {\n                    p = selectSource(sol.pos, rem, nearNeg, sourceMode, maxAmount);\n                    if (p >= 0) {\n                        int nearestDemand = nearNeg[sol.pos];\n                        int dp = DIST[sol.pos][p];\n\n                        if (nearestDemand > 0 &&\n                            1LL * dp * ratioDen <= 1LL * nearestDemand * ratioNum) {\n                            takePos = true;\n                        }\n                    }\n                }\n            }\n\n            if (takePos) {\n                sol.moveTo(p);\n                int a = rem[p];\n                sol.addLoad(a);\n                rem[p] = 0;\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                sol.moveTo(q);\n                int x = (int)min<long long>(sol.load, -rem[q]);\n                sol.addUnload(x);\n                rem[q] += x;\n            }\n        }\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\n// Opportunistic path-servicing greedy.\nvoid serviceCell(Solution& sol, vector<int>& rem, int cap) {\n    int v = sol.pos;\n\n    if (rem[v] < 0 && sol.load > 0) {\n        long long x = min<long long>(sol.load, -rem[v]);\n        sol.addUnload(x);\n        rem[v] += (int)x;\n    }\n\n    if (rem[v] > 0 && sol.load < cap) {\n        long long x = min<long long>(rem[v], (long long)cap - sol.load);\n        sol.addLoad(x);\n        rem[v] -= (int)x;\n    }\n}\n\nlong long stepScoreForService(int nxt, int target, const vector<int>& rem, long long load, int cap) {\n    long long score = 0;\n\n    if (rem[nxt] < 0 && load > 0) {\n        long long x = min<long long>(load, -rem[nxt]);\n        score -= 100000LL * x;\n        score -= 3000LL * x * DIST[nxt][target];\n    }\n\n    if (rem[nxt] > 0 && load < cap) {\n        long long x = min<long long>(rem[nxt], (long long)cap - load);\n        score -= 20000LL * x;\n        score += 700LL * x * DIST[nxt][target];\n    }\n\n    return score;\n}\n\nvoid moveToService(Solution& sol, int target, vector<int>& rem, int cap, int pathMode) {\n    serviceCell(sol, rem, cap);\n\n    while (sol.pos != target) {\n        int r = sol.pos / N;\n        int c = sol.pos % N;\n        int tr = target / N;\n        int tc = target % N;\n\n        char chosen = 0;\n\n        if (pathMode == 0) {\n            if (r < tr) chosen = 'D';\n            else if (r > tr) chosen = 'U';\n            else if (c < tc) chosen = 'R';\n            else chosen = 'L';\n        } else if (pathMode == 1) {\n            if (c < tc) chosen = 'R';\n            else if (c > tc) chosen = 'L';\n            else if (r < tr) chosen = 'D';\n            else chosen = 'U';\n        } else {\n            vector<pair<char, int>> cand;\n            if (r < tr) cand.push_back({'D', cell_id(r + 1, c)});\n            if (r > tr) cand.push_back({'U', cell_id(r - 1, c)});\n            if (c < tc) cand.push_back({'R', cell_id(r, c + 1)});\n            if (c > tc) cand.push_back({'L', cell_id(r, c - 1)});\n\n            long long best = INFLL;\n            for (auto [ch, id] : cand) {\n                long long sc = stepScoreForService(id, target, rem, sol.load, cap);\n                if (sc < best) {\n                    best = sc;\n                    chosen = ch;\n                }\n            }\n        }\n\n        sol.moveOne(chosen);\n        serviceCell(sol, rem, cap);\n    }\n}\n\nSolution makeGreedyServiceSolution(\n    int cap,\n    int ratioNum,\n    int ratioDen,\n    int sourceMode,\n    int demandMode,\n    int pathMode\n) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 20000; ++iter) {\n        serviceCell(sol, rem, cap);\n\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            moveToService(sol, p, rem, cap, pathMode);\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (sol.load < cap && hasPos) {\n                p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n                if (p >= 0) {\n                    int direct = nearNeg[sol.pos];\n                    int via = DIST[sol.pos][p] + nearNeg[p];\n\n                    if (direct >= INF) direct = 1000;\n                    if (via * ratioDen <= direct * ratioNum + 2 * ratioDen) {\n                        takePos = true;\n                    }\n\n                    if (DIST[sol.pos][p] <= 2 && sol.load < cap * 3LL / 4) {\n                        takePos = true;\n                    }\n                }\n            }\n\n            if (takePos) {\n                moveToService(sol, p, rem, cap, pathMode);\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                moveToService(sol, q, rem, cap, pathMode);\n            }\n        }\n    }\n\n    serviceCell(sol, rem, cap);\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev;\n        long long cap, cost;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow(int n_) : n(n_), g(n_) {}\n\n    int addEdge(int fr, int to, long long cap, long long cost) {\n        Edge f{to, (int)g[to].size(), cap, cost};\n        Edge r{fr, (int)g[fr].size(), 0, -cost};\n        g[fr].push_back(f);\n        g[to].push_back(r);\n        return (int)g[fr].size() - 1;\n    }\n\n    pair<long long, long long> minCostFlow(int s, int t, long long maxf) {\n        long long flow = 0;\n        long long cost = 0;\n\n        vector<long long> pot(n, 0), dist(n);\n        vector<int> pv(n), pe(n);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INFLL);\n            dist[s] = 0;\n\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != d) continue;\n\n                for (int i = 0; i < (int)g[v].size(); ++i) {\n                    Edge& e = g[v][i];\n                    if (e.cap <= 0) continue;\n\n                    long long nd = d + e.cost + pot[v] - pot[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INFLL) break;\n\n            for (int v = 0; v < n; ++v) {\n                if (dist[v] < INFLL) pot[v] += dist[v];\n            }\n\n            long long add = maxf - flow;\n            for (int v = t; v != s; v = pv[v]) {\n                add = min(add, g[pv[v]][pe[v]].cap);\n            }\n\n            for (int v = t; v != s; v = pv[v]) {\n                Edge& e = g[pv[v]][pe[v]];\n                e.cap -= add;\n                g[v][e.rev].cap += add;\n                cost += add * e.cost;\n            }\n\n            flow += add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nstruct Flow {\n    int s, t, amount;\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\nvector<Flow> computeMinCostFlows(int variant) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n            total += H[i];\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n    if (total == 0) return {};\n\n    int SRC = 0;\n    int posBase = 1;\n    int negBase = 1 + P;\n    int SNK = 1 + P + Q;\n    int nodes = SNK + 1;\n\n    MinCostFlow mf(nodes);\n\n    for (int i = 0; i < P; ++i) {\n        mf.addEdge(SRC, posBase + i, posAmt[i], 0);\n    }\n\n    for (int j = 0; j < Q; ++j) {\n        mf.addEdge(negBase + j, SNK, negAmt[j], 0);\n    }\n\n    struct Ref {\n        int node, edgeIndex, pi, qi;\n    };\n    vector<Ref> refs;\n\n    const long long CAP = 1e9;\n    const long long W = 100000000LL;\n\n    for (int i = 0; i < P; ++i) {\n        for (int j = 0; j < Q; ++j) {\n            long long tie = 0;\n\n            if (variant != 0) {\n                uint64_t seed = ((uint64_t)variant << 48) ^ ((uint64_t)posCells[i] << 24) ^ (uint64_t)negCells[j];\n                tie = splitmix64(seed) % 1000;\n            }\n\n            long long c = 1LL * DIST[posCells[i]][negCells[j]] * W + tie;\n            int idx = mf.addEdge(posBase + i, negBase + j, CAP, c);\n            refs.push_back({posBase + i, idx, i, j});\n        }\n    }\n\n    mf.minCostFlow(SRC, SNK, total);\n\n    vector<Flow> flows;\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            flows.push_back({posCells[ref.pi], negCells[ref.qi], (int)used});\n        }\n    }\n\n    return flows;\n}\n\nvector<Flow> computeGreedyFlows(int mode) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n\n    vector<Flow> flows;\n\n    for (int step = 0; step < P + Q + 5; ++step) {\n        long long bestScore = INFLL;\n        int bi = -1, bj = -1;\n\n        for (int i = 0; i < P; ++i) {\n            if (posAmt[i] <= 0) continue;\n\n            for (int j = 0; j < Q; ++j) {\n                if (negAmt[j] <= 0) continue;\n\n                int a = min(posAmt[i], negAmt[j]);\n                int d = DIST[posCells[i]][negCells[j]];\n\n                long long score;\n                if (mode == 0) {\n                    score = 100000LL * d - 700LL * a;\n                } else if (mode == 1) {\n                    score = 100000LL * d\n                          + 150LL * (DIST[0][posCells[i]] + DIST[0][negCells[j]])\n                          - 500LL * a;\n                } else {\n                    score = 100000LL * d\n                          - 1200LL * a\n                          + 20LL * abs(posAmt[i] - negAmt[j]);\n                }\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi < 0) break;\n\n        int a = min(posAmt[bi], negAmt[bj]);\n        flows.push_back({posCells[bi], negCells[bj], a});\n        posAmt[bi] -= a;\n        negAmt[bj] -= a;\n    }\n\n    return flows;\n}\n\nvector<int> optimizeOrder(const vector<int>& starts, const vector<int>& ends) {\n    int m = (int)starts.size();\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    vector<int> startLink(m);\n    vector<vector<int>> link(m, vector<int>(m));\n\n    for (int i = 0; i < m; ++i) {\n        startLink[i] = DIST[0][starts[i]];\n    }\n\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < m; ++j) {\n            link[i][j] = DIST[ends[i]][starts[j]];\n        }\n    }\n\n    auto L = [&](int prev, int cur) -> int {\n        if (prev < 0) return startLink[cur];\n        return link[prev][cur];\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n\n    for (int cnt = 0; cnt < m; ++cnt) {\n        int bestG = -1, bestPos = 0;\n        int bestInc = INF;\n\n        for (int g = 0; g < m; ++g) {\n            if (used[g]) continue;\n\n            for (int p = 0; p <= (int)order.size(); ++p) {\n                int prev = (p == 0 ? -1 : order[p - 1]);\n                int nxt = (p == (int)order.size() ? -2 : order[p]);\n\n                int inc = L(prev, g);\n                if (nxt != -2) inc += L(g, nxt) - L(prev, nxt);\n\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestG = g;\n                    bestPos = p;\n                }\n            }\n        }\n\n        order.insert(order.begin() + bestPos, bestG);\n        used[bestG] = true;\n    }\n\n    for (int pass = 0; pass < 30; ++pass) {\n        int bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prev = (i == 0 ? -1 : order[i - 1]);\n            int nxt = (i + 1 == m ? -2 : order[i + 1]);\n\n            int oldRemove = L(prev, x);\n            if (nxt != -2) oldRemove += L(x, nxt);\n\n            int newRemove = 0;\n            if (nxt != -2) newRemove += L(prev, nxt);\n\n            int removeDelta = newRemove - oldRemove;\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int oldInsert = 0;\n                if (after != -2) oldInsert += L(before, after);\n\n                int newInsert = L(before, x);\n                if (after != -2) newInsert += L(x, after);\n\n                int delta = removeDelta + newInsert - oldInsert;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            int oldInternal = 0;\n            int newInternal = 0;\n            int prev = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += L(order[r - 1], order[r]);\n                newInternal += L(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                int oldCost = L(prev, order[l]) + oldInternal;\n                if (after != -2) oldCost += L(order[r], after);\n\n                int newCost = L(prev, order[r]) + newInternal;\n                if (after != -2) newCost += L(order[l], after);\n\n                int delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else if (bestType == 2) {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nstruct SourceGroup {\n    int source = -1;\n    int total = 0;\n    int end = -1;\n    vector<int> dest, amt, order;\n    long long internalCost = 0;\n};\n\nvoid computeSourceOrder(SourceGroup& g, int target) {\n    int k = (int)g.dest.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            dp[idx(mask, j)] = 1LL * DIST[g.source][g.dest[j]] * (100 + total);\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = total - sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.dest[last]][g.dest[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)];\n            if (target >= 0) c += 100LL * DIST[g.dest[last]][target];\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = g.source;\n        int load = total;\n\n        for (int left = k; left > 0; --left) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score = 1LL * DIST[cur][g.dest[j]] * (100 + load);\n                if (left == 1 && target >= 0) {\n                    score += 100LL * DIST[g.dest[j]][target];\n                }\n\n                score -= 5LL * g.amt[j];\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.dest[bj];\n            load -= g.amt[bj];\n        }\n    }\n\n    g.end = g.dest[g.order.back()];\n\n    long long c = 0;\n    int cur = g.source;\n    int load = total;\n\n    for (int idx2 : g.order) {\n        c += 1LL * DIST[cur][g.dest[idx2]] * (100 + load);\n        load -= g.amt[idx2];\n        cur = g.dest[idx2];\n    }\n\n    g.internalCost = c;\n}\n\nvector<SourceGroup> buildSourceGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.s].push_back({f.t, f.amount});\n    }\n\n    vector<SourceGroup> groups;\n\n    for (int s = 0; s < V; ++s) {\n        if (mp[s].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [t, a] : mp[s]) comb[t] += a;\n\n        SourceGroup g;\n        g.source = s;\n\n        for (auto [t, a] : comb) {\n            g.dest.push_back(t);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeSourceOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeSourceGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildSourceGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].source;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n            computeSourceOrder(groups[gi], target);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].source;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n        computeSourceOrder(groups[gi], target);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        sol.moveTo(g.source);\n        sol.addLoad(g.total);\n\n        for (int idx : g.order) {\n            sol.moveTo(g.dest[idx]);\n            sol.addUnload(g.amt[idx]);\n        }\n    }\n\n    return sol;\n}\n\nSolution makePairSolution(const vector<Flow>& flows) {\n    Solution sol;\n    int m = (int)flows.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = flows[i].s;\n        ends[i] = flows[i].t;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int idx : order) {\n        const auto& f = flows[idx];\n\n        sol.moveTo(f.s);\n        sol.addLoad(f.amount);\n        sol.moveTo(f.t);\n        sol.addUnload(f.amount);\n    }\n\n    return sol;\n}\n\nstruct DemandGroup {\n    int demand = -1;\n    int total = 0;\n    int start = -1;\n    int end = -1;\n    vector<int> src, amt, order;\n};\n\nvoid computeDemandOrder(DemandGroup& g, int prevCell) {\n    int k = (int)g.src.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            long long entry = 0;\n            if (prevCell >= 0) entry = 100LL * DIST[prevCell][g.src[j]];\n\n            dp[idx(mask, j)] = entry;\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.src[last]][g.src[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)] + 1LL * DIST[g.src[last]][g.demand] * (100 + total);\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = -1;\n        int load = 0;\n\n        for (int step = 0; step < k; ++step) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score;\n\n                if (step == 0) {\n                    score = 0;\n                    if (prevCell >= 0) score += 100LL * DIST[prevCell][g.src[j]];\n                    score -= 50LL * DIST[g.src[j]][g.demand];\n                } else {\n                    score = 1LL * DIST[cur][g.src[j]] * (100 + load)\n                          + 10LL * DIST[g.src[j]][g.demand];\n                }\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.src[bj];\n            load += g.amt[bj];\n        }\n    }\n\n    g.start = g.src[g.order.front()];\n    g.end = g.demand;\n}\n\nvector<DemandGroup> buildDemandGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.t].push_back({f.s, f.amount});\n    }\n\n    vector<DemandGroup> groups;\n\n    for (int t = 0; t < V; ++t) {\n        if (mp[t].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [s, a] : mp[t]) comb[s] += a;\n\n        DemandGroup g;\n        g.demand = t;\n\n        for (auto [s, a] : comb) {\n            g.src.push_back(s);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeDemandOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeDemandGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildDemandGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].start;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n            computeDemandOrder(groups[gi], prev);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].start;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n        computeDemandOrder(groups[gi], prev);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        for (int idx : g.order) {\n            sol.moveTo(g.src[idx]);\n            sol.addLoad(g.amt[idx]);\n        }\n\n        sol.moveTo(g.demand);\n        sol.addUnload(g.total);\n    }\n\n    return sol;\n}\n\n// Aggregated adjacent-edge flow route.\nstruct EdgeJob {\n    int s, t, amount;\n};\n\nlong long edgeTieCost(int variant, int u, int v) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    int ar2 = r1 + r2;\n    int ac2 = c1 + c2;\n\n    if (variant == 0) return 0;\n\n    if (variant == 1) {\n        return ar2 + ac2;\n    }\n\n    if (variant == 2) {\n        return (2 * (N - 1) - ar2) + (2 * (N - 1) - ac2);\n    }\n\n    if (variant == 3) {\n        return abs(ar2 - (N - 1)) + abs(ac2 - (N - 1));\n    }\n\n    uint64_t seed = ((uint64_t)variant << 40) ^ ((uint64_t)u << 20) ^ (uint64_t)v;\n    return splitmix64(seed) % 50;\n}\n\nvoid addSignedEdgeFlow(vector<long long>& right, vector<long long>& down, int u, int v, long long a) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    if (r1 == r2) {\n        if (c2 == c1 + 1) {\n            right[r1 * (N - 1) + c1] += a;\n        } else if (c2 == c1 - 1) {\n            right[r1 * (N - 1) + c2] -= a;\n        }\n    } else if (c1 == c2) {\n        if (r2 == r1 + 1) {\n            down[r1 * N + c1] += a;\n        } else if (r2 == r1 - 1) {\n            down[r2 * N + c1] -= a;\n        }\n    }\n}\n\nvector<EdgeJob> computeGridEdgeJobs(int variant) {\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) total += H[i];\n    }\n\n    if (total == 0) return {};\n\n    int SRC = V;\n    int SNK = V + 1;\n    MinCostFlow mf(V + 2);\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) mf.addEdge(SRC, i, H[i], 0);\n        if (H[i] < 0) mf.addEdge(i, SNK, -H[i], 0);\n    }\n\n    struct Ref {\n        int u, v, node, edgeIndex;\n    };\n\n    vector<Ref> refs;\n\n    const long long CAP = 1000000000LL;\n    const long long W = 100000LL;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int u = cell_id(r, c);\n\n            if (r + 1 < N) {\n                int v = cell_id(r + 1, c);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n\n            if (c + 1 < N) {\n                int v = cell_id(r, c + 1);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n        }\n    }\n\n    auto [flow, cost] = mf.minCostFlow(SRC, SNK, total);\n    if (flow != total) return {};\n\n    vector<long long> right(N * (N - 1), 0), down((N - 1) * N, 0);\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            addSignedEdgeFlow(right, down, ref.u, ref.v, used);\n        }\n    }\n\n    vector<EdgeJob> jobs;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c + 1 < N; ++c) {\n            long long f = right[r * (N - 1) + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r, c + 1), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r, c + 1), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    for (int r = 0; r + 1 < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            long long f = down[r * N + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r + 1, c), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r + 1, c), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    return jobs;\n}\n\nvector<int> optimizeEdgeOrder(const vector<EdgeJob>& jobs) {\n    int m = (int)jobs.size();\n\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    auto link = [&](int a, int b) -> long long {\n        if (b == -2) {\n            if (a == -1) return 0;\n            return jobs[a].amount;\n        }\n\n        if (a == -1) {\n            return 100LL * DIST[0][jobs[b].s] + jobs[b].amount;\n        }\n\n        if (jobs[a].t == jobs[b].s) {\n            return llabs((long long)jobs[a].amount - jobs[b].amount);\n        }\n\n        return jobs[a].amount\n             + 100LL * DIST[jobs[a].t][jobs[b].s]\n             + jobs[b].amount;\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n    int prev = -1;\n\n    for (int k = 0; k < m; ++k) {\n        long long best = INFLL;\n        int bj = -1;\n\n        for (int j = 0; j < m; ++j) {\n            if (used[j]) continue;\n\n            long long sc = link(prev, j);\n            if (sc < best) {\n                best = sc;\n                bj = j;\n            }\n        }\n\n        used[bj] = true;\n        order.push_back(bj);\n        prev = bj;\n    }\n\n    int maxPass = (m > 500 ? 5 : 10);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        long long bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prevNode = (i == 0 ? -1 : order[i - 1]);\n            int nextNode = (i + 1 == m ? -2 : order[i + 1]);\n\n            long long removeDelta = link(prevNode, nextNode) - link(prevNode, x) - link(x, nextNode);\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                long long delta = removeDelta\n                                + link(before, x)\n                                + link(x, after)\n                                - link(before, after);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            long long oldInternal = 0;\n            long long newInternal = 0;\n            int before = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += link(order[r - 1], order[r]);\n                newInternal += link(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                long long oldCost = link(before, order[l]) + oldInternal + link(order[r], after);\n                long long newCost = link(before, order[r]) + newInternal + link(order[l], after);\n\n                long long delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nSolution makeEdgeRelaySolution(const vector<EdgeJob>& jobs) {\n    Solution sol;\n\n    vector<long long> delta(V, 0);\n\n    for (auto& e : jobs) {\n        if (DIST[e.s][e.t] != 1 || e.amount <= 0) {\n            sol.valid = false;\n            return sol;\n        }\n\n        delta[e.s] -= e.amount;\n        delta[e.t] += e.amount;\n    }\n\n    for (int i = 0; i < V; ++i) {\n        if (delta[i] != -H[i]) {\n            sol.valid = false;\n            return sol;\n        }\n    }\n\n    if (jobs.empty()) return sol;\n\n    vector<int> order = optimizeEdgeOrder(jobs);\n\n    for (int idx : order) {\n        const auto& e = jobs[idx];\n\n        if (sol.pos != e.s) {\n            if (sol.load > 0) sol.addUnload(sol.load);\n            sol.moveTo(e.s);\n        }\n\n        if (sol.load < e.amount) {\n            sol.addLoad(e.amount - sol.load);\n        } else if (sol.load > e.amount) {\n            sol.addUnload(sol.load - e.amount);\n        }\n\n        sol.moveTo(e.t);\n    }\n\n    if (sol.load > 0) sol.addUnload(sol.load);\n\n    return sol;\n}\n\nSolution makeGridRelaySolution(int variant) {\n    vector<EdgeJob> jobs = computeGridEdgeJobs(variant);\n    return makeEdgeRelaySolution(jobs);\n}\n\npair<int, int> transformCoord(int r, int c, int type) {\n    if (type == 0) return {r, c};\n    if (type == 1) return {c, N - 1 - r};\n    if (type == 2) return {N - 1 - r, N - 1 - c};\n    if (type == 3) return {N - 1 - c, r};\n    if (type == 4) return {r, N - 1 - c};\n    if (type == 5) return {N - 1 - r, c};\n    if (type == 6) return {c, r};\n    return {N - 1 - c, N - 1 - r};\n}\n\nSolution makeCycleSolution() {\n    vector<pair<int, int>> base;\n\n    for (int i = 0; i < N; ++i) base.push_back({i, 0});\n\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) base.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) base.push_back({i, j});\n        }\n    }\n\n    for (int j = N - 1; j >= 1; --j) base.push_back({0, j});\n\n    long long bestCost = INFLL;\n    vector<int> bestCycle;\n    int bestStart = -1;\n\n    for (int type = 0; type < 8; ++type) {\n        vector<int> cyc;\n        cyc.reserve(V);\n\n        for (auto [r, c] : base) {\n            auto [nr, nc] = transformCoord(r, c, type);\n            cyc.push_back(cell_id(nr, nc));\n        }\n\n        for (int rev = 0; rev < 2; ++rev) {\n            if (rev) reverse(cyc.begin(), cyc.end());\n\n            for (int s = 0; s < V; ++s) {\n                long long load = 0;\n                long long cost = BASE_COST + 100LL * DIST[0][cyc[s]];\n                bool ok = true;\n\n                for (int k = 0; k < V; ++k) {\n                    int id = cyc[(s + k) % V];\n                    load += H[id];\n\n                    if (load < 0) {\n                        ok = false;\n                        break;\n                    }\n\n                    if (k + 1 < V) {\n                        int nxt = cyc[(s + k + 1) % V];\n                        cost += 1LL * DIST[id][nxt] * (100 + load);\n                    }\n                }\n\n                if (ok && cost < bestCost) {\n                    bestCost = cost;\n                    bestCycle = cyc;\n                    bestStart = s;\n                }\n            }\n\n            if (rev) reverse(cyc.begin(), cyc.end());\n        }\n    }\n\n    Solution sol;\n\n    if (bestStart < 0) {\n        sol.valid = false;\n        return sol;\n    }\n\n    sol.moveTo(bestCycle[bestStart]);\n\n    for (int k = 0; k < V; ++k) {\n        int id = bestCycle[(bestStart + k) % V];\n\n        if (H[id] > 0) sol.addLoad(H[id]);\n        else if (H[id] < 0) sol.addUnload(-H[id]);\n\n        if (k + 1 < V) {\n            int nxt = bestCycle[(bestStart + k + 1) % V];\n            sol.moveTo(nxt);\n        }\n    }\n\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int inputN;\n    cin >> inputN;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> H[cell_id(i, j)];\n        }\n    }\n\n    for (int a = 0; a < V; ++a) {\n        int ar = a / N;\n        int ac = a % N;\n\n        for (int b = 0; b < V; ++b) {\n            int br = b / N;\n            int bc = b % N;\n            DIST[a][b] = abs(ar - br) + abs(ac - bc);\n        }\n    }\n\n    for (int i = 0; i < V; ++i) BASE_COST += abs(H[i]);\n\n    if (BASE_COST == 0) {\n        return 0;\n    }\n\n    Solution best;\n    best.cost = INFLL;\n    best.valid = false;\n\n    auto consider = [&](Solution&& sol) {\n        if (!sol.valid) return;\n        if (sol.load != 0) return;\n        if (sol.ops.size() > 100000) return;\n\n        if (!best.valid || sol.cost < best.cost) {\n            best = std::move(sol);\n        }\n    };\n\n    // Original greedy candidates.\n    vector<int> maxLoads = {0, 120, 250, 500};\n    vector<pair<int, int>> ratios = {{1, 1}, {3, 2}, {2, 1}};\n    vector<int> sourceModes = {0, 2};\n    vector<int> demandModes = {0, 1, 2};\n\n    for (int ml : maxLoads) {\n        for (auto [rn, rd] : ratios) {\n            if (ml == 0 && !(rn == 1 && rd == 1)) continue;\n\n            for (int sm : sourceModes) {\n                for (int dm : demandModes) {\n                    consider(makeGreedySolution(ml, rn, rd, sm, dm));\n                }\n            }\n        }\n    }\n\n    // Opportunistic path-servicing greedy candidates.\n    vector<int> caps = {120, 250, 500, 1000000000};\n\n    for (int cap : caps) {\n        for (auto [rn, rd] : ratios) {\n            for (int sm : sourceModes) {\n                for (int dm : {0, 1}) {\n                    consider(makeGreedyServiceSolution(cap, rn, rd, sm, dm, 2));\n                }\n            }\n        }\n    }\n\n    // A few deterministic path variants.\n    for (int pm : {0, 1}) {\n        consider(makeGreedyServiceSolution(250, 3, 2, 2, 1, pm));\n        consider(makeGreedyServiceSolution(500, 3, 2, 2, 1, pm));\n    }\n\n    // Transportation-flow based candidates.\n    for (int variant = 0; variant < 3; ++variant) {\n        vector<Flow> flows = computeMinCostFlows(variant);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // Greedy transportation variants.\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<Flow> flows = computeGreedyFlows(mode);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // New: aggregated adjacent-edge min-cost flow with chained execution.\n    for (int variant = 0; variant < 5; ++variant) {\n        consider(makeGridRelaySolution(variant));\n    }\n\n    // Hamiltonian fallback/candidate.\n    consider(makeCycleSolution());\n\n    for (const string& s : best.ops) {\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, T;\n    int S, G;\n    int MAXV;\n\n    vector<vector<int>> X;\n    vector<int> initMax;\n\n    vector<vector<int>> neigh;\n    vector<int> degSlot;\n    vector<pair<int,int>> gridEdges;\n    vector<int> posOrder;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, int T_, const vector<vector<int>>& X_)\n        : N(N_), M(M_), T(T_), X(X_), rng(123456789) {\n        S = 2 * N * (N - 1);\n        G = N * N;\n        MAXV = M * 100;\n\n        initMax.assign(M, 1);\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n            initMax[l] = max(1, mx);\n        }\n\n        build_grid_info();\n    }\n\n    void build_grid_info() {\n        neigh.assign(S, {});\n        degSlot.assign(S, 0);\n        gridEdges.clear();\n\n        auto id = [&](int i, int j) { return i * N + j; };\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = id(i, j);\n                if (j + 1 < N) {\n                    int q = id(i, j + 1);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    gridEdges.push_back({p, q});\n                }\n                if (i + 1 < N) {\n                    int q = id(i + 1, j);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    gridEdges.push_back({p, q});\n                }\n            }\n        }\n\n        for (int p = 0; p < S; p++) degSlot[p] = (int)neigh[p].size();\n\n        posOrder.resize(G);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            if (degSlot[a] != degSlot[b]) return degSlot[a] > degSlot[b];\n\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n            double ca = (ai - (N - 1) / 2.0) * (ai - (N - 1) / 2.0)\n                      + (aj - (N - 1) / 2.0) * (aj - (N - 1) / 2.0);\n            double cb = (bi - (N - 1) / 2.0) * (bi - (N - 1) / 2.0)\n                      + (bj - (N - 1) / 2.0) * (bj - (N - 1) / 2.0);\n            return ca < cb;\n        });\n    }\n\n    inline double PW(const vector<double>& pairW, int a, int b) const {\n        return pairW[a * S + b];\n    }\n\n    double objective(\n        const vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        double ret = 0.0;\n\n        for (int p = 0; p < G; p++) {\n            ret += nodeCoef * degSlot[p] * nodeW[slotSeed[p]];\n        }\n\n        for (auto [p, q] : gridEdges) {\n            ret += PW(pairW, slotSeed[p], slotSeed[q]);\n        }\n\n        return ret;\n    }\n\n    double swap_delta(\n        const vector<int>& slotSeed,\n        int p,\n        int q,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        if (p == q) return 0.0;\n\n        int a = slotSeed[p];\n        int b = slotSeed[q];\n\n        double delta = 0.0;\n\n        delta += nodeCoef * degSlot[p] * (nodeW[b] - nodeW[a]);\n        delta += nodeCoef * degSlot[q] * (nodeW[a] - nodeW[b]);\n\n        for (int r : neigh[p]) {\n            if (r == q) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, b, c) - PW(pairW, a, c);\n        }\n\n        for (int r : neigh[q]) {\n            if (r == p) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, a, c) - PW(pairW, b, c);\n        }\n\n        return delta;\n    }\n\n    double local_search(\n        vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        int maxIter\n    ) const {\n        double cur = objective(slotSeed, pairW, nodeW, nodeCoef);\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            double bestD = 1e-9;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < S; p++) {\n                for (int q = p + 1; q < S; q++) {\n                    if (degSlot[p] == 0 && degSlot[q] == 0) continue;\n\n                    double d = swap_delta(slotSeed, p, q, pairW, nodeW, nodeCoef);\n                    if (d > bestD) {\n                        bestD = d;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur += bestD;\n        }\n\n        return cur;\n    }\n\n    vector<int> make_sorted_initial(const vector<double>& key, bool shuffleGrid) {\n        vector<int> seeds(S);\n        iota(seeds.begin(), seeds.end(), 0);\n\n        sort(seeds.begin(), seeds.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> slotSeed(S, -1);\n\n        for (int k = 0; k < G; k++) {\n            slotSeed[posOrder[k]] = seeds[k];\n        }\n        for (int k = G; k < S; k++) {\n            slotSeed[k] = seeds[k];\n        }\n\n        if (shuffleGrid) {\n            vector<int> planted;\n            for (int p = 0; p < G; p++) planted.push_back(slotSeed[p]);\n            shuffle(planted.begin(), planted.end(), rng);\n            for (int p = 0; p < G; p++) slotSeed[p] = planted[p];\n        }\n\n        return slotSeed;\n    }\n\n    vector<int> make_greedy_initial(\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        double noiseAmp\n    ) {\n        vector<int> slotSeed(S, -1);\n        vector<char> used(S, 0);\n\n        uniform_real_distribution<double> dist(-noiseAmp, noiseAmp);\n\n        for (int p : posOrder) {\n            int best = -1;\n            double bestScore = -1e100;\n\n            for (int s = 0; s < S; s++) {\n                if (used[s]) continue;\n\n                double sc = nodeCoef * degSlot[p] * nodeW[s];\n\n                for (int r : neigh[p]) {\n                    if (r < G && slotSeed[r] != -1) {\n                        sc += PW(pairW, s, slotSeed[r]);\n                    }\n                }\n\n                if (noiseAmp > 0) sc += dist(rng);\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = s;\n                }\n            }\n\n            slotSeed[p] = best;\n            used[best] = 1;\n        }\n\n        int out = G;\n        for (int s = 0; s < S; s++) {\n            if (!used[s]) slotSeed[out++] = s;\n        }\n\n        return slotSeed;\n    }\n\n    void compute_node_info(\n        int turn,\n        vector<int>& val,\n        vector<double>& nodeW,\n        vector<double>& criticalKey\n    ) const {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n\n        val.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) val[i] += X[i][l];\n        }\n\n        vector<double> rankBonus(S, 0.0);\n        vector<int> curMax(M, 1);\n\n        static const double rw[10] = {\n            260.0, 160.0, 100.0, 60.0, 36.0,\n            22.0, 14.0, 9.0, 6.0, 4.0\n        };\n\n        double rankScale = 1.15 - 0.25 * prog;\n\n        for (int l = 0; l < M; l++) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                return a < b;\n            });\n\n            curMax[l] = max(1, X[ids[0]][l]);\n\n            for (int r = 0; r < min(10, S); r++) {\n                int id = ids[r];\n                double frac0 = (double)X[id][l] / initMax[l];\n                double frac1 = (double)X[id][l] / curMax[l];\n                double frac = 0.6 * frac0 + 0.4 * frac1;\n                rankBonus[id] += rankScale * rw[r] * frac;\n            }\n\n            int second = X[ids[min(1, S - 1)]][l];\n            int gap = X[ids[0]][l] - second;\n            rankBonus[ids[0]] += (1.0 - 0.3 * prog) * 3.0 * gap;\n        }\n\n        nodeW.assign(S, 0.0);\n        criticalKey.assign(S, 0.0);\n\n        double quadCoef = 0.85 - 0.30 * prog;\n\n        for (int i = 0; i < S; i++) {\n            double quad = 0.0;\n            for (int l = 0; l < M; l++) {\n                quad += (double)X[i][l] * X[i][l] / initMax[l];\n            }\n\n            nodeW[i] = val[i] + quadCoef * quad + rankBonus[i];\n            criticalKey[i] = nodeW[i] + 0.75 * rankBonus[i];\n        }\n    }\n\n    vector<double> build_pair_quantile(double beta, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double mean = 0.5 * (ysum[i] + ysum[j]);\n                double var = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double d = a - b;\n                    var += 0.25 * d * d;\n                    pot += max(a, b);\n                }\n\n                double sd = sqrt(max(0.0, var));\n                double w = (1.0 - potCoef) * (mean + beta * sd) + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    vector<double> build_pair_ce(double tau, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double ce = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double mx = max(a, b);\n                    double diff = fabs(a - b);\n\n                    ce += mx + tau * log(0.5 * (1.0 + exp(-diff / tau)));\n                    pot += mx;\n                }\n\n                double w = (1.0 - potCoef) * ce + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    void build_raw_pair_stats(\n        const vector<int>& val,\n        vector<double>& mu,\n        vector<double>& sd\n    ) const {\n        mu.assign(S * S, 0.0);\n        sd.assign(S * S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            mu[i * S + i] = val[i];\n            sd[i * S + i] = 0.0;\n\n            for (int j = i + 1; j < S; j++) {\n                double m = 0.5 * (val[i] + val[j]);\n                double var = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double d = X[i][l] - X[j][l];\n                    var += 0.25 * d * d;\n                }\n\n                double s = sqrt(max(0.0, var));\n\n                mu[i * S + j] = mu[j * S + i] = m;\n                sd[i * S + j] = sd[j * S + i] = s;\n            }\n        }\n    }\n\n    static inline double normal_cdf(double z) {\n        if (z < -8.0) return 0.0;\n        if (z > 8.0) return 1.0;\n        return 0.5 * erfc(-z * 0.70710678118654752440);\n    }\n\n    double approx_expected_max_normal(\n        const vector<int>& slotSeed,\n        const vector<double>& mu,\n        const vector<double>& sd\n    ) const {\n        const int STEP = 5;\n        double ret = 0.0;\n\n        for (int s = 0; s < MAXV; s += STEP) {\n            double prod = 1.0;\n\n            for (auto [p, q] : gridEdges) {\n                int a = slotSeed[p];\n                int b = slotSeed[q];\n                double m = mu[a * S + b];\n                double sig = sd[a * S + b];\n\n                double cdf;\n                if (sig < 1e-9) {\n                    cdf = (m <= s ? 1.0 : 0.0);\n                } else {\n                    cdf = normal_cdf((s + 0.5 - m) / sig);\n                }\n\n                prod *= cdf;\n                if (prod <= 1e-15) {\n                    prod = 0.0;\n                    break;\n                }\n            }\n\n            ret += (1.0 - prod) * STEP;\n        }\n\n        return ret;\n    }\n\n    double coord_max_expectation(const vector<int>& slotSeed) const {\n        double total = 0.0;\n\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n\n            for (int th = 1; th <= mx; th++) {\n                double prod = 1.0;\n\n                for (auto [p, q] : gridEdges) {\n                    int a = X[slotSeed[p]][l];\n                    int b = X[slotSeed[q]][l];\n\n                    int ge = 0;\n                    if (a >= th) ge++;\n                    if (b >= th) ge++;\n\n                    double pLess = 1.0 - 0.5 * ge;\n\n                    if (pLess <= 0.0) {\n                        prod = 0.0;\n                        break;\n                    }\n\n                    prod *= pLess;\n                    if (prod <= 1e-15) {\n                        prod = 0.0;\n                        break;\n                    }\n                }\n\n                total += 1.0 - prod;\n            }\n        }\n\n        return total;\n    }\n\n    vector<float> build_pair_cdf() const {\n        int L = MAXV + 1;\n        vector<float> cdf(S * S * L, 0.0f);\n\n        vector<double> dp(L, 0.0), ndp(L, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i; j < S; j++) {\n                fill(dp.begin(), dp.end(), 0.0);\n                dp[0] = 1.0;\n\n                int curMaxSum = 0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = X[i][l];\n                    int b = X[j][l];\n                    int nxtMaxSum = curMaxSum + max(a, b);\n\n                    fill(ndp.begin(), ndp.begin() + nxtMaxSum + 1, 0.0);\n\n                    if (a == b) {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            ndp[s + a] += dp[s];\n                        }\n                    } else {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            double p = 0.5 * dp[s];\n                            ndp[s + a] += p;\n                            ndp[s + b] += p;\n                        }\n                    }\n\n                    dp.swap(ndp);\n                    curMaxSum = nxtMaxSum;\n                }\n\n                int idx1 = (i * S + j) * L;\n                int idx2 = (j * S + i) * L;\n\n                double cum = 0.0;\n                for (int s = 0; s <= MAXV; s++) {\n                    if (s <= curMaxSum) cum += dp[s];\n                    if (cum < 0.0) cum = 0.0;\n                    if (cum > 1.0) cum = 1.0;\n\n                    float v = (float)cum;\n                    cdf[idx1 + s] = v;\n                    cdf[idx2 + s] = v;\n                }\n            }\n        }\n\n        return cdf;\n    }\n\n    vector<double> build_pair_tail(\n        const vector<float>& cdf,\n        int threshold,\n        double scale\n    ) const {\n        int L = MAXV + 1;\n        vector<double> pairW(S * S, 0.0);\n\n        int start = max(0, threshold - 1);\n        if (start >= MAXV) return pairW;\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                int idx = (i * S + j) * L;\n\n                double tail = 0.0;\n                for (int s = start; s < MAXV; s++) {\n                    double f = cdf[idx + s];\n                    if (f < 0.0) f = 0.0;\n                    if (f > 1.0) f = 1.0;\n                    tail += 1.0 - f;\n                }\n\n                tail *= scale;\n\n                pairW[i * S + j] = pairW[j * S + i] = tail;\n            }\n        }\n\n        return pairW;\n    }\n\n    double exact_expected_max(\n        const vector<int>& slotSeed,\n        const vector<float>& cdf\n    ) const {\n        int L = MAXV + 1;\n        vector<double> prod(MAXV, 1.0);\n\n        for (auto [p, q] : gridEdges) {\n            int a = slotSeed[p];\n            int b = slotSeed[q];\n            int idx = (a * S + b) * L;\n\n            for (int s = 0; s < MAXV; s++) {\n                double f = cdf[idx + s];\n                if (f < 0.0) f = 0.0;\n                if (f > 1.0) f = 1.0;\n                prod[s] *= f;\n            }\n        }\n\n        double ret = 0.0;\n        for (int s = 0; s < MAXV; s++) {\n            ret += 1.0 - prod[s];\n        }\n\n        return ret;\n    }\n\n    vector<vector<int>> solve_turn(int turn) {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n        bool isFinal = (turn == T - 1);\n\n        vector<int> val;\n        vector<double> nodeW, criticalKey;\n        compute_node_info(turn, val, nodeW, criticalKey);\n\n        vector<double> valKey(S);\n        for (int i = 0; i < S; i++) valKey[i] = val[i];\n\n        vector<double> rawMu, rawSd;\n        build_raw_pair_stats(val, rawMu, rawSd);\n\n        double masterNodeCoef = max(0.09, 0.19 - 0.07 * prog);\n        if (isFinal) masterNodeCoef *= 0.55;\n\n        vector<double> masterPairW =\n            build_pair_quantile(\n                1.55 + 0.45 * prog,\n                0.12 + 0.10 * prog,\n                0.16 * (1.0 - prog)\n            );\n\n        vector<float> finalCDF;\n        if (isFinal) finalCDF = build_pair_cdf();\n\n        struct Work {\n            vector<double> pairW;\n            double nodeCoef;\n            int iter;\n        };\n\n        vector<Work> works;\n\n        works.push_back(Work{\n            masterPairW,\n            masterNodeCoef,\n            isFinal ? 90 : 105\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                50.0 - 20.0 * prog,\n                0.06 + 0.17 * prog,\n                0.0\n            ),\n            (isFinal ? 0.07 : max(0.11, 0.22 - 0.07 * prog)),\n            isFinal ? 75 : 85\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                2.00 + 0.45 * prog,\n                0.18 + 0.12 * prog,\n                0.10 * (1.0 - prog)\n            ),\n            (isFinal ? 0.055 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 80\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                1.05 + 0.25 * prog,\n                0.38,\n                0.20 * (1.0 - prog)\n            ),\n            (isFinal ? 0.06 : max(0.09, 0.18 - 0.05 * prog)),\n            isFinal ? 70 : 75\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                24.0 - 10.0 * prog,\n                0.08 + 0.12 * prog,\n                0.15 * (1.0 - prog)\n            ),\n            (isFinal ? 0.05 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 75\n        });\n\n        if (turn >= T - 3) {\n            works.push_back(Work{\n                build_pair_quantile(\n                    2.35 + 0.35 * prog,\n                    0.26,\n                    0.0\n                ),\n                isFinal ? 0.04 : 0.08,\n                isFinal ? 80 : 70\n            });\n        }\n\n        if (isFinal) {\n            works.push_back(Work{\n                build_pair_ce(14.0, 0.18, 0.0),\n                0.04,\n                80\n            });\n            works.push_back(Work{\n                build_pair_ce(9.0, 0.24, 0.0),\n                0.035,\n                80\n            });\n\n            int bestNow = 0;\n            for (int v : val) bestNow = max(bestNow, v);\n\n            vector<int> thresholds = {\n                bestNow - 30,\n                bestNow,\n                bestNow + 25,\n                bestNow + 50\n            };\n\n            for (int th : thresholds) {\n                works.push_back(Work{\n                    build_pair_tail(finalCDF, th, 10.0),\n                    0.02,\n                    85\n                });\n            }\n        }\n\n        double bestScore = -1e100;\n        vector<int> bestSlotSeed;\n\n        auto eval_candidate = [&](const vector<int>& slotSeed) -> double {\n            if (isFinal) {\n                return exact_expected_max(slotSeed, finalCDF);\n            } else {\n                double edgeObj = objective(slotSeed, masterPairW, nodeW, masterNodeCoef);\n                double geneObj = coord_max_expectation(slotSeed);\n                double maxObj = approx_expected_max_normal(slotSeed, rawMu, rawSd);\n\n                double geneLambda = 22.0 - 10.0 * prog;\n                double maxLambda = 13.0 + 10.0 * prog;\n\n                return edgeObj + geneLambda * geneObj + maxLambda * maxObj;\n            }\n        };\n\n        auto process = [&](vector<int> start, const Work& w) {\n            local_search(start, w.pairW, nodeW, w.nodeCoef, w.iter);\n            double sc = eval_candidate(start);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestSlotSeed = start;\n            }\n        };\n\n        uniform_real_distribution<double> noise(-1.0, 1.0);\n\n        for (int wi = 0; wi < (int)works.size(); wi++) {\n            const Work& w = works[wi];\n\n            if (wi == 0) {\n                process(make_sorted_initial(nodeW, false), w);\n                process(make_sorted_initial(valKey, false), w);\n                process(make_sorted_initial(criticalKey, false), w);\n                process(make_sorted_initial(criticalKey, true), w);\n            }\n\n            if (wi == 1) {\n                process(make_sorted_initial(nodeW, false), w);\n            }\n\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 0.0), w);\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 38.0 + 13.0 * wi), w);\n\n            if (wi < 5) {\n                vector<double> key = criticalKey;\n                double amp = 55.0 + 25.0 * wi;\n                for (int i = 0; i < S; i++) key[i] += amp * noise(rng);\n                process(make_sorted_initial(key, wi % 2), w);\n            }\n        }\n\n        if (bestSlotSeed.empty()) {\n            bestSlotSeed = make_sorted_initial(valKey, false);\n        }\n\n        vector<vector<int>> A(N, vector<int>(N));\n\n        for (int p = 0; p < G; p++) {\n            A[p / N][p % N] = bestSlotSeed[p];\n        }\n\n        return A;\n    }\n\n    void update_X(const vector<vector<int>>& nx) {\n        X = nx;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n\n    int S = 2 * N * (N - 1);\n    vector<vector<int>> X(S, vector<int>(M));\n\n    for (int i = 0; i < S; i++) {\n        for (int l = 0; l < M; l++) cin >> X[i][l];\n    }\n\n    Solver solver(N, M, T, X);\n\n    for (int t = 0; t < T; t++) {\n        auto A = solver.solve_turn(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << A[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        vector<vector<int>> nx(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                if (!(cin >> nx[i][l])) return 0;\n            }\n        }\n\n        solver.update_X(nx);\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\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 Assignment {\n    int f;\n    int dir;\n    int cell;\n};\n\nstruct Estimate {\n    int cnt = 0;\n    int maxrot = 0;\n    int pairCnt = 0;\n};\n\nstruct Choice {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct NextMove {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nstruct PlanResult {\n    int Vp = 0;\n    vector<int> parent;\n    vector<int> edgeLen;\n    int initX = 0, initY = 0;\n    vector<string> ops;\n    long long score = (1LL << 60);\n    bool complete = false;\n    bool valid = false;\n    int remT = 0;\n};\n\nclass StarPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    vector<int> outLen;\n    vector<int> len;\n    vector<int> dir;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    StarPlanner(int N_, int V_,\n                const vector<unsigned char>& src0,\n                const vector<unsigned char>& tgt0,\n                const vector<int>& lengths,\n                int scoreMode_,\n                int strategy_,\n                double pairBonus_)\n        : N(N_), Vp(V_), k(V_ - 1), C(N_ * N_),\n          outLen(lengths),\n          len(V_, 0), dir(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_), pairBonus(pairBonus_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 1; i <= k; i++) len[i] = lengths[i - 1];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else runHybrid();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n        for (int i = 1; i < Vp; i++) {\n            res.parent[i] = 0;\n            res.edgeLen[i] = outLen[i - 1];\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int f, int d) const {\n        int x = rootX + DX[d] * len[f];\n        int y = rootY + DY[d] * len[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        return cellAt(rx, ry, f, dir[f]);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    Estimate estimateAtRoot(int x, int y, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int r = rotDist(dir[f], d);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) {\n            return (travel + 0.3) / cnt + 0.002 * dist;\n        } else {\n            return travel - 1.5 * (cnt - 1) + 0.01 * dist;\n        }\n    }\n\n    Choice findBestRoot(int mode) {\n        Choice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, mode);\n                if (e.cnt == 0) continue;\n\n                int dist = abs(rx - x) + abs(ry - y);\n                int travel = max(dist, max(e.maxrot, 1));\n                double sc = rootScore(travel, e.cnt, dist);\n                sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                if (!best.exists ||\n                    sc < best.score - 1e-12 ||\n                    (fabs(sc - best.score) < 1e-12 &&\n                     (e.cnt > best.cnt ||\n                      (e.cnt == best.cnt && travel < best.travel)))) {\n                    best.exists = true;\n                    best.x = x;\n                    best.y = y;\n                    best.score = sc;\n                    best.cnt = e.cnt;\n                    best.travel = travel;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, PICK);\n                if (e.cnt == 0) continue;\n\n                int travel = max(e.maxrot, 1);\n                int center = abs(x - N / 2) + abs(y - N / 2);\n                double sc = (travel + 0.3) / e.cnt\n                            - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                            + 0.0005 * center;\n\n                if (sc < bestScore - 1e-12 ||\n                    (fabs(sc - bestScore) < 1e-12 &&\n                     (e.cnt > bestCnt ||\n                      (e.cnt == bestCnt && center < bestCenter)))) {\n                    bestScore = sc;\n                    bestCnt = e.cnt;\n                    bestCenter = center;\n                    rx = x;\n                    ry = y;\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int mode) {\n        struct Edge {\n            int cellIdx;\n            int dir;\n            int rot;\n        };\n\n        vector<int> fingers;\n        vector<vector<Edge>> edges;\n        vector<int> cells;\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                edges[li].push_back({tmpIndex[cid], d, rotDist(dir[f], d)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const Edge& a, const Edge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> order(L);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return edges[a].size() < edges[b].size();\n        });\n\n        vector<int> matchCell(R, -1), matchDir(R, -1);\n        vector<unsigned char> seen(R);\n\n        function<bool(int)> dfs = [&](int li) -> bool {\n            for (const Edge& e : edges[li]) {\n                if (seen[e.cellIdx]) continue;\n                seen[e.cellIdx] = 1;\n\n                if (matchCell[e.cellIdx] == -1 || dfs(matchCell[e.cellIdx])) {\n                    matchCell[e.cellIdx] = li;\n                    matchDir[e.cellIdx] = e.dir;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int li : order) {\n            if (edges[li].empty()) continue;\n            fill(seen.begin(), seen.end(), 0);\n            dfs(li);\n        }\n\n        vector<Assignment> assigns;\n        for (int ci = 0; ci < R; ci++) {\n            if (matchCell[ci] == -1) continue;\n            int li = matchCell[ci];\n            assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n        }\n\n        sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n            return a.f < b.f;\n        });\n\n        return assigns;\n    }\n\n    NextMove fallbackNext(int mode) {\n        NextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 1; f <= k; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int d = 0; d < 4; d++) {\n                    int tx = cx - DX[d] * len[f];\n                    int ty = cy - DY[d] * len[f];\n                    if (!inside(tx, ty)) continue;\n\n                    int md = abs(rx - tx) + abs(ry - ty);\n                    int travel = max(md, max(rotDist(dir[f], d), 1));\n                    double sc = travel;\n\n                    if (!best.exists || sc < best.score) {\n                        best.exists = true;\n                        best.x = tx;\n                        best.y = ty;\n                        best.score = sc;\n                        best.assigns = {Assignment{f, d, cid}};\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    NextMove makeNext(int mode, const Choice& ch) {\n        NextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    NextMove chooseNext(int mode) {\n        return makeNext(mode, findBestRoot(mode));\n    }\n\n    int potentialForRoot(int nx, int ny,\n                         const vector<unsigned char>& selected,\n                         const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        int cnt = 0;\n\n        static const int DELTA[3] = {0, 1, 3};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(nx, ny, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                mark[cid] = st;\n                cnt++;\n                break;\n            }\n        }\n\n        return cnt;\n    }\n\n    char chooseMoveChar(int tx, int ty,\n                        const vector<unsigned char>& selected,\n                        const vector<unsigned char>& reserved) {\n        vector<pair<char, pair<int, int>>> cand;\n\n        if (rx < tx) cand.push_back({'D', {rx + 1, ry}});\n        if (rx > tx) cand.push_back({'U', {rx - 1, ry}});\n        if (ry < ty) cand.push_back({'R', {rx, ry + 1}});\n        if (ry > ty) cand.push_back({'L', {rx, ry - 1}});\n\n        if (cand.empty()) return '.';\n        if (cand.size() == 1) return cand[0].first;\n\n        int bestPot = -1;\n        char bestChar = cand[0].first;\n        int bestDimRemain = -1;\n\n        for (auto& c : cand) {\n            int pot = potentialForRoot(c.second.first, c.second.second, selected, reserved);\n            bool vertical = (c.first == 'U' || c.first == 'D');\n            int dimRemain = vertical ? abs(tx - rx) : abs(ty - ry);\n\n            if (pot > bestPot || (pot == bestPot && dimRemain > bestDimRemain)) {\n                bestPot = pot;\n                bestChar = c.first;\n                bestDimRemain = dimRemain;\n            }\n        }\n\n        return bestChar;\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenDir = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(rx, ry, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenDir = nd;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                dir[f] = chosenDir;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 1; f <= k; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetDir(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxrot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetDir[a.f] = a.dir;\n            reserved[a.cell] = 1;\n            maxrot = max(maxrot, rotDist(dir[a.f], a.dir));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max(md, max(maxrot, 1));\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty, selected, reserved);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (dir[f] != targetDir[f]) {\n                    char rc = rotateStep(dir[f], targetDir[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (dir[a.f] != a.dir) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                NextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                NextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) {\n                mode = PICK;\n            } else {\n                mode = DROP;\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n};\n\nstruct PChoice {\n    bool exists = false;\n    int x = 0, y = 0, sdir = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct PNextMove {\n    bool exists = false;\n    int x = 0, y = 0, sdir = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nclass PalmPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    int A;\n    vector<int> leafLen;\n\n    int sd = 0;\n    vector<int> rel;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus = 0.25;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    PalmPlanner(int N_, int V_,\n                const vector<unsigned char>& src0,\n                const vector<unsigned char>& tgt0,\n                int A_,\n                const vector<int>& lengths,\n                int scoreMode_,\n                int strategy_)\n        : N(N_), Vp(V_), k(V_ - 2), C(N_ * N_),\n          A(A_), leafLen(V_, 0), rel(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 0; i < k; i++) leafLen[i + 2] = lengths[i];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else runHybrid();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n\n        res.parent[1] = 0;\n        res.edgeLen[1] = A;\n        for (int f = 2; f < Vp; f++) {\n            res.parent[f] = 1;\n            res.edgeLen[f] = leafLen[f];\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int shoulderDir, int f, int absDir) const {\n        int x = rootX + DX[shoulderDir] * A + DX[absDir] * leafLen[f];\n        int y = rootY + DY[shoulderDir] * A + DY[absDir] * leafLen[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        int ad = (sd + rel[f]) & 3;\n        return cellAt(rx, ry, sd, f, ad);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    Estimate estimateAtState(int x, int y, int sdir, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 2; f < Vp; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int ad = 0; ad < 4; ad++) {\n                int cid = cellAt(x, y, sdir, f, ad);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int tr = (ad - sdir + 4) & 3;\n                int r = rotDist(rel[f], tr);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) return (travel + 0.3) / cnt + 0.002 * dist;\n        return travel - 1.4 * (cnt - 1) + 0.01 * dist;\n    }\n\n    PChoice findBestState(int mode) {\n        PChoice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    Estimate e = estimateAtState(x, y, sdir, mode);\n                    if (e.cnt == 0) continue;\n\n                    int dist = abs(rx - x) + abs(ry - y);\n                    int travel = max({dist, rotDist(sd, sdir), e.maxrot, 1});\n                    double sc = rootScore(travel, e.cnt, dist + rotDist(sd, sdir));\n                    sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                    if (!best.exists ||\n                        sc < best.score - 1e-12 ||\n                        (fabs(sc - best.score) < 1e-12 &&\n                         (e.cnt > best.cnt ||\n                          (e.cnt == best.cnt && travel < best.travel)))) {\n                        best.exists = true;\n                        best.x = x;\n                        best.y = y;\n                        best.sdir = sdir;\n                        best.score = sc;\n                        best.cnt = e.cnt;\n                        best.travel = travel;\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    Estimate e = estimateAtState(x, y, sdir, PICK);\n                    if (e.cnt == 0) continue;\n\n                    int travel = max({rotDist(0, sdir), e.maxrot, 1});\n                    int center = abs(x - N / 2) + abs(y - N / 2);\n                    double sc = (travel + 0.3) / e.cnt\n                                - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                                + 0.0005 * center;\n\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) < 1e-12 &&\n                         (e.cnt > bestCnt ||\n                          (e.cnt == bestCnt && center < bestCenter)))) {\n                        bestScore = sc;\n                        bestCnt = e.cnt;\n                        bestCenter = center;\n                        rx = x;\n                        ry = y;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int sdir, int mode) {\n        struct Edge {\n            int cellIdx;\n            int dir;\n            int rot;\n        };\n\n        vector<int> fingers;\n        vector<vector<Edge>> edges;\n        vector<int> cells;\n\n        for (int f = 2; f < Vp; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int ad = 0; ad < 4; ad++) {\n                int cid = cellAt(x, y, sdir, f, ad);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                int tr = (ad - sdir + 4) & 3;\n                edges[li].push_back({tmpIndex[cid], ad, rotDist(rel[f], tr)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const Edge& a, const Edge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> order(L);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return edges[a].size() < edges[b].size();\n        });\n\n        vector<int> matchCell(R, -1), matchDir(R, -1);\n        vector<unsigned char> seen(R);\n\n        function<bool(int)> dfs = [&](int li) -> bool {\n            for (const Edge& e : edges[li]) {\n                if (seen[e.cellIdx]) continue;\n                seen[e.cellIdx] = 1;\n\n                if (matchCell[e.cellIdx] == -1 || dfs(matchCell[e.cellIdx])) {\n                    matchCell[e.cellIdx] = li;\n                    matchDir[e.cellIdx] = e.dir;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int li : order) {\n            if (edges[li].empty()) continue;\n            fill(seen.begin(), seen.end(), 0);\n            dfs(li);\n        }\n\n        vector<Assignment> assigns;\n        for (int ci = 0; ci < R; ci++) {\n            if (matchCell[ci] == -1) continue;\n            int li = matchCell[ci];\n            assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n        }\n\n        sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n            return a.f < b.f;\n        });\n\n        return assigns;\n    }\n\n    PNextMove fallbackNext(int mode) {\n        PNextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 2; f < Vp; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    for (int ad = 0; ad < 4; ad++) {\n                        int tx = cx - DX[sdir] * A - DX[ad] * leafLen[f];\n                        int ty = cy - DY[sdir] * A - DY[ad] * leafLen[f];\n                        if (!inside(tx, ty)) continue;\n\n                        int tr = (ad - sdir + 4) & 3;\n                        int travel = max({abs(rx - tx) + abs(ry - ty),\n                                          rotDist(sd, sdir),\n                                          rotDist(rel[f], tr),\n                                          1});\n                        double sc = travel;\n\n                        if (!best.exists || sc < best.score) {\n                            best.exists = true;\n                            best.x = tx;\n                            best.y = ty;\n                            best.sdir = sdir;\n                            best.score = sc;\n                            best.assigns = {Assignment{f, ad, cid}};\n                        }\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    PNextMove makeNext(int mode, const PChoice& ch) {\n        PNextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, ch.sdir, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.sdir = ch.sdir;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    PNextMove chooseNext(int mode) {\n        return makeNext(mode, findBestState(mode));\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    char chooseMoveChar(int tx, int ty) {\n        if (rx < tx) return 'D';\n        if (rx > tx) return 'U';\n        if (ry < ty) return 'R';\n        if (ry > ty) return 'L';\n        return '.';\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 2; f < Vp; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenRel = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nr = (rel[f] + DELTA[oi]) & 3;\n                int ad = (sd + nr) & 3;\n                int cid = cellAt(rx, ry, sd, f, ad);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenRel = nr;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                rel[f] = chosenRel;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 2; f < Vp; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, int tsd, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetRel(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxLeafRot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetRel[a.f] = (a.dir - tsd + 4) & 3;\n            reserved[a.cell] = 1;\n            maxLeafRot = max(maxLeafRot, rotDist(rel[a.f], targetRel[a.f]));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max({md, rotDist(sd, tsd), maxLeafRot, 1});\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            if (sd != tsd) {\n                char rc = rotateStep(sd, tsd);\n                cmd[1] = rc;\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (rel[f] != targetRel[f]) {\n                    char rc = rotateStep(rel[f], targetRel[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty || sd != tsd) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (rel[a.f] != targetRel[a.f]) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                PNextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                PNextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            PChoice cp, cd;\n            if (canPick) cp = findBestState(PICK);\n            if (canDrop) cd = findBestState(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) mode = PICK;\n            else mode = DROP;\n\n            PNextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            PChoice cp, cd;\n            if (canPick) cp = findBestState(PICK);\n            if (canDrop) cd = findBestState(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            PNextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\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\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    int C = N * N;\n    vector<unsigned char> src(C, 0), tgt(C, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int cid = i * N + j;\n            if (s[i][j] == '1' && t[i][j] == '0') src[cid] = 1;\n            if (s[i][j] == '0' && t[i][j] == '1') tgt[cid] = 1;\n        }\n    }\n\n    int maxL = max(1, N / 2);\n\n    auto buildLengthSets = [&](int K) {\n        vector<vector<int>> sets;\n\n        auto clampLen = [&](int x) {\n            return max(1, min(maxL, x));\n        };\n\n        auto addSet = [&](vector<int> a) {\n            if ((int)a.size() != K) return;\n            for (int& x : a) x = clampLen(x);\n            for (auto& b : sets) {\n                if (a == b) return;\n            }\n            sets.push_back(a);\n        };\n\n        if (K <= 0) return sets;\n\n        auto cycleSet = [&](int L) {\n            L = max(1, min(L, maxL));\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = 1 + (i % L);\n            return a;\n        };\n\n        auto repeatVals = [&](vector<int> vals) {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = vals[i % vals.size()];\n            return a;\n        };\n\n        addSet(cycleSet(maxL));\n        addSet(cycleSet(6));\n        addSet(cycleSet(4));\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    a[i] = (int)llround(1.0 + (double)i * (maxL - 1) / (K - 1));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                a[i] = (int)llround((i + 0.5) * maxL / K);\n                if (a[i] < 1) a[i] = 1;\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    double r = (double)i / (K - 1);\n                    a[i] = (int)llround(pow((double)maxL, r));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                if (i % 2 == 0) a[i] = 1 + (i / 2) % maxL;\n                else a[i] = maxL - (i / 2) % maxL;\n            }\n            addSet(a);\n        }\n\n        addSet(vector<int>(K, 1));\n        addSet(vector<int>(K, maxL));\n        addSet(vector<int>(K, max(1, maxL / 2)));\n\n        addSet(repeatVals(vector<int>{1, maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 2), maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 3), max(1, 2 * maxL / 3), maxL}));\n        addSet(repeatVals(vector<int>{max(1, maxL / 4), max(1, maxL / 2), max(1, 3 * maxL / 4), maxL}));\n\n        return sets;\n    };\n\n    vector<vector<int>> starLengthSets = buildLengthSets(V - 1);\n\n    auto startTime = chrono::steady_clock::now();\n\n    auto elapsedMs = [&]() {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration_cast<chrono::milliseconds>(now - startTime).count();\n    };\n\n    PlanResult best;\n\n    auto consider = [&](PlanResult&& res) {\n        if (res.valid &&\n            (res.score < best.score ||\n             (res.score == best.score && res.ops.size() < best.ops.size()))) {\n            best = std::move(res);\n        }\n    };\n\n    struct StarParam {\n        int li;\n        int sm;\n        int st;\n        double pb;\n    };\n\n    vector<StarParam> starParams;\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.0});\n\n    int split = (int)starParams.size();\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 1, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 1, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.30});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.30});\n\n    auto runStarRange = [&](int l, int r) {\n        for (int idx = l; idx < r; idx++) {\n            if (idx > l && elapsedMs() > 2760) break;\n\n            auto p = starParams[idx];\n            StarPlanner planner(N, V, src, tgt, starLengthSets[p.li], p.sm, p.st, p.pb);\n            PlanResult res = planner.run();\n            consider(std::move(res));\n        }\n    };\n\n    runStarRange(0, split);\n\n    if (elapsedMs() < 2300 && V >= 5) {\n        int kp = V - 2;\n        vector<vector<int>> palmLengthSets = buildLengthSets(kp);\n        vector<int> As = {\n            maxL,\n            max(1, (2 * maxL + 1) / 3),\n            max(1, maxL / 2)\n        };\n        sort(As.begin(), As.end());\n        As.erase(unique(As.begin(), As.end()), As.end());\n        reverse(As.begin(), As.end());\n\n        int limSets = min(5, (int)palmLengthSets.size());\n        vector<int> palmStrategies = {0, 2, 1};\n\n        for (int A : As) {\n            for (int li = 0; li < limSets; li++) {\n                for (int stg : palmStrategies) {\n                    if (elapsedMs() > 2760) goto palm_done;\n\n                    PalmPlanner planner(N, V, src, tgt, A, palmLengthSets[li], 0, stg);\n                    PlanResult res = planner.run();\n                    consider(std::move(res));\n                }\n            }\n        }\n    }\npalm_done:\n\n    if (elapsedMs() < 2760) {\n        runStarRange(split, (int)starParams.size());\n    }\n\n    if (!best.valid) {\n        best.valid = true;\n        best.Vp = V;\n        best.parent.assign(V, -1);\n        best.edgeLen.assign(V, 0);\n        vector<int> lens = starLengthSets.empty() ? vector<int>(V - 1, 1) : starLengthSets[0];\n\n        for (int i = 1; i < V; i++) {\n            best.parent[i] = 0;\n            best.edgeLen[i] = lens[i - 1];\n        }\n        best.initX = 0;\n        best.initY = 0;\n        best.ops.clear();\n    }\n\n    cout << best.Vp << '\\n';\n    for (int i = 1; i < best.Vp; i++) {\n        cout << best.parent[i] << ' ' << best.edgeLen[i] << '\\n';\n    }\n    cout << best.initX << ' ' << best.initY << '\\n';\n\n    for (const string& op : best.ops) {\n        cout << op << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing ll = long long;\nusing uchar = unsigned char;\n\nconstexpr int CMAX = 100000;\nconstexpr int MAXLEN = 400000;\nconstexpr int MAXV = 1000;\n\nstruct Fish {\n    int x, y, w;\n};\n\nstruct Candidate {\n    int approx;\n    vector<pair<int,int>> poly;\n};\n\nvector<Fish> fishes;\nvector<Candidate> candidates;\nvector<pair<int,int>> bestPoly;\nint bestApprox = -1;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nvector<pair<int,int>> square_poly() {\n    return {{0,0}, {CMAX,0}, {CMAX,CMAX}, {0,CMAX}};\n}\n\nvoid record_candidate(const vector<pair<int,int>>& poly, int approx) {\n    if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return;\n    if (approx < 0) return;\n    if (approx == 0 && bestApprox >= 0) return;\n\n    if (approx > bestApprox) {\n        bestApprox = approx;\n        bestPoly = poly;\n    }\n    candidates.push_back({approx, poly});\n\n    if (candidates.size() > 120) {\n        nth_element(candidates.begin(), candidates.begin() + 80, candidates.end(),\n                    [](const Candidate& a, const Candidate& b) {\n                        return a.approx > b.approx;\n                    });\n        candidates.resize(80);\n    }\n}\n\nbool inside_or_on(const vector<pair<int,int>>& poly, int px, int py) {\n    bool inside = false;\n    int m = (int)poly.size();\n\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n\n        if (x1 == x2) {\n            if (px == x1 && min(y1, y2) <= py && py <= max(y1, y2)) return true;\n            int yl = min(y1, y2), yh = max(y1, y2);\n            if (yl <= py && py < yh && x1 > px) inside = !inside;\n        } else {\n            if (py == y1 && min(x1, x2) <= px && px <= max(x1, x2)) return true;\n        }\n    }\n    return inside;\n}\n\nint exact_score(const vector<pair<int,int>>& poly) {\n    int s = 0;\n    for (const auto& f : fishes) {\n        if (inside_or_on(poly, f.x, f.y)) s += f.w;\n    }\n    return s;\n}\n\nstruct GridSolver {\n    int D, G, maxEdges, ncell;\n    vector<int> w;\n\n    struct Comp {\n        vector<int> cells;\n        int score = 0;\n    };\n\n    struct Eval {\n        int score;\n        int len;\n    };\n\n    GridSolver(int d) : D(d), G(CMAX / d), maxEdges(MAXLEN / d), ncell(G * G), w(ncell, 0) {\n        for (const auto& f : fishes) {\n            int x = f.x / D;\n            int y = f.y / D;\n            if (x >= G) x = G - 1;\n            if (y >= G) y = G - 1;\n            w[idx(x, y)] += f.w;\n        }\n    }\n\n    inline int idx(int x, int y) const {\n        return y * G + x;\n    }\n\n    inline bool in_grid(int x, int y) const {\n        return 0 <= x && x < G && 0 <= y && y < G;\n    }\n\n    int mask_score(const vector<uchar>& mask) const {\n        int s = 0;\n        for (int i = 0; i < ncell; i++) if (mask[i]) s += w[i];\n        return s;\n    }\n\n    int selected_neighbor_count(const vector<uchar>& mask, int x, int y) const {\n        int c = 0;\n        if (x > 0 && mask[idx(x - 1, y)]) c++;\n        if (x + 1 < G && mask[idx(x + 1, y)]) c++;\n        if (y > 0 && mask[idx(x, y - 1)]) c++;\n        if (y + 1 < G && mask[idx(x, y + 1)]) c++;\n        return c;\n    }\n\n    int selected_neighbor_count_id(const vector<uchar>& mask, int v) const {\n        int x = v % G, y = v / G;\n        return selected_neighbor_count(mask, x, y);\n    }\n\n    int boundary_edges(const vector<uchar>& mask) const {\n        int p = 0;\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n                if (x == 0 || !mask[idx(x - 1, y)]) p++;\n                if (x + 1 == G || !mask[idx(x + 1, y)]) p++;\n                if (y == 0 || !mask[idx(x, y - 1)]) p++;\n                if (y + 1 == G || !mask[idx(x, y + 1)]) p++;\n            }\n        }\n        return p;\n    }\n\n    void fix_diagonal(vector<uchar>& mask) const {\n        for (int it = 0; it < 30; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < G; y++) {\n                for (int x = 0; x + 1 < G; x++) {\n                    int a = idx(x, y);\n                    int b = idx(x + 1, y);\n                    int c = idx(x, y + 1);\n                    int d = idx(x + 1, y + 1);\n\n                    bool A = mask[a], B = mask[b], C = mask[c], DD = mask[d];\n\n                    if (A && DD && !B && !C) {\n                        int choose = (w[b] >= w[c] ? b : c);\n                        mask[choose] = 1;\n                        changed = true;\n                    } else if (B && C && !A && !DD) {\n                        int choose = (w[a] >= w[d] ? a : d);\n                        mask[choose] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void fill_holes(vector<uchar>& mask) const {\n        vector<uchar> out(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto push = [&](int x, int y) {\n            int id = idx(x, y);\n            if (!mask[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < G; x++) {\n            push(x, 0);\n            push(x, G - 1);\n        }\n        for (int y = 0; y < G; y++) {\n            push(0, y);\n            push(G - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % G, y = v / G;\n            const int dx[4] = {1, -1, 0, 0};\n            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 (!in_grid(nx, ny)) continue;\n                int ni = idx(nx, ny);\n                if (!mask[ni] && !out[ni]) {\n                    out[ni] = 1;\n                    q.push_back(ni);\n                }\n            }\n        }\n\n        for (int i = 0; i < ncell; i++) {\n            if (!mask[i] && !out[i]) mask[i] = 1;\n        }\n    }\n\n    vector<Comp> find_components(const vector<uchar>& mask, vector<int>* compIdOut = nullptr) const {\n        vector<int> compId(ncell, -1);\n        vector<Comp> comps;\n        vector<int> q;\n        q.reserve(ncell);\n\n        for (int s = 0; s < ncell; s++) {\n            if (!mask[s] || compId[s] != -1) continue;\n\n            int cid = (int)comps.size();\n            comps.push_back(Comp{});\n            compId[s] = cid;\n            q.clear();\n            q.push_back(s);\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                comps[cid].cells.push_back(v);\n                comps[cid].score += w[v];\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n                    int ni = idx(nx, ny);\n                    if (mask[ni] && compId[ni] == -1) {\n                        compId[ni] = cid;\n                        q.push_back(ni);\n                    }\n                }\n            }\n        }\n\n        if (compIdOut) *compIdOut = move(compId);\n        return comps;\n    }\n\n    void trim_leaves(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        vector<uchar> inq(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto maybe_push = [&](int id) {\n            if (!mask[id] || w[id] > 0 || inq[id]) return;\n            if (selected_neighbor_count_id(mask, id) <= 1) {\n                inq[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < ncell; i++) maybe_push(i);\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            inq[v] = 0;\n            if (!mask[v] || w[v] > 0) continue;\n            if (sel <= 1) continue;\n\n            int k = selected_neighbor_count_id(mask, v);\n            if (k <= 1) {\n                mask[v] = 0;\n                sel--;\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (in_grid(nx, ny)) maybe_push(idx(nx, ny));\n                }\n            }\n        }\n    }\n\n    void add_positive_boundary(vector<uchar>& mask) const {\n        int P = boundary_edges(mask);\n\n        for (int it = 0; it < 4; it++) {\n            bool changed = false;\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool extract_polygon(const vector<uchar>& mask, vector<pair<int,int>>& poly) const {\n        int V = (G + 1) * (G + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (G + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n        };\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n\n                if (y == 0 || !mask[idx(x, y - 1)]) set_edge(x, y, x + 1, y);\n                if (x + 1 == G || !mask[idx(x + 1, y)]) set_edge(x + 1, y, x + 1, y + 1);\n                if (y + 1 == G || !mask[idx(x, y + 1)]) set_edge(x + 1, y + 1, x, y + 1);\n                if (x == 0 || !mask[idx(x - 1, y)]) set_edge(x, y + 1, x, y);\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (1LL * edges * D > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n        int cur = start;\n\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int px = pv % (G + 1), py = pv / (G + 1);\n            int cx = cv % (G + 1), cy = cv / (G + 1);\n            int nx = nv % (G + 1), ny = nv / (G + 1);\n\n            int dx1 = cx - px, dy1 = cy - py;\n            int dx2 = nx - cx, dy2 = ny - cy;\n\n            if (dx1 == dx2 && dy1 == dy2) continue;\n\n            poly.push_back({cx * D, cy * D});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    void finalize_candidate(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.90) return;\n\n        bool any = false;\n        for (uchar v : mask) {\n            if (v) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        trim_leaves(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        add_positive_boundary(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n        if (sc == 0 && bestApprox >= 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc);\n    }\n\n    Eval eval_l_path(int src, int dst, bool xFirst,\n                     const vector<uchar>& cur,\n                     int targetCid,\n                     const vector<int>& compId) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        int score = 0, len = 0;\n\n        auto visit = [&](int x, int y) {\n            int id = idx(x, y);\n            len++;\n            if (!cur[id] && compId[id] != targetCid) score += w[id];\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, ty);\n                }\n            }\n        }\n\n        return {score, len};\n    }\n\n    vector<int> build_l_path(int src, int dst, bool xFirst) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        vector<int> res;\n        res.reserve(abs(tx - sx) + abs(ty - sy) + 1);\n\n        auto add = [&](int x, int y) {\n            res.push_back(idx(x, y));\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, ty);\n                }\n            }\n        }\n\n        return res;\n    }\n\n    void greedy_connect(const vector<Comp>& comps,\n                        const vector<int>& compId,\n                        const vector<int>& ids,\n                        int maxAdd,\n                        int compLimit) const {\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> cur(ncell, 0);\n        vector<int> curCells;\n        curCells.reserve(ncell / 4);\n\n        auto add_cell = [&](int cell) {\n            if (!cur[cell]) {\n                cur[cell] = 1;\n                curCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            for (int cell : comps[cid].cells) add_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0])) addedConsidered++;\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c == 1 || c == 2 || c == 3 || c == 5 || c == 8 ||\n                   c == 13 || c == 21 || c == 34;\n        };\n\n        finalize_candidate(cur);\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : curCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                bool xFirst = true;\n                int gain = 0;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1) continue;\n                int src = root[bestCell];\n                if (src < 0) continue;\n\n                Eval e1 = eval_l_path(src, bestCell, true, cur, cid, compId);\n                Eval e2 = eval_l_path(src, bestCell, false, cur, cid, compId);\n\n                bool xf = true;\n                Eval e = e1;\n                if (e2.score > e1.score || (e2.score == e1.score && e2.len < e1.len)) {\n                    e = e2;\n                    xf = false;\n                }\n\n                int gain = comps[cid].score + e.score;\n                if (gain <= 0) continue;\n\n                double metric = (double)gain / (e.len + 5.0) + 0.03 * gain;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = src;\n                    best.dst = bestCell;\n                    best.xFirst = xf;\n                    best.gain = gain;\n                    best.len = e.len;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path = build_l_path(best.src, best.dst, best.xFirst);\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cell : path) add_cell(cell);\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            if (snapshot(addedConsidered)) finalize_candidate(cur);\n\n            if (iter % 3 == 0 && boundary_edges(cur) > maxEdges * 3 / 2) break;\n        }\n\n        finalize_candidate(cur);\n    }\n\n    void process_mask(vector<uchar> mask, int maxAdd, int compLimit) const {\n        if (elapsed_sec() > 1.82) return;\n\n        bool any = false;\n        for (uchar v : mask) {\n            if (v) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        vector<int> compId;\n        vector<Comp> comps = find_components(mask, &compId);\n        if (comps.empty()) return;\n\n        vector<int> ids;\n        for (int i = 0; i < (int)comps.size(); i++) {\n            if (comps[i].score > 0) ids.push_back(i);\n        }\n        if (ids.empty()) return;\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return comps[a].score > comps[b].score;\n        });\n\n        int alone = min(3, (int)ids.size());\n        for (int k = 0; k < alone; k++) {\n            vector<uchar> cur(ncell, 0);\n            for (int cell : comps[ids[k]].cells) cur[cell] = 1;\n            finalize_candidate(cur);\n        }\n\n        if ((int)ids.size() >= 2) {\n            greedy_connect(comps, compId, ids, maxAdd, compLimit);\n        }\n    }\n\n    void run_best_rectangle() const {\n        if (elapsed_sec() > 1.80) return;\n\n        int best = INT_MIN;\n        int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0;\n\n        vector<int> col(G, 0);\n        for (int x1 = 0; x1 < G; x1++) {\n            fill(col.begin(), col.end(), 0);\n\n            for (int x2 = x1; x2 < G; x2++) {\n                for (int y = 0; y < G; y++) col[y] += w[idx(x2, y)];\n\n                int cur = 0, st = 0;\n                for (int y = 0; y < G; y++) {\n                    if (y == 0 || cur <= 0) {\n                        cur = col[y];\n                        st = y;\n                    } else {\n                        cur += col[y];\n                    }\n\n                    if (cur > best) {\n                        best = cur;\n                        bx1 = x1;\n                        bx2 = x2;\n                        by1 = st;\n                        by2 = y;\n                    }\n                }\n            }\n        }\n\n        if (best <= 0) return;\n\n        vector<uchar> mask(ncell, 0);\n        for (int y = by1; y <= by2; y++) {\n            for (int x = bx1; x <= bx2; x++) {\n                mask[idx(x, y)] = 1;\n            }\n        }\n        finalize_candidate(mask);\n    }\n\n    vector<double> gaussian_blur(double sigma) const {\n        int r = max(1, (int)ceil(3.0 * sigma));\n        vector<double> ker(2 * r + 1);\n        double sum = 0.0;\n\n        for (int d = -r; d <= r; d++) {\n            double v = exp(-(double)d * d / (2.0 * sigma * sigma));\n            ker[d + r] = v;\n            sum += v;\n        }\n        for (double& v : ker) v /= sum;\n\n        vector<double> src(ncell), tmp(ncell), out(ncell);\n        for (int i = 0; i < ncell; i++) src[i] = (double)w[i];\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int nx = x + d;\n                    if (0 <= nx && nx < G) s += src[idx(nx, y)] * ker[d + r];\n                }\n                tmp[idx(x, y)] = s;\n            }\n        }\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int ny = y + d;\n                    if (0 <= ny && ny < G) s += tmp[idx(x, ny)] * ker[d + r];\n                }\n                out[idx(x, y)] = s;\n            }\n        }\n\n        return out;\n    }\n\n    void run_smoothing(const vector<double>& sigmas,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime) const {\n        vector<double> ratios = {-0.05, -0.02, 0.0, 0.02, 0.05, 0.10, 0.18, 0.30};\n\n        for (double sigma : sigmas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<double> blur = gaussian_blur(sigma);\n            double mx = *max_element(blur.begin(), blur.end());\n            if (mx <= 1e-12) continue;\n\n            for (double r : ratios) {\n                if (elapsed_sec() > stopTime) return;\n\n                double th = mx * r;\n                vector<uchar> mask(ncell, 0);\n                int cnt = 0;\n\n                for (int i = 0; i < ncell; i++) {\n                    if (blur[i] > th) {\n                        mask[i] = 1;\n                        cnt++;\n                    }\n                }\n\n                if (cnt == 0 || cnt == ncell) continue;\n                process_mask(move(mask), maxAdd, compLimit);\n            }\n        }\n    }\n\n    void run_weight_thresholds(const vector<int>& thresholds,\n                               int maxAdd,\n                               int compLimit,\n                               double stopTime) const {\n        for (int th : thresholds) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask(ncell, 0);\n            int cnt = 0;\n            for (int i = 0; i < ncell; i++) {\n                if (w[i] >= th) {\n                    mask[i] = 1;\n                    cnt++;\n                }\n            }\n            if (cnt == 0) continue;\n            process_mask(move(mask), maxAdd, compLimit);\n        }\n    }\n\n    vector<uchar> graph_cut_mask(int lam, int scale) const {\n        int S = ncell;\n        int T = ncell + 1;\n        atcoder::mf_graph<ll> g(ncell + 2);\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int v = idx(x, y);\n                ll profit = (ll)w[v] * scale;\n\n                if (profit > 0) g.add_edge(S, v, profit);\n                else if (profit < 0) g.add_edge(v, T, -profit);\n\n                int bs = 0;\n                if (x == 0) bs++;\n                if (x + 1 == G) bs++;\n                if (y == 0) bs++;\n                if (y + 1 == G) bs++;\n                if (bs) g.add_edge(v, T, (ll)lam * bs);\n\n                if (x + 1 < G) {\n                    int u = idx(x + 1, y);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n                if (y + 1 < G) {\n                    int u = idx(x, y + 1);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n            }\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n\n        vector<uchar> mask(ncell, 0);\n        for (int i = 0; i < ncell; i++) mask[i] = cut[i] ? 1 : 0;\n        return mask;\n    }\n\n    void run_graph_cut(const vector<int>& lambdas,\n                       int scale,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime) const {\n        for (int lam : lambdas) {\n            if (elapsed_sec() > stopTime) return;\n            vector<uchar> mask = graph_cut_mask(lam, scale);\n            process_mask(move(mask), maxAdd, compLimit);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int N;\n    cin >> N;\n\n    fishes.reserve(2 * N);\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n        int w = (i < N ? 1 : -1);\n        fishes.push_back({x, y, w});\n    }\n\n    bestApprox = -1;\n    record_candidate(square_poly(), 0);\n\n    GridSolver g500(500);\n    g500.run_best_rectangle();\n    g500.run_weight_thresholds(vector<int>{1, 2, 3}, 30, 120, 0.55);\n    g500.run_smoothing(vector<double>{2.0, 3.5, 5.5, 8.0, 12.0}, 18, 90, 1.00);\n\n    if (elapsed_sec() < 1.25) {\n        g500.run_graph_cut(vector<int>{10, 16, 25, 40, 70, 120}, 100, 22, 100, 1.38);\n    }\n\n    if (elapsed_sec() < 1.65) {\n        GridSolver g400(400);\n        g400.run_best_rectangle();\n        g400.run_smoothing(vector<double>{2.5, 4.0, 6.5, 10.0, 14.0}, 14, 80, 1.72);\n    }\n\n    vector<pair<int,int>> output = bestPoly.empty() ? square_poly() : bestPoly;\n\n    if (bestApprox >= 0) candidates.push_back({bestApprox, bestPoly});\n\n    if (elapsed_sec() < 1.82) {\n        sort(candidates.begin(), candidates.end(),\n             [](const Candidate& a, const Candidate& b) {\n                 return a.approx > b.approx;\n             });\n\n        int bestExact = 0;\n        vector<pair<int,int>> exactBest = square_poly();\n\n        int limit = min((int)candidates.size(), 10);\n        bool evaluated = false;\n\n        for (int i = 0; i < limit; i++) {\n            if (elapsed_sec() > 1.94) break;\n\n            int sc = exact_score(candidates[i].poly);\n            evaluated = true;\n\n            if (sc > bestExact) {\n                bestExact = sc;\n                exactBest = candidates[i].poly;\n            }\n        }\n\n        if (evaluated) output = exactBest;\n    }\n\n    cout << output.size() << '\\n';\n    for (auto [x, y] : output) {\n        cout << x << ' ' << y << '\\n';\n    }\n\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectD {\n    double w, h;\n};\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    double estScore = 1e100;\n    double baseW = 0, baseH = 0;\n    uint64_t hash = 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};\n\nstatic constexpr double TRUE_U = 100000.0;\nstatic constexpr double TRUE_L_MIN = 10000.0;\nstatic constexpr double TRUE_L_MAX = 50000.0;\nstatic constexpr double INF = 1e100;\n\nint N, T;\ndouble SIGMA;\nvector<double> sumWObs, sumHObs;\nvector<int> cntWObs, cntHObs;\n\nmt19937_64 rng(123456789);\n\ndouble normal_pdf(double x) {\n    static const double INV_SQRT_2PI = 0.39894228040143267794;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble normal_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble clamp_double(double x, double lo, double hi) {\n    return max(lo, min(hi, x));\n}\n\ndouble truncated_normal_mean(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    double a = (L - obsMean) / sd;\n    double b = (U - obsMean) / sd;\n    double Z = normal_cdf(b) - normal_cdf(a);\n    if (Z < 1e-12) return clamp_double(obsMean, L, U);\n    double m = obsMean + sd * (normal_pdf(a) - normal_pdf(b)) / Z;\n    return clamp_double(m, L, U);\n}\n\ndouble sample_truncated_normal(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    normal_distribution<double> nd(obsMean, sd);\n    for (int t = 0; t < 200; t++) {\n        double x = nd(rng);\n        if (L <= x && x <= U) return x;\n    }\n    return clamp_double(obsMean, L, U);\n}\n\ndouble estimate_L_from_current_observations() {\n    vector<double> vals;\n    vector<double> noiseVars;\n    vals.reserve(2 * N);\n    noiseVars.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        vals.push_back(sumWObs[i] / cntWObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntWObs[i]);\n        vals.push_back(sumHObs[i] / cntHObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntHObs[i]);\n    }\n\n    double mean = accumulate(vals.begin(), vals.end(), 0.0) / vals.size();\n    double L1 = 2.0 * mean - TRUE_U;\n\n    double var = 0.0;\n    for (double x : vals) var += (x - mean) * (x - mean);\n    var /= vals.size();\n\n    double avgNoise = accumulate(noiseVars.begin(), noiseVars.end(), 0.0) / noiseVars.size();\n    double trueVar = max(0.0, var - avgNoise);\n    double L2 = TRUE_U - sqrt(max(0.0, 12.0 * trueVar));\n\n    double L = 0.72 * L1 + 0.28 * L2;\n    return clamp_double(L, TRUE_L_MIN, TRUE_L_MAX);\n}\n\nvector<RectD> posterior_mean_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = truncated_normal_mean(mw, sw, L, TRUE_U);\n        res[i].h = truncated_normal_mean(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> posterior_sample_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = sample_truncated_normal(mw, sw, L, TRUE_U);\n        res[i].h = sample_truncated_normal(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nstatic inline bool overlap_interval(double l1, double r1, double l2, double r2) {\n    return max(l1, l2) < min(r1, r2) - 1e-9;\n}\n\npair<double, double> simulate_ops(const vector<Op>& ops, const vector<RectD>& rects) {\n    vector<double> x(N, 0), y(N, 0), w(N, 0), h(N, 0);\n    vector<int> placed;\n    placed.reserve(ops.size());\n\n    double W = 0, H = 0;\n\n    for (const Op& op : ops) {\n        int p = op.p;\n        double rw = op.r ? rects[p].h : rects[p].w;\n        double rh = op.r ? rects[p].w : rects[p].h;\n\n        double nx = 0, ny = 0;\n        if (op.d == 'U') {\n            nx = (op.b == -1 ? 0.0 : x[op.b] + w[op.b]);\n            ny = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(nx, nx + rw, x[q], x[q] + w[q])) {\n                    ny = max(ny, y[q] + h[q]);\n                }\n            }\n        } else {\n            ny = (op.b == -1 ? 0.0 : y[op.b] + h[op.b]);\n            nx = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(ny, ny + rh, y[q], y[q] + h[q])) {\n                    nx = max(nx, x[q] + w[q]);\n                }\n            }\n        }\n\n        x[p] = nx;\n        y[p] = ny;\n        w[p] = rw;\n        h[p] = rh;\n        placed.push_back(p);\n        W = max(W, nx + rw);\n        H = max(H, ny + rh);\n    }\n    return {W, H};\n}\n\nuint64_t splitmix64_u(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\nuint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (const Op& op : ops) {\n        uint64_t v = (uint64_t)(op.p + 1);\n        v = v * 1315423911ULL + (uint64_t)(op.r + 3);\n        v = v * 1315423911ULL + (uint64_t)(op.d == 'L' ? 7 : 11);\n        v = v * 1315423911ULL + (uint64_t)(op.b + 2);\n        h ^= splitmix64_u(v + h);\n    }\n    return h;\n}\n\nvoid add_candidate(vector<Candidate>& pool,\n                   unordered_set<uint64_t>& seen,\n                   const vector<Op>& ops,\n                   const vector<RectD>& baseRects) {\n    if ((int)ops.size() != N) return;\n\n    uint64_t hv = hash_ops(ops);\n    if (seen.find(hv) != seen.end()) return;\n    seen.insert(hv);\n\n    auto [W, H] = simulate_ops(ops, baseRects);\n    if (!isfinite(W) || !isfinite(H)) return;\n\n    Candidate c;\n    c.ops = ops;\n    c.baseW = W;\n    c.baseH = H;\n    c.estScore = W + H;\n    c.hash = hv;\n    pool.push_back(std::move(c));\n}\n\nstruct ShelfResult {\n    bool ok = false;\n    vector<Op> ops;\n};\n\n// mode 0: vertical columns using U\n// mode 1: horizontal rows using L\nShelfResult make_shelf_layout(const vector<RectD>& planRects, int mode, double cap) {\n    vector<array<double, 2>> cross(N), len(N);\n\n    for (int i = 0; i < N; i++) {\n        double w = planRects[i].w;\n        double h = planRects[i].h;\n        if (mode == 0) {\n            cross[i][0] = w; len[i][0] = h;\n            cross[i][1] = h; len[i][1] = w;\n        } else {\n            cross[i][0] = h; len[i][0] = w;\n            cross[i][1] = w; len[i][1] = h;\n        }\n    }\n\n    vector<double> vals;\n    vals.reserve(2 * N);\n    for (int i = 0; i < N; i++) {\n        vals.push_back(cross[i][0]);\n        vals.push_back(cross[i][1]);\n    }\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end(), [](double a, double b) {\n        return fabs(a - b) <= 1e-7 * max(1.0, max(fabs(a), fabs(b)));\n    }), vals.end());\n\n    int C = vals.size();\n\n    vector<vector<double>> pref(C, vector<double>(N + 1, 0.0));\n    for (int m = 0; m < C; m++) {\n        double M = vals[m];\n        for (int i = 0; i < N; i++) {\n            double bestLen = INF;\n            if (cross[i][0] <= M + 1e-7) bestLen = min(bestLen, len[i][0]);\n            if (cross[i][1] <= M + 1e-7) bestLen = min(bestLen, len[i][1]);\n            if (bestLen >= INF / 2 || pref[m][i] >= INF / 2) pref[m][i + 1] = INF;\n            else pref[m][i + 1] = min(INF, pref[m][i] + bestLen);\n        }\n    }\n\n    auto get_cost_idx = [&](int l, int r) -> int {\n        int lo = 0, hi = C;\n        while (lo < hi) {\n            int mid = (lo + hi) >> 1;\n            double s = pref[mid][r] - pref[mid][l];\n            if (s <= cap + 1e-7) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo == C) return -1;\n        return lo;\n    };\n\n    vector<double> dp(N + 1, INF);\n    vector<int> prv(N + 1, -1), prvM(N + 1, -1);\n    dp[0] = 0.0;\n\n    for (int r = 1; r <= N; r++) {\n        for (int l = 0; l < r; l++) {\n            if (dp[l] >= INF / 2) continue;\n            int mi = get_cost_idx(l, r);\n            if (mi < 0) continue;\n            double ndp = dp[l] + vals[mi];\n            if (ndp < dp[r]) {\n                dp[r] = ndp;\n                prv[r] = l;\n                prvM[r] = mi;\n            }\n        }\n    }\n\n    if (prv[N] < 0) return {};\n\n    vector<pair<int, int>> segs;\n    for (int r = N; r > 0; r = prv[r]) {\n        segs.push_back({prv[r], r});\n    }\n    reverse(segs.begin(), segs.end());\n\n    vector<int> orient(N, 0);\n    vector<int> anchorOfSeg(segs.size(), -1);\n\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        int mi = get_cost_idx(l, r);\n        double M = vals[mi];\n\n        int anchor = l;\n        double bestCross = -1.0;\n\n        for (int i = l; i < r; i++) {\n            int chosen = 0;\n            double bestLen = INF, bestCr = INF;\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (cross[i][rr] <= M + 1e-7) {\n                    if (len[i][rr] < bestLen - 1e-7 ||\n                        (fabs(len[i][rr] - bestLen) <= 1e-7 && cross[i][rr] < bestCr)) {\n                        bestLen = len[i][rr];\n                        bestCr = cross[i][rr];\n                        chosen = rr;\n                    }\n                }\n            }\n            orient[i] = chosen;\n\n            double cr = cross[i][chosen];\n            if (cr > bestCross) {\n                bestCross = cr;\n                anchor = i;\n            }\n        }\n        anchorOfSeg[si] = anchor;\n    }\n\n    vector<Op> ops;\n    ops.reserve(N);\n\n    int boundaryRef = -1;\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        for (int i = l; i < r; i++) {\n            Op op;\n            op.p = i;\n            op.r = orient[i];\n            op.d = (mode == 0 ? 'U' : 'L');\n            op.b = boundaryRef;\n            ops.push_back(op);\n        }\n        boundaryRef = anchorOfSeg[si];\n    }\n\n    ShelfResult res;\n    res.ok = true;\n    res.ops = std::move(ops);\n    return res;\n}\n\nvector<double> make_caps(const vector<RectD>& rects, int mode, int cnt) {\n    double area = 0.0;\n    double minCap = 0.0;\n    for (int i = 0; i < N; i++) {\n        area += rects[i].w * rects[i].h;\n        minCap = max(minCap, min(rects[i].w, rects[i].h));\n    }\n\n    double S = sqrt(max(1.0, area));\n    vector<double> caps;\n\n    double loF = 0.52, hiF = 2.35;\n    for (int k = 0; k < cnt; k++) {\n        double u = (cnt == 1 ? 0.5 : (double)k / (cnt - 1));\n        double f = exp(log(loF) + u * (log(hiF) - log(loF)));\n        caps.push_back(max(minCap, S * f));\n    }\n\n    // Extra dense points near square.\n    for (double f : {0.72, 0.80, 0.88, 0.96, 1.04, 1.12, 1.20, 1.32, 1.48}) {\n        caps.push_back(max(minCap, S * f));\n    }\n\n    sort(caps.begin(), caps.end());\n    vector<double> uniq;\n    for (double x : caps) {\n        if (uniq.empty() || fabs(x - uniq.back()) > 1e-6 * max(1.0, x)) uniq.push_back(x);\n    }\n    return uniq;\n}\n\ndouble min_final_perimeter_lb(double W, double H, double A) {\n    double S = sqrt(max(1.0, A));\n    double ans = INF;\n\n    if (W <= S && H <= S) ans = min(ans, 2.0 * S);\n    ans = min(ans, W + max(H, A / max(W, 1.0)));\n    ans = min(ans, H + max(W, A / max(H, 1.0)));\n    ans = max(ans, W + H);\n    return ans;\n}\n\nvector<Op> make_greedy_layout(const vector<RectD>& planRects,\n                              double aspect,\n                              double scale,\n                              double wOverflow,\n                              double wWaste,\n                              double wBal,\n                              double wLB,\n                              double jitter) {\n    vector<Op> ops;\n    ops.reserve(N);\n\n    vector<double> x(N), y(N), ww(N), hh(N);\n    double W = 0.0, H = 0.0;\n    double totalArea = 0.0;\n    for (auto &r : planRects) totalArea += r.w * r.h;\n\n    double S = sqrt(max(1.0, totalArea)) * scale;\n    double Wlim = S * sqrt(aspect);\n    double Hlim = S / sqrt(aspect);\n\n    double usedArea = 0.0;\n    uniform_real_distribution<double> ud(0.0, 1.0);\n\n    for (int i = 0; i < N; i++) {\n        double itemArea = planRects[i].w * planRects[i].h;\n\n        double bestCost = INF;\n        Op bestOp{i, 0, 'U', -1};\n        double bestX = 0, bestY = 0, bestW = 0, bestH = 0;\n        double bestBW = 0, bestBH = 0;\n\n        for (int r = 0; r < 2; r++) {\n            double rw = r ? planRects[i].h : planRects[i].w;\n            double rh = r ? planRects[i].w : planRects[i].h;\n\n            for (int dd = 0; dd < 2; dd++) {\n                char d = (dd == 0 ? 'U' : 'L');\n                for (int b = -1; b < i; b++) {\n                    double nx = 0, ny = 0;\n\n                    if (d == 'U') {\n                        nx = (b == -1 ? 0.0 : x[b] + ww[b]);\n                        ny = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(nx, nx + rw, x[q], x[q] + ww[q])) {\n                                ny = max(ny, y[q] + hh[q]);\n                            }\n                        }\n                    } else {\n                        ny = (b == -1 ? 0.0 : y[b] + hh[b]);\n                        nx = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(ny, ny + rh, y[q], y[q] + hh[q])) {\n                                nx = max(nx, x[q] + ww[q]);\n                            }\n                        }\n                    }\n\n                    double nW = max(W, nx + rw);\n                    double nH = max(H, ny + rh);\n                    double nUsed = usedArea + itemArea;\n\n                    double overflow = max(0.0, nW - Wlim) + max(0.0, nH - Hlim);\n                    double wasteLen = max(0.0, nW * nH - nUsed) / sqrt(max(1.0, nUsed));\n                    double bal = fabs(nW / Wlim - nH / Hlim) * sqrt(totalArea);\n                    double lb = min_final_perimeter_lb(nW, nH, totalArea);\n                    double progress = 0.25 + 0.75 * (double)(i + 1) / N;\n\n                    double cost =\n                        wLB * lb +\n                        progress * (nW + nH) +\n                        wOverflow * overflow +\n                        wWaste * wasteLen +\n                        wBal * bal +\n                        0.0007 * (nx + ny) +\n                        jitter * ud(rng) * sqrt(totalArea);\n\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestOp = {i, r, d, b};\n                        bestX = nx;\n                        bestY = ny;\n                        bestW = rw;\n                        bestH = rh;\n                        bestBW = nW;\n                        bestBH = nH;\n                    }\n                }\n            }\n        }\n\n        ops.push_back(bestOp);\n        x[i] = bestX;\n        y[i] = bestY;\n        ww[i] = bestW;\n        hh[i] = bestH;\n        W = bestBW;\n        H = bestBH;\n        usedArea += itemArea;\n    }\n\n    return ops;\n}\n\nvoid output_query(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const Op& 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    Timer timer;\n\n    cin >> N >> T >> SIGMA;\n\n    sumWObs.assign(N, 0.0);\n    sumHObs.assign(N, 0.0);\n    cntWObs.assign(N, 1);\n    cntHObs.assign(N, 1);\n\n    for (int i = 0; i < N; i++) {\n        long long w, h;\n        cin >> w >> h;\n        sumWObs[i] = (double)w;\n        sumHObs[i] = (double)h;\n    }\n\n    // Optional individual measurements when there are many extra turns and noise is large.\n    double noiseFactor = clamp_double((SIGMA - 3000.0) / 7000.0, 0.0, 1.0);\n    int extra = max(0, T - 2 * N);\n    int measureQ = min(N, (int)round(extra * noiseFactor));\n\n    if (measureQ > 0) {\n        double L0 = estimate_L_from_current_observations();\n        vector<RectD> base0 = posterior_mean_rects(L0);\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            double ia = base0[a].w * base0[a].h + 0.25 * (base0[a].w + base0[a].h) * sqrt(base0[a].w * base0[a].h);\n            double ib = base0[b].w * base0[b].h + 0.25 * (base0[b].w + base0[b].h) * sqrt(base0[b].w * base0[b].h);\n            return ia > ib;\n        });\n\n        for (int k = 0; k < measureQ; k++) {\n            int i = ids[k];\n            vector<Op> ops;\n            ops.push_back({i, 0, 'U', -1});\n            output_query(ops);\n\n            long long Wm, Hm;\n            if (!(cin >> Wm >> Hm)) return 0;\n\n            sumWObs[i] += (double)Wm;\n            sumHObs[i] += (double)Hm;\n            cntWObs[i]++;\n            cntHObs[i]++;\n        }\n    }\n\n    int remainingTurns = T - measureQ;\n    if (remainingTurns <= 0) return 0;\n\n    double Lest = estimate_L_from_current_observations();\n    vector<RectD> baseRects = posterior_mean_rects(Lest);\n\n    // Evaluation / posterior scenarios.\n    int randomScenarioCount = (N <= 50 ? 10 : 8);\n    if (remainingTurns <= 30) randomScenarioCount = min(randomScenarioCount, 6);\n\n    vector<vector<RectD>> scenarios;\n    scenarios.push_back(baseRects);\n    for (int s = 0; s < randomScenarioCount; s++) {\n        scenarios.push_back(posterior_sample_rects(Lest));\n    }\n    int S = scenarios.size();\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    int targetPool = max(450, min(1300, remainingTurns * 3));\n\n    // Shelf DP layouts.\n    int planScenarios = min(S, 5);\n    for (int ps = 0; ps < planScenarios; ps++) {\n        const auto& plan = scenarios[ps];\n        int capCnt = (ps == 0 ? 82 : 42);\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(plan, mode, capCnt);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Greedy BL-style layouts.\n    uniform_real_distribution<double> ud(0.0, 1.0);\n    int greedyAttempts = 0;\n    while ((int)pool.size() < targetPool && timer.elapsed() < 2.15) {\n        int ps = greedyAttempts % planScenarios;\n        const auto& plan = scenarios[ps];\n\n        double aspect = exp(log(0.48) + ud(rng) * (log(2.10) - log(0.48)));\n        double scale = 1.00 + 0.42 * ud(rng);\n\n        double wOverflow = 2.0 + 18.0 * ud(rng);\n        double wWaste = 0.05 + 2.50 * ud(rng);\n        double wBal = 0.02 + 1.10 * ud(rng);\n        double wLB = 1.0 + 6.0 * ud(rng);\n        double jitter = 0.000 + 0.035 * ud(rng);\n\n        vector<Op> ops = make_greedy_layout(plan, aspect, scale, wOverflow, wWaste, wBal, wLB, jitter);\n        add_candidate(pool, seen, ops, baseRects);\n        greedyAttempts++;\n    }\n\n    if (pool.empty()) {\n        // Extremely defensive fallback.\n        vector<Op> ops;\n        for (int i = 0; i < N; i++) ops.push_back({i, 0, 'U', -1});\n        add_candidate(pool, seen, ops, baseRects);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.estScore < b.estScore;\n    });\n\n    int maxKeep = max(remainingTurns, min((int)pool.size(), 1200));\n    if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n\n    int C = pool.size();\n\n    // Precompute predicted W,H,score for scenario-weighted online selection.\n    vector<float> predW(C * S), predH(C * S), predScore(C * S);\n\n    for (int c = 0; c < C; c++) {\n        for (int s = 0; s < S; s++) {\n            pair<double, double> wh;\n            if (s == 0) wh = {pool[c].baseW, pool[c].baseH};\n            else wh = simulate_ops(pool[c].ops, scenarios[s]);\n            predW[c * S + s] = (float)wh.first;\n            predH[c * S + s] = (float)wh.second;\n            predScore[c * S + s] = (float)(wh.first + wh.second);\n        }\n    }\n\n    vector<double> logWeight(S, 0.0);\n    vector<double> weight(S, 1.0 / S);\n    vector<double> bestScenarioScore(S, INF);\n    vector<char> used(C, 0);\n\n    int bestBaseIdx = 0;\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        int chosen = -1;\n        double bestVal = INF;\n\n        for (int c = 0; c < C; c++) {\n            if (used[c]) continue;\n            double val = 0.0;\n            for (int s = 0; s < S; s++) {\n                double sc = predScore[c * S + s];\n                val += weight[s] * min(bestScenarioScore[s], sc);\n            }\n            val += 1e-9 * pool[c].estScore; // stable tie-breaker\n            if (val < bestVal) {\n                bestVal = val;\n                chosen = c;\n            }\n        }\n\n        if (chosen < 0) chosen = bestBaseIdx;\n\n        output_query(pool[chosen].ops);\n\n        long long Wobs, Hobs;\n        if (!(cin >> Wobs >> Hobs)) return 0;\n\n        if (chosen >= 0 && chosen < C) {\n            used[chosen] = 1;\n\n            for (int s = 0; s < S; s++) {\n                bestScenarioScore[s] = min(bestScenarioScore[s], (double)predScore[chosen * S + s]);\n            }\n\n            // Tempered likelihood: scenario set is sparse, so avoid overconfidence.\n            double effSigma = max(2500.0, 2.25 * SIGMA);\n            for (int s = 0; s < S; s++) {\n                double dw = (double)Wobs - predW[chosen * S + s];\n                double dh = (double)Hobs - predH[chosen * S + s];\n                logWeight[s] += -0.5 * (dw * dw + dh * dh) / (effSigma * effSigma);\n            }\n\n            double mx = *max_element(logWeight.begin(), logWeight.end());\n            double sm = 0.0;\n            for (int s = 0; s < S; s++) {\n                weight[s] = exp(logWeight[s] - mx);\n                sm += weight[s];\n            }\n            if (sm <= 0 || !isfinite(sm)) {\n                fill(weight.begin(), weight.end(), 1.0 / S);\n            } else {\n                for (int s = 0; s < S; s++) {\n                    weight[s] = weight[s] / sm;\n                    // Small floor for exploration / model mismatch.\n                    weight[s] = 0.965 * weight[s] + 0.035 / S;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, M, HH;\nvector<int> A;\nvector<vector<int>> adj;\nvector<int> highOrder, lowOrder;\nvector<vector<int>> dpCost;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ULL;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct State {\n    vector<int> d;\n    vector<int> cnt;\n    long long val = 0; // sum depth[v] * A[v]\n};\n\nbool hasNeighborDepth(const vector<int>& d, int v, int dep) {\n    for (int u : adj[v]) if (d[u] == dep) return true;\n    return false;\n}\n\nvoid initState(State& s, const vector<int>& depth) {\n    s.d = depth;\n    s.cnt.assign(N, 0);\n    s.val = 0;\n    for (int v = 0; v < N; v++) {\n        s.val += 1LL * s.d[v] * A[v];\n        if (s.d[v] > 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) s.cnt[v]++;\n            }\n        }\n    }\n}\n\nbool verifyState(const State& s) {\n    if ((int)s.d.size() != N) return false;\n    for (int v = 0; v < N; v++) {\n        if (s.d[v] < 0 || s.d[v] > HH) return false;\n        if (s.d[v] > 0) {\n            bool ok = false;\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n    }\n    return true;\n}\n\nbool canMove(const State& s, int v, int nd) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n    return true;\n}\n\nvoid applyMove(State& s, int v, int nd) {\n    int od = s.d[v];\n    if (od == nd) return;\n\n    for (int w : adj[v]) {\n        if (s.d[w] > 0) {\n            if (s.d[w] - 1 == od) s.cnt[w]--;\n            if (s.d[w] - 1 == nd) s.cnt[w]++;\n        }\n    }\n\n    s.val += 1LL * (nd - od) * A[v];\n    s.d[v] = nd;\n\n    int c = 0;\n    if (nd > 0) {\n        for (int u : adj[v]) if (s.d[u] == nd - 1) c++;\n    }\n    s.cnt[v] = c;\n}\n\nbool tryRaise(State& s, int v) {\n    int od = s.d[v];\n    for (int nd = HH; nd > od; nd--) {\n        if (canMove(s, v, nd)) {\n            applyMove(s, v, nd);\n            return true;\n        }\n    }\n    return false;\n}\n\nbool greedyImprove(State& s, int maxPass = 10) {\n    bool any = false;\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool moved = false;\n        for (int v : highOrder) {\n            if (tryRaise(s, v)) {\n                moved = true;\n                any = true;\n            }\n        }\n        if (!moved) break;\n    }\n    return any;\n}\n\nvector<int> aroundMark;\nint aroundStamp = 1;\n\nvoid greedyAround(State& s, int v) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n    auto add = [&](int x) {\n        if (aroundMark[x] != aroundStamp) {\n            aroundMark[x] = aroundStamp;\n            list.push_back(x);\n        }\n    };\n\n    add(v);\n    for (int u : adj[v]) {\n        add(u);\n        for (int w : adj[u]) add(w);\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        for (int x : list) tryRaise(s, x);\n    }\n}\n\nvoid computeDPCost() {\n    const int INF = 1e9;\n    dpCost.assign(HH, vector<int>(N, INF));\n    if (HH <= 0) return;\n\n    for (int v = 0; v < N; v++) {\n        dpCost[0][v] = HH * A[v];\n    }\n\n    for (int k = 1; k < HH; k++) {\n        for (int v = 0; v < N; v++) {\n            int best = INF;\n            for (int u : adj[v]) best = min(best, dpCost[k - 1][u]);\n            dpCost[k][v] = best + (HH - k) * A[v];\n        }\n    }\n}\n\nstruct Mode {\n    bool indepTop;\n    bool indepLower;\n    bool lookahead;\n    int kind;\n    double noise;\n    double dpWeight;\n};\n\ndouble coverScore(int cov, double cost, int future, int kind, double noise) {\n    double c = (double)cov;\n    double score;\n\n    if ((kind & 3) == 0) {\n        score = c / cost;\n    } else if ((kind & 3) == 1) {\n        score = c * c / cost;\n    } else if ((kind & 3) == 2) {\n        score = c / sqrt(cost);\n    } else {\n        score = c * sqrt(c) / cost;\n    }\n\n    score *= (1.0 + 0.025 * future);\n\n    if (noise > 0) {\n        score *= (1.0 + noise * (rng.nextDouble() - 0.5));\n    }\n    return score;\n}\n\nbool selectCoverLevel(\n    int k,\n    const vector<int>& target,\n    vector<int>& depth,\n    vector<char>& used,\n    bool independent,\n    const Mode& mode\n) {\n    vector<char> targetMark(N, 0), covered(N, 0), banned(N, 0);\n    for (int t : target) targetMark[t] = 1;\n\n    int rem = (int)target.size();\n    vector<int> selected;\n\n    auto candidateCost = [&](int c) -> double {\n        double base = (double)(HH - k) * A[c];\n        if (mode.dpWeight > 0 && k >= 0 && k < HH && !dpCost.empty()) {\n            double extra = max(0, dpCost[k][c] - (HH - k) * A[c]);\n            base += mode.dpWeight * extra;\n        }\n        return max(1.0, base);\n    };\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (used[c]) continue;\n            if (independent && banned[c]) continue;\n\n            int future = 0;\n            if (k > 0) {\n                for (int u : adj[c]) if (!used[u]) future++;\n                if (mode.lookahead && future == 0) continue;\n            }\n\n            int cov = 0;\n            if (k == HH - 1 && targetMark[c] && !covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (targetMark[u] && !covered[u]) cov++;\n            }\n            if (cov == 0) continue;\n\n            double sc = coverScore(cov, candidateCost(c), future, mode.kind, mode.noise);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        used[best] = 1;\n        depth[best] = k;\n        selected.push_back(best);\n\n        if (independent) {\n            banned[best] = 1;\n            for (int u : adj[best]) banned[u] = 1;\n        }\n\n        auto mark = [&](int x) {\n            if (targetMark[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        if (k == HH - 1) mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    auto addCover = [&](int c, int delta) {\n        if (k == HH - 1) {\n            coverCnt[c] += delta;\n            for (int u : adj[c]) coverCnt[u] += delta;\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u]) coverCnt[u] += delta;\n            }\n        }\n    };\n\n    for (int c : selected) {\n        if (used[c] && depth[c] == k) addCover(c, 1);\n    }\n\n    for (int t : target) {\n        if (coverCnt[t] <= 0) return false;\n    }\n\n    sort(selected.begin(), selected.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selected) {\n        if (!used[c] || depth[c] != k) continue;\n\n        // Important refinement:\n        // If this level-k vertex is removed, it becomes depth H.\n        // For k < H-1, this is feasible only when it already has a depth H-1 neighbor.\n        if (k < HH - 1 && !hasNeighborDepth(depth, c, HH - 1)) continue;\n\n        bool ok = true;\n        if (k == HH - 1) {\n            if (coverCnt[c] <= 1) ok = false;\n            if (ok) {\n                for (int u : adj[c]) {\n                    if (coverCnt[u] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u] && coverCnt[u] <= 1) {\n                    ok = false;\n                    break;\n                }\n            }\n        }\n\n        if (ok) {\n            addCover(c, -1);\n            used[c] = 0;\n            depth[c] = HH;\n        }\n    }\n\n    return true;\n}\n\nbool buildChain(vector<int>& outDepth, const Mode& mode) {\n    vector<int> depth(N, HH);\n    vector<char> used(N, 0);\n\n    for (int k = HH - 1; k >= 0; k--) {\n        vector<int> target;\n        if (k == HH - 1) {\n            target.resize(N);\n            iota(target.begin(), target.end(), 0);\n        } else {\n            for (int v = 0; v < N; v++) {\n                if (depth[v] == k + 1) target.push_back(v);\n            }\n        }\n\n        if (target.empty()) continue;\n\n        bool independent = (k == HH - 1 ? mode.indepTop : mode.indepLower);\n        if (!selectCoverLevel(k, target, depth, used, independent, mode)) {\n            return false;\n        }\n    }\n\n    State s;\n    initState(s, depth);\n    if (!verifyState(s)) return false;\n\n    outDepth = depth;\n    return true;\n}\n\nbool localImproveCover(\n    const vector<char>& targetMark,\n    const vector<char>& candidate,\n    vector<char>& selected,\n    const vector<char>& forced,\n    const vector<double>& cost,\n    bool topClosed,\n    int maxLoops\n) {\n    vector<vector<int>> cover(N);\n\n    for (int c = 0; c < N; c++) {\n        if (!candidate[c] && !selected[c]) continue;\n\n        if (topClosed && targetMark[c]) cover[c].push_back(c);\n        for (int u : adj[c]) {\n            if (targetMark[u]) cover[c].push_back(u);\n        }\n    }\n\n    vector<int> coverCnt(N, 0);\n    for (int c = 0; c < N; c++) {\n        if (!selected[c]) continue;\n        for (int t : cover[c]) coverCnt[t]++;\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    auto removable = [&](int c) -> bool {\n        if (forced[c]) return false;\n        if (cost[c] <= 1e-9) return false;\n        for (int t : cover[c]) {\n            if (coverCnt[t] <= 1) return false;\n        }\n        return true;\n    };\n\n    auto prune = [&]() {\n        vector<int> sels;\n        for (int c = 0; c < N; c++) if (selected[c]) sels.push_back(c);\n\n        sort(sels.begin(), sels.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        for (int c : sels) {\n            if (!selected[c]) continue;\n            if (!removable(c)) continue;\n\n            selected[c] = 0;\n            for (int t : cover[c]) coverCnt[t]--;\n        }\n    };\n\n    prune();\n\n    if (maxLoops <= 0) return true;\n\n    vector<int> candList;\n    for (int c = 0; c < N; c++) if (candidate[c]) candList.push_back(c);\n\n    vector<int> tmpCnt(N);\n\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9) selOrder.push_back(c);\n        }\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        double bestGain = 1e-6;\n        int bestC = -1;\n        vector<int> bestRem;\n\n        for (int c : candList) {\n            if (selected[c]) continue;\n            if (cover[c].empty()) continue;\n\n            copy(coverCnt.begin(), coverCnt.end(), tmpCnt.begin());\n\n            for (int t : cover[c]) tmpCnt[t]++;\n\n            double gain = -cost[c];\n            vector<int> rems;\n\n            for (int s : selOrder) {\n                bool ok = true;\n                for (int t : cover[s]) {\n                    if (tmpCnt[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    for (int t : cover[s]) tmpCnt[t]--;\n                    gain += cost[s];\n                    rems.push_back(s);\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestC = c;\n                bestRem.swap(rems);\n            }\n        }\n\n        if (bestC == -1) break;\n\n        selected[bestC] = 1;\n        for (int t : cover[bestC]) coverCnt[t]++;\n\n        for (int r : bestRem) {\n            if (!selected[r]) continue;\n            selected[r] = 0;\n            for (int t : cover[r]) coverCnt[t]--;\n        }\n\n        prune();\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    return true;\n}\n\nbool reoptTop(State& s, int improveLoops) {\n    if (HH == 0) return false;\n\n    int k = HH - 1;\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0), candidate(N, 0), selected(N, 0), covered(N, 0), forced(N, 0);\n    vector<double> cost(N, 1e18);\n\n    int rem = 0;\n    for (int v = 0; v < N; v++) {\n        if (d[v] >= k) {\n            target[v] = 1;\n            rem++;\n        }\n    }\n    if (rem == 0) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (!target[v]) continue;\n        if (k == 0 || hasNeighborDepth(d, v, k - 1)) {\n            candidate[v] = 1;\n            cost[v] = A[v];\n        }\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            if (target[c] && !covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n            if (cov == 0) continue;\n\n            double sc = (double)cov / A[c];\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n\n        auto mark = [&](int x) {\n            if (target[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, true, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n    for (int v = 0; v < N; v++) {\n        if (target[v]) nd[v] = HH;\n    }\n    for (int v = 0; v < N; v++) {\n        if (selected[v]) nd[v] = k;\n    }\n\n    State ns;\n    initState(ns, nd);\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n    return false;\n}\n\nbool reoptLevel(State& s, int k, int improveLoops) {\n    if (k < 0 || k >= HH - 1) return false;\n\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0);\n    int targetCount = 0;\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k + 1) {\n            target[v] = 1;\n            targetCount++;\n        }\n    }\n    if (targetCount == 0) return false;\n\n    vector<char> candidate(N, 0), selected(N, 0), forced(N, 0), covered(N, 0);\n    vector<double> cost(N, 1e18);\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            candidate[v] = 1;\n            cost[v] = (HH - k) * A[v];\n\n            bool topSupport = hasNeighborDepth(d, v, HH - 1);\n            if (!topSupport) {\n                forced[v] = 1;\n                selected[v] = 1;\n            }\n        } else if (d[v] == HH) {\n            bool supp = (k == 0) || hasNeighborDepth(d, v, k - 1);\n            if (supp) {\n                candidate[v] = 1;\n                cost[v] = (HH - k) * A[v];\n            }\n        }\n    }\n\n    int rem = targetCount;\n\n    auto markBy = [&](int c) {\n        for (int u : adj[c]) {\n            if (target[u] && !covered[u]) {\n                covered[u] = 1;\n                rem--;\n            }\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (forced[v]) markBy(v);\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n            if (cov == 0) continue;\n\n            double sc = (double)cov / cost[c];\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n        markBy(best);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, false, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            nd[v] = selected[v] ? k : HH;\n        } else if (d[v] == HH && selected[v]) {\n            nd[v] = k;\n        }\n    }\n\n    State ns;\n    initState(ns, nd);\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n    return false;\n}\n\nvoid polish(State& s, int passes, int improveLoops, double stopTime) {\n    for (int p = 0; p < passes; p++) {\n        if (elapsed() > stopTime) return;\n\n        reoptTop(s, improveLoops);\n\n        for (int k = HH - 2; k >= 0; k--) {\n            if (elapsed() > stopTime) return;\n            reoptLevel(s, k, improveLoops);\n        }\n\n        greedyImprove(s, 8);\n    }\n}\n\nState makeFallback() {\n    vector<int> dist(N, -1);\n    queue<int> q;\n    dist[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u : adj[v]) {\n            if (dist[u] == -1) {\n                dist[u] = dist[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    vector<int> depth(N, 0);\n    for (int v = 0; v < N; v++) {\n        if (dist[v] < 0) depth[v] = 0;\n        else depth[v] = dist[v] % (HH + 1);\n    }\n\n    State s;\n    initState(s, depth);\n    if (!verifyState(s)) {\n        fill(depth.begin(), depth.end(), 0);\n        initState(s, depth);\n    }\n\n    greedyImprove(s, 12);\n    return s;\n}\n\nvoid anneal(State& best, double endTime) {\n    State cur = best;\n\n    double st = elapsed();\n    double duration = max(0.001, endTime - st);\n\n    double T0 = 120.0;\n    double T1 = 0.8;\n    double T = T0;\n\n    int iter = 0;\n    while (true) {\n        if ((iter & 4095) == 0) {\n            double now = elapsed();\n            if (now >= endTime) break;\n\n            double prog = min(1.0, (now - st) / duration);\n            T = T0 * pow(T1 / T0, prog);\n\n            if ((iter & 65535) == 0 && iter > 0) {\n                greedyImprove(cur, 3);\n                if (cur.val > best.val) best = cur;\n                if (cur.val + 7000 < best.val) cur = best;\n            }\n        }\n        iter++;\n\n        int v = -1, nd = -1;\n        bool prechecked = false;\n\n        int type = rng.nextInt(100);\n\n        if (type < 30) {\n            int w = -1;\n            for (int t = 0; t < 6; t++) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] > 0 && cur.cnt[cand] <= 1) {\n                    w = cand;\n                    break;\n                }\n            }\n            if (w == -1) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] == 0) continue;\n                w = cand;\n            }\n\n            nd = cur.d[w] - 1;\n            int bestU = -1;\n            int bestDelta = INT_MIN;\n\n            for (int u : adj[w]) {\n                if (cur.d[u] == nd) continue;\n                if (!canMove(cur, u, nd)) continue;\n\n                int delta = (nd - cur.d[u]) * A[u];\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestU = u;\n                }\n            }\n\n            if (bestU == -1) continue;\n            v = bestU;\n            prechecked = true;\n        } else if (type < 55) {\n            int K = min(N, 450);\n            v = lowOrder[rng.nextInt(K)];\n            if (cur.d[v] == 0) continue;\n            nd = rng.nextInt(cur.d[v]);\n        } else if (type < 85) {\n            int K = min(N, 750);\n            v = highOrder[rng.nextInt(K)];\n            if (cur.d[v] == HH) continue;\n\n            nd = -1;\n            for (int x = HH; x > cur.d[v]; x--) {\n                if (canMove(cur, v, x)) {\n                    nd = x;\n                    break;\n                }\n            }\n            if (nd == -1) continue;\n            prechecked = true;\n        } else {\n            v = rng.nextInt(N);\n            nd = rng.nextInt(HH + 1);\n            if (nd == cur.d[v]) continue;\n        }\n\n        if (!prechecked && !canMove(cur, v, nd)) continue;\n\n        int delta = (nd - cur.d[v]) * A[v];\n\n        bool accept = false;\n        if (delta >= 0) {\n            accept = true;\n        } else {\n            if (delta > -30.0 * T) {\n                double prob = exp(delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n        }\n\n        if (!accept) continue;\n\n        applyMove(cur, v, nd);\n\n        if (delta < 0) {\n            greedyAround(cur, v);\n        }\n\n        if (cur.val > best.val) {\n            best = cur;\n        }\n    }\n\n    greedyImprove(best, 10);\n}\n\nbool isBad(const State& s, int v) {\n    return s.d[v] > 0 && s.cnt[v] <= 0;\n}\n\nvoid repairState(State& s) {\n    deque<int> q;\n    vector<char> inq(N, 0);\n\n    auto push = [&](int v) {\n        if (!inq[v]) {\n            inq[v] = 1;\n            q.push_back(v);\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (isBad(s, v)) push(v);\n    }\n\n    int guard = 0;\n    while (!q.empty() && guard < 50000) {\n        int v = q.front();\n        q.pop_front();\n        inq[v] = 0;\n\n        if (!isBad(s, v)) continue;\n\n        int old = s.d[v];\n        int nd = 0;\n\n        for (int x = old - 1; x >= 1; x--) {\n            bool ok = false;\n            for (int u : adj[v]) {\n                if (s.d[u] == x - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (ok) {\n                nd = x;\n                break;\n            }\n        }\n\n        applyMove(s, v, nd);\n\n        push(v);\n        for (int u : adj[v]) push(u);\n\n        guard++;\n    }\n\n    if (!verifyState(s)) {\n        vector<int> zero(N, 0);\n        initState(s, zero);\n    }\n}\n\nvoid lns(State& best, double endTime) {\n    State base = best;\n\n    while (elapsed() < endTime) {\n        State s = (rng.nextInt(100) < 85 ? best : base);\n\n        int remCnt = 2 + rng.nextInt(12);\n        if (rng.nextInt(100) < 15) remCnt += rng.nextInt(20);\n\n        for (int i = 0; i < remCnt; i++) {\n            int v = -1;\n\n            for (int t = 0; t < 60; t++) {\n                int cand;\n                if (rng.nextInt(100) < 65) {\n                    cand = highOrder[rng.nextInt(min(N, 800))];\n                } else {\n                    cand = rng.nextInt(N);\n                }\n\n                if (s.d[cand] < HH) {\n                    v = cand;\n                    break;\n                }\n            }\n\n            if (v != -1) {\n                applyMove(s, v, HH);\n            }\n        }\n\n        int addCnt = 4 + rng.nextInt(24);\n\n        for (int i = 0; i < addCnt; i++) {\n            int K = min(N, 250 + rng.nextInt(550));\n            int v = lowOrder[rng.nextInt(K)];\n\n            int nd;\n            if (rng.nextInt(100) < 70) {\n                nd = rng.nextInt(HH);\n            } else {\n                nd = max(0, s.d[v] - 1 - rng.nextInt(3));\n            }\n\n            if (nd < 0) nd = 0;\n            if (nd > HH) nd = HH;\n\n            applyMove(s, v, nd);\n        }\n\n        for (int t = 0; t < 35; t++) {\n            int v = rng.nextInt(N);\n            if (!isBad(s, v)) continue;\n\n            int need = s.d[v] - 1;\n            if (need < 0) continue;\n\n            int bu = -1;\n            int bestCost = INT_MAX;\n\n            for (int u : adj[v]) {\n                int c = abs(s.d[u] - need) * A[u] + A[u];\n                if (c < bestCost) {\n                    bestCost = c;\n                    bu = u;\n                }\n            }\n\n            if (bu != -1) {\n                applyMove(s, bu, need);\n            }\n        }\n\n        repairState(s);\n\n        if (!verifyState(s)) continue;\n\n        greedyImprove(s, 5);\n\n        if (s.val > best.val - 3000 && elapsed() < endTime - 0.03) {\n            polish(s, 1, 1, endTime);\n        }\n\n        if (s.val > best.val) {\n            best = s;\n            base = s;\n        } else if (s.val > base.val || rng.nextInt(100) < 5) {\n            base = s;\n        }\n    }\n\n    greedyImprove(best, 8);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> HH;\n\n    A.resize(N);\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        cin >> A[i];\n        seed = seed * 1000003ULL + A[i] + 97;\n    }\n\n    adj.assign(N, {});\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n        seed ^= (uint64_t)(u + 1) * 1000000007ULL + (uint64_t)(v + 1) * 1000003ULL;\n    }\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n        seed ^= ((uint64_t)x << 32) ^ (uint64_t)y ^ ((uint64_t)i * 11995408973635179863ULL);\n    }\n\n    if (seed == 0) seed = 88172645463325252ULL;\n    rng.x = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    highOrder.resize(N);\n    lowOrder.resize(N);\n    iota(highOrder.begin(), highOrder.end(), 0);\n    iota(lowOrder.begin(), lowOrder.end(), 0);\n\n    sort(highOrder.begin(), highOrder.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n    sort(lowOrder.begin(), lowOrder.end(), [&](int a, int b) {\n        return A[a] < A[b];\n    });\n\n    aroundMark.assign(N, 0);\n\n    computeDPCost();\n\n    State best = makeFallback();\n    polish(best, 1, 0, 0.20);\n\n    vector<State> pool;\n\n    auto addPool = [&](const State& s) {\n        if (!verifyState(s)) return;\n\n        const int POOL_SIZE = 4;\n\n        if ((int)pool.size() < POOL_SIZE) {\n            pool.push_back(s);\n            return;\n        }\n\n        int worst = 0;\n        for (int i = 1; i < POOL_SIZE; i++) {\n            if (pool[i].val < pool[worst].val) worst = i;\n        }\n\n        if (s.val > pool[worst].val) {\n            pool[worst] = s;\n        }\n    };\n\n    addPool(best);\n\n    const double CONSTRUCT_LIMIT = 0.70;\n    int attempt = 0;\n\n    double dpWs[] = {0.0, 0.0, 0.015, 0.03, 0.06, 0.10};\n\n    while (attempt < 220 && elapsed() < CONSTRUCT_LIMIT) {\n        Mode mode;\n\n        if (attempt < 24) {\n            mode.indepTop = (attempt & 1);\n            mode.indepLower = (attempt & 2);\n            mode.kind = (attempt / 6) & 3;\n            mode.noise = 0.0;\n            mode.dpWeight = dpWs[(attempt / 4) % 6];\n        } else {\n            mode.indepTop = (rng.nextInt(100) < 45);\n            mode.indepLower = (rng.nextInt(100) < 25);\n            mode.kind = rng.nextInt(4);\n            mode.noise = 0.20 + 0.70 * rng.nextDouble();\n            mode.dpWeight = dpWs[rng.nextInt(6)] * (0.7 + 0.8 * rng.nextDouble());\n        }\n\n        mode.lookahead = true;\n\n        vector<int> depth;\n        if (buildChain(depth, mode)) {\n            State s;\n            initState(s, depth);\n\n            polish(s, 1, 0, CONSTRUCT_LIMIT);\n\n            if (s.val > best.val) best = s;\n            addPool(s);\n        }\n\n        attempt++;\n    }\n\n    for (State s : pool) {\n        if (elapsed() > 0.95) break;\n        polish(s, 1, 4, 0.98);\n        if (s.val > best.val) best = s;\n    }\n\n    polish(best, 1, 5, 1.08);\n\n    anneal(best, 1.58);\n\n    polish(best, 1, 4, 1.68);\n\n    lns(best, 1.84);\n\n    polish(best, 1, 6, 1.875);\n    greedyImprove(best, 10);\n\n    if (!verifyState(best)) {\n        best = makeFallback();\n    }\n\n    vector<int> parent(N, -1);\n    bool ok = true;\n\n    for (int v = 0; v < N; v++) {\n        if (best.d[v] == 0) {\n            parent[v] = -1;\n        } else {\n            int p = -1;\n            for (int u : adj[v]) {\n                if (best.d[u] == best.d[v] - 1) {\n                    p = u;\n                    break;\n                }\n            }\n            if (p == -1) {\n                ok = false;\n                break;\n            }\n            parent[v] = p;\n        }\n    }\n\n    if (!ok) {\n        for (int i = 0; i < N; i++) parent[i] = -1;\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N;\nuint32_t FULL;\nconst int MAXN = 20;\n\nstruct Op {\n    char d;\n    int p;\n};\n\nstruct GAct {\n    char d;\n    int p;\n    int k;\n};\n\nstruct State {\n    array<uint32_t, MAXN> x{}, o{};\n    int xcnt = 0;\n};\n\nState INIT;\nvector<pair<int,int>> initialXs;\nint idxAt[MAXN][MAXN];\n\nchrono::steady_clock::time_point START;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nint popc(uint32_t v) {\n    return __builtin_popcount(v);\n}\n\nint firstBit(uint32_t m) {\n    return m ? __builtin_ctz(m) : N;\n}\n\nint lastBit(uint32_t m) {\n    return m ? 31 - __builtin_clz(m) : -1;\n}\n\nchar invDir(char d) {\n    if (d == 'L') return 'R';\n    if (d == 'R') return 'L';\n    if (d == 'U') return 'D';\n    return 'U';\n}\n\nvoid appendOps(vector<Op>& ops, char d, int p, int k) {\n    for (int i = 0; i < k; i++) ops.push_back({d, p});\n}\n\nbool edgeO(const State& s, const Op& op) {\n    int p = op.p;\n    uint32_t bit = 1u << p;\n    if (op.d == 'L') return s.o[p] & 1u;\n    if (op.d == 'R') return s.o[p] & (1u << (N - 1));\n    if (op.d == 'U') return s.o[0] & bit;\n    return s.o[N - 1] & bit;\n}\n\ninline void setBit(uint32_t& m, uint32_t bit, bool v) {\n    if (v) m |= bit;\n    else m &= ~bit;\n}\n\nvoid applyOp(State& s, const Op& op) {\n    int p = op.p;\n    if (op.d == 'L') {\n        if (s.x[p] & 1u) s.xcnt--;\n        s.x[p] >>= 1;\n        s.o[p] >>= 1;\n    } else if (op.d == 'R') {\n        if (s.x[p] & (1u << (N - 1))) s.xcnt--;\n        s.x[p] = (s.x[p] << 1) & FULL;\n        s.o[p] = (s.o[p] << 1) & FULL;\n    } else if (op.d == 'U') {\n        uint32_t bit = 1u << p;\n        if (s.x[0] & bit) s.xcnt--;\n        for (int i = 0; i < N - 1; i++) {\n            bool xb = s.x[i + 1] & bit;\n            bool ob = s.o[i + 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[N - 1] &= ~bit;\n        s.o[N - 1] &= ~bit;\n    } else {\n        uint32_t bit = 1u << p;\n        if (s.x[N - 1] & bit) s.xcnt--;\n        for (int i = N - 1; i >= 1; i--) {\n            bool xb = s.x[i - 1] & bit;\n            bool ob = s.o[i - 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[0] &= ~bit;\n        s.o[0] &= ~bit;\n    }\n}\n\nvoid applyGAct(State& s, const GAct& a) {\n    Op op{a.d, a.p};\n    for (int i = 0; i < a.k; i++) applyOp(s, op);\n}\n\nvector<Op> expandGSeq(const vector<GAct>& gs) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& g : gs) total += g.k;\n    ops.reserve(total);\n    for (auto& g : gs) appendOps(ops, g.d, g.p, g.k);\n    return ops;\n}\n\nbool isPerfectFull(const vector<Op>& ops) {\n    if ((int)ops.size() > 4 * N * N) return false;\n    State s = INIT;\n    for (auto& op : ops) {\n        if (edgeO(s, op)) return false;\n        applyOp(s, op);\n    }\n    return s.xcnt == 0;\n}\n\n// Truncate to the earliest prefix that already removes all Oni.\n// Returns false if no valid prefix exists.\nbool truncateToPerfectPrefix(vector<Op>& ops) {\n    if (INIT.xcnt == 0) {\n        ops.clear();\n        return true;\n    }\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) {\n            ops.resize(t + 1);\n            return true;\n        }\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkip(const vector<Op>& ops, int l, int r) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (l <= t && t < r) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nvoid pruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n\n        int maxLen = min(50, (int)seq.size());\n        for (int len = maxLen; len >= 2 && elapsed() < until; len--) {\n            for (int i = 0; i + len <= (int)seq.size() && elapsed() < until; ) {\n                if (canPerfectSkip(seq, i, i + len)) {\n                    seq.erase(seq.begin() + i, seq.begin() + i + len);\n                    truncateToPerfectPrefix(seq);\n                    changed = true;\n                    i = max(0, i - len);\n                } else {\n                    i++;\n                }\n            }\n        }\n\n        for (int i = 0; i < (int)seq.size() && elapsed() < until; ) {\n            if (canPerfectSkip(seq, i, i + 1)) {\n                seq.erase(seq.begin() + i);\n                truncateToPerfectPrefix(seq);\n                changed = true;\n                if (i > 0) i--;\n            } else {\n                i++;\n            }\n        }\n    }\n}\n\nstruct OInfo {\n    int firstRow[MAXN], lastRow[MAXN], rowCnt[MAXN];\n    int firstCol[MAXN], lastCol[MAXN], colCnt[MAXN];\n};\n\nvoid computeOInfo(const State& s, OInfo& info) {\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.o[i];\n        info.firstRow[i] = firstBit(m);\n        info.lastRow[i] = lastBit(m);\n        info.rowCnt[i] = popc(m);\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t cm = 0;\n        uint32_t bit = 1u << j;\n        for (int i = 0; i < N; i++) {\n            if (s.o[i] & bit) cm |= 1u << i;\n        }\n        info.firstCol[j] = firstBit(cm);\n        info.lastCol[j] = lastBit(cm);\n        info.colCnt[j] = popc(cm);\n    }\n}\n\nstruct Analysis {\n    int xcnt = 0;\n    int invis = 0;\n    double sumMin = 0;\n};\n\nAnalysis analyzeState(const State& s) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    Analysis a;\n    a.xcnt = s.xcnt;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            int md = 100;\n\n            if (j < info.firstRow[i]) vis++, md = min(md, j + 1);\n            if (j > info.lastRow[i]) vis++, md = min(md, N - j);\n            if (i < info.firstCol[j]) vis++, md = min(md, i + 1);\n            if (i > info.lastCol[j]) vis++, md = min(md, N - i);\n\n            if (vis == 0) {\n                a.invis++;\n                a.sumMin += N;\n            } else {\n                a.sumMin += md;\n            }\n        }\n    }\n    return a;\n}\n\nstruct GenParam {\n    double alpha = 1.0;\n    double critW = 6.0;\n    double twoW = 2.0;\n    double multiW = 1.0;\n    double damageW = 0.0;\n};\n\nstruct Cand {\n    char d;\n    int p, k;\n    int cnt;\n    double benefit;\n    double score;\n};\n\nvector<Cand> genCandidates(const State& s, const GenParam& gp) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    static double w[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) w[i][j] = 0.0;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            if (j < info.firstRow[i]) vis++;\n            if (j > info.lastRow[i]) vis++;\n            if (i < info.firstCol[j]) vis++;\n            if (i > info.lastCol[j]) vis++;\n\n            if (vis == 1) w[i][j] = gp.critW;\n            else if (vis == 2) w[i][j] = gp.twoW;\n            else if (vis >= 3) w[i][j] = gp.multiW;\n        }\n    }\n\n    vector<Cand> res;\n    res.reserve(160);\n\n    auto addCand = [&](char d, int p, int k, int cnt, double benefit, int movedO) {\n        if (cnt <= 0) return;\n        double b = max(1e-9, benefit);\n        double sc = (double)k / pow(b, gp.alpha) + gp.damageW * movedO * k;\n        res.push_back({d, p, k, cnt, benefit, sc});\n    };\n\n    for (int i = 0; i < N; i++) {\n        // L\n        {\n            int clear = info.firstRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int j = 0; j < clear; j++) {\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('L', i, j + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n        // R\n        {\n            int clear = N - 1 - info.lastRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int j = N - 1 - t;\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('R', i, t + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n        // U\n        {\n            int clear = info.firstCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int i = 0; i < clear; i++) {\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('U', j, i + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n        // D\n        {\n            int clear = N - 1 - info.lastCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int i = N - 1 - t;\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('D', j, t + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\n// ---------- Guaranteed cover construction ----------\n\nstruct CoverCand {\n    char d;\n    int p, k;\n    uint64_t mask;\n};\n\nvector<CoverCand> buildCoverCandidates() {\n    vector<CoverCand> cands;\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        for (int j = 0; j < N; j++) {\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'L', i, j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int j = N - 1 - t;\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'R', i, t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n\n        uint64_t mask = 0;\n        for (int i = 0; i < N; i++) {\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'U', j, i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int i = N - 1 - t;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'D', j, t + 1, mask});\n            }\n        }\n    }\n\n    return cands;\n}\n\nuint64_t unionIds(const vector<int>& ids, const vector<CoverCand>& cands) {\n    uint64_t m = 0;\n    for (int id : ids) m |= cands[id].mask;\n    return m;\n}\n\nint objectiveCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    if (ids.empty()) return 0;\n    int sum = 0, mx = 0;\n    for (int id : ids) {\n        sum += 2 * cands[id].k;\n        mx = max(mx, cands[id].k);\n    }\n    return sum - mx;\n}\n\nvoid removeRedundant(vector<int>& ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int a = 0; a < (int)ids.size(); a++) {\n            uint64_t u = 0;\n            for (int b = 0; b < (int)ids.size(); b++) if (a != b) {\n                u |= cands[ids[b]].mask;\n            }\n            if (u == ALL) {\n                ids.erase(ids.begin() + a);\n                changed = true;\n                break;\n            }\n        }\n    }\n}\n\nvector<int> greedyCover(int pre, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    vector<int> ids;\n    uint64_t covered = 0;\n\n    if (pre >= 0) {\n        ids.push_back(pre);\n        covered |= cands[pre].mask;\n    }\n\n    while (covered != ALL) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            uint64_t nm = cands[i].mask & ~covered;\n            if (!nm) continue;\n\n            int nc = __builtin_popcountll(nm);\n            int cost = 2 * cands[i].k;\n            double sc;\n\n            if (mode == 0) sc = cost / (double)nc;\n            else if (mode == 1) sc = cost / pow((double)nc, 1.3);\n            else if (mode == 2) sc = (cost - 0.3 * cands[i].k) / pow((double)nc, 1.1);\n            else if (mode == 3) sc = cost / (double)(nc * nc);\n            else sc = (cost + 0.05 * __builtin_popcountll(cands[i].mask)) / pow((double)nc, 1.5);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) break;\n        ids.push_back(best);\n        covered |= cands[best].mask;\n    }\n\n    removeRedundant(ids, cands, ALL);\n    return ids;\n}\n\nvector<int> improveCoverPlan(vector<int> ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    removeRedundant(ids, cands, ALL);\n\n    for (int iter = 0; iter < 12; iter++) {\n        int curObj = objectiveCover(ids, cands);\n        vector<int> bestIds = ids;\n        int bestObj = curObj;\n\n        vector<char> in(cands.size(), 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int c = 0; c < (int)cands.size(); c++) {\n            if (in[c]) continue;\n            vector<int> tmp = ids;\n            tmp.push_back(c);\n            removeRedundant(tmp, cands, ALL);\n            if (unionIds(tmp, cands) != ALL) continue;\n\n            int obj = objectiveCover(tmp, cands);\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestIds = tmp;\n            }\n        }\n\n        if (bestObj < curObj) ids = bestIds;\n        else break;\n    }\n\n    return ids;\n}\n\nstruct Plan {\n    vector<int> ids;\n    int obj;\n};\n\nstring keyIds(vector<int> ids) {\n    sort(ids.begin(), ids.end());\n    string s;\n    for (int id : ids) {\n        s += to_string(id);\n        s += ',';\n    }\n    return s;\n}\n\nvector<Plan> generateCoverPlans(const vector<CoverCand>& cands) {\n    int M = (int)initialXs.size();\n    uint64_t ALL = (M == 64 ? ~0ULL : ((1ULL << M) - 1));\n\n    vector<Plan> plans;\n    unordered_set<string> seen;\n\n    auto addPlan = [&](vector<int> ids) {\n        if (ids.empty()) return;\n        removeRedundant(ids, cands, ALL);\n        if (unionIds(ids, cands) != ALL) return;\n        string key = keyIds(ids);\n        if (seen.insert(key).second) {\n            plans.push_back({ids, objectiveCover(ids, cands)});\n        }\n    };\n\n    for (int mode = 0; mode < 5; mode++) {\n        addPlan(greedyCover(-1, mode, cands, ALL));\n        for (int pre = 0; pre < (int)cands.size(); pre++) {\n            addPlan(greedyCover(pre, mode, cands, ALL));\n        }\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    int top = min(25, (int)plans.size());\n    for (int i = 0; i < top; i++) {\n        addPlan(improveCoverPlan(plans[i].ids, cands, ALL));\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    if ((int)plans.size() > 60) plans.resize(60);\n    return plans;\n}\n\nvector<int> orderedIds(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = plan.ids;\n\n    if (variant == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k > cands[b].k;\n        });\n    } else if (variant == 3) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (cands[a].d != cands[b].d) return cands[a].d < cands[b].d;\n            if (cands[a].p != cands[b].p) return cands[a].p < cands[b].p;\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant >= 4) {\n        for (int i = (int)ids.size() - 1; i >= 1; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ids[i], ids[j]);\n        }\n    }\n\n    return ids;\n}\n\nvector<Op> buildRoundTripOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n    if (ids.empty()) return ops;\n\n    int maxK = -1;\n    vector<int> finals;\n    for (int id : ids) {\n        if (cands[id].k > maxK) {\n            maxK = cands[id].k;\n            finals.clear();\n            finals.push_back(id);\n        } else if (cands[id].k == maxK) {\n            finals.push_back(id);\n        }\n    }\n\n    int finalId = finals[variant % finals.size()];\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += 2 * cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        if (id == finalId) continue;\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n        appendOps(ops, invDir(c.d), c.p, c.k);\n    }\n\n    auto& f = cands[finalId];\n    appendOps(ops, f.d, f.p, f.k);\n    return ops;\n}\n\nvector<Op> buildOneWayOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n    }\n    return ops;\n}\n\nvector<Op> makeHintSequence() {\n    vector<Op> ops;\n\n    for (auto [i, j] : initialXs) {\n        int bestK = 1e9;\n        char bestD = 'L';\n\n        auto upd = [&](char d, int k) {\n            if (k < bestK) {\n                bestK = k;\n                bestD = d;\n            }\n        };\n\n        uint32_t leftMask = (j == 0 ? 0u : ((1u << j) - 1));\n        if ((INIT.o[i] & leftMask) == 0) upd('L', j + 1);\n\n        uint32_t rightMask = FULL & ~((1u << (j + 1)) - 1);\n        if ((INIT.o[i] & rightMask) == 0) upd('R', N - j);\n\n        uint32_t bit = 1u << j;\n\n        bool ok = true;\n        for (int r = 0; r < i; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('U', i + 1);\n\n        ok = true;\n        for (int r = i + 1; r < N; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('D', N - i);\n\n        if (bestK < 1e9) {\n            appendOps(ops, bestD, (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n            appendOps(ops, invDir(bestD), (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n        }\n    }\n\n    return ops;\n}\n\n// ---------- Direct search ----------\n\nuint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nuint64_t hashState(const State& s) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (int i = 0; i < N; i++) {\n        uint64_t v = ((uint64_t)s.x[i] << 32) ^ s.o[i] ^ (uint64_t)i * 0x9e3779b97f4a7c15ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\ndouble stateHeuristic(const State& s) {\n    Analysis a = analyzeState(s);\n    return 0.32 * a.sumMin + 4.5 * a.invis + 0.15 * a.xcnt;\n}\n\nstruct TrialParam {\n    GenParam gen;\n    double noise = 0.0;\n    int topK = 1;\n    double topBias = 2.0;\n    double lookInvW = 0.0;\n    double lookSumW = 0.0;\n};\n\nTrialParam makeTrialParam(int t, RNG& rng) {\n    TrialParam p;\n\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.lookInvW = 4.0;\n        p.lookSumW = 0.015;\n    } else if (t == 1) {\n        p.gen = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.lookInvW = 3.0;\n        p.lookSumW = 0.010;\n    } else if (t == 2) {\n        p.gen = {1.5, 4.0, 1.8, 1.0, 0.02};\n    } else if (t == 3) {\n        p.gen = {0.85, 10.0, 2.5, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.15;\n        p.lookInvW = 2.0;\n    } else if (t == 4) {\n        p.gen = {1.2, 8.0, 3.0, 1.0, 0.03};\n        p.topK = 2;\n    } else if (t == 5) {\n        p.gen = {0.55, 5.0, 1.5, 1.0, 0.00};\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.9;\n        p.gen.critW = 3.0 + rng.nextDouble() * 8.0;\n        p.gen.twoW = 1.2 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.04;\n        p.noise = 0.15 + rng.nextDouble() * 0.9;\n        p.topK = 1 + rng.nextInt(8);\n        p.topBias = 1.5 + rng.nextDouble() * 3.0;\n\n        if (t % 7 == 0) {\n            p.lookInvW = 1.5 + rng.nextDouble() * 3.0;\n            p.lookSumW = 0.004 + rng.nextDouble() * 0.012;\n        }\n    }\n\n    return p;\n}\n\nvector<Op> directTrial(const TrialParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = INIT;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n\n        vector<Cand> viable;\n        viable.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            double score = c.score;\n\n            if (tp.lookInvW > 0 || tp.lookSumW > 0) {\n                State tmp = st;\n                applyGAct(tmp, {c.d, c.p, c.k});\n                Analysis a = analyzeState(tmp);\n\n                if (a.xcnt > 0 && a.invis == a.xcnt) score += 1e6;\n                score += tp.lookInvW * a.invis;\n                score += tp.lookSumW * a.sumMin;\n            }\n\n            if (tp.noise > 0) {\n                double z = tp.noise * (2.0 * rng.nextDouble() - 1.0);\n                score *= exp(z);\n            }\n\n            c.score = score;\n            viable.push_back(c);\n        }\n\n        if (viable.empty()) return {};\n\n        sort(viable.begin(), viable.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        int m = min(tp.topK, (int)viable.size());\n        int idx = 0;\n        if (m > 1) {\n            idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.topBias) * m));\n        }\n\n        Cand ch = viable[idx];\n\n        GAct ga{ch.d, ch.p, ch.k};\n        applyGAct(st, ga);\n        seq.push_back(ga);\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nstruct BeamState {\n    State st;\n    int g;\n    vector<GAct> seq;\n    double eval;\n    uint64_t h;\n};\n\nvector<Op> beamSearch(int moveLimit, double until, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    GenParam gp;\n    gp.alpha = 1.15;\n    gp.critW = 7.5;\n    gp.twoW = 2.4;\n    gp.multiW = 1.0;\n    gp.damageW = 0.015;\n\n    const int WIDTH = 260;\n    const int PER_STATE = 12;\n\n    vector<BeamState> beam;\n    beam.push_back({INIT, 0, {}, stateHeuristic(INIT), hashState(INIT)});\n\n    int bestG = INT_MAX;\n    vector<GAct> bestSeq;\n\n    for (int depth = 0; depth < 45 && elapsed() < until; depth++) {\n        vector<BeamState> next;\n        next.reserve(WIDTH * PER_STATE);\n\n        for (auto& bs : beam) {\n            if (elapsed() >= until) break;\n            if (bs.st.xcnt == 0) {\n                if (bs.g < bestG) {\n                    bestG = bs.g;\n                    bestSeq = bs.seq;\n                }\n                continue;\n            }\n\n            vector<Cand> cands = genCandidates(bs.st, gp);\n            if (cands.empty()) continue;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                return a.score < b.score;\n            });\n\n            int take = min(PER_STATE, (int)cands.size());\n            for (int ci = 0; ci < take; ci++) {\n                const Cand& c = cands[ci];\n                int ng = bs.g + c.k;\n                if (ng > moveLimit) continue;\n\n                State ns = bs.st;\n                applyGAct(ns, {c.d, c.p, c.k});\n\n                BeamState child;\n                child.st = ns;\n                child.g = ng;\n                child.seq = bs.seq;\n                child.seq.push_back({c.d, c.p, c.k});\n                child.h = hashState(ns);\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestG) {\n                        bestG = ng;\n                        bestSeq = child.seq;\n                    }\n                    continue;\n                }\n\n                child.eval = ng + stateHeuristic(ns);\n                next.push_back(std::move(child));\n            }\n        }\n\n        if (next.empty()) break;\n\n        sort(next.begin(), next.end(), [](const BeamState& a, const BeamState& b) {\n            return a.eval < b.eval;\n        });\n\n        vector<BeamState> nb;\n        nb.reserve(WIDTH);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(WIDTH * 2);\n\n        for (auto& s : next) {\n            if (seen.insert(s.h).second) {\n                nb.push_back(std::move(s));\n                if ((int)nb.size() >= WIDTH) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    if (bestG < INT_MAX) return expandGSeq(bestSeq);\n    return {};\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START = chrono::steady_clock::now();\n\n    cin >> N;\n    FULL = (1u << N) - 1;\n\n    INIT.x.fill(0);\n    INIT.o.fill(0);\n    INIT.xcnt = 0;\n    memset(idxAt, -1, sizeof(idxAt));\n\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') {\n                idxAt[i][j] = (int)initialXs.size();\n                initialXs.push_back({i, j});\n                INIT.x[i] |= 1u << j;\n                INIT.xcnt++;\n            } else if (C[i][j] == 'o') {\n                INIT.o[i] |= 1u << j;\n            }\n        }\n    }\n\n    uint64_t seed = hashState(INIT) ^ 0xa5a5a5a5deadbeefULL;\n    RNG rng(seed);\n\n    const double HARD = 1.85;\n\n    vector<Op> best = makeHintSequence();\n    truncateToPerfectPrefix(best);\n\n    vector<CoverCand> coverCands = buildCoverCandidates();\n    vector<Plan> plans = generateCoverPlans(coverCands);\n\n    auto consider = [&](vector<Op> ops, double pruneUntil) {\n        if (ops.empty()) return;\n        if (!truncateToPerfectPrefix(ops)) return;\n        if (pruneUntil > elapsed()) pruneSequence(ops, pruneUntil);\n        if (isPerfectFull(ops) && ops.size() < best.size()) {\n            best = std::move(ops);\n        }\n    };\n\n    if (!plans.empty()) {\n        vector<Op> ops = buildRoundTripOps(plans[0], coverCands, 0, rng);\n        consider(ops, 0.20);\n    }\n\n    pruneSequence(best, min(0.22, HARD));\n\n    // Try several guaranteed cover orders and aggressive one-way orders.\n    for (int pi = 0; pi < (int)plans.size() && pi < 10 && elapsed() < 0.45; pi++) {\n        for (int v = 0; v < 6 && elapsed() < 0.45; v++) {\n            {\n                vector<Op> ops = buildOneWayOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.020));\n            }\n            {\n                vector<Op> ops = buildRoundTripOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.025));\n            }\n        }\n    }\n\n    pruneSequence(best, min(0.50, HARD));\n\n    // Beam search for dynamic one-way sweeps.\n    if (elapsed() < 1.05) {\n        vector<Op> bops = beamSearch((int)best.size() + 70, 1.05, rng);\n        consider(bops, min(1.15, elapsed() + 0.08));\n    }\n\n    // Randomized greedy dynamic trials.\n    int trial = 0;\n    int pruneCnt = 0;\n    while (elapsed() < 1.70) {\n        TrialParam tp = makeTrialParam(trial, rng);\n        int limit = min(4 * N * N, (int)best.size() + 70);\n\n        vector<Op> ops = directTrial(tp, limit, rng);\n        if (!ops.empty()) {\n            double until = elapsed();\n            if ((int)ops.size() < (int)best.size() + 50 && pruneCnt < 25) {\n                until = min(1.72, elapsed() + 0.018);\n                pruneCnt++;\n            }\n            consider(ops, until);\n        }\n\n        trial++;\n    }\n\n    if (elapsed() < HARD) {\n        pruneSequence(best, HARD);\n    }\n\n    if (!isPerfectFull(best)) {\n        best = makeHintSequence();\n        truncateToPerfectPrefix(best);\n    }\n\n    for (auto& op : best) {\n        cout << op.d << ' ' << op.p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 100;\nconstexpr int MAXE = 200;\n\nint N, L;\narray<int, MAXN> T;\narray<int, MAXN> Cdes;\narray<int, MAXN> demandIn;\n\nvector<int> activeChoices;\nvector<int> validZs;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int randint(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n} rng;\n\ntemplate<class Tvec>\nvoid shuffle_vec(vector<Tvec>& v) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nchrono::steady_clock::time_point st_time;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - st_time).count();\n}\n\nstruct Cand {\n    array<int, MAXN> a, b;\n    array<unsigned char, MAXE> prot;\n};\n\nstruct SimResult {\n    long long err;\n    array<int, MAXN> cnt;\n    int last;\n};\n\nstruct Entry {\n    long long err;\n    Cand cand;\n    SimResult res;\n};\n\nCand bestCand;\nSimResult bestRes;\nlong long bestErr = (1LL << 60);\nvector<Entry> pool;\n\ninline long long absl(long long x) {\n    return x >= 0 ? x : -x;\n}\n\nlong long cellCost(long long diff, int mode) {\n    long long a = absl(diff);\n    if (mode == 0) return diff * diff;\n    if (mode == 1) return a;\n    return diff * diff + 1000LL * a;\n}\n\nvoid getDest(const Cand& c, array<int, MAXE>& dest) {\n    for (int i = 0; i < N; ++i) {\n        dest[2 * i] = c.a[i];\n        dest[2 * i + 1] = c.b[i];\n    }\n}\n\nvoid setEdge(Cand& c, int e, int to) {\n    int v = e / 2;\n    if (e & 1) c.b[v] = to;\n    else c.a[v] = to;\n}\n\nSimResult simulate(const Cand& c) {\n    SimResult r;\n    r.cnt.fill(0);\n\n    int x = 0;\n    r.cnt[0] = 1;\n\n    for (int step = 1; step < L; ++step) {\n        int nx = (r.cnt[x] & 1) ? c.a[x] : c.b[x];\n        x = nx;\n        ++r.cnt[x];\n    }\n\n    r.last = x;\n\n    long long e = 0;\n    for (int i = 0; i < N; ++i) {\n        e += llabs((long long)r.cnt[i] - T[i]);\n    }\n    r.err = e;\n    return r;\n}\n\nbool addEvaluated(const Cand& c, const SimResult& r) {\n    bool improved = false;\n\n    if (r.err < bestErr) {\n        bestErr = r.err;\n        bestCand = c;\n        bestRes = r;\n        improved = true;\n    }\n\n    if ((int)pool.size() < 12 || r.err < pool.back().err) {\n        pool.push_back({r.err, c, r});\n        sort(pool.begin(), pool.end(), [](const Entry& x, const Entry& y) {\n            return x.err < y.err;\n        });\n        while ((int)pool.size() > 12) pool.pop_back();\n    }\n\n    return improved;\n}\n\nbool consider(const Cand& c) {\n    SimResult r = simulate(c);\n    return addEvaluated(c, r);\n}\n\nvoid optimizeItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty() || items.empty()) return;\n\n    vector<int> order = items;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        bool improved = false;\n\n        if (randomize) shuffle_vec(order);\n\n        for (int e : order) {\n            int ww = w[e];\n            if (ww == 0) continue;\n\n            int old = dest[e];\n            long long oldCostOld = cellCost(loads[old] - dem[old], objMode);\n            long long bestDelta = 0;\n            int bestY = old;\n\n            for (int y : choices) {\n                if (y == old) continue;\n\n                long long delta =\n                    cellCost(loads[old] - ww - dem[old], objMode) +\n                    cellCost(loads[y] + ww - dem[y], objMode) -\n                    oldCostOld -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestY = y;\n                }\n            }\n\n            if (bestY != old) {\n                loads[old] -= ww;\n                loads[bestY] += ww;\n                dest[e] = bestY;\n                improved = true;\n            }\n        }\n\n        int M = (int)order.size();\n\n        for (int ii = 0; ii < M; ++ii) {\n            int e = order[ii];\n            int we = w[e];\n            if (we == 0) continue;\n\n            for (int jj = ii + 1; jj < M; ++jj) {\n                int f = order[jj];\n                int wf = w[f];\n\n                if (wf == 0 || we == wf) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n\n                if (x == y) continue;\n\n                long long nx = loads[x] - we + wf;\n                long long ny = loads[y] - wf + we;\n\n                long long delta =\n                    cellCost(nx - dem[x], objMode) +\n                    cellCost(ny - dem[y], objMode) -\n                    cellCost(loads[x] - dem[x], objMode) -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < 0) {\n                    loads[x] = nx;\n                    loads[y] = ny;\n                    swap(dest[e], dest[f]);\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid assignItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty()) return;\n\n    vector<int> order = items;\n\n    if (randomize) shuffle_vec(order);\n\n    stable_sort(order.begin(), order.end(), [&](int e1, int e2) {\n        return w[e1] > w[e2];\n    });\n\n    int root = choices[0];\n\n    for (int e : order) {\n        int ww = w[e];\n\n        if (ww == 0) {\n            dest[e] = root;\n            continue;\n        }\n\n        vector<pair<long long, int>> cand;\n        cand.reserve(choices.size());\n\n        for (int y : choices) {\n            long long delta =\n                cellCost(loads[y] + ww - dem[y], objMode) -\n                cellCost(loads[y] - dem[y], objMode);\n            cand.push_back({delta, y});\n        }\n\n        int take = min((int)cand.size(), max(1, topR));\n\n        nth_element(cand.begin(), cand.begin() + take - 1, cand.end());\n        sort(cand.begin(), cand.begin() + take);\n\n        int idx = 0;\n        if (randomize && take > 1) {\n            int r = rng.randint(100);\n            if (r >= 70) idx = 1 + rng.randint(take - 1);\n        }\n\n        int y = cand[idx].second;\n        dest[e] = y;\n        loads[y] += ww;\n    }\n\n    optimizeItems(dest, w, items, choices, loads, dem, objMode, maxPass, randomize);\n}\n\nint computeSCC(const array<int, MAXE>& dest, vector<int>& comp, vector<vector<int>>& comps) {\n    comp.assign(N, -1);\n    comps.clear();\n\n    if (activeChoices.empty()) return 0;\n\n    array<char, MAXN> active{};\n    active.fill(0);\n    for (int v : activeChoices) active[v] = 1;\n\n    vector<int> g[MAXN], rg[MAXN];\n\n    for (int v : activeChoices) {\n        for (int p = 0; p < 2; ++p) {\n            int to = dest[2 * v + p];\n            if (0 <= to && to < N && active[to]) {\n                g[v].push_back(to);\n                rg[to].push_back(v);\n            }\n        }\n    }\n\n    vector<int> order;\n    array<char, MAXN> vis{};\n    vis.fill(0);\n\n    function<void(int)> dfs1 = [&](int v) {\n        vis[v] = 1;\n        for (int to : g[v]) {\n            if (!vis[to]) dfs1(to);\n        }\n        order.push_back(v);\n    };\n\n    function<void(int, int)> dfs2 = [&](int v, int id) {\n        comp[v] = id;\n        comps[id].push_back(v);\n        for (int to : rg[v]) {\n            if (comp[to] == -1) dfs2(to, id);\n        }\n    };\n\n    for (int v : activeChoices) {\n        if (!vis[v]) dfs1(v);\n    }\n\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            comps.push_back({});\n            dfs2(v, (int)comps.size() - 1);\n        }\n    }\n\n    return (int)comps.size();\n}\n\nvoid repairStrong(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 4; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        for (int c = 0; c < K; ++c) {\n            int tc = (c + 1) % K;\n\n            long long bestDelta = (1LL << 62);\n            int bestE = -1;\n            int bestY = -1;\n\n            for (int s : comps[c]) {\n                for (int p = 0; p < 2; ++p) {\n                    int e = 2 * s + p;\n                    int ww = w[e];\n                    int old = dest[e];\n\n                    long long oldCostOld = cellCost(loads[old] - dem[old], objMode);\n\n                    for (int y : comps[tc]) {\n                        long long delta =\n                            cellCost(loads[old] - ww - dem[old], objMode) +\n                            cellCost(loads[y] + ww - dem[y], objMode) -\n                            oldCostOld -\n                            cellCost(loads[y] - dem[y], objMode);\n\n                        if (\n                            delta < bestDelta ||\n                            (delta == bestDelta && bestE != -1 && ww < w[bestE])\n                        ) {\n                            bestDelta = delta;\n                            bestE = e;\n                            bestY = y;\n                        }\n                    }\n                }\n            }\n\n            if (bestE != -1) {\n                int old = dest[bestE];\n                int ww = w[bestE];\n\n                loads[old] -= ww;\n                loads[bestY] += ww;\n                dest[bestE] = bestY;\n                prot[bestE] = 1;\n            }\n        }\n    }\n}\n\nCand buildSimpleCycle(bool activeOnly) {\n    Cand c;\n    c.prot.fill(0);\n\n    if (activeOnly && !activeChoices.empty()) {\n        int root = activeChoices[0];\n\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = root;\n            c.b[i] = root;\n        }\n\n        int m = (int)activeChoices.size();\n\n        for (int k = 0; k < m; ++k) {\n            int v = activeChoices[k];\n            int to = activeChoices[(k + 1) % m];\n\n            c.a[v] = to;\n            c.b[v] = to;\n        }\n    } else {\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = (i + 1) % N;\n            c.b[i] = (i + 1) % N;\n        }\n    }\n\n    return c;\n}\n\nCand buildFree(\n    int z,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    bool doRepair\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] > 0) items.push_back(e);\n        else dest[e] = root;\n    }\n\n    assignItems(dest, w, items, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    if (doRepair) {\n        repairStrong(dest, w, loads, demandIn, objMode, prot);\n    }\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand buildBackbone(\n    int fixedParity,\n    int z,\n    int K,\n    int noiseAmp,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct NK {\n        int key;\n        int dem;\n        int node;\n    };\n\n    vector<NK> keys;\n    keys.reserve(activeChoices.size());\n\n    for (int v : activeChoices) {\n        int key = demandIn[v];\n\n        if (noiseAmp > 0) {\n            key += rng.randint(2 * noiseAmp + 1) - noiseAmp;\n        }\n\n        keys.push_back({key, demandIn[v], v});\n    }\n\n    sort(keys.begin(), keys.end(), [](const NK& x, const NK& y) {\n        if (x.key != y.key) return x.key > y.key;\n        if (x.dem != y.dem) return x.dem > y.dem;\n        return x.node < y.node;\n    });\n\n    vector<int> base;\n    for (auto& x : keys) base.push_back(x.node);\n\n    vector<int> order;\n    int m = (int)base.size();\n\n    if (m == 0) {\n        order.push_back(0);\n    } else {\n        K = max(1, min(K, m));\n\n        for (int r = 0; r < K; ++r) {\n            for (int idx = r; idx < m; idx += K) {\n                order.push_back(base[idx]);\n            }\n        }\n    }\n\n    root = order[0];\n    dest.fill(root);\n\n    array<char, MAXN> isAct{};\n    isAct.fill(0);\n    for (int v : order) isAct[v] = 1;\n\n    vector<int> flexItems;\n    flexItems.reserve(MAXE);\n\n    for (int k = 0; k < (int)order.size(); ++k) {\n        int s = order[k];\n        int to = order[(k + 1) % order.size()];\n\n        int fixedIdx = 2 * s + fixedParity;\n        int flexIdx = 2 * s + (1 - fixedParity);\n\n        dest[fixedIdx] = to;\n        prot[fixedIdx] = 1;\n        loads[to] += w[fixedIdx];\n\n        flexItems.push_back(flexIdx);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (isAct[i]) continue;\n\n        for (int p = 0; p < 2; ++p) {\n            int e = 2 * i + p;\n\n            if (w[e] > 0) flexItems.push_back(e);\n            else dest[e] = root;\n        }\n    }\n\n    assignItems(dest, w, flexItems, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand rebalanceCandidate(\n    const Entry& base,\n    bool fullReassign,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    bool doRepair\n) {\n    array<int, MAXE> dest;\n    getDest(base.cand, dest);\n\n    array<unsigned char, MAXE> prot = base.cand.prot;\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = base.res.cnt[i] - (base.res.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    array<long long, MAXN> loads;\n    loads.fill(0);\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n\n    if (fullReassign) {\n        for (int e = 0; e < 2 * N; ++e) {\n            if (prot[e]) {\n                loads[dest[e]] += w[e];\n            } else {\n                items.push_back(e);\n                dest[e] = root;\n            }\n        }\n\n        assignItems(dest, w, items, activeChoices, loads, demandIn,\n                    objMode, topR, maxPass, randomize);\n    } else {\n        for (int e = 0; e < 2 * N; ++e) {\n            loads[dest[e]] += w[e];\n\n            if (!prot[e]) {\n                items.push_back(e);\n            }\n        }\n\n        optimizeItems(dest, w, items, activeChoices, loads, demandIn,\n                      objMode, maxPass, randomize);\n    }\n\n    if (doRepair) {\n        repairStrong(dest, w, loads, demandIn, objMode, prot);\n    }\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nbool validZ(int z) {\n    if (z < 0 || z >= N) return false;\n    if (Cdes[z] <= 0) return false;\n    if (z == 0 && Cdes[0] <= 1) return false;\n    return true;\n}\n\nint randomZ() {\n    if (!validZs.empty()) {\n        return validZs[rng.randint((int)validZs.size())];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (Cdes[i] > 0) return i;\n    }\n\n    return 0;\n}\n\nbool tryLocalImprove(double TL) {\n    if (activeChoices.empty()) return false;\n\n    array<int, MAXE> dest;\n    getDest(bestCand, dest);\n\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = bestRes.cnt[i] - (bestRes.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct Change {\n        long long delta;\n        int type;\n        int e;\n        int f;\n        int y;\n    };\n\n    vector<Change> moves;\n    moves.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        int ww = w[e];\n        if (ww == 0) continue;\n\n        int old = dest[e];\n\n        for (int y : activeChoices) {\n            if (y == old) continue;\n\n            long long delta =\n                llabs((long long)bestRes.cnt[old] - ww - T[old]) +\n                llabs((long long)bestRes.cnt[y] + ww - T[y]) -\n                llabs((long long)bestRes.cnt[old] - T[old]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) {\n                moves.push_back({delta, 0, e, -1, y});\n            }\n        }\n    }\n\n    sort(moves.begin(), moves.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    int testLimit = min(36, (int)moves.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n        setEdge(c, moves[i].e, moves[i].y);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    vector<Change> swaps;\n    swaps.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] == 0) continue;\n\n        for (int f = e + 1; f < 2 * N; ++f) {\n            if (w[f] == 0) continue;\n\n            int x = dest[e];\n            int y = dest[f];\n\n            if (x == y) continue;\n\n            int we = w[e];\n            int wf = w[f];\n\n            if (we == wf) continue;\n\n            long long nx = (long long)bestRes.cnt[x] - we + wf;\n            long long ny = (long long)bestRes.cnt[y] - wf + we;\n\n            long long delta =\n                llabs(nx - T[x]) +\n                llabs(ny - T[y]) -\n                llabs((long long)bestRes.cnt[x] - T[x]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) {\n                swaps.push_back({delta, 1, e, f, -1});\n            }\n        }\n    }\n\n    sort(swaps.begin(), swaps.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    testLimit = min(36, (int)swaps.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n\n        int e = swaps[i].e;\n        int f = swaps[i].f;\n\n        setEdge(c, e, dest[f]);\n        setEdge(c, f, dest[e]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\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    cin >> N >> L;\n\n    uint64_t seed = 123456789;\n\n    for (int i = 0; i < N; ++i) {\n        cin >> T[i];\n        seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    }\n\n    rng = RNG(seed);\n    st_time = chrono::steady_clock::now();\n\n    Cdes = T;\n\n    if (T[0] == 0) {\n        Cdes[0] = 1;\n\n        int k = 1;\n        for (int i = 1; i < N; ++i) {\n            if (T[i] > T[k]) k = i;\n        }\n\n        --Cdes[k];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        demandIn[i] = Cdes[i];\n    }\n\n    --demandIn[0];\n\n    if (demandIn[0] < 0) demandIn[0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (demandIn[i] > 0) {\n            activeChoices.push_back(i);\n        }\n    }\n\n    if (activeChoices.empty()) {\n        int k = max_element(Cdes.begin(), Cdes.begin() + N) - Cdes.begin();\n        activeChoices.push_back(k);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (validZ(i)) validZs.push_back(i);\n    }\n\n    if (validZs.empty()) {\n        for (int i = 0; i < N; ++i) {\n            if (Cdes[i] > 0) validZs.push_back(i);\n        }\n    }\n\n    consider(buildSimpleCycle(false));\n    consider(buildSimpleCycle(true));\n\n    vector<int> zlist;\n\n    auto addZ = [&](int z) {\n        if (!validZ(z)) return;\n        if (find(zlist.begin(), zlist.end(), z) == zlist.end()) {\n            zlist.push_back(z);\n        }\n    };\n\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        return Cdes[x] > Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) {\n        addZ(ids[i]);\n    }\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        if ((Cdes[x] > 0) != (Cdes[y] > 0)) return Cdes[x] > 0;\n        return Cdes[x] < Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) {\n        addZ(ids[i]);\n    }\n\n    addZ(0);\n\n    if (zlist.empty() && !validZs.empty()) {\n        zlist.push_back(validZs[0]);\n    }\n\n    const double TL = 1.86;\n    const double PHASE_FREE_DET = 0.58;\n    const double PHASE_FREE_RAND = 1.08;\n    const double PHASE_REBAL = 1.52;\n\n    // New main construction: all edges free, then optional SCC repair.\n    for (int z : zlist) {\n        for (int repair = 0; repair <= 1; ++repair) {\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() > PHASE_FREE_DET) break;\n\n                Cand c = buildFree(z, mode, 1, 8, false, repair);\n                consider(c);\n            }\n        }\n    }\n\n    // Small amount of the older safe backbone construction as fallback/diversity.\n    for (int z : zlist) {\n        for (int fixed = 0; fixed < 2; ++fixed) {\n            for (int K = 1; K <= 4; ++K) {\n                if (elapsed_sec() > 0.78) break;\n\n                Cand c = buildBackbone(fixed, z, K, 0, 0, 1, 4, false);\n                consider(c);\n            }\n        }\n    }\n\n    // Random free constructions.\n    while (elapsed_sec() < PHASE_FREE_RAND) {\n        int z = randomZ();\n        int mode = rng.randint(3);\n        int topR = 1 + rng.randint(5);\n        int maxPass = 3 + rng.randint(5);\n        bool repair = (rng.randint(100) < 75);\n\n        Cand c = buildFree(z, mode, topR, maxPass, true, repair);\n        consider(c);\n    }\n\n    // Rebalance using actual simulated counts.\n    int it = 0;\n\n    while (elapsed_sec() < PHASE_REBAL && !pool.empty()) {\n        Entry base;\n\n        if (it % 3 == 0) {\n            base = pool[0];\n        } else {\n            base = pool[rng.randint((int)pool.size())];\n        }\n\n        bool full = (it % 3 != 1);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? (4 + rng.randint(4)) : (6 + rng.randint(4));\n\n        Cand c = rebalanceCandidate(base, full, mode, topR, maxPass, true, true);\n        consider(c);\n\n        ++it;\n    }\n\n    // Final validated local search and extra rebalances.\n    bool localAllowed = true;\n\n    while (elapsed_sec() < TL) {\n        if (bestErr == 0) break;\n\n        if (localAllowed) {\n            if (tryLocalImprove(TL)) {\n                localAllowed = true;\n                continue;\n            }\n\n            localAllowed = false;\n        }\n\n        if (pool.empty() || elapsed_sec() >= TL) break;\n\n        Entry base = pool[rng.randint((int)pool.size())];\n\n        bool full = rng.randint(2);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? 4 : 7;\n\n        bool imp = consider(rebalanceCandidate(base, full, mode, topR, maxPass, true, true));\n\n        if (imp) localAllowed = true;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestCand.a[i] << ' ' << bestCand.b[i] << '\\n';\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, varp, norm2;\n    vector<int> sx_int, sy_int;\n    vector<unsigned long long> hilb;\n\n    vector<float> distBase; // uncertainty-aware estimated distance\n    vector<float> distRank; // optimistic distance for query neighbor selection\n    vector<unsigned char> known; // queried edge flag\n\n    vector<float> bonusMat;\n    vector<vector<pair<int, float>>> bonusAdj;\n\n    unordered_set<unsigned long long> usedQueries;\n    unordered_map<unsigned long long, vector<pair<int,int>>> responseMap;\n\n    int queryCount = 0;\n    float knownEvalFactor;\n    float knownFinalFactor;\n\n    mt19937 rng{1234567};\n\n    int ID(int i, int j) const { return i * N + j; }\n\n    static unsigned long long hilbertOrder(int x, int y) {\n        const int B = 14;\n        const int SZ = 1 << B;\n        unsigned long long d = 0;\n        for (int s = SZ / 2; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (unsigned long long)s * (unsigned long long)s * ((3 * rx) ^ ry);\n            if (ry == 0) {\n                if (rx == 1) {\n                    x = SZ - 1 - x;\n                    y = SZ - 1 - y;\n                }\n                swap(x, y);\n            }\n        }\n        return d;\n    }\n\n    unsigned long long subsetHash(vector<int> s) const {\n        sort(s.begin(), s.end());\n        unsigned long long h = 1469598103934665603ULL;\n        h ^= (unsigned long long)s.size();\n        h *= 1099511628211ULL;\n        for (int v : s) {\n            h ^= (unsigned long long)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    }\n\n    void readInput() {\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); varp.resize(N); norm2.resize(N);\n        sx_int.resize(N); sy_int.resize(N); hilb.resize(N);\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            double wx = rx[i] - lx[i];\n            double wy = ry[i] - ly[i];\n            varp[i] = (wx * wx + wy * wy) / 12.0;\n            norm2[i] = cx[i] * cx[i] + cy[i] * cy[i];\n        }\n\n        const int SZ = 1 << 14;\n        for (int i = 0; i < N; i++) {\n            sx_int[i] = min(SZ - 1, max(0, (int)llround(cx[i] * (SZ - 1) / 10000.0)));\n            sy_int[i] = min(SZ - 1, max(0, (int)llround(cy[i] * (SZ - 1) / 10000.0)));\n            hilb[i] = hilbertOrder(sx_int[i], sy_int[i]);\n        }\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        knownEvalFactor = (float)(0.72 - 0.22 * unc);   // 0.72 -> 0.50\n        knownFinalFactor = (float)(0.82 - 0.22 * unc);  // 0.82 -> 0.60\n    }\n\n    void computeDistances() {\n        distBase.assign(N * N, 0.0f);\n        distRank.assign(N * N, 0.0f);\n\n        const double alpha = 0.70;\n\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 cd = sqrt(dx * dx + dy * dy);\n\n                double base = sqrt(dx * dx + dy * dy + alpha * (varp[i] + varp[j]));\n\n                double gx = 0.0, gy = 0.0;\n                if (rx[i] < lx[j]) gx = lx[j] - rx[i];\n                else if (rx[j] < lx[i]) gx = lx[i] - rx[j];\n\n                if (ry[i] < ly[j]) gy = ly[j] - ry[i];\n                else if (ry[j] < ly[i]) gy = ly[i] - ry[j];\n\n                double minRect = sqrt(gx * gx + gy * gy);\n                double rankd = 0.70 * minRect + 0.30 * cd;\n\n                distBase[ID(i, j)] = distBase[ID(j, i)] = (float)base;\n                distRank[ID(i, j)] = distRank[ID(j, i)] = (float)rankd;\n            }\n        }\n        known.assign(N * N, 0);\n    }\n\n    vector<pair<int,int>> askNew(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        usedQueries.insert(h);\n\n        cout << \"? \" << subset.size();\n        for (int v : subset) cout << ' ' << v;\n        cout << '\\n';\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        int l = (int)subset.size();\n        ret.reserve(l - 1);\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            if (a > b) swap(a, b);\n            ret.emplace_back(a, b);\n        }\n        queryCount++;\n        responseMap[h] = ret;\n        return ret;\n    }\n\n    vector<pair<int,int>> getOrAsk(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        auto it = responseMap.find(h);\n        if (it != responseMap.end() && (int)it->second.size() == (int)subset.size() - 1) {\n            return it->second;\n        }\n        if (queryCount >= Q) return {};\n        return askNew(subset);\n    }\n\n    void addKnownEdges(const vector<pair<int,int>>& es) {\n        for (auto [a, b] : es) {\n            if (a > b) swap(a, b);\n            known[ID(a, b)] = known[ID(b, a)] = 1;\n        }\n    }\n\n    vector<int> buildSubsetGlobal(int center, int variant, int mode) {\n        vector<pair<float,int>> arr;\n        arr.reserve(N - 1);\n        for (int v = 0; v < N; v++) {\n            if (v == center) continue;\n            float d = (mode == 0 ? distRank[ID(center, v)] : distBase[ID(center, v)]);\n            arr.emplace_back(d, v);\n        }\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n            for (int i = 0; i < common; i++) sub.push_back(arr[i].second);\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n        return sub;\n    }\n\n    vector<int> buildSubsetInGroup(int center, const vector<int>& group, int variant) {\n        vector<pair<float,int>> arr;\n        arr.reserve(group.size());\n        for (int v : group) {\n            if (v == center) continue;\n            arr.emplace_back(distBase[ID(center, v)], v);\n        }\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n            for (int i = 0; i < common; i++) sub.push_back(arr[i].second);\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n        return sub;\n    }\n\n    int reserveFinalQueryCount() const {\n        int res = 0;\n        int chunk = L - 1;\n        for (int g : G) {\n            if (g <= 2) continue;\n            if (g <= L) {\n                res++;\n            } else {\n                int total = g - 1;\n                int full = total / chunk;\n                int rem = total % chunk;\n                res += full;\n                if (rem >= 2) res++;\n            }\n        }\n        return min(res, Q);\n    }\n\n    void performPrequeries(int targetQueries) {\n        if (targetQueries <= 0) return;\n\n        vector<int> byUnc(N), byHilb(N);\n        iota(byUnc.begin(), byUnc.end(), 0);\n        iota(byHilb.begin(), byHilb.end(), 0);\n\n        sort(byUnc.begin(), byUnc.end(), [&](int a, int b) {\n            if (varp[a] != varp[b]) return varp[a] > varp[b];\n            return a < b;\n        });\n        sort(byHilb.begin(), byHilb.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n\n        vector<int> centers;\n        vector<char> seen(N, 0);\n        for (int t = 0; t < N; t++) {\n            int c1 = byUnc[t];\n            if (!seen[c1]) {\n                seen[c1] = 1;\n                centers.push_back(c1);\n            }\n            int c2 = byHilb[(t * 37) % N];\n            if (!seen[c2]) {\n                seen[c2] = 1;\n                centers.push_back(c2);\n            }\n        }\n\n        for (int c : centers) {\n            if (queryCount >= targetQueries) break;\n            for (int v = 0; v < 4 && queryCount < targetQueries; v++) {\n                int mode = v & 1;\n                int variant = v / 2;\n                auto sub = buildSubsetGlobal(c, variant, mode);\n                if ((int)sub.size() < 2) continue;\n                unsigned long long h = subsetHash(sub);\n                if (usedQueries.count(h)) continue;\n                auto ret = askNew(sub);\n                addKnownEdges(ret);\n                break;\n            }\n        }\n\n        int attempts = 0;\n        while (queryCount < targetQueries && attempts < 5000) {\n            int c = attempts % N;\n            int variant = (attempts / N) % 6;\n            int mode = (attempts / (N * 6)) & 1;\n            attempts++;\n\n            auto sub = buildSubsetGlobal(c, variant, mode);\n            if ((int)sub.size() < 2) continue;\n            unsigned long long h = subsetHash(sub);\n            if (usedQueries.count(h)) continue;\n            auto ret = askNew(sub);\n            addKnownEdges(ret);\n        }\n    }\n\n    float evalWeight(int u, int v) const {\n        float d = distBase[ID(u, v)];\n        if (known[ID(u, v)]) d *= knownEvalFactor;\n        return d;\n    }\n\n    double primCostEval(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        if (n <= 1) return 0.0;\n        vector<float> best(n, 1e30f);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\n\n        double cost = 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 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n            cost += best[v];\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    float w = evalWeight(vs[v], vs[u]);\n                    if (w < best[u]) best[u] = w;\n                }\n            }\n        }\n        return cost;\n    }\n\n    double evalCandidate(const vector<int>& gid) const {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n\n        for (int i = 0; i < N; i++) {\n            if (gid[i] < 0 || gid[i] >= M) return 1e100;\n            groups[gid[i]].push_back(i);\n        }\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) return 1e100;\n        }\n\n        double score = 0.0;\n        for (int k = 0; k < M; k++) score += primCostEval(groups[k]);\n        return score;\n    }\n\n    vector<vector<int>> makeCityOrders() {\n        vector<vector<int>> orders;\n        const int S = (1 << 14) - 1;\n\n        auto addHilbert = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n                    if (type == 1) { tx = y; ty = x; }\n                    else if (type == 2) { tx = S - x; ty = y; }\n                    else if (type == 3) { tx = x; ty = S - y; }\n                    else if (type == 4) { tx = S - x; ty = S - y; }\n                    else if (type == 5) { tx = S - y; ty = x; }\n                    return hilbertOrder(tx, ty);\n                };\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 6; t++) addHilbert(t);\n\n        auto addSort = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                double ka, kb;\n                if (type == 0) { ka = cx[a] * 10001.0 + cy[a]; kb = cx[b] * 10001.0 + cy[b]; }\n                else if (type == 1) { ka = cy[a] * 10001.0 + cx[a]; kb = cy[b] * 10001.0 + cx[b]; }\n                else if (type == 2) { ka = cx[a] + cy[a]; kb = cx[b] + cy[b]; }\n                else { ka = cx[a] - cy[a]; kb = cx[b] - cy[b]; }\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addSort(t);\n        return orders;\n    }\n\n    vector<vector<int>> makeGroupOrders() {\n        vector<vector<int>> orders;\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        orders.push_back(ids);\n\n        vector<int> asc = ids, desc = ids;\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n        orders.push_back(asc);\n        orders.push_back(desc);\n\n        for (int r = 0; r < 6; r++) {\n            vector<int> p = ids;\n            shuffle(p.begin(), p.end(), rng);\n            orders.push_back(p);\n        }\n        return orders;\n    }\n\n    vector<int> partitionCandidate(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n        vector<int> gid(N, -1);\n        int pos = 0;\n        for (int g : groupOrder) {\n            for (int t = 0; t < G[g]; t++) {\n                gid[cityOrder[pos++]] = g;\n            }\n        }\n        return gid;\n    }\n\n    struct EP {\n        float w;\n        int u, v;\n        bool operator<(const EP& other) const {\n            if (w != other.w) return w < other.w;\n            if (u != other.u) return u < other.u;\n            return v < other.v;\n        }\n    };\n\n    vector<EP> makeSortedPairs() {\n        vector<EP> ps;\n        ps.reserve(N * (N - 1) / 2);\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                ps.push_back({evalWeight(i, j), i, j});\n            }\n        }\n        sort(ps.begin(), ps.end());\n        return ps;\n    }\n\n    vector<int> greedyCandidate(const vector<int>& groupOrder, const vector<EP>& pairs) {\n        vector<int> gid(N, -1);\n        vector<char> alive(N, 1);\n        int rem = N;\n        int ptr = 0;\n\n        auto addCity = [&](vector<int>& sel, int v) {\n            if (!alive[v]) return;\n            alive[v] = 0;\n            rem--;\n            sel.push_back(v);\n        };\n\n        for (int gr : groupOrder) {\n            int need = G[gr];\n            vector<int> sel;\n            sel.reserve(need);\n\n            if (need == rem) {\n                for (int i = 0; i < N; i++) if (alive[i]) {\n                    gid[i] = gr;\n                    alive[i] = 0;\n                }\n                rem = 0;\n                continue;\n            }\n\n            if (need == 1) {\n                double mx = 0.0, my = 0.0;\n                for (int i = 0; i < N; i++) if (alive[i]) {\n                    mx += cx[i];\n                    my += cy[i];\n                }\n                mx /= rem;\n                my /= rem;\n\n                int best = -1;\n                double bestVal = -1.0;\n                for (int i = 0; i < N; i++) if (alive[i]) {\n                    double dx = cx[i] - mx;\n                    double dy = cy[i] - my;\n                    double val = dx * dx + dy * dy + 0.05 * varp[i];\n                    if (val > bestVal) {\n                        bestVal = val;\n                        best = i;\n                    }\n                }\n                addCity(sel, best);\n            } else {\n                while (ptr < (int)pairs.size() && !(alive[pairs[ptr].u] && alive[pairs[ptr].v])) ptr++;\n                if (ptr < (int)pairs.size()) {\n                    addCity(sel, pairs[ptr].u);\n                    addCity(sel, pairs[ptr].v);\n                } else {\n                    for (int i = 0; i < N && (int)sel.size() < min(2, need); i++) {\n                        if (alive[i]) addCity(sel, i);\n                    }\n                }\n\n                vector<float> best(N, 1e30f);\n                for (int v = 0; v < N; v++) if (alive[v]) {\n                    for (int s : sel) best[v] = min(best[v], evalWeight(v, s));\n                }\n\n                while ((int)sel.size() < need) {\n                    int bv = -1;\n                    for (int v = 0; v < N; v++) if (alive[v]) {\n                        if (bv == -1 || best[v] < best[bv]) bv = v;\n                    }\n                    if (bv == -1) break;\n                    addCity(sel, bv);\n                    for (int v = 0; v < N; v++) if (alive[v]) {\n                        best[v] = min(best[v], evalWeight(v, bv));\n                    }\n                }\n            }\n\n            for (int v : sel) gid[v] = gr;\n        }\n\n        return gid;\n    }\n\n    void kdRec(vector<int> cities, vector<int> gids, vector<int>& assign, int depth, int mode, mt19937& rr) {\n        if (gids.size() == 1) {\n            int g = gids[0];\n            for (int c : cities) assign[c] = g;\n            return;\n        }\n\n        int n = (int)cities.size();\n\n        double minx = 1e100, maxx = -1e100, miny = 1e100, maxy = -1e100;\n        for (int c : cities) {\n            minx = min(minx, cx[c]); maxx = max(maxx, cx[c]);\n            miny = min(miny, cy[c]); maxy = max(maxy, cy[c]);\n        }\n        double rxr = maxx - minx, ryr = maxy - miny;\n\n        int axis;\n        if (mode % 3 == 0) axis = (rxr >= ryr ? 0 : 1);\n        else if (mode % 3 == 1) axis = depth & 1;\n        else axis = (rxr < ryr ? 0 : 1);\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            double ka = axis == 0 ? cx[a] : cy[a];\n            double kb = axis == 0 ? cx[b] : cy[b];\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        vector<int> order = gids;\n        if (mode >= 3) shuffle(order.begin(), order.end(), rr);\n        else if (mode == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] > G[b];\n                return a < b;\n            });\n        } else if (mode == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] < G[b];\n                return a < b;\n            });\n        }\n\n        vector<char> dp(n + 1, 0);\n        vector<int> parS(n + 1, -1), parG(n + 1, -1);\n        dp[0] = 1;\n        for (int g : order) {\n            int s = G[g];\n            for (int sum = n - s; sum >= 0; sum--) {\n                if (dp[sum] && !dp[sum + s]) {\n                    dp[sum + s] = 1;\n                    parS[sum + s] = sum;\n                    parG[sum + s] = g;\n                }\n            }\n        }\n\n        int target = n / 2;\n        int best = -1, bd = 1e9;\n        for (int s = 1; s < n; s++) if (dp[s]) {\n            int d = abs(s - target);\n            if (d < bd) {\n                bd = d;\n                best = s;\n            }\n        }\n        if (best == -1) best = G[gids[0]];\n\n        vector<char> selected(M, 0);\n        int cur = best;\n        while (cur > 0) {\n            int g = parG[cur];\n            if (g < 0) break;\n            selected[g] = 1;\n            cur = parS[cur];\n        }\n\n        vector<int> leftG, rightG;\n        for (int g : gids) {\n            if (selected[g]) leftG.push_back(g);\n            else rightG.push_back(g);\n        }\n        if (leftG.empty() || rightG.empty()) {\n            leftG.clear(); rightG.clear();\n            int acc = 0;\n            for (int g : gids) {\n                if (acc + G[g] <= best && leftG.empty() == false) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else if (acc < best) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else {\n                    rightG.push_back(g);\n                }\n            }\n            if (leftG.empty() || rightG.empty()) {\n                leftG = {gids[0]};\n                rightG.assign(gids.begin() + 1, gids.end());\n                best = G[gids[0]];\n            }\n        }\n\n        bool flip = (mode >= 3 && ((depth + mode) & 1));\n        vector<int> leftC, rightC;\n        if (!flip) {\n            leftC.assign(cities.begin(), cities.begin() + best);\n            rightC.assign(cities.begin() + best, cities.end());\n        } else {\n            leftC.assign(cities.end() - best, cities.end());\n            rightC.assign(cities.begin(), cities.end() - best);\n        }\n\n        kdRec(leftC, leftG, assign, depth + 1, mode, rr);\n        kdRec(rightC, rightG, assign, depth + 1, mode, rr);\n    }\n\n    vector<int> kdCandidate(int mode) {\n        vector<int> cities(N), gids(M), assign(N, -1);\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n        mt19937 rr(1000 + mode * 97);\n        kdRec(cities, gids, assign, 0, mode, rr);\n        return assign;\n    }\n\n    void buildBonus() {\n        bonusMat.assign(N * N, 0.0f);\n        bonusAdj.assign(N, {});\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        double coef = 0.20 + 0.30 * unc;\n        double cap = 2.0e6;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (!known[ID(i, j)]) continue;\n                double d = distBase[ID(i, j)];\n                float b = (float)min(cap, coef * d * d);\n                bonusMat[ID(i, j)] = bonusMat[ID(j, i)] = b;\n                bonusAdj[i].push_back({j, b});\n                bonusAdj[j].push_back({i, b});\n            }\n        }\n    }\n\n    void localSearch(vector<int>& gid, int maxPass) {\n        vector<double> sxg(M, 0.0), syg(M, 0.0), sqg(M, 0.0);\n        for (int i = 0; i < N; i++) {\n            int g = gid[i];\n            sxg[g] += cx[i];\n            syg[g] += cy[i];\n            sqg[g] += norm2[i];\n        }\n\n        vector<float> ktg((size_t)N * M, 0.0f);\n        for (int u = 0; u < N; u++) {\n            for (auto [v, b] : bonusAdj[u]) if (u < v) {\n                ktg[(size_t)u * M + gid[v]] += b;\n                ktg[(size_t)v * M + gid[u]] += b;\n            }\n        }\n\n        auto deltaReplace = [&](int g, int out, int in) -> double {\n            double nsx = sxg[g] - cx[out] + cx[in];\n            double nsy = syg[g] - cy[out] + cy[in];\n            double oldS2 = sxg[g] * sxg[g] + syg[g] * syg[g];\n            double newS2 = nsx * nsx + nsy * nsy;\n            return (-norm2[out] + norm2[in]) - (newS2 - oldS2) / G[g];\n        };\n\n        auto applySwap = [&](int i, int j, int A, int B) {\n            sxg[A] += -cx[i] + cx[j];\n            syg[A] += -cy[i] + cy[j];\n            sqg[A] += -norm2[i] + norm2[j];\n\n            sxg[B] += -cx[j] + cx[i];\n            syg[B] += -cy[j] + cy[i];\n            sqg[B] += -norm2[j] + norm2[i];\n\n            for (auto [t, b] : bonusAdj[i]) {\n                ktg[(size_t)t * M + A] -= b;\n                ktg[(size_t)t * M + B] += b;\n            }\n            for (auto [t, b] : bonusAdj[j]) {\n                ktg[(size_t)t * M + B] -= b;\n                ktg[(size_t)t * M + A] += b;\n            }\n\n            gid[i] = B;\n            gid[j] = A;\n        };\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            int swaps = 0;\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    int A = gid[i], B = gid[j];\n                    if (A == B) continue;\n\n                    double ds = deltaReplace(A, i, j) + deltaReplace(B, j, i);\n\n                    float bij = bonusMat[ID(i, j)];\n                    double before = ktg[(size_t)i * M + A] + ktg[(size_t)j * M + B];\n                    double after = ktg[(size_t)i * M + B] + ktg[(size_t)j * M + A] - 2.0 * bij;\n                    double delta = ds - (after - before);\n\n                    if (delta < -1e-7) {\n                        applySwap(i, j, A, B);\n                        swaps++;\n                    }\n                }\n            }\n            if (swaps == 0) break;\n        }\n    }\n\n    vector<int> makeGrouping() {\n        if (M == 1) return vector<int>(N, 0);\n\n        struct Cand {\n            double score;\n            vector<int> gid;\n        };\n        vector<Cand> top;\n        const int TOPK = 8;\n\n        auto addCand = [&](vector<int> gid) {\n            double sc = evalCandidate(gid);\n            if (sc > 1e90) return;\n            if ((int)top.size() < TOPK) {\n                top.push_back({sc, move(gid)});\n            } else {\n                int worst = 0;\n                for (int i = 1; i < (int)top.size(); i++) {\n                    if (top[i].score > top[worst].score) worst = i;\n                }\n                if (sc < top[worst].score) top[worst] = {sc, move(gid)};\n            }\n        };\n\n        auto cityOrders = makeCityOrders();\n        auto groupOrders = makeGroupOrders();\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                addCand(partitionCandidate(co, go));\n            }\n        }\n\n        auto pairs = makeSortedPairs();\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        vector<int> asc = ids, desc = ids;\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        addCand(greedyCandidate(asc, pairs));\n        addCand(greedyCandidate(ids, pairs));\n        addCand(greedyCandidate(desc, pairs));\n\n        for (int mode = 0; mode < 6; mode++) {\n            addCand(kdCandidate(mode));\n        }\n\n        if (top.empty()) {\n            auto co = cityOrders[0];\n            auto go = groupOrders[0];\n            return partitionCandidate(co, go);\n        }\n\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        buildBonus();\n\n        vector<int> best = top[0].gid;\n        double bestScore = top[0].score;\n\n        int lim = min(6, (int)top.size());\n        int passes = (M > 250 ? 12 : 9);\n\n        for (int i = 0; i < lim; i++) {\n            vector<int> gid = top[i].gid;\n            localSearch(gid, passes);\n            double sc = evalCandidate(gid);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = move(gid);\n            }\n        }\n\n        return best;\n    }\n\n    vector<vector<int>> buildGroups(const vector<int>& gid) {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n        for (int i = 0; i < N; i++) groups[gid[i]].push_back(i);\n\n        bool ok = true;\n        for (int k = 0; k < M; k++) if ((int)groups[k].size() != G[k]) ok = false;\n\n        if (!ok) {\n            groups.assign(M, {});\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n            int pos = 0;\n            for (int k = 0; k < M; k++) {\n                for (int t = 0; t < G[k]; t++) groups[k].push_back(ids[pos++]);\n            }\n        }\n\n        return groups;\n    }\n\n    void performFinalQueries(\n        vector<vector<int>>& groups,\n        vector<char>& exact,\n        vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        exact.assign(M, 0);\n        exactEdges.assign(M, {});\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                auto ret = getOrAsk(groups[k]);\n                if ((int)ret.size() == g - 1) {\n                    addKnownEdges(ret);\n                    exact[k] = 1;\n                    exactEdges[k] = ret;\n                }\n            } else {\n                vector<int> ord = groups[k];\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                    return a < b;\n                });\n\n                int connector = ord[0];\n                int pos = 1;\n                while (pos < g) {\n                    int s = min(L - 1, g - pos);\n                    if (s >= 2) {\n                        vector<int> sub;\n                        sub.reserve(s + 1);\n                        sub.push_back(connector);\n                        for (int t = 0; t < s; t++) sub.push_back(ord[pos + t]);\n\n                        auto ret = getOrAsk(sub);\n                        if (!ret.empty()) addKnownEdges(ret);\n                    }\n                    connector = ord[pos + s - 1];\n                    pos += s;\n                }\n            }\n        }\n\n        if (queryCount >= Q) return;\n\n        vector<int> candGroups;\n        int maxG = 0;\n        vector<vector<int>> ords(M);\n        for (int k = 0; k < M; k++) {\n            if (exact[k]) continue;\n            int g = (int)groups[k].size();\n            if (g < 3) continue;\n            candGroups.push_back(k);\n            ords[k] = groups[k];\n            sort(ords[k].begin(), ords[k].end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n            maxG = max(maxG, g);\n        }\n\n        for (int variant = 0; variant < 5 && queryCount < Q; variant++) {\n            for (int r = 0; r < maxG && queryCount < Q; r++) {\n                for (int k : candGroups) {\n                    if (queryCount >= Q) break;\n                    if (r >= (int)ords[k].size()) continue;\n\n                    int center = ords[k][r];\n                    auto sub = buildSubsetInGroup(center, groups[k], variant);\n                    if ((int)sub.size() < 3) continue;\n                    unsigned long long h = subsetHash(sub);\n                    if (usedQueries.count(h)) continue;\n\n                    auto ret = askNew(sub);\n                    addKnownEdges(ret);\n                }\n            }\n        }\n    }\n\n    vector<pair<int,int>> finalPrimEdges(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        vector<pair<int,int>> edges;\n        if (n <= 1) return edges;\n\n        vector<float> best(n, 1e30f);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\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 || best[i] < best[v])) v = i;\n            }\n            used[v] = 1;\n            if (par[v] != -1) edges.push_back({vs[v], vs[par[v]]});\n\n            for (int u = 0; u < n; u++) if (!used[u]) {\n                int a = vs[v], b = vs[u];\n                float w = distBase[ID(a, b)];\n                if (known[ID(a, b)]) w *= knownFinalFactor;\n                if (w < best[u]) {\n                    best[u] = w;\n                    par[u] = v;\n                }\n            }\n        }\n\n        return edges;\n    }\n\n    void outputAnswer(\n        const vector<vector<int>>& groups,\n        const vector<char>& exact,\n        const vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        vector<vector<pair<int,int>>> ansEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n            if (g <= 1) {\n                ansEdges[k] = {};\n            } else if (g == 2) {\n                ansEdges[k] = {{groups[k][0], groups[k][1]}};\n            } else if (exact[k]) {\n                ansEdges[k] = exactEdges[k];\n            } else {\n                ansEdges[k] = finalPrimEdges(groups[k]);\n            }\n        }\n\n        cout << \"!\\n\";\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << '\\n';\n\n            for (auto [a, b] : ansEdges[k]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n        cout.flush();\n    }\n\n    void solve() {\n        readInput();\n        computeDistances();\n\n        usedQueries.reserve(Q * 4 + 10);\n        responseMap.reserve(Q * 4 + 10);\n\n        int reserveQ = reserveFinalQueryCount();\n        int preBudget = max(0, Q - reserveQ);\n\n        performPrequeries(preBudget);\n\n        vector<int> gid = makeGrouping();\n        auto groups = buildGroups(gid);\n\n        vector<char> exact;\n        vector<vector<pair<int,int>>> exactEdges;\n        performFinalQueries(groups, exact, exactEdges);\n\n        outputAnswer(groups, exact, exactEdges);\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}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 20;\nstatic const int MAXV = 400;\nstatic const int INF = 1e9;\n\nstruct Grid {\n    uint32_t row[MAXN];\n    uint32_t col[MAXN];\n    int cnt;\n    uint64_t hash;\n    Grid() {\n        memset(row, 0, sizeof(row));\n        memset(col, 0, sizeof(col));\n        cnt = 0;\n        hash = 0;\n    }\n};\n\nstruct Solver {\n    int N, M, V;\n    int LIMIT;\n    uint32_t FULL;\n    vector<int> pos;\n\n    int rr[MAXV], cc[MAXV];\n    int mv[MAXV][4];\n\n    int dr[4] = {-1, 1, 0, 0};\n    int dc[4] = {0, 0, -1, 1};\n    int opp[4] = {1, 0, 3, 2};\n\n    bool future[45][MAXV];\n    int adjVal[45][MAXV];\n\n    uint64_t zob[MAXV];\n    uint64_t rngState;\n\n    int seen[MAXV], distArr[MAXV], prevArr[MAXV], que[MAXV];\n    unsigned char actArr[MAXV];\n    int stamp = 1;\n\n    int validBits[45], inBits[45];\n    bool isPlanOpt[45][16];\n    vector<int> planOpts[45];\n\n    chrono::steady_clock::time_point startTime;\n\n    vector<string> candidates;\n    string pureFallback;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    uint64_t rnd() {\n        uint64_t z = (rngState += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    inline char enc(int type, int d) const {\n        return char(type * 4 + d);\n    }\n\n    inline bool isBlocked(const Grid& g, int v) const {\n        return (g.row[rr[v]] >> cc[v]) & 1u;\n    }\n\n    inline void setBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (!(g.row[r] & br)) {\n            g.row[r] |= br;\n            g.col[c] |= (1u << r);\n            g.cnt++;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void clearBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (g.row[r] & br) {\n            g.row[r] &= ~br;\n            g.col[c] &= ~(1u << r);\n            g.cnt--;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void toggleBlock(Grid& g, int v) {\n        if (isBlocked(g, v)) clearBlock(g, v);\n        else setBlock(g, v);\n    }\n\n    inline int highestBit(uint32_t x) const {\n        return 31 - __builtin_clz(x);\n    }\n\n    inline int slideDestRC(const Grid& g, int r, int c, int d) const {\n        if (d == 0) {\n            uint32_t mask = g.col[c] & ((1u << r) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return (b + 1) * N + c;\n            }\n            return c;\n        } else if (d == 1) {\n            uint32_t mask = g.col[c] & (FULL ^ ((1u << (r + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return (b - 1) * N + c;\n            }\n            return (N - 1) * N + c;\n        } else if (d == 2) {\n            uint32_t mask = g.row[r] & ((1u << c) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return r * N + (b + 1);\n            }\n            return r * N;\n        } else {\n            uint32_t mask = g.row[r] & (FULL ^ ((1u << (c + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return r * N + (b - 1);\n            }\n            return r * N + (N - 1);\n        }\n    }\n\n    inline int slideDest(const Grid& g, int v, int d) const {\n        return slideDestRC(g, rr[v], cc[v], d);\n    }\n\n    void nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n    }\n\n    int bfsSearch(const Grid& g, int s, int t, bool storePath) {\n        if (s < 0 || t < 0) return INF;\n        if (isBlocked(g, s) || isBlocked(g, t)) return INF;\n        if (s == t) return 0;\n\n        nextStamp();\n        int head = 0, tail = 0;\n        que[tail++] = s;\n        seen[s] = stamp;\n        distArr[s] = 0;\n        if (storePath) prevArr[s] = -1;\n\n        while (head < tail) {\n            int v = que[head++];\n            int nd = distArr[v] + 1;\n            int r = rr[v], c = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDestRC(g, r, c, d);\n                if (to == v) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(1, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[v][d];\n                if (to < 0 || isBlocked(g, to)) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(0, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n        }\n        return INF;\n    }\n\n    int bfsDist(const Grid& g, int s, int t) {\n        return bfsSearch(g, s, t, false);\n    }\n\n    bool bfsPath(const Grid& g, int s, int t, string& out) {\n        int d = bfsSearch(g, s, t, true);\n        if (d >= INF) return false;\n        out.clear();\n        int v = t;\n        while (v != s) {\n            out.push_back(char(actArr[v]));\n            v = prevArr[v];\n            if (v < 0) return false;\n        }\n        reverse(out.begin(), out.end());\n        return true;\n    }\n\n    void init() {\n        V = N * N;\n        LIMIT = 2 * N * M;\n        FULL = (1u << N) - 1u;\n\n        for (int v = 0; v < V; v++) {\n            rr[v] = v / N;\n            cc[v] = v % N;\n        }\n\n        for (int v = 0; v < V; v++) {\n            for (int d = 0; d < 4; d++) {\n                int nr = rr[v] + dr[d];\n                int nc = cc[v] + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) mv[v][d] = nr * N + nc;\n                else mv[v][d] = -1;\n            }\n        }\n\n        memset(future, 0, sizeof(future));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                future[k][pos[t]] = true;\n            }\n        }\n\n        memset(adjVal, 0, sizeof(adjVal));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                int w = max(1, 8 - (t - k));\n                for (int d = 0; d < 4; d++) {\n                    int v = mv[pos[t]][d];\n                    if (v >= 0) adjVal[k][v] += w;\n                }\n            }\n        }\n\n        rngState = 1234567891234567ULL;\n        for (int p : pos) {\n            rngState ^= uint64_t(p + 1009) * 0x9e3779b97f4a7c15ULL;\n            rnd();\n        }\n        for (int i = 0; i < V; i++) zob[i] = rnd();\n\n        memset(seen, 0, sizeof(seen));\n\n        memset(isPlanOpt, 0, sizeof(isPlanOpt));\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            inBits[k] = 0;\n            validBits[k] = 0;\n            for (int d = 0; d < 4; d++) {\n                int q = mv[p][d];\n                if (q < 0) continue;\n                inBits[k] |= (1 << d);\n                if (!future[k][q]) validBits[k] |= (1 << d);\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~validBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planOpts[k].push_back(sub);\n                isPlanOpt[k][sub] = true;\n            }\n            if (planOpts[k].empty()) {\n                planOpts[k].push_back(0);\n                isPlanOpt[k][0] = true;\n            }\n        }\n    }\n\n    string makePureMoves() {\n        string s;\n        int cur = pos[0];\n        int r = rr[cur], c = cc[cur];\n\n        for (int k = 1; k < M; k++) {\n            int gr = rr[pos[k]], gc = cc[pos[k]];\n            while (r < gr) {\n                s.push_back(enc(0, 1));\n                r++;\n            }\n            while (r > gr) {\n                s.push_back(enc(0, 0));\n                r--;\n            }\n            while (c < gc) {\n                s.push_back(enc(0, 3));\n                c++;\n            }\n            while (c > gc) {\n                s.push_back(enc(0, 2));\n                c--;\n            }\n        }\n        return s;\n    }\n\n    int firstCompletionPrefix(const string& acts) {\n        if (M <= 1) return 0;\n\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return -1;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return -1;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(g, p, d);\n            } else {\n                int to = mv[p][d];\n                if (to < 0) return -1;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                nxt++;\n                if (nxt == M) return t + 1;\n            }\n        }\n        return -1;\n    }\n\n    void addCandidate(const string& acts) {\n        int p = firstCompletionPrefix(acts);\n        if (p < 0 || p > LIMIT) return;\n        string t = acts.substr(0, p);\n        candidates.push_back(move(t));\n    }\n\n    string greedyDelete(string a, double endTime = 1.90) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return \"\";\n        a.resize(pref);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (size_t i = 0; i < a.size();) {\n                if (elapsed() > endTime) return a;\n                string b = a;\n                b.erase(b.begin() + i);\n                int p = firstCompletionPrefix(b);\n                if (p >= 0 && p <= LIMIT) {\n                    b.resize(p);\n                    a.swap(b);\n                    changed = true;\n                    if (i > 0) --i;\n                    if (i > a.size()) i = a.size();\n                } else {\n                    ++i;\n                }\n            }\n            if (!changed) break;\n        }\n\n        for (int w = 2; w <= 3; w++) {\n            bool any = true;\n            while (any) {\n                any = false;\n                for (size_t i = 0; i + w <= a.size();) {\n                    if (elapsed() > endTime + 0.02) return a;\n                    string b = a;\n                    b.erase(i, w);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        a.swap(b);\n                        any = true;\n                        if (i > 0) --i;\n                        if (i > a.size()) i = a.size();\n                    } else {\n                        ++i;\n                    }\n                }\n            }\n        }\n\n        return a;\n    }\n\n    string replaceImprove(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        a = greedyDelete(a, min(endTime, 1.91));\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (int i = 0; i < (int)a.size() && elapsed() < endTime; i++) {\n                string bestLocal;\n                int bestLen = (int)a.size();\n\n                for (int code = 0; code < 12 && elapsed() < endTime; code++) {\n                    if (code == (unsigned char)a[i]) continue;\n\n                    string b = a;\n                    b[i] = char(code);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        } else if ((int)b.size() == (int)a.size()) {\n                            int L = max(0, i - 6);\n                            int R = min((int)b.size(), i + 12);\n                            for (int j = L; j < R && elapsed() < endTime; j++) {\n                                string c = b;\n                                c.erase(c.begin() + j);\n                                int pp = firstCompletionPrefix(c);\n                                if (pp >= 0 && pp <= LIMIT) {\n                                    c.resize(pp);\n                                    if ((int)c.size() < bestLen) {\n                                        bestLen = (int)c.size();\n                                        bestLocal = c;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                if (i + 1 < (int)a.size() && elapsed() < endTime) {\n                    string b = a;\n                    swap(b[i], b[i + 1]);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        }\n                    }\n                }\n\n                if (!bestLocal.empty() && bestLen < (int)a.size()) {\n                    string del = greedyDelete(bestLocal, min(endTime, 1.93));\n                    int pp = firstCompletionPrefix(del);\n                    if (pp >= 0 && pp <= LIMIT) {\n                        del.resize(pp);\n                        if (del.size() < bestLocal.size()) bestLocal.swap(del);\n                    }\n                    if (bestLocal.size() < a.size()) {\n                        a.swap(bestLocal);\n                        changed = true;\n                        i = max(-1, i - 6);\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n        return a;\n    }\n\n    int dirToward(int a, int b) const {\n        int vr = rr[b] - rr[a];\n        int vc = cc[b] - cc[a];\n        if (abs(vr) >= abs(vc)) {\n            if (vr < 0) return 0;\n            if (vr > 0) return 1;\n        }\n        if (vc < 0) return 2;\n        if (vc > 0) return 3;\n        return 0;\n    }\n\n    int evalPlan(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int dist = bfsDist(g, p, pos[k + 1]);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    bool buildFromMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            int bestDir = -1;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    if (isBlocked(tg, p)) continue;\n                    setBlock(tg, p);\n\n                    int dist = bfsDist(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                acts.push_back(enc(0, bestDir));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> makeZeroMasks() {\n        return vector<int>(M - 1, 0);\n    }\n\n    vector<int> makeDenseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeExitMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int m = validBits[k];\n            int ex = dirToward(pos[k], pos[k + 1]);\n            m &= ~(1 << ex);\n\n            while (!isPlanOpt[k][m]) {\n                bool removed = false;\n                for (int d = 0; d < 4; d++) {\n                    if (m & (1 << d)) {\n                        m &= ~(1 << d);\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) {\n                    m = 0;\n                    break;\n                }\n            }\n            masks[k] = m;\n        }\n        return masks;\n    }\n\n    vector<int> makeSparseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 100;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = abs(pc - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeValueMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n            for (int m : planOpts[k]) {\n                int val = 0;\n                int pc = __builtin_popcount((unsigned)m);\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q >= 0) val += adjVal[k][q];\n                }\n                int sc = val * 4 - pc * 5;\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planOpts[k].size());\n            masks[k] = planOpts[k][id];\n        }\n        return masks;\n    }\n\n    pair<int, vector<int>> coordinateDescent(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlan(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlan(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    struct Node {\n        int parent;\n        string add;\n    };\n\n    struct BeamState {\n        Grid g;\n        int cost;\n        int node;\n    };\n\n    string solveBeam(int keepPerBeta) {\n        vector<int> betas = {0, 70, 130, 190, 250};\n\n        vector<Node> nodes;\n        nodes.push_back({-1, \"\"});\n\n        BeamState init;\n        init.cost = 0;\n        init.node = 0;\n        vector<BeamState> beam;\n        beam.push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            vector<BeamState> gen;\n            gen.reserve(beam.size() * 45);\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(beam.size() * 80 + 100);\n            mp.max_load_factor(0.7);\n\n            int p = pos[k];\n            int goal = pos[k + 1];\n\n            auto addState = [&](const BeamState& parent, const Grid& ng, int newCost, const string& app) {\n                if (newCost > LIMIT) return;\n\n                auto it = mp.find(ng.hash);\n                if (it != mp.end()) {\n                    int idx = it->second;\n                    if (newCost >= gen[idx].cost) return;\n                }\n\n                int nodeId = (int)nodes.size();\n                nodes.push_back({parent.node, app});\n\n                BeamState ns;\n                ns.g = ng;\n                ns.cost = newCost;\n                ns.node = nodeId;\n\n                if (it == mp.end()) {\n                    mp[ng.hash] = (int)gen.size();\n                    gen.push_back(ns);\n                } else {\n                    gen[it->second] = ns;\n                }\n            };\n\n            for (const BeamState& st : beam) {\n                int candBits = 0;\n                for (int d = 0; d < 4; d++) {\n                    int q = mv[p][d];\n                    if (q < 0) continue;\n                    bool blk = isBlocked(st.g, q);\n                    if (blk || !future[k][q]) candBits |= (1 << d);\n                }\n\n                for (int sub = candBits;; sub = (sub - 1) & candBits) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    string path;\n                    if (bfsPath(ng, p, goal, path)) {\n                        string app = prep + path;\n                        addState(st, ng, st.cost + (int)app.size(), app);\n                    }\n\n                    if (sub == 0) break;\n                }\n\n                vector<int> backSubs;\n                backSubs.push_back(0);\n                for (int d = 0; d < 4; d++) {\n                    if (candBits & (1 << d)) backSubs.push_back(1 << d);\n                }\n\n                for (int sub : backSubs) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    if (isBlocked(ng, p)) continue;\n\n                    for (int e = 0; e < 4; e++) {\n                        int nb = mv[p][e];\n                        if (nb < 0 || isBlocked(ng, nb)) continue;\n\n                        Grid bg = ng;\n                        setBlock(bg, p);\n\n                        string path;\n                        if (!bfsPath(bg, nb, goal, path)) continue;\n\n                        string app = prep;\n                        app.push_back(enc(0, e));\n                        app.push_back(enc(2, opp[e]));\n                        app += path;\n\n                        addState(st, bg, st.cost + (int)app.size(), app);\n                    }\n                }\n            }\n\n            if (gen.empty()) return \"\";\n\n            if (k == M - 2) {\n                int best = 0;\n                for (int i = 1; i < (int)gen.size(); i++) {\n                    if (gen[i].cost < gen[best].cost) best = i;\n                }\n\n                vector<int> chain;\n                for (int id = gen[best].node; id != -1; id = nodes[id].parent) {\n                    chain.push_back(id);\n                }\n                reverse(chain.begin(), chain.end());\n\n                string res;\n                for (int id : chain) res += nodes[id].add;\n                return res;\n            }\n\n            vector<char> mark(gen.size(), 0);\n            vector<int> idx(gen.size());\n            iota(idx.begin(), idx.end(), 0);\n\n            for (int beta : betas) {\n                int K = min(keepPerBeta, (int)idx.size());\n                auto comp = [&](int a, int b) {\n                    long long ea = 100LL * gen[a].cost - 1LL * beta * gen[a].g.cnt;\n                    long long eb = 100LL * gen[b].cost - 1LL * beta * gen[b].g.cnt;\n                    if (ea != eb) return ea < eb;\n                    return gen[a].cost < gen[b].cost;\n                };\n\n                if (K < (int)idx.size()) {\n                    nth_element(idx.begin(), idx.begin() + K, idx.end(), comp);\n                }\n\n                for (int i = 0; i < K; i++) mark[idx[i]] = 1;\n            }\n\n            vector<BeamState> nxt;\n            nxt.reserve(keepPerBeta * (int)betas.size());\n\n            for (int i = 0; i < (int)gen.size(); i++) {\n                if (mark[i]) nxt.push_back(gen[i]);\n            }\n\n            if (nxt.empty()) {\n                int best = min_element(gen.begin(), gen.end(), [](const BeamState& a, const BeamState& b) {\n                    return a.cost < b.cost;\n                }) - gen.begin();\n                nxt.push_back(gen[best]);\n            }\n\n            beam.swap(nxt);\n        }\n\n        return \"\";\n    }\n\n    struct LocalNode {\n        Grid g;\n        int p;\n        int parent;\n        int dist;\n        int altCnt;\n        int valDelta;\n        unsigned char act;\n    };\n\n    inline uint64_t localKey(uint64_t h, int p) const {\n        return h ^ (0x9e3779b97f4a7c15ULL * uint64_t(p + 1));\n    }\n\n    bool localSegmentSearch(\n        const Grid& startG,\n        int s,\n        int goal,\n        int k,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& path,\n        Grid& outG\n    ) {\n        if (elapsed() > endTime) return false;\n        if (isBlocked(startG, s) || isBlocked(startG, goal)) return false;\n        if (s == goal) {\n            path.clear();\n            outG = startG;\n            return true;\n        }\n\n        int base = bfsDist(startG, s, goal);\n        int maxDepth = 24;\n        if (base < INF) maxDepth = min(24, base + slack + 3);\n        maxDepth = max(maxDepth, 8);\n\n        vector<LocalNode> nodes;\n        nodes.reserve(maxNodes + 5);\n        vector<int> q;\n        q.reserve(maxNodes + 5);\n\n        unordered_map<uint64_t, int> mp;\n        mp.reserve(maxNodes * 2 + 100);\n        mp.max_load_factor(0.7);\n\n        LocalNode root;\n        root.g = startG;\n        root.p = s;\n        root.parent = -1;\n        root.dist = 0;\n        root.altCnt = 0;\n        root.valDelta = 0;\n        root.act = 255;\n        nodes.push_back(root);\n        q.push_back(0);\n        mp[localKey(startG.hash, s)] = 0;\n\n        int startCnt = startG.cnt;\n        int bestGoalId = -1;\n        int bestGoalDist = INF;\n        int bestGoalCost = INF;\n        double bestScore = 1e100;\n\n        auto recordGoal = [&](int id) {\n            const LocalNode& nd = nodes[id];\n            bestGoalDist = min(bestGoalDist, nd.dist);\n            double sc = double(nd.dist)\n                - betaCnt * double(nd.g.cnt - startCnt)\n                - betaVal * double(nd.valDelta);\n            if (sc < bestScore - 1e-9 ||\n                (fabs(sc - bestScore) <= 1e-9 && nd.dist < bestGoalCost)) {\n                bestScore = sc;\n                bestGoalId = id;\n                bestGoalCost = nd.dist;\n            }\n        };\n\n        auto addNode = [&](const Grid& ng, int np, int parent, unsigned char act, int ndist, int nalt, int nval) -> int {\n            if ((int)nodes.size() >= maxNodes) return -1;\n            uint64_t key = localKey(ng.hash, np);\n            if (mp.find(key) != mp.end()) return -1;\n\n            int id = (int)nodes.size();\n            LocalNode node;\n            node.g = ng;\n            node.p = np;\n            node.parent = parent;\n            node.dist = ndist;\n            node.altCnt = nalt;\n            node.valDelta = nval;\n            node.act = act;\n            nodes.push_back(node);\n            mp[key] = id;\n            q.push_back(id);\n\n            if (np == goal) recordGoal(id);\n            return id;\n        };\n\n        int head = 0;\n        while (head < (int)q.size()) {\n            if (elapsed() > endTime) return false;\n\n            int id = q[head++];\n            LocalNode cur = nodes[id];\n\n            if (cur.p == goal) continue;\n            if (cur.dist >= maxDepth) continue;\n            if (bestGoalDist < INF && cur.dist >= bestGoalDist + slack) continue;\n\n            int ndist = cur.dist + 1;\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDest(cur.g, cur.p, d);\n                if (to == cur.p) continue;\n                addNode(cur.g, to, id, enc(1, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[cur.p][d];\n                if (to < 0 || isBlocked(cur.g, to)) continue;\n                addNode(cur.g, to, id, enc(0, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int cell = mv[cur.p][d];\n                if (cell < 0) continue;\n\n                bool blk = isBlocked(cur.g, cell);\n                if (!blk && future[k][cell]) continue;\n\n                bool startBlk = isBlocked(startG, cell);\n                bool beforeDiff = (blk != startBlk);\n                int nalt = cur.altCnt + (beforeDiff ? -1 : 1);\n                if (nalt > maxAlt) continue;\n\n                Grid ng = cur.g;\n                toggleBlock(ng, cell);\n\n                int nval = cur.valDelta + (blk ? -adjVal[k][cell] : adjVal[k][cell]);\n                addNode(ng, cur.p, id, enc(2, d), ndist, nalt, nval);\n            }\n        }\n\n        if (bestGoalId < 0) return false;\n\n        path.clear();\n        for (int id = bestGoalId; nodes[id].parent != -1; id = nodes[id].parent) {\n            path.push_back(char(nodes[id].act));\n        }\n        reverse(path.begin(), path.end());\n        outG = nodes[bestGoalId].g;\n        return true;\n    }\n\n    bool buildGreedyAction(\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& acts\n    ) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            if (elapsed() > endTime) return false;\n\n            string seg;\n            Grid ng;\n            bool ok = localSegmentSearch(\n                g, pos[k], pos[k + 1], k,\n                betaCnt, betaVal, maxAlt, slack, maxNodes,\n                endTime, seg, ng\n            );\n\n            if (!ok) {\n                if (!bfsPath(g, pos[k], pos[k + 1], seg)) return false;\n                ng = g;\n            }\n\n            acts += seg;\n            g = ng;\n            if ((int)acts.size() > LIMIT) return false;\n        }\n        return true;\n    }\n\n    void solve() {\n        cin >> N >> M;\n        pos.resize(M);\n        for (int i = 0; i < M; i++) {\n            int r, c;\n            cin >> r >> c;\n            pos[i] = r * N + c;\n        }\n\n        startTime = chrono::steady_clock::now();\n        init();\n\n        pureFallback = makePureMoves();\n        addCandidate(pureFallback);\n\n        string beamAns = solveBeam(25);\n        if (!beamAns.empty()) addCandidate(beamAns);\n\n        vector<pair<int, vector<int>>> maskCands;\n\n        vector<vector<int>> starts;\n        starts.push_back(makeZeroMasks());\n        starts.push_back(makeDenseMasks());\n        starts.push_back(makeExitMasks());\n        starts.push_back(makeSparseMasks());\n        starts.push_back(makeValueMasks());\n        for (int i = 0; i < 6; i++) starts.push_back(makeRandomMasks());\n\n        double planEnd = 1.52;\n\n        for (auto st : starts) {\n            if (elapsed() > planEnd) break;\n            auto res = coordinateDescent(st, 3, planEnd);\n            maskCands.push_back(res);\n        }\n\n        if (maskCands.empty()) {\n            vector<int> z = makeZeroMasks();\n            maskCands.push_back({evalPlan(z), z});\n        }\n\n        sort(maskCands.begin(), maskCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedMaskKeys;\n        vector<double> backBetas = {-1.0, 0.0, 1.0, 1.5, 2.0, 2.5, 3.0};\n\n        int used = 0;\n        for (auto& pr : maskCands) {\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedMaskKeys.count(key)) continue;\n            usedMaskKeys.insert(key);\n\n            for (double beta : backBetas) {\n                string acts;\n                if (buildFromMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            used++;\n            if (used >= 8) break;\n        }\n\n        vector<tuple<double, double, int, int, int>> localCfgs = {\n            {0.0, 0.00, 3, 1, 1600},\n            {0.5, 0.06, 4, 2, 2000},\n            {0.9, 0.10, 4, 3, 2400},\n            {1.2, 0.14, 5, 3, 2800},\n        };\n\n        double localEnd = 1.74;\n        for (auto [bc, bv, ma, sl, mn] : localCfgs) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyAction(bc, bv, ma, sl, mn, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        if (candidates.empty()) candidates.push_back(pureFallback);\n\n        string best = candidates[0];\n        for (const string& s : candidates) {\n            if (s.size() < best.size()) best = s;\n        }\n\n        vector<int> order(candidates.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return candidates[a].size() < candidates[b].size();\n        });\n\n        for (int id : order) {\n            if (elapsed() > 1.88) break;\n            string improved = greedyDelete(candidates[id], 1.88);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        if (elapsed() < 1.94) {\n            string improved = replaceImprove(best, 1.96);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        int pp = firstCompletionPrefix(best);\n        if (pp >= 0 && pp <= LIMIT) {\n            best.resize(pp);\n        } else {\n            best = pureFallback;\n        }\n\n        const string A = \"MSA\";\n        const string D = \"UDLR\";\n\n        for (unsigned char ch : best) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            cout << A[type] << ' ' << D[d] << '\\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\n    return 0;\n}"},"4":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Rect {\n    int a, b, c, d;\n};\n\nstatic uint64_t splitmix64_hash(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nclass Solver {\n    static constexpr int SZ = 10000;\n    static constexpr double TIME_LIMIT = 4.84;\n\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    vector<double> rd, invR;\n    FastRNG rng;\n    Timer timer;\n\n    struct State {\n        vector<Rect> rect;\n        vector<double> val;\n        double total = 0.0;\n    };\n\n    struct Move {\n        bool ok = false;\n        int dir = 0;\n        int coord = 0;\n        double newScore = 0.0;\n        double delta = 0.0;\n    };\n\n    struct PairMove {\n        bool ok = false;\n        int orient = 0;\n        int i = -1, j = -1;\n        int coord = 0;\n        double newScoreI = 0.0;\n        double newScoreJ = 0.0;\n        double delta = 0.0;\n    };\n\n    struct LineComp {\n        int orient = 0;\n        int coord = -1;\n        vector<int> A;\n        vector<int> B;\n    };\n\n    struct LineMove {\n        bool ok = false;\n        int orient = 0;\n        int coord = -1;\n        int newCoord = 0;\n        vector<int> A, B;\n        double delta = 0.0;\n    };\n\n    struct SplitCand {\n        int orient;\n        int k;\n        int t;\n        double cost;\n    };\n\n    long long rectArea(const Rect& rc) const {\n        return 1LL * (rc.c - rc.a) * (rc.d - rc.b);\n    }\n\n    double scoreOne(int i, long long s) const {\n        double ratio;\n        if (s <= r[i]) ratio = (double)s * invR[i];\n        else ratio = rd[i] / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    static double scoreRatio(long long s, long long target) {\n        double ratio;\n        if (s <= target) ratio = (double)s / (double)target;\n        else ratio = (double)target / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    State makeState(const vector<Rect>& rects) const {\n        State st;\n        st.rect = rects;\n        st.val.assign(n, 0.0);\n        st.total = 0.0;\n        for (int i = 0; i < n; i++) {\n            st.val[i] = scoreOne(i, rectArea(st.rect[i]));\n            st.total += st.val[i];\n        }\n        return st;\n    }\n\n    int clampLL(long long v, int lo, int hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return (int)v;\n    }\n\n    bool yOverlap(const Rect& p, const Rect& q) const {\n        return max(p.b, q.b) < min(p.d, q.d);\n    }\n\n    bool xOverlap(const Rect& p, const Rect& q) const {\n        return max(p.a, q.a) < min(p.c, q.c);\n    }\n\n    bool overlapRect(const Rect& p, const Rect& q) const {\n        return xOverlap(p, q) && yOverlap(p, q);\n    }\n\n    void sortIds(vector<int>& ord, int orient) const {\n        if (orient == 0) {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (x[u] != x[v]) return x[u] < x[v];\n                return y[u] < y[v];\n            });\n        } else {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (y[u] != y[v]) return y[u] < y[v];\n                return x[u] < x[v];\n            });\n        }\n    }\n\n    void buildRec(const vector<int>& ids, const Rect& box, vector<Rect>& out, double temp) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return;\n        }\n\n        long long totalR = 0;\n        for (int id : ids) totalR += r[id];\n\n        long long A = rectArea(box);\n        int W = box.c - box.a;\n        int H = box.d - box.b;\n\n        vector<SplitCand> cands;\n        cands.reserve(m * 40);\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<int> ord = ids;\n            sortIds(ord, orient);\n\n            long long pref = 0;\n            for (int k = 1; k < m; k++) {\n                pref += r[ord[k - 1]];\n\n                int lo, hi;\n                if (orient == 0) {\n                    int xl = x[ord[k - 1]];\n                    int xr = x[ord[k]];\n                    lo = max(box.a + 1, xl + 1);\n                    hi = min(box.c - 1, xr);\n                } else {\n                    int yl = y[ord[k - 1]];\n                    int yr = y[ord[k]];\n                    lo = max(box.b + 1, yl + 1);\n                    hi = min(box.d - 1, yr);\n                }\n\n                if (lo > hi) continue;\n\n                vector<int> ts;\n                ts.reserve(32);\n\n                auto addT = [&](int t) {\n                    if (t < lo || t > hi) return;\n                    for (int u : ts) if (u == t) return;\n                    ts.push_back(t);\n                };\n\n                auto addReal = [&](long double real) {\n                    long long f = (long long)floorl(real);\n                    for (long long v = f - 2; v <= f + 2; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                    long long rr = (long long)llroundl(real);\n                    for (long long v = rr - 1; v <= rr + 1; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                };\n\n                if (orient == 0) {\n                    long double prop = box.a + ((long double)A * pref / totalR) / H;\n                    long double exactL = box.a + (long double)pref / H;\n                    long double exactR = box.a + ((long double)A - (long double)(totalR - pref)) / H;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                } else {\n                    long double prop = box.b + ((long double)A * pref / totalR) / W;\n                    long double exactL = box.b + (long double)pref / W;\n                    long double exactR = box.b + ((long double)A - (long double)(totalR - pref)) / W;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                }\n\n                addT(lo);\n                addT(hi);\n\n                for (int t : ts) {\n                    long long leftA;\n                    if (orient == 0) leftA = 1LL * (t - box.a) * H;\n                    else leftA = 1LL * W * (t - box.b);\n\n                    long long rightA = A - leftA;\n                    if (leftA <= 0 || rightA <= 0) continue;\n\n                    double sc =\n                        k * scoreRatio(leftA, pref) +\n                        (m - k) * scoreRatio(rightA, totalR - pref);\n\n                    double loss = 1.0 - sc / m;\n\n                    auto aspectPenalty = [&](int ww, int hh, int cnt) -> double {\n                        if (cnt <= 1) return 0.0;\n                        double ar = max((double)ww / hh, (double)hh / ww);\n                        return 0.00025 * (cnt / (double)m) * max(0.0, log(ar) - 2.0);\n                    };\n\n                    double cost = loss;\n                    cost += 0.00020 * abs(m - 2 * k) / (double)m;\n\n                    if (orient == 0) {\n                        cost += aspectPenalty(t - box.a, H, k);\n                        cost += aspectPenalty(box.c - t, H, m - k);\n                    } else {\n                        cost += aspectPenalty(W, t - box.b, k);\n                        cost += aspectPenalty(W, box.d - t, m - k);\n                    }\n\n                    cands.push_back({orient, k, t, cost});\n                }\n            }\n        }\n\n        if (cands.empty()) {\n            for (int id : ids) {\n                out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            }\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int chosen = 0;\n        if (temp > 1e-12) {\n            double bestCost = cands[0].cost;\n            double maxDiff = max(0.03, temp * 12.0);\n\n            vector<pair<int, double>> cumulative;\n            double sum = 0.0;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                double diff = cands[i].cost - bestCost;\n                if (diff > maxDiff) continue;\n                double w = exp(-diff / temp);\n                if (w < 1e-12) continue;\n                sum += w;\n                cumulative.push_back({i, sum});\n            }\n\n            if (sum > 0.0) {\n                double z = rng.nextDouble() * sum;\n                for (auto [idx, cum] : cumulative) {\n                    if (z <= cum) {\n                        chosen = idx;\n                        break;\n                    }\n                }\n            }\n        }\n\n        SplitCand sp = cands[chosen];\n\n        vector<int> ord = ids;\n        sortIds(ord, sp.orient);\n\n        vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n        vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n        if (sp.orient == 0) {\n            Rect L{box.a, box.b, sp.t, box.d};\n            Rect R{sp.t, box.b, box.c, box.d};\n            buildRec(leftIds, L, out, temp);\n            buildRec(rightIds, R, out, temp);\n        } else {\n            Rect B{box.a, box.b, box.c, sp.t};\n            Rect T{box.a, sp.t, box.c, box.d};\n            buildRec(leftIds, B, out, temp);\n            buildRec(rightIds, T, out, temp);\n        }\n    }\n\n    vector<Rect> buildRecursive(double temp) {\n        vector<Rect> out(n);\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        buildRec(ids, Rect{0, 0, SZ, SZ}, out, temp);\n        return out;\n    }\n\n    vector<Rect> buildUnit() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; i++) {\n            rects[i] = {x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        return rects;\n    }\n\n    pair<int, int> legalInterval(const State& st, int i, int dir) const {\n        const Rect& ri = st.rect[i];\n\n        if (dir == 0) {\n            int lo = 0;\n            int hi = min(x[i], ri.c - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.a < ri.c) {\n                    lo = max(lo, rj.c);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 1) {\n            int lo = max(x[i] + 1, ri.a + 1);\n            int hi = SZ;\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.c > ri.a) {\n                    hi = min(hi, rj.a);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 2) {\n            int lo = 0;\n            int hi = min(y[i], ri.d - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (xOverlap(ri, rj) && rj.b < ri.d) {\n                    lo = max(lo, rj.d);\n                }\n            }\n            return {lo, hi};\n        }\n\n        int lo = max(y[i] + 1, ri.b + 1);\n        int hi = SZ;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& rj = st.rect[j];\n            if (xOverlap(ri, rj) && rj.d > ri.b) {\n                hi = min(hi, rj.b);\n            }\n        }\n        return {lo, hi};\n    }\n\n    int getCoord(const Rect& rc, int dir) const {\n        if (dir == 0) return rc.a;\n        if (dir == 1) return rc.c;\n        if (dir == 2) return rc.b;\n        return rc.d;\n    }\n\n    void setCoord(Rect& rc, int dir, int v) {\n        if (dir == 0) rc.a = v;\n        else if (dir == 1) rc.c = v;\n        else if (dir == 2) rc.b = v;\n        else rc.d = v;\n    }\n\n    long long areaAfterCoord(const Rect& rc, int dir, int coord) const {\n        if (dir == 0) return 1LL * (rc.c - coord) * (rc.d - rc.b);\n        if (dir == 1) return 1LL * (coord - rc.a) * (rc.d - rc.b);\n        if (dir == 2) return 1LL * (rc.c - rc.a) * (rc.d - coord);\n        return 1LL * (rc.c - rc.a) * (coord - rc.b);\n    }\n\n    Move bestEdgeDir(const State& st, int i, int dir) const {\n        Move mv;\n        mv.ok = false;\n\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return mv;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n\n        mv.ok = true;\n        mv.dir = dir;\n        mv.coord = cur;\n        mv.newScore = st.val[i];\n        mv.delta = 0.0;\n\n        int cand[48];\n        int cnt = 0;\n\n        auto addCand = [&](int v) {\n            if (v < lo) v = lo;\n            if (v > hi) v = hi;\n            for (int k = 0; k < cnt; k++) if (cand[k] == v) return;\n            cand[cnt++] = v;\n        };\n\n        addCand(cur);\n        addCand(lo);\n        addCand(hi);\n\n        long double real;\n        if (dir == 0 || dir == 1) {\n            int h = rc.d - rc.b;\n            long double wantW = (long double)r[i] / h;\n            if (dir == 0) real = rc.c - wantW;\n            else real = rc.a + wantW;\n        } else {\n            int w = rc.c - rc.a;\n            long double wantH = (long double)r[i] / w;\n            if (dir == 2) real = rc.d - wantH;\n            else real = rc.b + wantH;\n        }\n\n        long long f = (long long)floorl(real);\n        for (long long v = f - 5; v <= f + 5; v++) {\n            addCand(clampLL(v, lo, hi));\n        }\n\n        double bestScore = st.val[i];\n        int bestCoord = cur;\n\n        for (int k = 0; k < cnt; k++) {\n            int v = cand[k];\n            long long ar = areaAfterCoord(rc, dir, v);\n            double ns = scoreOne(i, ar);\n            if (ns > bestScore + 1e-15) {\n                bestScore = ns;\n                bestCoord = v;\n            }\n        }\n\n        mv.coord = bestCoord;\n        mv.newScore = bestScore;\n        mv.delta = bestScore - st.val[i];\n        return mv;\n    }\n\n    Move bestMove(const State& st, int i) const {\n        Move best;\n        best.ok = false;\n        best.delta = 0.0;\n        best.newScore = st.val[i];\n\n        for (int dir = 0; dir < 4; dir++) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) continue;\n            if (!best.ok || mv.delta > best.delta) best = mv;\n        }\n        return best;\n    }\n\n    void applyCoord(State& st, int i, int dir, int coord, double newScore) {\n        setCoord(st.rect[i], dir, coord);\n        st.total += newScore - st.val[i];\n        st.val[i] = newScore;\n    }\n\n    void applyMove(State& st, int i, const Move& mv) {\n        applyCoord(st, i, mv.dir, mv.coord, mv.newScore);\n    }\n\n    PairMove bestPairVertical(const State& st, int li, int ri) const {\n        PairMove pm;\n        pm.ok = false;\n        pm.orient = 0;\n        pm.i = li;\n        pm.j = ri;\n\n        if (li == ri) return pm;\n        const Rect& L = st.rect[li];\n        const Rect& R = st.rect[ri];\n\n        if (L.c > R.a) return pm;\n        if (!yOverlap(L, R)) return pm;\n\n        int lo1 = max(x[li] + 1, L.a + 1);\n        int hi1 = SZ;\n\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(L, K) && K.c > L.a) {\n                hi1 = min(hi1, K.a);\n            }\n        }\n\n        int lo2 = 0;\n        int hi2 = min(x[ri], R.c - 1);\n\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(R, K) && K.a < R.c) {\n                lo2 = max(lo2, K.c);\n            }\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int hL = L.d - L.b;\n        int hR = R.d - R.b;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * (t - L.a) * hL;\n            long long a2 = 1LL * (R.c - t) * hR;\n            return scoreOne(li, a1) + scoreOne(ri, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(L.c, lo, hi));\n        test(clampLL(R.a, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) {\n                test(clampLL(v, lo, hi));\n            }\n        };\n\n        addReal((long double)L.a + (long double)r[li] / hL);\n        addReal((long double)R.c - (long double)r[ri] / hR);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * (bestT - L.a) * hL;\n        long long a2 = 1LL * (R.c - bestT) * hR;\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(li, a1);\n        pm.newScoreJ = scoreOne(ri, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[li] - st.val[ri];\n        return pm;\n    }\n\n    PairMove bestPairHorizontal(const State& st, int bi, int ti) const {\n        PairMove pm;\n        pm.ok = false;\n        pm.orient = 1;\n        pm.i = bi;\n        pm.j = ti;\n\n        if (bi == ti) return pm;\n        const Rect& B = st.rect[bi];\n        const Rect& T = st.rect[ti];\n\n        if (B.d > T.b) return pm;\n        if (!xOverlap(B, T)) return pm;\n\n        int lo1 = max(y[bi] + 1, B.b + 1);\n        int hi1 = SZ;\n\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(B, K) && K.d > B.b) {\n                hi1 = min(hi1, K.b);\n            }\n        }\n\n        int lo2 = 0;\n        int hi2 = min(y[ti], T.d - 1);\n\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(T, K) && K.b < T.d) {\n                lo2 = max(lo2, K.d);\n            }\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int wB = B.c - B.a;\n        int wT = T.c - T.a;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * wB * (t - B.b);\n            long long a2 = 1LL * wT * (T.d - t);\n            return scoreOne(bi, a1) + scoreOne(ti, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(B.d, lo, hi));\n        test(clampLL(T.b, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) {\n                test(clampLL(v, lo, hi));\n            }\n        };\n\n        addReal((long double)B.b + (long double)r[bi] / wB);\n        addReal((long double)T.d - (long double)r[ti] / wT);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * wB * (bestT - B.b);\n        long long a2 = 1LL * wT * (T.d - bestT);\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(bi, a1);\n        pm.newScoreJ = scoreOne(ti, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[bi] - st.val[ti];\n        return pm;\n    }\n\n    void applyPair(State& st, const PairMove& pm) {\n        int i = pm.i;\n        int j = pm.j;\n\n        if (pm.orient == 0) {\n            st.rect[i].c = pm.coord;\n            st.rect[j].a = pm.coord;\n        } else {\n            st.rect[i].d = pm.coord;\n            st.rect[j].b = pm.coord;\n        }\n\n        st.total += pm.newScoreI - st.val[i];\n        st.total += pm.newScoreJ - st.val[j];\n\n        st.val[i] = pm.newScoreI;\n        st.val[j] = pm.newScoreJ;\n    }\n\n    void shuffleVector(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int selectBad(const State& st) {\n        int best = rng.nextInt(n);\n        double bv = st.val[best];\n\n        int K = min(n, 6);\n        for (int k = 1; k < K; k++) {\n            int j = rng.nextInt(n);\n            if (st.val[j] < bv) {\n                bv = st.val[j];\n                best = j;\n            }\n        }\n        return best;\n    }\n\n    bool greedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ord);\n\n            bool any = false;\n            for (int id : ord) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairGreedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            shuffleVector(ord);\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < n; ai++) {\n                int i = ord[ai];\n                for (int bj = ai + 1; bj < n; bj++) {\n                    if ((checks++ & 255) == 0 && timer.elapsed() > stopTime) {\n                        return globalAny;\n                    }\n\n                    int j = ord[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.ok = false;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    vector<LineComp> buildLineComponents(const State& st, int orient) const {\n        vector<int> coords;\n        coords.reserve(2 * n);\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = st.rect[i];\n            if (orient == 0) {\n                if (0 < rc.c && rc.c < SZ) coords.push_back(rc.c);\n                if (0 < rc.a && rc.a < SZ) coords.push_back(rc.a);\n            } else {\n                if (0 < rc.d && rc.d < SZ) coords.push_back(rc.d);\n                if (0 < rc.b && rc.b < SZ) coords.push_back(rc.b);\n            }\n        }\n\n        sort(coords.begin(), coords.end());\n        coords.erase(unique(coords.begin(), coords.end()), coords.end());\n\n        vector<LineComp> comps;\n\n        for (int coord : coords) {\n            vector<int> A, B;\n            for (int i = 0; i < n; i++) {\n                const Rect& rc = st.rect[i];\n                if (orient == 0) {\n                    if (rc.c == coord) A.push_back(i);\n                    if (rc.a == coord) B.push_back(i);\n                } else {\n                    if (rc.d == coord) A.push_back(i);\n                    if (rc.b == coord) B.push_back(i);\n                }\n            }\n\n            if (A.empty() || B.empty()) continue;\n\n            int na = (int)A.size();\n            int nb = (int)B.size();\n            vector<vector<int>> adj(na + nb);\n\n            for (int i = 0; i < na; i++) {\n                for (int j = 0; j < nb; j++) {\n                    bool ov = (orient == 0)\n                        ? yOverlap(st.rect[A[i]], st.rect[B[j]])\n                        : xOverlap(st.rect[A[i]], st.rect[B[j]]);\n                    if (ov) {\n                        adj[i].push_back(na + j);\n                        adj[na + j].push_back(i);\n                    }\n                }\n            }\n\n            vector<char> vis(na + nb, 0);\n            for (int s = 0; s < na + nb; s++) {\n                if (vis[s]) continue;\n\n                vector<int> q = {s};\n                vis[s] = 1;\n                for (int qi = 0; qi < (int)q.size(); qi++) {\n                    int v = q[qi];\n                    for (int to : adj[v]) {\n                        if (!vis[to]) {\n                            vis[to] = 1;\n                            q.push_back(to);\n                        }\n                    }\n                }\n\n                LineComp cp;\n                cp.orient = orient;\n                cp.coord = coord;\n\n                for (int v : q) {\n                    if (v < na) cp.A.push_back(A[v]);\n                    else cp.B.push_back(B[v - na]);\n                }\n\n                if (!cp.A.empty() && !cp.B.empty()) {\n                    comps.push_back(std::move(cp));\n                }\n            }\n        }\n\n        return comps;\n    }\n\n    bool componentInternalOK(const State& st, const LineComp& cp) const {\n        vector<unsigned char> side(n, 0);\n\n        for (int id : cp.A) {\n            if (side[id] & 1) return false;\n            side[id] |= 1;\n        }\n        for (int id : cp.B) {\n            if (side[id] & 2) return false;\n            if (side[id] & 1) return false;\n            side[id] |= 2;\n        }\n\n        auto perpOverlap = [&](int u, int v) -> bool {\n            if (cp.orient == 0) return yOverlap(st.rect[u], st.rect[v]);\n            else return xOverlap(st.rect[u], st.rect[v]);\n        };\n\n        for (int i = 0; i < (int)cp.A.size(); i++) {\n            for (int j = i + 1; j < (int)cp.A.size(); j++) {\n                if (perpOverlap(cp.A[i], cp.A[j])) return false;\n            }\n        }\n        for (int i = 0; i < (int)cp.B.size(); i++) {\n            for (int j = i + 1; j < (int)cp.B.size(); j++) {\n                if (perpOverlap(cp.B[i], cp.B[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\n    vector<LineComp> buildFrontierComponents(const State& st, int orient) const {\n        const int INF = 1e9;\n        vector<int> bestA(n, INF), bestB(n, INF);\n\n        auto canFace = [&](int i, int j, int& gap) -> bool {\n            if (i == j) return false;\n            const Rect& P = st.rect[i];\n            const Rect& Q = st.rect[j];\n\n            if (orient == 0) {\n                if (!yOverlap(P, Q)) return false;\n                if (P.c <= Q.a) {\n                    gap = Q.a - P.c;\n                    return true;\n                }\n            } else {\n                if (!xOverlap(P, Q)) return false;\n                if (P.d <= Q.b) {\n                    gap = Q.b - P.d;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int gap;\n                if (canFace(i, j, gap)) {\n                    bestA[i] = min(bestA[i], gap);\n                    bestB[j] = min(bestB[j], gap);\n                }\n            }\n        }\n\n        vector<vector<int>> adj(2 * n);\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int gap;\n                if (canFace(i, j, gap)) {\n                    if (gap == bestA[i] && gap == bestB[j]) {\n                        adj[i].push_back(n + j);\n                        adj[n + j].push_back(i);\n                    }\n                }\n            }\n        }\n\n        vector<LineComp> comps;\n        vector<char> vis(2 * n, 0);\n\n        for (int s = 0; s < 2 * n; s++) {\n            if (vis[s] || adj[s].empty()) continue;\n\n            vector<int> q = {s};\n            vis[s] = 1;\n\n            for (int qi = 0; qi < (int)q.size(); qi++) {\n                int v = q[qi];\n                for (int to : adj[v]) {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q.push_back(to);\n                    }\n                }\n            }\n\n            LineComp cp;\n            cp.orient = orient;\n            cp.coord = -1;\n\n            for (int v : q) {\n                if (v < n) cp.A.push_back(v);\n                else cp.B.push_back(v - n);\n            }\n\n            if (cp.A.empty() || cp.B.empty()) continue;\n            if (!componentInternalOK(st, cp)) continue;\n\n            bool sameCoord = true;\n            int common = -1;\n\n            auto feedCoord = [&](int z) {\n                if (common < 0) common = z;\n                else if (common != z) sameCoord = false;\n            };\n\n            if (orient == 0) {\n                for (int id : cp.A) feedCoord(st.rect[id].c);\n                for (int id : cp.B) feedCoord(st.rect[id].a);\n            } else {\n                for (int id : cp.A) feedCoord(st.rect[id].d);\n                for (int id : cp.B) feedCoord(st.rect[id].b);\n            }\n\n            if (sameCoord) continue;\n            comps.push_back(std::move(cp));\n        }\n\n        return comps;\n    }\n\n    LineMove bestBoundaryComponent(const State& st, const LineComp& cp, double stopTime) {\n        LineMove lm;\n        lm.ok = false;\n        lm.orient = cp.orient;\n        lm.coord = cp.coord;\n        lm.A = cp.A;\n        lm.B = cp.B;\n\n        if (cp.A.empty() || cp.B.empty()) return lm;\n        if (!componentInternalOK(st, cp)) return lm;\n\n        if (cp.coord >= 0) {\n            if (cp.orient == 0) {\n                for (int id : cp.A) if (st.rect[id].c != cp.coord) return lm;\n                for (int id : cp.B) if (st.rect[id].a != cp.coord) return lm;\n            } else {\n                for (int id : cp.A) if (st.rect[id].d != cp.coord) return lm;\n                for (int id : cp.B) if (st.rect[id].b != cp.coord) return lm;\n            }\n        }\n\n        vector<char> moved(n, 0);\n        double curScore = 0.0;\n\n        for (int id : cp.A) {\n            if (!moved[id]) {\n                moved[id] = 1;\n                curScore += st.val[id];\n            }\n        }\n        for (int id : cp.B) {\n            if (!moved[id]) {\n                moved[id] = 1;\n                curScore += st.val[id];\n            }\n        }\n\n        int lo = 0;\n        int hi = SZ;\n\n        if (cp.orient == 0) {\n            for (int id : cp.A) {\n                const Rect& ri = st.rect[id];\n                lo = max(lo, max(x[id] + 1, ri.a + 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (yOverlap(ri, rk) && rk.c > ri.a) {\n                        hi = min(hi, rk.a);\n                    }\n                }\n            }\n\n            for (int id : cp.B) {\n                const Rect& ri = st.rect[id];\n                hi = min(hi, min(x[id], ri.c - 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (yOverlap(ri, rk) && rk.a < ri.c) {\n                        lo = max(lo, rk.c);\n                    }\n                }\n            }\n        } else {\n            for (int id : cp.A) {\n                const Rect& ri = st.rect[id];\n                lo = max(lo, max(y[id] + 1, ri.b + 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (xOverlap(ri, rk) && rk.d > ri.b) {\n                        hi = min(hi, rk.b);\n                    }\n                }\n            }\n\n            for (int id : cp.B) {\n                const Rect& ri = st.rect[id];\n                hi = min(hi, min(y[id], ri.d - 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (xOverlap(ri, rk) && rk.b < ri.d) {\n                        lo = max(lo, rk.d);\n                    }\n                }\n            }\n        }\n\n        if (lo > hi) return lm;\n\n        auto eval = [&](int t) -> double {\n            double sc = 0.0;\n\n            if (cp.orient == 0) {\n                for (int id : cp.A) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (t - rc.a) * (rc.d - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n                for (int id : cp.B) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - t) * (rc.d - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n            } else {\n                for (int id : cp.A) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - rc.a) * (t - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n                for (int id : cp.B) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - rc.a) * (rc.d - t);\n                    sc += scoreOne(id, ar);\n                }\n            }\n\n            return sc;\n        };\n\n        double bestScore = curScore;\n        int bestT = (cp.coord >= 0 ? clampLL(cp.coord, lo, hi) : lo);\n\n        for (int t = lo; t <= hi; t++) {\n            if (((t - lo) & 1023) == 0 && timer.elapsed() > stopTime) break;\n\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        }\n\n        lm.ok = true;\n        lm.newCoord = bestT;\n        lm.delta = bestScore - curScore;\n        return lm;\n    }\n\n    void applyLineMove(State& st, const LineMove& lm) {\n        int t = lm.newCoord;\n\n        if (lm.orient == 0) {\n            for (int id : lm.A) st.rect[id].c = t;\n            for (int id : lm.B) st.rect[id].a = t;\n        } else {\n            for (int id : lm.A) st.rect[id].d = t;\n            for (int id : lm.B) st.rect[id].b = t;\n        }\n\n        vector<char> upd(n, 0);\n        for (int id : lm.A) {\n            if (!upd[id]) {\n                upd[id] = 1;\n                double ns = scoreOne(id, rectArea(st.rect[id]));\n                st.total += ns - st.val[id];\n                st.val[id] = ns;\n            }\n        }\n        for (int id : lm.B) {\n            if (!upd[id]) {\n                upd[id] = 1;\n                double ns = scoreOne(id, rectArea(st.rect[id]));\n                st.total += ns - st.val[id];\n                st.val[id] = ns;\n            }\n        }\n    }\n\n    bool boundarySequentialPass(State& st, int orient, bool includeFrontier, double stopTime) {\n        vector<LineComp> comps = buildLineComponents(st, orient);\n\n        if (includeFrontier) {\n            vector<LineComp> extra = buildFrontierComponents(st, orient);\n            for (auto& cp : extra) comps.push_back(std::move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [](const LineComp& p, const LineComp& q) {\n            int sp = (int)p.A.size() + (int)p.B.size();\n            int sq = (int)q.A.size() + (int)q.B.size();\n            if (sp != sq) return sp > sq;\n            bool lp = p.coord >= 0;\n            bool lq = q.coord >= 0;\n            if (lp != lq) return lp > lq;\n            return p.coord < q.coord;\n        });\n\n        bool any = false;\n\n        for (const LineComp& cp : comps) {\n            if (timer.elapsed() > stopTime) break;\n\n            LineMove mv = bestBoundaryComponent(st, cp, stopTime);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyLineMove(st, mv);\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool boundaryGreedyPasses(State& st, int passes, double stopTime, bool includeFrontier) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n\n            bool any = false;\n            if (rng.nextInt(2) == 0) {\n                any |= boundarySequentialPass(st, 0, includeFrontier, stopTime);\n                any |= boundarySequentialPass(st, 1, includeFrontier, stopTime);\n            } else {\n                any |= boundarySequentialPass(st, 1, includeFrontier, stopTime);\n                any |= boundarySequentialPass(st, 0, includeFrontier, stopTime);\n            }\n\n            if (!any) break;\n            globalAny = true;\n        }\n\n        return globalAny;\n    }\n\n    Rect groupBoundingBox(const State& st, const vector<int>& ids) const {\n        Rect box{SZ, SZ, 0, 0};\n        for (int id : ids) {\n            const Rect& rc = st.rect[id];\n            box.a = min(box.a, rc.a);\n            box.b = min(box.b, rc.b);\n            box.c = max(box.c, rc.c);\n            box.d = max(box.d, rc.d);\n        }\n        return box;\n    }\n\n    bool bboxClearForGroup(const State& st, const vector<int>& ids, const Rect& box) const {\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n        for (int i = 0; i < n; i++) {\n            if (in[i]) continue;\n            if (overlapRect(st.rect[i], box)) return false;\n        }\n        return true;\n    }\n\n    bool validSubsetRects(const vector<Rect>& v, const vector<int>& ids) const {\n        for (int id : ids) {\n            const Rect& rc = v[id];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[id] && x[id] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[id] && y[id] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            for (int j = i + 1; j < (int)ids.size(); j++) {\n                if (overlapRect(v[ids[i]], v[ids[j]])) return false;\n            }\n        }\n\n        return true;\n    }\n\n    void recomputeSubset(State& st, const vector<int>& ids) {\n        for (int id : ids) {\n            double ns = scoreOne(id, rectArea(st.rect[id]));\n            st.total += ns - st.val[id];\n            st.val[id] = ns;\n        }\n    }\n\n    bool greedySubset(State& st, vector<int> ids, int passes, double stopTime) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ids);\n\n            bool any = false;\n            for (int id : ids) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairSubsetPass(State& st, vector<int> ids, int passes, double stopTime) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ids);\n\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < (int)ids.size(); ai++) {\n                int i = ids[ai];\n                for (int bj = ai + 1; bj < (int)ids.size(); bj++) {\n                    if ((checks++ & 63) == 0 && timer.elapsed() > stopTime) {\n                        return globalAny;\n                    }\n\n                    int j = ids[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.ok = false;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool tryRepackGroup(State& st, vector<int> ids, double stopTime, int trials) {\n        if (timer.elapsed() > stopTime) return false;\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if ((int)ids.size() < 2 || (int)ids.size() > 7) return false;\n\n        Rect box = groupBoundingBox(st, ids);\n        if (!(box.a < box.c && box.b < box.d)) return false;\n        if (!bboxClearForGroup(st, ids, box)) return false;\n\n        State bestLocal = st;\n\n        auto consider = [&](const vector<Rect>& fullRects) {\n            if (timer.elapsed() > stopTime) return;\n            if (!validSubsetRects(fullRects, ids)) return;\n\n            State tr = st;\n            for (int id : ids) tr.rect[id] = fullRects[id];\n            recomputeSubset(tr, ids);\n\n            greedySubset(tr, ids, 2, stopTime);\n            pairSubsetPass(tr, ids, 1, stopTime);\n            greedySubset(tr, ids, 1, stopTime);\n\n            if (tr.total > bestLocal.total + 1e-12) {\n                bestLocal = std::move(tr);\n            }\n        };\n\n        {\n            vector<Rect> rects = st.rect;\n            buildRec(ids, box, rects, 0.0);\n            consider(rects);\n        }\n\n        if (trials >= 3 && timer.elapsed() < stopTime) {\n            vector<Rect> rects = st.rect;\n            for (int id : ids) rects[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            consider(rects);\n        }\n\n        for (int t = 0; t < trials && timer.elapsed() < stopTime; t++) {\n            vector<Rect> rects = st.rect;\n            double temp = 0.0005 * pow(500.0, rng.nextDouble());\n            buildRec(ids, box, rects, temp);\n            consider(rects);\n        }\n\n        if (bestLocal.total > st.total + 1e-12) {\n            st = std::move(bestLocal);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool componentRepackPass(State& st, double stopTime, int maxGroups) {\n        struct GC {\n            double key;\n            vector<int> ids;\n        };\n\n        vector<GC> groups;\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<LineComp> comps = buildLineComponents(st, orient);\n            for (const LineComp& cp : comps) {\n                vector<int> ids = cp.A;\n                for (int id : cp.B) ids.push_back(id);\n                sort(ids.begin(), ids.end());\n                ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n                int k = (int)ids.size();\n                if (k < 2 || k > 7) continue;\n\n                double loss = 0.0;\n                for (int id : ids) loss += 1.0 - st.val[id];\n\n                double key = loss + 0.002 * k + 1e-5 * rng.nextDouble();\n                groups.push_back({key, ids});\n            }\n        }\n\n        sort(groups.begin(), groups.end(), [](const GC& p, const GC& q) {\n            return p.key > q.key;\n        });\n\n        bool any = false;\n        int tried = 0;\n\n        for (auto& g : groups) {\n            if (timer.elapsed() > stopTime) break;\n            if (tried++ >= maxGroups) break;\n\n            int k = (int)g.ids.size();\n            int trials = (k <= 3 ? 5 : 3);\n\n            if (tryRepackGroup(st, g.ids, stopTime, trials)) {\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool pairBlockRepackPass(State& st, double stopTime, int maxGroups) {\n        struct PC {\n            double key;\n            int i, j;\n        };\n\n        vector<PC> cand;\n        int checks = 0;\n\n        for (int i = 0; i < n; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if ((checks++ & 511) == 0 && timer.elapsed() > stopTime) break;\n\n                double loss = (1.0 - st.val[i]) + (1.0 - st.val[j]);\n                if (loss < 1e-6 && rng.nextDouble() > 0.03) continue;\n\n                Rect box{\n                    min(st.rect[i].a, st.rect[j].a),\n                    min(st.rect[i].b, st.rect[j].b),\n                    max(st.rect[i].c, st.rect[j].c),\n                    max(st.rect[i].d, st.rect[j].d)\n                };\n\n                bool clear = true;\n                for (int k = 0; k < n; k++) {\n                    if (k == i || k == j) continue;\n                    if (overlapRect(st.rect[k], box)) {\n                        clear = false;\n                        break;\n                    }\n                }\n                if (!clear) continue;\n\n                cand.push_back({loss + 1e-5 * rng.nextDouble(), i, j});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [](const PC& p, const PC& q) {\n            return p.key > q.key;\n        });\n\n        bool any = false;\n        int lim = min(maxGroups, (int)cand.size());\n\n        for (int t = 0; t < lim; t++) {\n            if (timer.elapsed() > stopTime) break;\n            if (tryRepackGroup(st, vector<int>{cand[t].i, cand[t].j}, stopTime, 2)) {\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    int rectGap(const Rect& A, const Rect& B) const {\n        int dx = 0;\n        if (A.c < B.a) dx = B.a - A.c;\n        else if (B.c < A.a) dx = A.a - B.c;\n\n        int dy = 0;\n        if (A.d < B.b) dy = B.b - A.d;\n        else if (B.d < A.b) dy = A.b - B.d;\n\n        int penalty = (dx > 0 && dy > 0) ? 10000 : 0;\n        return dx + dy + penalty;\n    }\n\n    bool randomBlockRepackAttempts(State& st, double stopTime, int attempts) {\n        bool any = false;\n\n        for (int at = 0; at < attempts && timer.elapsed() < stopTime; at++) {\n            int base;\n            if (rng.nextDouble() < 0.75) base = selectBad(st);\n            else base = rng.nextInt(n);\n\n            vector<int> group{base};\n            vector<char> used(n, 0);\n            used[base] = 1;\n\n            int target = 2 + rng.nextInt(4);\n\n            for (int step = 1; step < target && timer.elapsed() < stopTime; step++) {\n                vector<pair<double, int>> cands;\n\n                for (int j = 0; j < n; j++) {\n                    if (used[j]) continue;\n\n                    int g = 1e9;\n                    for (int id : group) {\n                        g = min(g, rectGap(st.rect[id], st.rect[j]));\n                    }\n\n                    double key = (double)g - 1800.0 * (1.0 - st.val[j]) + 20.0 * rng.nextDouble();\n                    cands.push_back({key, j});\n                }\n\n                if (cands.empty()) break;\n                sort(cands.begin(), cands.end());\n\n                int lim = min(6, (int)cands.size());\n                int pick = 0;\n                if (rng.nextDouble() > 0.70) pick = rng.nextInt(lim);\n\n                int add = cands[pick].second;\n                used[add] = 1;\n                group.push_back(add);\n\n                if ((int)group.size() >= 2) {\n                    if (tryRepackGroup(st, group, stopTime, 3)) {\n                        any = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        return any;\n    }\n\n    void randomGreedyOps(State& st, int ops, double stopTime) {\n        for (int op = 0; op < ops; op++) {\n            if ((op & 255) == 0 && timer.elapsed() > stopTime) break;\n\n            int i;\n            if (rng.nextDouble() < 0.85) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Move mv = bestMove(st, i);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyMove(st, i, mv);\n            }\n        }\n    }\n\n    bool randomPairMove(State& st) {\n        int i;\n        if (rng.nextDouble() < 0.80) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n\n        static constexpr int K = 8;\n        int cand[K];\n        int gap[K];\n        int cnt = 0;\n\n        auto addCand = [&](int j, int g) {\n            if (cnt < K) {\n                cand[cnt] = j;\n                gap[cnt] = g;\n                cnt++;\n            } else {\n                int worst = 0;\n                for (int t = 1; t < K; t++) {\n                    if (gap[t] > gap[worst]) worst = t;\n                }\n                if (g < gap[worst] || rng.nextDouble() < 0.02) {\n                    cand[worst] = j;\n                    gap[worst] = g;\n                }\n            }\n        };\n\n        const Rect& R = st.rect[i];\n\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = st.rect[j];\n\n            if (dir == 0) {\n                if (Q.c <= R.a && yOverlap(Q, R)) addCand(j, R.a - Q.c);\n            } else if (dir == 1) {\n                if (R.c <= Q.a && yOverlap(R, Q)) addCand(j, Q.a - R.c);\n            } else if (dir == 2) {\n                if (Q.d <= R.b && xOverlap(Q, R)) addCand(j, R.b - Q.d);\n            } else {\n                if (R.d <= Q.b && xOverlap(R, Q)) addCand(j, Q.b - R.d);\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int pos = 0;\n        for (int t = 1; t < cnt; t++) {\n            if (gap[t] < gap[pos]) pos = t;\n        }\n        if (rng.nextDouble() < 0.35) pos = rng.nextInt(cnt);\n\n        int j = cand[pos];\n\n        PairMove mv;\n        if (dir == 0) mv = bestPairVertical(st, j, i);\n        else if (dir == 1) mv = bestPairVertical(st, i, j);\n        else if (dir == 2) mv = bestPairHorizontal(st, j, i);\n        else mv = bestPairHorizontal(st, i, j);\n\n        if (mv.ok && mv.delta > 1e-12) {\n            applyPair(st, mv);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomResize(State& st, double temp, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.55) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return false;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n        if (lo == hi) return false;\n\n        int coord = cur;\n        double q = rng.nextDouble();\n\n        if (q < 0.25) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) return false;\n            coord = mv.coord;\n        } else if (q < 0.80) {\n            long long ar = rectArea(rc);\n            bool under = ar < r[i];\n            bool preferImprove = rng.nextDouble() < 0.72;\n\n            int sign;\n            if (dir == 0 || dir == 2) {\n                sign = under ? -1 : +1;\n            } else {\n                sign = under ? +1 : -1;\n            }\n            if (!preferImprove) sign = -sign;\n\n            int maxd = (sign < 0 ? cur - lo : hi - cur);\n            if (maxd <= 0) {\n                sign = -sign;\n                maxd = (sign < 0 ? cur - lo : hi - cur);\n            }\n\n            if (maxd > 0) {\n                int step = 1 + (int)(3000.0 * (1.0 - progress) * (1.0 - progress));\n                int d = 1 + rng.nextInt(min(maxd, step));\n                coord = cur + sign * d;\n            } else {\n                coord = lo + rng.nextInt(hi - lo + 1);\n            }\n        } else {\n            coord = lo + rng.nextInt(hi - lo + 1);\n        }\n\n        if (coord == cur) return false;\n\n        long long newArea = areaAfterCoord(rc, dir, coord);\n        double ns = scoreOne(i, newArea);\n        double delta = ns - st.val[i];\n\n        if (delta >= 0.0 || rng.nextDouble() < exp(delta / max(temp, 1e-9))) {\n            applyCoord(st, i, dir, coord, ns);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomShift(State& st, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.5) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int orient = rng.nextInt(2);\n        Rect& ri = st.rect[i];\n\n        int lo, hi;\n\n        if (orient == 0) {\n            lo = max(-ri.a, x[i] + 1 - ri.c);\n            hi = min(SZ - ri.c, x[i] - ri.a);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!yOverlap(ri, rj)) continue;\n\n                if (rj.c <= ri.a) lo = max(lo, rj.c - ri.a);\n                else if (rj.a >= ri.c) hi = min(hi, rj.a - ri.c);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.a += d;\n            ri.c += d;\n            return true;\n        } else {\n            lo = max(-ri.b, y[i] + 1 - ri.d);\n            hi = min(SZ - ri.d, y[i] - ri.b);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!xOverlap(ri, rj)) continue;\n\n                if (rj.d <= ri.b) lo = max(lo, rj.d - ri.b);\n                else if (rj.b >= ri.d) hi = min(hi, rj.b - ri.d);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.b += d;\n            ri.d += d;\n            return true;\n        }\n    }\n\n    bool randomReshape(State& st, double progress) {\n        for (int attempt = 0; attempt < 3; attempt++) {\n            int i;\n            if (rng.nextDouble() < 0.25) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Rect oldRect = st.rect[i];\n            double oldVal = st.val[i];\n            double oldTotal = st.total;\n\n            int dir1 = rng.nextInt(4);\n            int dir2;\n            if (dir1 < 2) dir2 = 2 + rng.nextInt(2);\n            else dir2 = rng.nextInt(2);\n\n            auto [lo, hi] = legalInterval(st, i, dir1);\n            if (lo > hi) continue;\n\n            int cur = getCoord(st.rect[i], dir1);\n            if (lo == hi) continue;\n\n            int coord = cur;\n            double q = rng.nextDouble();\n\n            if (q < 0.22) {\n                coord = (rng.nextInt(2) ? lo : hi);\n            } else {\n                int step = 1 + (int)(2600.0 * (1.0 - progress) + 80.0);\n                int L = max(lo, cur - step);\n                int R = min(hi, cur + step);\n                if (L > R) {\n                    L = lo;\n                    R = hi;\n                }\n                coord = L + rng.nextInt(R - L + 1);\n            }\n\n            if (coord == cur) {\n                if (cur > lo) coord = cur - 1;\n                else if (cur < hi) coord = cur + 1;\n                else continue;\n            }\n\n            long long ar1 = areaAfterCoord(st.rect[i], dir1, coord);\n            double ns1 = scoreOne(i, ar1);\n            applyCoord(st, i, dir1, coord, ns1);\n\n            Move mv = bestEdgeDir(st, i, dir2);\n            if (mv.ok) applyMove(st, i, mv);\n\n            bool changed =\n                st.rect[i].a != oldRect.a || st.rect[i].b != oldRect.b ||\n                st.rect[i].c != oldRect.c || st.rect[i].d != oldRect.d;\n\n            if (changed && st.val[i] + 1e-12 >= oldVal) {\n                return true;\n            }\n\n            st.rect[i] = oldRect;\n            st.val[i] = oldVal;\n            st.total = oldTotal;\n        }\n\n        return false;\n    }\n\n    State initialSolution() {\n        constexpr double INIT_END = 0.80;\n\n        State best;\n        bool hasBest = false;\n\n        auto consider = [&](const State& st) {\n            if (!hasBest || st.total > best.total) {\n                best = st;\n                hasBest = true;\n            }\n        };\n\n        {\n            vector<Rect> rects = buildRecursive(0.0);\n            State st = makeState(rects);\n            greedyPasses(st, 5, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            boundaryGreedyPasses(st, 1, INIT_END, false);\n            randomGreedyOps(st, 5 * n, INIT_END);\n            consider(st);\n        }\n\n        if (timer.elapsed() < INIT_END) {\n            vector<Rect> rects = buildUnit();\n            State st = makeState(rects);\n            greedyPasses(st, 7, INIT_END);\n            randomGreedyOps(st, 12 * n, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            consider(st);\n        }\n\n        while (timer.elapsed() < INIT_END) {\n            double temp = 0.00035 * pow(180.0, rng.nextDouble());\n            vector<Rect> rects = buildRecursive(temp);\n            State st = makeState(rects);\n\n            greedyPasses(st, 2, INIT_END);\n            randomGreedyOps(st, 3 * n, INIT_END);\n            consider(st);\n        }\n\n        return best;\n    }\n\n    State improve(State bestState) {\n        State cur = bestState;\n\n        double preEnd = min(TIME_LIMIT - 0.72, timer.elapsed() + 0.38);\n        boundaryGreedyPasses(cur, 2, preEnd, true);\n        pairGreedyPasses(cur, 1, preEnd);\n        greedyPasses(cur, 2, preEnd);\n        boundaryGreedyPasses(cur, 1, preEnd, true);\n\n        if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n        double saStart = timer.elapsed();\n        double saEnd = TIME_LIMIT - 0.50;\n\n        int iter = 0;\n        double progress = 0.0;\n        double temp = 0.05;\n\n        while (true) {\n            if ((iter & 1023) == 0) {\n                double now = timer.elapsed();\n                if (now > saEnd) break;\n\n                progress = (now - saStart) / max(1e-9, saEnd - saStart);\n                progress = min(1.0, max(0.0, progress));\n\n                double T0 = 0.050;\n                double T1 = 0.00001;\n                temp = T0 * pow(T1 / T0, progress);\n            }\n\n            double q = rng.nextDouble();\n\n            if (q < 0.05) {\n                randomShift(cur, progress);\n            } else if (q < 0.12) {\n                randomReshape(cur, progress);\n            } else if (q < 0.34) {\n                int i;\n                if (rng.nextDouble() < 0.82) i = selectBad(cur);\n                else i = rng.nextInt(n);\n\n                Move mv = bestMove(cur, i);\n                if (mv.ok && mv.delta > 1e-12) {\n                    applyMove(cur, i, mv);\n                }\n            } else if (q < 0.62) {\n                randomPairMove(cur);\n            } else {\n                randomResize(cur, temp, progress);\n            }\n\n            if (cur.total > bestState.total + 1e-12) {\n                bestState = cur;\n            }\n\n            if ((iter & 65535) == 0) {\n                double threshold = max(1.0, 0.015 * n);\n                if (cur.total < bestState.total - threshold) {\n                    cur = bestState;\n                }\n            }\n\n            iter++;\n        }\n\n        cur = bestState;\n\n        int stagnant = 0;\n        while (timer.elapsed() < TIME_LIMIT) {\n            bool imp = false;\n\n            imp |= boundaryGreedyPasses(cur, 1, TIME_LIMIT, true);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            imp |= pairGreedyPasses(cur, 1, TIME_LIMIT);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            imp |= greedyPasses(cur, 1, TIME_LIMIT);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            double rem = TIME_LIMIT - timer.elapsed();\n            if (rem > 0.18) {\n                double blockStop = min(TIME_LIMIT - 0.06, timer.elapsed() + 0.12);\n\n                imp |= componentRepackPass(cur, blockStop, 28);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= pairBlockRepackPass(cur, blockStop, 24);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= randomBlockRepackAttempts(cur, blockStop, 8);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n            }\n\n            for (int k = 0; k < 260 && timer.elapsed() < TIME_LIMIT; k++) {\n                double q = rng.nextDouble();\n\n                if (q < 0.28) {\n                    if (randomPairMove(cur)) imp = true;\n                } else if (q < 0.40) {\n                    if (randomReshape(cur, 1.0)) imp = true;\n                } else {\n                    int i;\n                    if (rng.nextDouble() < 0.90) i = selectBad(cur);\n                    else i = rng.nextInt(n);\n\n                    Move mv = bestMove(cur, i);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(cur, i, mv);\n                        imp = true;\n                    }\n                }\n\n                if (cur.total > bestState.total + 1e-12) {\n                    bestState = cur;\n                }\n            }\n\n            if (!imp) {\n                stagnant++;\n                if (stagnant >= 4) break;\n            } else {\n                stagnant = 0;\n            }\n        }\n\n        return bestState;\n    }\n\n    bool validateRects(const vector<Rect>& v) const {\n        if ((int)v.size() != n) return false;\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = v[i];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[i] && x[i] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[i] && y[i] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (xOverlap(v[i], v[j]) && yOverlap(v[i], v[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n);\n        y.resize(n);\n        r.resize(n);\n        rd.resize(n);\n        invR.resize(n);\n\n        uint64_t seed = 1234567891234567ULL;\n        for (int i = 0; i < n; i++) {\n            cin >> x[i] >> y[i] >> r[i];\n            rd[i] = (double)r[i];\n            invR[i] = 1.0 / rd[i];\n\n            uint64_t z = ((uint64_t)x[i] << 32) ^ ((uint64_t)y[i] << 16) ^ (uint64_t)r[i];\n            seed ^= splitmix64_hash(z + seed);\n        }\n        rng = FastRNG(seed);\n\n        timer.reset();\n\n        State bestState = initialSolution();\n        bestState = improve(bestState);\n\n        if (!validateRects(bestState.rect)) {\n            bestState = makeState(buildUnit());\n        }\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = bestState.rect[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc002":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int V = N * N;\n    static constexpr int MAXT = V + 5;\n    static constexpr int MAXB = (V + 63) / 64;\n    static constexpr int POOL_LIMIT = 14;\n\n    using Bits = array<uint64_t, MAXB>;\n\n    int si, sj;\n    int startCell;\n    int M;\n\n    int tile[V];\n    int val[V];\n    int tilePot[MAXT];\n\n    int adj[V][4];\n    int adjN[V];\n    int borderDist[V];\n\n    int vis[MAXT];\n    int visitToken = 1;\n\n    int seenCell[V];\n    int seenTile[MAXT];\n    int seenBest[MAXT];\n    int bfsStamp = 1;\n    int que[V];\n\n    int pathIndex[V];\n    int rotSeen[V];\n    int rotStamp = 1;\n\n    Timer timer;\n    RNG rng;\n\n    double TL = 1.90;\n\n    vector<int> bestCells;\n    vector<int> bestCum;\n    int bestScore = -1;\n\n    vector<int> curCells;\n\n    struct PathCand {\n        vector<int> cells;\n        vector<int> cum;\n        int score;\n        uint64_t hash;\n    };\n\n    vector<PathCand> pool;\n\n    struct Params {\n        int reachW = 0;\n        int scoreW = 0;\n        int degW = 0;\n        int noise = 0;\n        int locW = 0;\n        int lossW = 0;\n        int endPenalty = 0;\n        int borderW = 0;\n        int straightW = 0;\n        int cntW = 0;\n    };\n\n    struct FloodResult {\n        int pot;\n        int cnt;\n    };\n\n    void buildAdj() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                adjN[c] = 0;\n                borderDist[c] = min(min(i, N - 1 - i), min(j, N - 1 - j));\n\n                if (i > 0) adj[c][adjN[c]++] = c - N;\n                if (i + 1 < N) adj[c][adjN[c]++] = c + N;\n                if (j > 0) adj[c][adjN[c]++] = c - 1;\n                if (j + 1 < N) adj[c][adjN[c]++] = c + 1;\n            }\n        }\n    }\n\n    void read() {\n        cin >> si >> sj;\n        startCell = si * N + sj;\n\n        uint64_t h = 0x123456789abcdefULL;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix(si);\n        mix(sj);\n\n        int maxTid = -1;\n        for (int i = 0; i < V; i++) {\n            cin >> tile[i];\n            maxTid = max(maxTid, tile[i]);\n            mix((uint64_t)tile[i] + 1009);\n        }\n\n        M = maxTid + 1;\n\n        for (int i = 0; i < V; i++) {\n            cin >> val[i];\n            mix((uint64_t)val[i] + 9176);\n        }\n\n        fill(tilePot, tilePot + MAXT, 0);\n        for (int i = 0; i < V; i++) {\n            tilePot[tile[i]] = max(tilePot[tile[i]], val[i]);\n        }\n\n        memset(vis, 0, sizeof(vis));\n        memset(seenCell, 0, sizeof(seenCell));\n        memset(seenTile, 0, sizeof(seenTile));\n        memset(rotSeen, 0, sizeof(rotSeen));\n\n        rng = RNG(h);\n        buildAdj();\n    }\n\n    int newVisitToken() {\n        ++visitToken;\n        if (visitToken == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            visitToken = 1;\n        }\n        return visitToken;\n    }\n\n    int newBfsStamp() {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            memset(seenCell, 0, sizeof(seenCell));\n            memset(seenTile, 0, sizeof(seenTile));\n            bfsStamp = 1;\n        }\n        return bfsStamp;\n    }\n\n    int newRotStamp() {\n        ++rotStamp;\n        if (rotStamp == INT_MAX) {\n            memset(rotSeen, 0, sizeof(rotSeen));\n            rotStamp = 1;\n        }\n        return rotStamp;\n    }\n\n    inline bool bitTest(const Bits& bits, int tid) const {\n        return (bits[tid >> 6] >> (tid & 63)) & 1ULL;\n    }\n\n    inline void bitSet(Bits& bits, int tid) const {\n        bits[tid >> 6] |= 1ULL << (tid & 63);\n    }\n\n    void makeBitsFromPath(const vector<int>& path, Bits& bits) const {\n        bits.fill(0);\n        for (int c : path) {\n            bitSet(bits, tile[c]);\n        }\n    }\n\n    uint64_t calcPathHash(const vector<int>& cells) const {\n        uint64_t h = 0xcbf29ce484222325ULL;\n        for (int c : cells) {\n            h ^= (uint64_t)c + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n            h *= 0x100000001b3ULL;\n        }\n        h ^= (uint64_t)cells.size() * 0x9e3779b97f4a7c15ULL;\n        return h;\n    }\n\n    void sortPool() {\n        sort(pool.begin(), pool.end(), [](const PathCand& a, const PathCand& b) {\n            if (a.score != b.score) return a.score > b.score;\n            return a.cells.size() > b.cells.size();\n        });\n\n        vector<PathCand> np;\n        np.reserve(POOL_LIMIT);\n\n        for (auto& pc : pool) {\n            bool dup = false;\n            for (auto& q : np) {\n                if (q.hash == pc.hash && q.cells.size() == pc.cells.size()) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                np.push_back(std::move(pc));\n                if ((int)np.size() >= POOL_LIMIT) break;\n            }\n        }\n\n        pool.swap(np);\n    }\n\n    void addCandidate(const vector<int>& cells, int /*scoreHint*/ = -1) {\n        if (cells.empty()) return;\n\n        vector<int> cum(cells.size());\n        int s = 0;\n        for (int i = 0; i < (int)cells.size(); i++) {\n            s += val[cells[i]];\n            cum[i] = s;\n        }\n\n        uint64_t h = calcPathHash(cells);\n\n        if (s > bestScore || (s == bestScore && cells.size() > bestCells.size())) {\n            bestScore = s;\n            bestCells = cells;\n            bestCum = cum;\n        }\n\n        bool good = false;\n        if ((int)pool.size() < POOL_LIMIT) good = true;\n        else if (s + 2500 >= pool.back().score) good = true;\n        else if (s + 4500 >= bestScore) good = true;\n\n        if (!good) return;\n\n        PathCand pc;\n        pc.cells = cells;\n        pc.cum = std::move(cum);\n        pc.score = s;\n        pc.hash = h;\n\n        pool.push_back(std::move(pc));\n        sortPool();\n    }\n\n    void setBestFrom(const vector<int>& cells, int score) {\n        addCandidate(cells, score);\n    }\n\n    void considerCurrent(int score) {\n        addCandidate(curCells, score);\n    }\n\n    int choosePoolIndex() {\n        if (pool.empty()) return -1;\n\n        int n = (int)pool.size();\n        int r = rng.nextInt(100);\n\n        if (r < 58) return 0;\n        if (r < 82) return rng.nextInt(min(n, 4));\n        if (r < 95) return rng.nextInt(min(n, 8));\n        return rng.nextInt(n);\n    }\n\n    inline int degreeAfterToken(int cell, int forbidTid, int token) {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localNeighborSumToken(int cell, int forbidTid, int token) {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int degreeAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localSumAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int countUnvisitedMoves(const Bits& bits, int cell) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) cnt++;\n        }\n        return cnt;\n    }\n\n    inline int sumUnvisitedMoveValues(const Bits& bits, int cell) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) s += val[nb];\n        }\n        return s;\n    }\n\n    FloodResult floodPotential(int start, int forbidTid, int token) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (tid == forbidTid) continue;\n                if (vis[tid] == token) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    FloodResult floodPotentialBits(int start, const Bits& bits) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (bitTest(bits, tid)) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    Params makeParams(bool flood) {\n        Params p;\n\n        if (flood) {\n            int rwArr[4] = {6, 8, 10, 12};\n            int exArr[5] = {0, 0, 2, 4, 6};\n\n            p.reachW = rwArr[rng.nextInt(4)];\n            p.scoreW = p.reachW + exArr[rng.nextInt(5)];\n\n            if (rng.nextInt(10) < 8) {\n                p.degW = 40 + rng.nextInt(260);\n            } else {\n                p.degW = -(20 + rng.nextInt(100));\n            }\n\n            p.noise = 20 + rng.nextInt(250);\n            p.locW = (rng.nextInt(4) == 0 ? 1 : 0);\n            p.cntW = rng.nextInt(6);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(16) : -rng.nextInt(8));\n            p.straightW = rng.nextInt(101) - 50;\n        } else {\n            p.scoreW = 4 + rng.nextInt(18);\n\n            int mode = rng.nextInt(10);\n            if (mode < 5) {\n                p.degW = 200 + rng.nextInt(700);\n            } else if (mode < 8) {\n                p.degW = 50 + rng.nextInt(250);\n            } else {\n                p.degW = -(20 + rng.nextInt(120));\n            }\n\n            p.noise = 100 + rng.nextInt(900);\n            p.locW = rng.nextInt(4);\n            p.lossW = rng.nextInt(8);\n            p.endPenalty = 3000 + rng.nextInt(7000);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(25) : -rng.nextInt(10));\n            p.straightW = rng.nextInt(121) - 60;\n        }\n\n        return p;\n    }\n\n    Params makePilotParam() {\n        Params p;\n        p.scoreW = 8 + rng.nextInt(22);\n\n        int mode = rng.nextInt(100);\n        if (mode < 55) {\n            p.degW = 180 + rng.nextInt(620);\n        } else if (mode < 85) {\n            p.degW = 30 + rng.nextInt(220);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = rng.nextInt(5);\n        p.lossW = rng.nextInt(9);\n        p.endPenalty = 3500 + rng.nextInt(8000);\n        p.borderW = (rng.nextInt(100) < 82 ? rng.nextInt(26) : -rng.nextInt(12));\n        p.straightW = rng.nextInt(151) - 75;\n        p.noise = 0;\n        return p;\n    }\n\n    Params makePosaParam() {\n        Params p;\n        p.scoreW = 10 + rng.nextInt(25);\n\n        int mode = rng.nextInt(100);\n        if (mode < 70) {\n            p.degW = 80 + rng.nextInt(500);\n        } else if (mode < 90) {\n            p.degW = rng.nextInt(120);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = 1 + rng.nextInt(4);\n        p.lossW = 3 + rng.nextInt(8);\n        p.endPenalty = 1000 + rng.nextInt(5000);\n        p.borderW = (rng.nextInt(100) < 75 ? rng.nextInt(20) : -rng.nextInt(8));\n        p.straightW = rng.nextInt(81) - 40;\n        p.noise = 50 + rng.nextInt(600);\n        return p;\n    }\n\n    int chooseCutLength(int L) {\n        if (L <= 1) return 0;\n\n        int r = rng.nextInt(100);\n\n        if (r < 22) return 0;\n\n        int cut = 0;\n\n        if (r < 66) {\n            int maxSuf = min(L - 1, 900);\n            int a = 1 + rng.nextInt(maxSuf);\n            int b = 1 + rng.nextInt(maxSuf);\n            int suf;\n            if (rng.nextInt(100) < 75) {\n                suf = min(a, b);\n            } else {\n                suf = max(a, b);\n            }\n            cut = L - 1 - suf;\n        } else if (r < 88) {\n            int a = rng.nextInt(L - 1);\n            int b = rng.nextInt(L - 1);\n            cut = max(a, b);\n        } else {\n            cut = rng.nextInt(L - 1);\n        }\n\n        return max(0, min(cut, L - 2));\n    }\n\n    int chooseSmartCut(const vector<int>& cells, const vector<int>& cum) {\n        int L = (int)cells.size();\n        if (L <= 2) return chooseCutLength(L);\n\n        Bits bits;\n        bits.fill(0);\n\n        long long bestEval = LLONG_MIN;\n        int bestCut = -1;\n\n        for (int i = 0; i < L - 1; i++) {\n            bitSet(bits, tile[cells[i]]);\n\n            int nextTid = tile[cells[i + 1]];\n            int altCnt = 0;\n            int altSum = 0;\n            int altMax = 0;\n\n            for (int k = 0; k < adjN[cells[i]]; k++) {\n                int nb = adj[cells[i]][k];\n                int tid = tile[nb];\n\n                if (bitTest(bits, tid)) continue;\n                if (tid == nextTid) continue;\n\n                altCnt++;\n                altSum += val[nb];\n                altMax = max(altMax, val[nb]);\n            }\n\n            if (altCnt == 0) continue;\n\n            int suffixLoss = cum[L - 1] - cum[i];\n\n            long long ev = 0;\n            ev += 15000LL * altCnt;\n            ev += 180LL * altSum;\n            ev += 280LL * altMax;\n            ev -= 2LL * suffixLoss;\n            ev += cum[i] / 3;\n            ev += rng.nextInt(30000);\n\n            if (ev > bestEval) {\n                bestEval = ev;\n                bestCut = i;\n            }\n        }\n\n        if (bestCut >= 0) return bestCut;\n        return chooseCutLength(L);\n    }\n\n    int chooseCutForBase(const PathCand& base, int zeroProb, int smartProb) {\n        int L = (int)base.cells.size();\n        if (L <= 1) return 0;\n\n        if (rng.nextInt(100) < zeroProb) return 0;\n        if (rng.nextInt(100) < smartProb) return chooseSmartCut(base.cells, base.cum);\n\n        return chooseCutLength(L);\n    }\n\n    int runGreedyFromPath(\n        const vector<int>& prefix,\n        int prefixScore,\n        bool useFlood,\n        const Params& par,\n        bool allowPosa = false\n    ) {\n        int token = newVisitToken();\n\n        curCells = prefix;\n\n        for (int c : curCells) {\n            vis[tile[c]] = token;\n        }\n\n        int score = prefixScore;\n        int pos = curCells.back();\n\n        int iter = 0;\n\n        while (true) {\n            if ((iter++ & 15) == 0 && timer.elapsed() > TL) break;\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (vis[tid] != token) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int prev = -1;\n            int lastDiff = 999999;\n            if ((int)curCells.size() >= 2) {\n                prev = curCells[(int)curCells.size() - 2];\n                lastDiff = pos - prev;\n            }\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterToken(cell, tid, token);\n                int loc = (par.locW ? localNeighborSumToken(cell, tid, token) : 0);\n\n                long long ev = 0;\n\n                if (useFlood) {\n                    FloodResult fr = floodPotential(cell, tid, token);\n                    ev += 1LL * par.reachW * fr.pot;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.cntW * fr.cnt;\n                } else {\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                    if (deg == 0 && nc > 1) {\n                        ev -= par.endPenalty;\n                    }\n                }\n\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                if (par.noise > 0) {\n                    ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n                }\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            vis[tid] = token;\n            score += val[nxt];\n            curCells.push_back(nxt);\n            pos = nxt;\n        }\n\n        if (allowPosa && timer.elapsed() < TL - 0.025 && score + 3500 >= bestScore) {\n            Bits bits;\n            makeBitsFromPath(curCells, bits);\n            Params pp = makePosaParam();\n            double stop = min(TL, timer.elapsed() + 0.012 + (rng.nextInt(100) < 30 ? 0.018 : 0.0));\n            posaExtendLocal(curCells, score, bits, stop, pp);\n        }\n\n        return score;\n    }\n\n    int runGreedyBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        bool useFlood,\n        const Params& par,\n        bool allowPosa = false\n    ) {\n        int L = (int)baseCells.size();\n        if (L == 0) return 0;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> prefix;\n        prefix.reserve(cut + 1);\n\n        for (int i = 0; i <= cut; i++) {\n            prefix.push_back(baseCells[i]);\n        }\n\n        return runGreedyFromPath(prefix, baseCum[cut], useFlood, par, allowPosa);\n    }\n\n    int runGreedy(int cut, bool useFlood, const Params& par) {\n        return runGreedyBase(bestCells, bestCum, cut, useFlood, par, false);\n    }\n\n    int rolloutScore(Bits& bits, int prev, int pos, int score, const Params& par, vector<int>* suffix) const {\n        while (true) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterBits(bits, cell, tid);\n                int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                long long ev = 0;\n                ev += 1LL * par.scoreW * val[cell];\n                ev -= 1LL * par.degW * deg;\n                ev += 1LL * par.locW * loc;\n                ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                if (ev > bestEval || (ev == bestEval && cell < candCell[bestIdx])) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            if (suffix) suffix->push_back(nxt);\n\n            prev = pos;\n            pos = nxt;\n        }\n\n        return score;\n    }\n\n    void considerRolloutPath(\n        const vector<int>& prefix,\n        int cand,\n        const Bits& bitsAfterCand,\n        int prev,\n        int scoreAfterCand,\n        const Params& par,\n        int estimatedScore\n    ) {\n        if (estimatedScore + 1800 < bestScore) return;\n\n        Bits b = bitsAfterCand;\n        vector<int> suffix;\n        suffix.reserve(1000);\n\n        int exactScore = rolloutScore(b, prev, cand, scoreAfterCand, par, &suffix);\n\n        if (exactScore + 2500 >= bestScore) {\n            vector<int> full;\n            full.reserve(prefix.size() + 1 + suffix.size());\n            full.insert(full.end(), prefix.begin(), prefix.end());\n            full.push_back(cand);\n            full.insert(full.end(), suffix.begin(), suffix.end());\n            addCandidate(full, exactScore);\n        }\n    }\n\n    void posaExtendLocal(vector<int>& path, int& score, Bits& bits, double stopTime, const Params& par) {\n        if (path.empty()) return;\n\n        fill(pathIndex, pathIndex + V, -1);\n        for (int i = 0; i < (int)path.size(); i++) {\n            pathIndex[path[i]] = i;\n        }\n\n        int stamp = newRotStamp();\n        rotSeen[path.back()] = stamp;\n\n        int rotationsSinceAppend = 0;\n        int rotLimit = 25 + rng.nextInt(65);\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() < M) {\n            int L = (int)path.size();\n            int pos = path.back();\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc > 0) {\n                int prev = (L >= 2 ? path[L - 2] : -1);\n                int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n                long long bestEval = LLONG_MIN;\n                int bestIdx = 0;\n\n                for (int a = 0; a < nc; a++) {\n                    int cell = candCell[a];\n                    int tid = candTid[a];\n\n                    int deg = degreeAfterBits(bits, cell, tid);\n                    int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                    long long ev = 0;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n                    ev -= 1LL * par.borderW * borderDist[cell];\n\n                    if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                    if (prev != -1 && cell - pos == lastDiff) ev += par.straightW;\n                    if (par.noise > 0) ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n\n                    if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                        bestEval = ev;\n                        bestIdx = a;\n                    }\n                }\n\n                int nxt = candCell[bestIdx];\n                int tid = candTid[bestIdx];\n\n                pathIndex[nxt] = L;\n                path.push_back(nxt);\n                bitSet(bits, tid);\n                score += val[nxt];\n\n                rotationsSinceAppend = 0;\n                rotLimit = 25 + rng.nextInt(65);\n                stamp = newRotStamp();\n                rotSeen[path.back()] = stamp;\n\n                continue;\n            }\n\n            if (L < 3) break;\n\n            int opts[4];\n            long long evs[4];\n            int no = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int idx = pathIndex[nb];\n\n                if (idx >= 0 && idx <= L - 3) {\n                    int newEnd = path[idx + 1];\n                    int cnt = countUnvisitedMoves(bits, newEnd);\n                    int sum = sumUnvisitedMoveValues(bits, newEnd);\n\n                    long long ev = 0;\n                    ev += 100000LL * cnt;\n                    ev += 120LL * sum;\n                    ev += 5LL * val[newEnd];\n                    ev -= 8LL * borderDist[newEnd];\n                    ev += rng.nextInt(10000);\n\n                    if (rotSeen[newEnd] == stamp) ev -= 60000;\n\n                    opts[no] = idx;\n                    evs[no] = ev;\n                    no++;\n                }\n            }\n\n            if (no == 0) break;\n\n            int bestOpt = 0;\n            for (int i = 1; i < no; i++) {\n                if (evs[i] > evs[bestOpt]) bestOpt = i;\n            }\n\n            int idx = opts[bestOpt];\n            int l = idx + 1;\n\n            reverse(path.begin() + l, path.end());\n\n            for (int i = l; i < L; i++) {\n                pathIndex[path[i]] = i;\n            }\n\n            rotSeen[path.back()] = stamp;\n\n            rotationsSinceAppend++;\n            if (rotationsSinceAppend > rotLimit) break;\n        }\n    }\n\n    int runPilotFromPath(\n        const vector<int>& initialPath,\n        int initialScore,\n        int variants,\n        bool allowPosa = false,\n        bool useReach = false\n    ) {\n        if (initialPath.empty()) return 0;\n\n        vector<int> path = initialPath;\n        path.reserve(V);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        int score = initialScore;\n        int pos = path.back();\n\n        Params pars[4];\n        variants = max(1, min(variants, 4));\n        for (int i = 0; i < variants; i++) pars[i] = makePilotParam();\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                Bits bitsAfter = bits;\n                bitSet(bitsAfter, tid);\n\n                int scoreAfter = score + val[cell];\n                int bestSim = -1;\n                int bestPar = 0;\n\n                for (int r = 0; r < variants; r++) {\n                    Bits b = bitsAfter;\n                    int simScore = rolloutScore(b, pos, cell, scoreAfter, pars[r], nullptr);\n\n                    if (simScore > bestSim) {\n                        bestSim = simScore;\n                        bestPar = r;\n                    }\n                }\n\n                FloodResult fr{0, 0};\n                if (useReach) {\n                    fr = floodPotentialBits(cell, bitsAfter);\n                }\n\n                if (bestSim + (useReach ? fr.pot / 30 : 0) >= bestScore - 1800) {\n                    considerRolloutPath(path, cell, bitsAfter, pos, scoreAfter, pars[bestPar], bestSim);\n                }\n\n                long long ev = 1LL * bestSim * 1000;\n                ev += 3LL * val[cell];\n\n                if (useReach) {\n                    ev += 32LL * fr.pot;\n                    ev += 180LL * fr.cnt;\n                }\n\n                ev += rng.nextInt(1001) - 500;\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            path.push_back(nxt);\n            pos = nxt;\n\n            if (score > bestScore || (score == bestScore && path.size() > bestCells.size())) {\n                setBestFrom(path, score);\n            }\n\n            if ((++iter & 7) == 0 && timer.elapsed() > TL) break;\n        }\n\n        if (allowPosa && timer.elapsed() < TL - 0.025 && score + 6000 >= bestScore) {\n            Params pp = makePosaParam();\n            double stop = min(TL, timer.elapsed() + 0.010 + (rng.nextInt(100) < 40 ? 0.018 : 0.0));\n            posaExtendLocal(path, score, bits, stop, pp);\n        }\n\n        addCandidate(path, score);\n        return score;\n    }\n\n    int runPilotBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        int variants,\n        bool allowPosa = false,\n        bool useReach = false\n    ) {\n        int L = (int)baseCells.size();\n        if (L == 0) return 0;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> prefix;\n        prefix.reserve(cut + 1);\n\n        for (int i = 0; i <= cut; i++) {\n            prefix.push_back(baseCells[i]);\n        }\n\n        return runPilotFromPath(prefix, baseCum[cut], variants, allowPosa, useReach);\n    }\n\n    int runPilot(int cut, int variants, bool allowPosa = false, bool useReach = false) {\n        return runPilotBase(bestCells, bestCum, cut, variants, allowPosa, useReach);\n    }\n\n    void runPosaFromBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        double budget\n    ) {\n        if (timer.elapsed() >= TL || budget <= 0) return;\n\n        int L = (int)baseCells.size();\n        if (L == 0) return;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> path;\n        path.reserve(V);\n        for (int i = 0; i <= cut; i++) path.push_back(baseCells[i]);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        int score = baseCum[cut];\n\n        Params p = makePosaParam();\n        double stop = min(TL, timer.elapsed() + budget);\n        posaExtendLocal(path, score, bits, stop, p);\n\n        addCandidate(path, score);\n    }\n\n    bool runRotationExtendFromBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        bool pilotMode\n    ) {\n        if (timer.elapsed() >= TL) return false;\n\n        int L0 = (int)baseCells.size();\n        if (L0 < 3) return false;\n\n        cut = max(0, min(cut, L0 - 1));\n        if (cut < 2) return false;\n\n        vector<int> path;\n        path.reserve(V);\n        for (int i = 0; i <= cut; i++) path.push_back(baseCells[i]);\n\n        int score = baseCum[cut];\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        fill(pathIndex, pathIndex + V, -1);\n        for (int i = 0; i < (int)path.size(); i++) {\n            pathIndex[path[i]] = i;\n        }\n\n        int stamp = newRotStamp();\n        rotSeen[path.back()] = stamp;\n\n        int maxRot = 1 + rng.nextInt(8);\n        bool rotated = false;\n\n        for (int step = 0; step < maxRot && timer.elapsed() < TL; step++) {\n            int L = (int)path.size();\n            if (L < 3) break;\n\n            int pos = path.back();\n\n            int opts[4];\n            long long evs[4];\n            int no = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int idx = pathIndex[nb];\n\n                if (idx >= 0 && idx <= L - 3) {\n                    int newEnd = path[idx + 1];\n                    int cnt = countUnvisitedMoves(bits, newEnd);\n                    int sum = sumUnvisitedMoveValues(bits, newEnd);\n\n                    long long ev = 0;\n                    ev += 100000LL * cnt;\n                    ev += 150LL * sum;\n                    ev += 5LL * val[newEnd];\n                    ev -= 6LL * borderDist[newEnd];\n                    ev += rng.nextInt(12000);\n\n                    if (rotSeen[newEnd] == stamp) ev -= 70000;\n\n                    opts[no] = idx;\n                    evs[no] = ev;\n                    no++;\n                }\n            }\n\n            if (no == 0) break;\n\n            int bestOpt = 0;\n            for (int i = 1; i < no; i++) {\n                if (evs[i] > evs[bestOpt]) bestOpt = i;\n            }\n\n            int idx = opts[bestOpt];\n            int l = idx + 1;\n\n            reverse(path.begin() + l, path.end());\n\n            for (int i = l; i < (int)path.size(); i++) {\n                pathIndex[path[i]] = i;\n            }\n\n            rotated = true;\n            rotSeen[path.back()] = stamp;\n\n            if (countUnvisitedMoves(bits, path.back()) > 0 && rng.nextInt(100) < 75) {\n                break;\n            }\n        }\n\n        if (!rotated) return false;\n        if (timer.elapsed() >= TL) return false;\n        if (countUnvisitedMoves(bits, path.back()) == 0) return false;\n\n        if (pilotMode) {\n            int variants = (timer.elapsed() < 0.95 && rng.nextInt(100) < 45 ? 2 : 1);\n            bool useReach = rng.nextInt(100) < 15;\n            runPilotFromPath(path, score, variants, rng.nextInt(100) < 35, useReach);\n        } else {\n            Params p = makeParams(false);\n            int sc = runGreedyFromPath(path, score, false, p, true);\n            considerCurrent(sc);\n        }\n\n        return true;\n    }\n\n    struct BeamNode {\n        int parent;\n        int cell;\n        int score;\n    };\n\n    struct BeamState {\n        Bits bits;\n        int pos;\n        int prev;\n        int score;\n        int node;\n        long long eval;\n    };\n\n    void runBeam(double endTime, int width) {\n        if (timer.elapsed() >= endTime) return;\n\n        vector<BeamNode> nodes;\n        nodes.reserve(width * 1200);\n\n        vector<BeamState> cur, nxt, cand;\n        cur.reserve(width);\n        nxt.reserve(width);\n        cand.reserve(width * 4 + 10);\n\n        BeamState init;\n        init.bits.fill(0);\n        bitSet(init.bits, tile[startCell]);\n        init.pos = startCell;\n        init.prev = -1;\n        init.score = val[startCell];\n        init.node = 0;\n        init.eval = init.score;\n\n        nodes.push_back({-1, startCell, val[startCell]});\n        cur.push_back(init);\n\n        int localBestScore = val[startCell];\n        int localBestNode = 0;\n\n        int degBias = -120 + rng.nextInt(241);\n        int noise = 2000 + rng.nextInt(4000);\n\n        for (int depth = 0; depth < M && !cur.empty(); depth++) {\n            if (timer.elapsed() >= endTime) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    int tid = tile[nb];\n\n                    if (bitTest(st.bits, tid)) continue;\n\n                    BeamState ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.prev = st.pos;\n                    ch.pos = nb;\n                    ch.score = st.score + val[nb];\n                    ch.node = st.node;\n\n                    int deg = degreeAfterBits(st.bits, nb, tid);\n                    int loc = localSumAfterBits(st.bits, nb, tid);\n\n                    long long ev = 1LL * ch.score * 100;\n                    ev += 3LL * loc;\n                    ev += 1LL * degBias * deg;\n                    ev -= 10LL * borderDist[nb];\n\n                    if (deg == 0) ev -= 4000;\n                    ev += rng.nextInt(noise);\n\n                    ch.eval = ev;\n                    cand.push_back(ch);\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            nxt.clear();\n\n            for (auto& ch : cand) {\n                int parent = ch.node;\n                nodes.push_back({parent, ch.pos, ch.score});\n                ch.node = (int)nodes.size() - 1;\n\n                if (ch.score > localBestScore) {\n                    localBestScore = ch.score;\n                    localBestNode = ch.node;\n                }\n\n                nxt.push_back(std::move(ch));\n            }\n\n            cur.swap(nxt);\n        }\n\n        if (localBestScore + 2500 >= bestScore) {\n            vector<int> cells;\n            int x = localBestNode;\n            while (x != -1) {\n                cells.push_back(nodes[x].cell);\n                x = nodes[x].parent;\n            }\n            reverse(cells.begin(), cells.end());\n            addCandidate(cells, localBestScore);\n        }\n\n        if (!cur.empty() && timer.elapsed() < endTime + 0.08) {\n            int take = min<int>(20, cur.size());\n\n            if ((int)cur.size() > take) {\n                nth_element(\n                    cur.begin(),\n                    cur.begin() + take,\n                    cur.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.score > b.score;\n                    }\n                );\n            }\n\n            cur.resize(take);\n\n            for (auto& st : cur) {\n                if (timer.elapsed() > endTime + 0.10) break;\n\n                vector<int> prefix;\n                int x = st.node;\n                while (x != -1) {\n                    prefix.push_back(nodes[x].cell);\n                    x = nodes[x].parent;\n                }\n                reverse(prefix.begin(), prefix.end());\n\n                Params p = makePilotParam();\n                Bits b = st.bits;\n                vector<int> suffix;\n                suffix.reserve(1000);\n\n                int sc = rolloutScore(b, st.prev, st.pos, st.score, p, &suffix);\n\n                if (sc + 2500 >= bestScore) {\n                    vector<int> full = prefix;\n                    full.insert(full.end(), suffix.begin(), suffix.end());\n                    addCandidate(full, sc);\n                }\n            }\n        }\n    }\n\n    bool validatePath(const vector<int>& cells) const {\n        if (cells.empty()) return false;\n        if (cells[0] != startCell) return false;\n\n        vector<char> used(M, 0);\n\n        for (int i = 0; i < (int)cells.size(); i++) {\n            int c = cells[i];\n            if (c < 0 || c >= V) return false;\n\n            int tid = tile[c];\n            if (used[tid]) return false;\n            used[tid] = 1;\n\n            if (i > 0) {\n                int d = abs(cells[i] - cells[i - 1]);\n                if (!(d == 1 || d == N)) return false;\n                if (d == 1 && cells[i] / N != cells[i - 1] / N) return false;\n            }\n        }\n\n        return true;\n    }\n\n    string cellsToMoves(const vector<int>& cells) const {\n        string s;\n        s.reserve(cells.size());\n\n        for (int i = 1; i < (int)cells.size(); i++) {\n            int d = cells[i] - cells[i - 1];\n\n            if (d == -N) s.push_back('U');\n            else if (d == N) s.push_back('D');\n            else if (d == -1) s.push_back('L');\n            else if (d == 1) s.push_back('R');\n        }\n\n        return s;\n    }\n\n    string solve() {\n        timer.reset();\n\n        pool.clear();\n        bestCells.clear();\n        bestCum.clear();\n        bestScore = -1;\n\n        vector<int> init{startCell};\n        addCandidate(init, val[startCell]);\n\n        curCells.reserve(V);\n\n        for (int i = 0; i < 22 && timer.elapsed() < 0.09; i++) {\n            bool flood = (i % 6 == 0);\n            Params par = makeParams(flood);\n            int sc = runGreedy(0, flood, par);\n            considerCurrent(sc);\n        }\n\n        runBeam(0.23, 280);\n\n        if (!pool.empty() && timer.elapsed() < 0.38) {\n            runPosaFromBase(pool[0].cells, pool[0].cum, (int)pool[0].cells.size() - 1, 0.035);\n        }\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            double e = timer.elapsed();\n\n            if (TL - e < 0.018) {\n                if (!pool.empty()) {\n                    runPosaFromBase(pool[0].cells, pool[0].cum, (int)pool[0].cells.size() - 1, max(0.0, TL - e - 0.002));\n                }\n                break;\n            }\n\n            if (pool.empty()) {\n                vector<int> init2{startCell};\n                addCandidate(init2, val[startCell]);\n            }\n\n            int mode = rng.nextInt(100);\n\n            if (e < 0.75) {\n                if (mode < 56) {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (iter <= 8 || base.cells.size() < 2 || rng.nextInt(100) < 32) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 12, 35);\n                    }\n\n                    int variants = (e < 0.60 ? 2 : (rng.nextInt(100) < 35 ? 2 : 1));\n                    bool useReach = rng.nextInt(100) < 16;\n\n                    runPilotBase(base.cells, base.cum, cut, variants, false, useReach);\n                } else if (mode < 72) {\n                    int bi = (rng.nextInt(100) < 68 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 68) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 45);\n\n                    runRotationExtendFromBase(base.cells, base.cum, cut, rng.nextInt(100) < 76);\n                } else if (mode < 82) {\n                    int bi = (rng.nextInt(100) < 75 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 75) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 45);\n\n                    runPosaFromBase(base.cells, base.cum, cut, 0.012 + 0.010 * (rng.nextInt(100) < 35));\n                } else {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int floodProb = 38;\n                    bool flood = (rng.nextInt(100) < floodProb);\n\n                    int cut;\n                    if (iter < 10 || base.cells.size() < 2 || rng.nextInt(100) < 30) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 18, 30);\n                    }\n\n                    Params par = makeParams(flood);\n                    int sc = runGreedyBase(base.cells, base.cum, cut, flood, par);\n                    considerCurrent(sc);\n                }\n            } else {\n                if (mode < 40) {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (base.cells.size() < 2 || rng.nextInt(100) < 26) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 10, 40);\n                    }\n\n                    int variants = (rng.nextInt(100) < 30 ? 2 : 1);\n                    bool allowPosa = (rng.nextInt(100) < 18);\n                    bool useReach = rng.nextInt(100) < 12;\n\n                    runPilotBase(base.cells, base.cum, cut, variants, allowPosa, useReach);\n                } else if (mode < 66) {\n                    int bi = (rng.nextInt(100) < 62 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 62) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 3, 45);\n\n                    runRotationExtendFromBase(base.cells, base.cum, cut, rng.nextInt(100) < 78);\n                } else if (mode < 86) {\n                    int bi = (rng.nextInt(100) < 80 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 80) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 40);\n\n                    runPosaFromBase(base.cells, base.cum, cut, 0.018 + 0.020 * (rng.nextInt(100) < 40));\n                } else {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int floodProb = 52;\n                    bool flood = (rng.nextInt(100) < floodProb);\n\n                    int cut;\n                    if (base.cells.size() < 2 || rng.nextInt(100) < 28) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 15, 35);\n                    }\n\n                    Params par = makeParams(flood);\n                    int sc = runGreedyBase(base.cells, base.cum, cut, flood, par);\n                    considerCurrent(sc);\n                }\n            }\n\n            iter++;\n        }\n\n        if (!validatePath(bestCells)) {\n            bool found = false;\n            for (auto& pc : pool) {\n                if (validatePath(pc.cells)) {\n                    bestCells = pc.cells;\n                    bestCum = pc.cum;\n                    bestScore = pc.score;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) return \"\";\n        }\n\n        return cellsToMoves(bestCells);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read();\n\n    cout << solver.solve() << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int LINE_VARS = 2 * N;          // 30 horizontal rows + 30 vertical columns\nstatic constexpr int BINS = 4;\nstatic constexpr int HBIN_VARS = N * BINS;\nstatic constexpr int BIN_VARS = 2 * N * BINS;\nstatic constexpr int SEG_VARS = 2 * LINE_VARS;   // 2 segments for each line\nstatic constexpr int EXPLORE_TURNS = 100;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    return min(hi, max(lo, x));\n}\n\nstatic inline int popcnt(uint32_t x) {\n    return __builtin_popcount(x);\n}\n\nstatic inline uint32_t lowMask(int x) {\n    if (x <= 0) return 0;\n    return (1u << x) - 1u; // x <= 29\n}\n\nstruct RidgeModel {\n    int n;\n    vector<double> ata;\n    vector<double> atb;\n\n    RidgeModel(int n_ = 0) : n(n_), ata(n_ * n_, 0.0), atb(n_, 0.0) {}\n\n    void addObservation(const vector<pair<int, int>>& counts, int steps, double result) {\n        if (steps <= 0) return;\n\n        vector<pair<int, double>> f;\n        f.reserve(counts.size());\n\n        double inv_steps = 1.0 / steps;\n        for (auto [idx, cnt] : counts) {\n            if (cnt > 0) f.push_back({idx, cnt * inv_steps});\n        }\n\n        double target = result * inv_steps;\n\n        for (auto [ia, va] : f) {\n            double* row = &ata[ia * n];\n            atb[ia] += va * target;\n            for (auto [ib, vb] : f) {\n                row[ib] += va * vb;\n            }\n        }\n    }\n\n    void solve(const vector<double>& prior, double lambda, vector<double>& out) const {\n        vector<double> a = ata;\n        vector<double> b(n);\n\n        for (int i = 0; i < n; i++) {\n            a[i * n + i] += lambda;\n            b[i] = atb[i] + lambda * prior[i];\n        }\n\n        // Cholesky decomposition: A = L L^T, lower triangle is used.\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j <= i; j++) {\n                double sum = a[i * n + j];\n                for (int k = 0; k < j; k++) {\n                    sum -= a[i * n + k] * a[j * n + k];\n                }\n\n                if (i == j) {\n                    if (sum < 1e-9) sum = 1e-9;\n                    a[i * n + j] = sqrt(sum);\n                } else {\n                    a[i * n + j] = sum / a[j * n + j];\n                }\n            }\n        }\n\n        vector<double> y(n);\n        for (int i = 0; i < n; i++) {\n            double sum = b[i];\n            for (int k = 0; k < i; k++) sum -= a[i * n + k] * y[k];\n            y[i] = sum / a[i * n + i];\n        }\n\n        out.assign(n, 0.0);\n        for (int i = n - 1; i >= 0; i--) {\n            double sum = y[i];\n            for (int k = i + 1; k < n; k++) sum -= a[k * n + i] * out[k];\n            out[i] = sum / a[i * n + i];\n            out[i] = clampd(out[i], 1000.0, 9000.0);\n        }\n    }\n};\n\nstruct Observation {\n    int result = 0;\n    int steps = 0;\n    array<uint32_t, LINE_VARS> mask;\n\n    Observation() {\n        mask.fill(0);\n    }\n};\n\nstruct Solver {\n    RidgeModel lineModel;\n    RidgeModel binModel;\n\n    vector<double> lineEst;\n    vector<double> binDelta;\n    vector<double> segEst;\n\n    array<int, LINE_VARS> lineSeen{};\n    array<int, BIN_VARS> binSeen{};\n    array<int, LINE_VARS> split{};\n    array<int, SEG_VARS> segSupport{};\n\n    vector<Observation> observations;\n\n    mt19937 rng;\n    int turn = 0;\n    double segGlobalConf = 0.0;\n\n    Solver()\n        : lineModel(LINE_VARS),\n          binModel(BIN_VARS),\n          lineEst(LINE_VARS, 5000.0),\n          binDelta(BIN_VARS, 0.0),\n          segEst(SEG_VARS, 5000.0),\n          rng(1234567) {\n        lineSeen.fill(0);\n        binSeen.fill(0);\n        split.fill(14);\n        segSupport.fill(0);\n    }\n\n    static int hVar(int i, int j) {\n        int q = j * BINS / (N - 1);\n        return i * BINS + q;\n    }\n\n    static int vVar(int i, int j) {\n        int q = i * BINS / (N - 1);\n        return HBIN_VARS + j * BINS + q;\n    }\n\n    double globalWeight() const {\n        return clampd(turn / 300.0, 0.0, 1.0);\n    }\n\n    double binWeight() const {\n        return clampd((turn - 80) / 420.0, 0.0, 1.0);\n    }\n\n    double segmentWeight() const {\n        double t = clampd((turn - 110) / 390.0, 0.0, 1.0);\n        return t * segGlobalConf;\n    }\n\n    double hCost(int i, int j) const {\n        int line = i;\n        int bv = hVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (j < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        raw = clampd(raw, 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCost(int i, int j) const {\n        int line = N + j;\n        int bv = vVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (i < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        raw = clampd(raw, 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    static void appendVertical(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    }\n\n    static void appendHorizontal(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    }\n\n    string makeDirect(int si, int sj, int ti, int tj, bool horizontalFirst) const {\n        string s;\n        if (horizontalFirst) {\n            appendHorizontal(s, sj, tj);\n            appendVertical(s, si, ti);\n        } else {\n            appendVertical(s, si, ti);\n            appendHorizontal(s, sj, tj);\n        }\n        return s;\n    }\n\n    string makeViaRow(int si, int sj, int ti, int tj, int r) const {\n        string s;\n        appendVertical(s, si, r);\n        appendHorizontal(s, sj, tj);\n        appendVertical(s, r, ti);\n        return s;\n    }\n\n    string makeViaCol(int si, int sj, int ti, int tj, int c) const {\n        string s;\n        appendHorizontal(s, sj, c);\n        appendVertical(s, si, ti);\n        appendHorizontal(s, c, tj);\n        return s;\n    }\n\n    bool validatePath(int si, int sj, int ti, int tj, const string& path) const {\n        array<char, N * N> vis{};\n        int r = si, c = sj;\n        vis[r * N + c] = 1;\n\n        for (char ch : path) {\n            if (ch == 'U') r--;\n            else if (ch == 'D') r++;\n            else if (ch == 'L') c--;\n            else if (ch == 'R') c++;\n            else return false;\n\n            if (r < 0 || r >= N || c < 0 || c >= N) return false;\n\n            int id = r * N + c;\n            if (vis[id]) return false;\n            vis[id] = 1;\n        }\n\n        return r == ti && c == tj;\n    }\n\n    double estimatePathCost(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCost(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCost(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCost(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCost(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double explorationSeenScore(int si, int sj, const string& path) const {\n        array<char, LINE_VARS> lu{};\n        array<char, BIN_VARS> bu{};\n\n        int r = si, c = sj;\n\n        for (char ch : path) {\n            int line = -1, bv = -1;\n\n            if (ch == 'R') {\n                line = r;\n                bv = hVar(r, c);\n                c++;\n            } else if (ch == 'L') {\n                c--;\n                line = r;\n                bv = hVar(r, c);\n            } else if (ch == 'D') {\n                line = N + c;\n                bv = vVar(r, c);\n                r++;\n            } else if (ch == 'U') {\n                r--;\n                line = N + c;\n                bv = vVar(r, c);\n            }\n\n            if (line >= 0) lu[line] = 1;\n            if (bv >= 0) bu[bv] = 1;\n        }\n\n        double score = 0.0;\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lu[i]) score += lineSeen[i];\n        }\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (bu[i]) score += 0.35 * binSeen[i];\n        }\n\n        return score;\n    }\n\n    string chooseBestDirect(int si, int sj, int ti, int tj) const {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        return (c1 <= c2 ? p1 : p2);\n    }\n\n    string chooseExplorationPath(int si, int sj, int ti, int tj) {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        double s1 = explorationSeenScore(si, sj, p1);\n        double s2 = explorationSeenScore(si, sj, p2);\n\n        double bonus = 1500.0 * (1.0 - turn / double(EXPLORE_TURNS));\n\n        double v1 = c1 + bonus * s1;\n        double v2 = c2 + bonus * s2;\n\n        if (abs(v1 - v2) < 1e-9) {\n            return (rng() & 1) ? p1 : p2;\n        }\n        return (v1 <= v2 ? p1 : p2);\n    }\n\n    string bestCorridorPath(int si, int sj, int ti, int tj) const {\n        string best;\n        double bestCost = 1e100;\n\n        auto consider = [&](const string& p) {\n            if (!validatePath(si, sj, ti, tj, p)) return;\n\n            double c = estimatePathCost(si, sj, p);\n            if (c < bestCost - 1e-9 ||\n                (abs(c - bestCost) < 1e-9 && (best.empty() || p.size() < best.size()))) {\n                bestCost = c;\n                best = p;\n            }\n        };\n\n        consider(makeDirect(si, sj, ti, tj, true));\n        consider(makeDirect(si, sj, ti, tj, false));\n\n        for (int r = 0; r < N; r++) {\n            consider(makeViaRow(si, sj, ti, tj, r));\n        }\n        for (int c = 0; c < N; c++) {\n            consider(makeViaCol(si, sj, ti, tj, c));\n        }\n\n        if (best.empty()) best = chooseBestDirect(si, sj, ti, tj);\n        return best;\n    }\n\n    string dijkstra(int si, int sj, int ti, int tj) const {\n        int S = si * N + sj;\n        int T = ti * N + tj;\n\n        const double INF = 1e100;\n        vector<double> dist(N * N, INF);\n        vector<int> pre(N * N, -1);\n        vector<char> pmove(N * N, 0);\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[S] = 0.0;\n        pre[S] = S;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n\n            if (d > dist[u] + 1e-9) continue;\n            if (u == T) break;\n\n            int r = u / N;\n            int c = u % N;\n\n            int dirs[4];\n            bool used[4] = {};\n            int m = 0;\n\n            auto addDir = [&](int x) {\n                if (!used[x]) {\n                    used[x] = true;\n                    dirs[m++] = x;\n                }\n            };\n\n            if (ti < r) addDir(0); // U\n            if (ti > r) addDir(1); // D\n            if (tj < c) addDir(2); // L\n            if (tj > c) addDir(3); // R\n            for (int x = 0; x < 4; x++) addDir(x);\n\n            for (int idx = 0; idx < 4; idx++) {\n                int dir = dirs[idx];\n\n                int nr = r, nc = c;\n                char mv = '?';\n                double w = 0.0;\n\n                if (dir == 0) {\n                    if (r == 0) continue;\n                    nr = r - 1;\n                    mv = 'U';\n                    w = vCost(r - 1, c);\n                } else if (dir == 1) {\n                    if (r == N - 1) continue;\n                    nr = r + 1;\n                    mv = 'D';\n                    w = vCost(r, c);\n                } else if (dir == 2) {\n                    if (c == 0) continue;\n                    nc = c - 1;\n                    mv = 'L';\n                    w = hCost(r, c - 1);\n                } else {\n                    if (c == N - 1) continue;\n                    nc = c + 1;\n                    mv = 'R';\n                    w = hCost(r, c);\n                }\n\n                int v = nr * N + nc;\n                double nd = d + w;\n\n                if (nd + 1e-9 < dist[v]) {\n                    dist[v] = nd;\n                    pre[v] = u;\n                    pmove[v] = mv;\n                    pq.push({nd, v});\n                }\n            }\n        }\n\n        if (pre[T] == -1) return \"\";\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmove[cur]);\n            cur = pre[cur];\n            if (cur < 0) return \"\";\n        }\n\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    string choosePath(int si, int sj, int ti, int tj) {\n        if (turn < EXPLORE_TURNS) {\n            return chooseExplorationPath(si, sj, ti, tj);\n        }\n\n        string safe = bestCorridorPath(si, sj, ti, tj);\n        string p = dijkstra(si, sj, ti, tj);\n\n        if (p.empty() || !validatePath(si, sj, ti, tj, p)) {\n            return safe;\n        }\n\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        int extraLimit;\n        if (turn < 200) extraLimit = 12;\n        else if (turn < 350) extraLimit = 25;\n        else if (turn < 500) extraLimit = 45;\n        else if (turn < 700) extraLimit = 65;\n        else extraLimit = 80 + int(20.0 * segGlobalConf);\n\n        double cd = estimatePathCost(si, sj, p);\n        double cs = estimatePathCost(si, sj, safe);\n\n        int extra = int(p.size()) - manhattan;\n\n        // Strong protection against suspiciously long detours.\n        if (extra > extraLimit) {\n            if ((int)p.size() > manhattan + 130) return safe;\n            if (cd > cs * 0.82) return safe;\n        }\n\n        // If Dijkstra is much longer than a robust corridor path, require\n        // a meaningful estimated gain.\n        int lenDiff = int(p.size()) - int(safe.size());\n        if (lenDiff > 30) {\n            double requiredRatio = 1.0 - min(0.08, 0.001 * lenDiff);\n            if (cd > cs * requiredRatio) return safe;\n        }\n\n        return p;\n    }\n\n    void updateModelsWithResult(int si, int sj, const string& path, int result) {\n        Observation ob;\n        ob.result = result;\n        ob.steps = (int)path.size();\n\n        array<int, LINE_VARS> lineCnt{};\n        array<int, BIN_VARS> binCnt{};\n\n        int r = si;\n        int c = sj;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n\n                c++;\n            } else if (ch == 'L') {\n                c--;\n\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n            } else if (ch == 'D') {\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n\n                r++;\n            } else if (ch == 'U') {\n                r--;\n\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                ob.mask[line] |= (1u << pos);\n            }\n        }\n\n        vector<pair<int, int>> lf;\n        vector<pair<int, int>> bf;\n\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lineCnt[i] > 0) {\n                lf.push_back({i, lineCnt[i]});\n                lineSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (binCnt[i] > 0) {\n                bf.push_back({i, binCnt[i]});\n                binSeen[i]++;\n            }\n        }\n\n        lineModel.addObservation(lf, ob.steps, result);\n        binModel.addObservation(bf, ob.steps, result);\n        observations.push_back(ob);\n    }\n\n    double predictObsSegment(const Observation& ob) const {\n        double sum = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            uint32_t m = ob.mask[line];\n            if (!m) continue;\n\n            int total = popcnt(m);\n            int x = split[line];\n            int cl = popcnt(m & lowMask(x));\n            int cr = total - cl;\n\n            sum += segEst[2 * line] * cl;\n            sum += segEst[2 * line + 1] * cr;\n        }\n\n        return sum / ob.steps;\n    }\n\n    void seedSplitsFromBin() {\n        static const int bounds[3] = {8, 15, 22};\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 2) continue;\n\n            double val[BINS];\n\n            for (int q = 0; q < BINS; q++) {\n                int idx;\n                if (line < N) idx = line * BINS + q;\n                else idx = HBIN_VARS + (line - N) * BINS + q;\n\n                val[q] = lineEst[line] + binDelta[idx];\n            }\n\n            double bestDiff = 0.0;\n            int bestBoundary = split[line];\n\n            for (int q = 0; q + 1 < BINS; q++) {\n                double d = abs(val[q + 1] - val[q]);\n                if (d > bestDiff) {\n                    bestDiff = d;\n                    bestBoundary = bounds[q];\n                }\n            }\n\n            double segDiff = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (bestDiff > 450.0 &&\n                (segDiff < 700.0 || observations.size() < 180)) {\n                split[line] = bestBoundary;\n            }\n        }\n    }\n\n    void solveSegmentRidge(double lambda) {\n        RidgeModel model(SEG_VARS);\n        segSupport.fill(0);\n\n        for (const auto& ob : observations) {\n            vector<pair<int, int>> f;\n            f.reserve(16);\n\n            for (int line = 0; line < LINE_VARS; line++) {\n                uint32_t m = ob.mask[line];\n                if (!m) continue;\n\n                int total = popcnt(m);\n                int x = split[line];\n                int cl = popcnt(m & lowMask(x));\n                int cr = total - cl;\n\n                if (cl > 0) {\n                    f.push_back({2 * line, cl});\n                    segSupport[2 * line] += cl;\n                }\n                if (cr > 0) {\n                    f.push_back({2 * line + 1, cr});\n                    segSupport[2 * line + 1] += cr;\n                }\n            }\n\n            model.addObservation(f, ob.steps, ob.result);\n        }\n\n        vector<double> prior(SEG_VARS);\n        for (int i = 0; i < SEG_VARS; i++) {\n            prior[i] = lineEst[i / 2];\n        }\n\n        model.solve(prior, lambda, segEst);\n    }\n\n    void refineSplits() {\n        int m = (int)observations.size();\n        if (m < 60) return;\n\n        vector<double> pred(m);\n        vector<double> target(m);\n\n        for (int i = 0; i < m; i++) {\n            pred[i] = predictObsSegment(observations[i]);\n            target[i] = observations[i].result / double(observations[i].steps);\n        }\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            double v0 = segEst[2 * line];\n            double v1 = segEst[2 * line + 1];\n\n            if (abs(v0 - v1) < 250.0) continue;\n\n            int active = 0;\n            for (const auto& ob : observations) {\n                if (ob.mask[line]) active++;\n            }\n\n            if (active < 8) continue;\n\n            int oldX = split[line];\n            uint32_t oldMask = lowMask(oldX);\n\n            double bestSSE = 1e100;\n            double oldSSE = 1e100;\n            int bestX = oldX;\n\n            for (int x = 1; x <= 28; x++) {\n                uint32_t xm = lowMask(x);\n                double sse = 0.0;\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    double baseResidualTarget = target[idx] - pred[idx] + oldContr;\n\n                    int newLeft = popcnt(mask & xm);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    double res = baseResidualTarget - newContr;\n                    sse += res * res;\n                }\n\n                if (x == oldX) oldSSE = sse;\n\n                if (sse < bestSSE) {\n                    bestSSE = sse;\n                    bestX = x;\n                }\n            }\n\n            double threshold = max(20000.0, 0.001 * oldSSE);\n\n            if (bestX != oldX && bestSSE + threshold < oldSSE) {\n                uint32_t newMask = lowMask(bestX);\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    int newLeft = popcnt(mask & newMask);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    pred[idx] += newContr - oldContr;\n                }\n\n                split[line] = bestX;\n            }\n        }\n    }\n\n    void updateSegmentConfidence() {\n        int strong = 0;\n        int usable = 0;\n        double sumConf = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 3) continue;\n            if (segSupport[2 * line] < 6) continue;\n            if (segSupport[2 * line + 1] < 6) continue;\n\n            usable++;\n\n            double d = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (d > 900.0) strong++;\n            sumConf += clampd((d - 500.0) / 1500.0, 0.0, 1.0);\n        }\n\n        double c1 = clampd((strong - 4) / 18.0, 0.0, 1.0);\n\n        double c2 = 0.0;\n        if (usable > 0) {\n            double avg = sumConf / usable;\n            c2 = clampd((avg - 0.12) / 0.38, 0.0, 1.0);\n        }\n\n        segGlobalConf = max(c1, 0.8 * c2);\n    }\n\n    void solveModels(int observationsCount) {\n        vector<double> priorLine(LINE_VARS, 5000.0);\n        lineModel.solve(priorLine, 0.1, lineEst);\n\n        int binPeriod = (observationsCount < 300 ? 10 : 20);\n        if (observationsCount % binPeriod == 0) {\n            vector<double> priorBin(BIN_VARS);\n\n            for (int i = 0; i < N; i++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[i * BINS + q] = lineEst[i];\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[HBIN_VARS + j * BINS + q] = lineEst[N + j];\n                }\n            }\n\n            double prog = min(1.0, observationsCount / 800.0);\n            double lambdaBin = 1.5 - prog; // 1.5 -> 0.5\n\n            vector<double> absBin;\n            binModel.solve(priorBin, lambdaBin, absBin);\n\n            for (int i = 0; i < BIN_VARS; i++) {\n                binDelta[i] = absBin[i] - priorBin[i];\n            }\n        }\n\n        if (observationsCount >= 80) {\n            int segPeriod = (observationsCount < 300 ? 20 : 30);\n\n            if (observationsCount % segPeriod == 0) {\n                seedSplitsFromBin();\n\n                double prog = min(1.0, observationsCount / 900.0);\n                double lambdaSeg = 0.9 - 0.55 * prog; // 0.9 -> 0.35\n\n                solveSegmentRidge(lambdaSeg);\n                refineSplits();\n                solveSegmentRidge(lambdaSeg);\n                updateSegmentConfidence();\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.turn = k;\n\n        string path = solver.choosePath(si, sj, ti, tj);\n\n        cout << path << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.updateModelsWithResult(si, sj, path, result);\n        solver.solveModels(k + 1);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int SZ = 20;\nstatic const int CELLS = 400;\nstatic const int POS = 800;\nstatic const int DOT = 8;\nstatic const int MAXPLEN = 20;\nstatic const int MASK_WORDS = 13;\n\nusing Mask = array<uint64_t, MASK_WORDS>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int randint(int n) {\n        return (int)(next() % n);\n    }\n    double drand() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\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\nint M_input;\nint U;\nint TOTAL;\ndouble avgLen = 0.0;\nint maxLenInput = 0;\n\nvector<string> uniqStr;\nvector<vector<uint8_t>> S;\nvector<int> Ls, W;\n\nuint16_t posCell[POS][MAXPLEN];\nvector<uint32_t> cellIncs[CELLS];\n\nint nearVal[13][13];\n\nXorShift rng;\n\ninline int countDotsVec(const vector<uint8_t>& g) {\n    int d = 0;\n    for (auto x : g) if (x == DOT) d++;\n    return d;\n}\n\nvoid initNearVal() {\n    memset(nearVal, 0, sizeof(nearVal));\n    for (int l = 1; l <= 12; l++) {\n        for (int m = 0; m <= l; m++) {\n            int q = l - m;\n            nearVal[l][m] = q * q * q;\n        }\n    }\n}\n\nvoid initPosCells() {\n    for (int pos = 0; pos < POS; pos++) {\n        for (int p = 0; p < MAXPLEN; p++) {\n            if (pos < 400) {\n                int r = pos / SZ;\n                int c = pos % SZ;\n                posCell[pos][p] = r * SZ + (c + p) % SZ;\n            } else {\n                int q = pos - 400;\n                int r = q / SZ;\n                int c = q % SZ;\n                posCell[pos][p] = ((r + p) % SZ) * SZ + c;\n            }\n        }\n    }\n}\n\nvoid buildIncidences() {\n    long long totalInc = 0;\n    for (int i = 0; i < U; i++) totalInc += 1LL * POS * Ls[i];\n    int reserveEach = (int)(totalInc / CELLS + 100);\n    for (int c = 0; c < CELLS; c++) cellIncs[c].reserve(reserveEach);\n\n    for (int sid = 0; sid < U; sid++) {\n        int base = sid * POS;\n        for (int pos = 0; pos < POS; pos++) {\n            int pid = base + pos;\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[pos][p];\n                uint32_t code = (uint32_t(pid) << 3) | uint32_t(S[sid][p]);\n                cellIncs[cell].push_back(code);\n            }\n        }\n    }\n}\n\nstruct State {\n    vector<uint8_t> grid;\n    vector<uint8_t> mism;\n    vector<uint16_t> cover;\n    vector<array<uint16_t, 13>> hist;\n    vector<array<int16_t, 13>> hdelta;\n\n    int obj = 0;\n\n    vector<int> markP, markS;\n    vector<int16_t> deltaM, deltaC;\n    vector<int> touchedP, touchedS;\n    int tagP = 1, tagS = 1;\n\n    void init() {\n        int Ptot = U * POS;\n        grid.assign(CELLS, DOT);\n        mism.assign(Ptot, 0);\n        cover.assign(U, 0);\n        hist.resize(U);\n        hdelta.resize(U);\n        for (auto& a : hist) a.fill(0);\n        for (auto& a : hdelta) a.fill(0);\n\n        markP.assign(Ptot, 0);\n        markS.assign(U, 0);\n        deltaM.assign(Ptot, 0);\n        deltaC.assign(U, 0);\n        touchedP.reserve(250000);\n        touchedS.reserve(U);\n    }\n\n    void nextTagP() {\n        ++tagP;\n        if (tagP == INT_MAX) {\n            fill(markP.begin(), markP.end(), 0);\n            tagP = 1;\n        }\n    }\n\n    void nextTagS() {\n        ++tagS;\n        if (tagS == INT_MAX) {\n            fill(markS.begin(), markS.end(), 0);\n            tagS = 1;\n        }\n    }\n\n    void build(const vector<uint8_t>& g) {\n        grid = g;\n        fill(cover.begin(), cover.end(), 0);\n        obj = 0;\n\n        for (int sid = 0; sid < U; sid++) {\n            hist[sid].fill(0);\n            int base = sid * POS;\n            const auto& str = S[sid];\n            int len = Ls[sid];\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = 0;\n                for (int p = 0; p < len; p++) {\n                    if (grid[posCell[pos][p]] != str[p]) m++;\n                }\n                mism[base + pos] = (uint8_t)m;\n                hist[sid][m]++;\n            }\n\n            cover[sid] = hist[sid][0];\n            if (cover[sid] > 0) obj += W[sid];\n        }\n    }\n\n    int evalChanges(const int cells[], const uint8_t vals[], int cnt) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        auto addSid = [&](int sid, int dc) {\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                deltaC[sid] = 0;\n                touchedS.push_back(sid);\n            }\n            deltaC[sid] += (int16_t)dc;\n        };\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (oldm == 0 && newm > 0) addSid(sid, -1);\n            else if (oldm > 0 && newm == 0) addSid(sid, +1);\n        }\n\n        int delta = 0;\n        for (int sid : touchedS) {\n            int cc = cover[sid];\n            int nc = cc + deltaC[sid];\n            if (cc == 0 && nc > 0) delta += W[sid];\n            else if (cc > 0 && nc == 0) delta -= W[sid];\n        }\n        return delta;\n    }\n\n    long long evalChangesSoft(const int cells[], const uint8_t vals[], int cnt, long long exactBonus) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                hdelta[sid].fill(0);\n                touchedS.push_back(sid);\n            }\n\n            hdelta[sid][oldm]--;\n            hdelta[sid][newm]++;\n        }\n\n        long long exactDelta = 0;\n        long long nearDelta = 0;\n\n        for (int sid : touchedS) {\n            int oldCov = cover[sid];\n            int newCov = hist[sid][0] + hdelta[sid][0];\n\n            if (oldCov == 0 && newCov > 0) exactDelta += W[sid];\n            else if (oldCov > 0 && newCov == 0) exactDelta -= W[sid];\n\n            int len = Ls[sid];\n\n            int oldMin = 0;\n            while (oldMin <= len && hist[sid][oldMin] == 0) oldMin++;\n\n            int newMin = 0;\n            while (newMin <= len && hist[sid][newMin] + hdelta[sid][newMin] <= 0) newMin++;\n\n            nearDelta += 1LL * W[sid] * (nearVal[len][newMin] - nearVal[len][oldMin]);\n\n            int oldRed = min(oldCov, 4);\n            int newRed = min(newCov, 4);\n            nearDelta += 80LL * W[sid] * (newRed - oldRed);\n        }\n\n        return exactDelta * exactBonus + nearDelta;\n    }\n\n    void changeCell(int cell, uint8_t newc) {\n        int oldc = grid[cell];\n        if (oldc == newc) return;\n\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            bool was = (oldc != req);\n            bool now = (newc != req);\n            if (was == now) continue;\n\n            int sid = pid / POS;\n            int m = mism[pid];\n\n            if (!was && now) {\n                hist[sid][m]--;\n                hist[sid][m + 1]++;\n\n                if (m == 0) {\n                    cover[sid]--;\n                    if (cover[sid] == 0) obj -= W[sid];\n                }\n                mism[pid] = (uint8_t)(m + 1);\n            } else {\n                hist[sid][m]--;\n                hist[sid][m - 1]++;\n\n                if (m == 1) {\n                    if (cover[sid] == 0) obj += W[sid];\n                    cover[sid]++;\n                }\n                mism[pid] = (uint8_t)(m - 1);\n            }\n        }\n\n        grid[cell] = newc;\n    }\n\n    void applyChanges(const int cells[], const uint8_t vals[], int cnt) {\n        for (int i = 0; i < cnt; i++) changeCell(cells[i], vals[i]);\n    }\n};\n\nstruct Best {\n    int obj = -1;\n    int dots = 1000000000;\n    vector<uint8_t> grid;\n\n    void consider(const State& st) {\n        int d = countDotsVec(st.grid);\n        bool upd = false;\n        if (st.obj > obj) upd = true;\n        else if (st.obj == obj) {\n            if (st.obj == TOTAL) {\n                if (d > dots) upd = true;\n            } else {\n                if (grid.empty() || d < dots) upd = true;\n            }\n        }\n\n        if (upd) {\n            obj = st.obj;\n            dots = d;\n            grid = st.grid;\n        }\n    }\n};\n\nvector<uint8_t> strToVec(const string& s) {\n    vector<uint8_t> v;\n    v.reserve(s.size());\n    for (char c : s) v.push_back((uint8_t)(c - 'A'));\n    return v;\n}\n\nstring vecToString(const vector<uint8_t>& v) {\n    string s;\n    s.reserve(v.size());\n    for (auto x : v) s.push_back(char('A' + x));\n    return s;\n}\n\nstring mergeLinear(const string& a, const string& b, int& ovOut) {\n    if (a.empty()) {\n        ovOut = 0;\n        return b;\n    }\n    if (b.empty()) {\n        ovOut = 0;\n        return a;\n    }\n\n    if (a.find(b) != string::npos) {\n        ovOut = (int)b.size();\n        return a;\n    }\n    if (b.find(a) != string::npos) {\n        ovOut = (int)a.size();\n        return b;\n    }\n\n    int bestOv = -1;\n    string best;\n\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            a.compare(a.size() - ov, ov, b, 0, ov) == 0) {\n            bestOv = ov;\n            best = a + b.substr(ov);\n            break;\n        }\n    }\n\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            b.compare(b.size() - ov, ov, a, 0, ov) == 0) {\n            if (ov > bestOv) {\n                bestOv = ov;\n                best = b + a.substr(ov);\n            }\n            break;\n        }\n    }\n\n    if (bestOv >= 0) {\n        ovOut = bestOv;\n        return best;\n    }\n\n    if ((int)a.size() + (int)b.size() <= MAXPLEN) {\n        ovOut = 0;\n        return a + b;\n    }\n\n    ovOut = -1;\n    return \"\";\n}\n\nint directedOverlap(const string& a, const string& b) {\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov > MAXPLEN) continue;\n        if (a.compare(a.size() - ov, ov, b, 0, ov) == 0) return ov;\n    }\n    return -1;\n}\n\nbool containsInSegment(const string& seg, const string& sub) {\n    if ((int)sub.size() > MAXPLEN) return false;\n    if ((int)seg.size() == SZ) {\n        string t = seg + seg.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    } else {\n        if (sub.size() > seg.size()) return false;\n        return seg.find(sub) != string::npos;\n    }\n}\n\nbool lineContains(const string& line, const string& sub) {\n    if (line.empty()) return false;\n    if ((int)line.size() == SZ) {\n        string t = line + line.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    }\n    if (sub.size() > line.size()) return false;\n    return line.find(sub) != string::npos;\n}\n\nstruct Segment {\n    vector<uint8_t> ch;\n    int val;\n    vector<int> contains;\n    Mask mask;\n};\n\nvector<Segment> generateSegments() {\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    unordered_set<string> seen;\n    seen.reserve(50000);\n    vector<string> cands;\n    cands.reserve(30000);\n\n    const size_t CAND_CAP = 42000;\n\n    auto addCand = [&](const string& x) {\n        if (x.size() < 2 || x.size() > MAXPLEN) return;\n        if (seen.size() >= CAND_CAP) return;\n        if (seen.insert(x).second) cands.push_back(x);\n    };\n\n    for (int id : ids) addCand(uniqStr[id]);\n\n    int minOv;\n    if (avgLen >= 8.0) minOv = 4;\n    else if (avgLen >= 6.0) minOv = 3;\n    else minOv = 2;\n\n    {\n        vector<string> segs;\n        for (int id : ids) {\n            const string& s = uniqStr[id];\n            bool contained = false;\n            int bestIdx = -1;\n            int bestOv = -1;\n            string bestMerged;\n\n            for (int i = 0; i < (int)segs.size(); i++) {\n                if (segs[i].find(s) != string::npos) {\n                    contained = true;\n                    break;\n                }\n\n                int ov;\n                string merged = mergeLinear(segs[i], s, ov);\n                if (!merged.empty() && (int)merged.size() <= MAXPLEN && ov > bestOv) {\n                    bestOv = ov;\n                    bestIdx = i;\n                    bestMerged = merged;\n                }\n            }\n\n            if (contained) continue;\n\n            if (bestIdx != -1 && bestOv >= minOv) {\n                segs[bestIdx] = bestMerged;\n            } else {\n                segs.push_back(s);\n            }\n        }\n        for (auto& x : segs) addCand(x);\n    }\n\n    int pairOv;\n    if (avgLen >= 8.0) pairOv = 4;\n    else if (avgLen >= 6.0) pairOv = 3;\n    else pairOv = 2;\n\n    for (int ai = 0; ai < U && seen.size() < CAND_CAP; ai++) {\n        const string& a = uniqStr[ai];\n        for (int bi = 0; bi < U && seen.size() < CAND_CAP; bi++) {\n            if (ai == bi) continue;\n            const string& b = uniqStr[bi];\n            int ov = directedOverlap(a, b);\n            if (ov >= pairOv) {\n                string m = a + b.substr(ov);\n                addCand(m);\n            }\n        }\n    }\n\n    int seedOv = minOv;\n    int seedLimit = U;\n    for (int si = 0; si < seedLimit && seen.size() < CAND_CAP; si++) {\n        string cur = uniqStr[ids[si]];\n        addCand(cur);\n\n        for (int step = 0; step < 6 && (int)cur.size() < MAXPLEN; step++) {\n            int bestOv = seedOv - 1;\n            int bestScore = -1;\n            string bestMerged;\n\n            for (int tid : ids) {\n                const string& t = uniqStr[tid];\n                if (cur.find(t) != string::npos) continue;\n\n                int ov;\n                string merged = mergeLinear(cur, t, ov);\n                if (merged.empty() || merged == cur || (int)merged.size() > MAXPLEN) continue;\n                if (ov < seedOv) continue;\n\n                int score = ov * 10000 + W[tid] * 100 + Ls[tid] * 10 + int(rng.next() & 31);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestOv = ov;\n                    bestMerged = merged;\n                }\n            }\n\n            if (bestScore < 0 || bestOv < seedOv) break;\n            cur = bestMerged;\n            addCand(cur);\n        }\n    }\n\n    vector<Segment> res;\n    res.reserve(cands.size());\n\n    for (auto& seg : cands) {\n        int val = 0;\n        vector<int> cont;\n        for (int i = 0; i < U; i++) {\n            if (containsInSegment(seg, uniqStr[i])) {\n                val += W[i];\n                cont.push_back(i);\n            }\n        }\n\n        if (val >= 2) {\n            Segment sg;\n            sg.ch = strToVec(seg);\n            sg.val = val;\n            sg.contains = std::move(cont);\n            sg.mask.fill(0);\n            for (int sid : sg.contains) {\n                sg.mask[sid >> 6] |= 1ULL << (sid & 63);\n            }\n            res.push_back(std::move(sg));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Segment& a, const Segment& b) {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.contains.size() != b.contains.size()) return a.contains.size() > b.contains.size();\n        return a.ch.size() > b.ch.size();\n    });\n\n    int lim = (avgLen >= 7.0 ? 440 : 540);\n    if ((int)res.size() > lim) res.resize(lim);\n    return res;\n}\n\nstruct CItem {\n    int type;\n    int idx;\n    int len;\n    int val;\n    int group;\n    uint32_t rnd;\n};\n\nconst vector<uint8_t>& getItemChars(const CItem& it, const vector<Segment>& segs) {\n    if (it.type == 0) return S[it.idx];\n    return segs[it.idx].ch;\n}\n\nvector<uint8_t> constructGreedy(int mode, const vector<Segment>& segs, Timer& timer, double endTime) {\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<CItem> items;\n\n    if (mode == 1 || mode == 2) {\n        int lim = min((int)segs.size(), avgLen >= 7.0 ? 150 : 220);\n        for (int i = 0; i < lim; i++) {\n            items.push_back({1, i, (int)segs[i].ch.size(), segs[i].val,\n                             mode == 1 ? 0 : 0, (uint32_t)rng.next()});\n        }\n    }\n\n    for (int sid = 0; sid < U; sid++) {\n        int group = (mode == 1 ? 1 : 0);\n        items.push_back({0, sid, Ls[sid], W[sid], group, (uint32_t)rng.next()});\n    }\n\n    sort(items.begin(), items.end(), [&](const CItem& a, const CItem& b) {\n        if (a.group != b.group) return a.group < b.group;\n\n        if (mode == 2) {\n            int sa = a.val * 1000 + a.len * 50 + int(a.rnd & 127);\n            int sb = b.val * 1000 + b.len * 50 + int(b.rnd & 127);\n            return sa > sb;\n        }\n\n        if (a.len != b.len) return a.len > b.len;\n        if (a.val != b.val) return a.val > b.val;\n        return a.rnd < b.rnd;\n    });\n\n    int processed = 0;\n    for (const CItem& it : items) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n\n        const auto& ch = getItemChars(it, segs);\n        int len = (int)ch.size();\n\n        int bestPos = -1;\n        int bestScore = INT_MIN;\n        bool already = false;\n\n        for (int pos = 0; pos < POS; pos++) {\n            int match = 0;\n            bool conflict = false;\n\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[pos][p];\n                int g = grid[cell];\n                if (g == DOT) continue;\n                if (g == ch[p]) match++;\n                else {\n                    conflict = true;\n                    break;\n                }\n            }\n\n            if (!conflict) {\n                if (match == len) {\n                    already = true;\n                    break;\n                }\n\n                int score = match * 10000 - (len - match) * 5 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestPos = pos;\n                }\n            }\n        }\n\n        if (already) continue;\n\n        if (bestPos != -1) {\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n    }\n\n    return grid;\n}\n\nvector<uint8_t> constructRowPack(Timer& timer, double endTime) {\n    vector<string> rows(SZ, \"\");\n\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    vector<uint32_t> rk(U);\n    for (int i = 0; i < U; i++) rk[i] = (uint32_t)rng.next();\n\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        if (W[a] != W[b]) return W[a] > W[b];\n        return rk[a] < rk[b];\n    });\n\n    int processed = 0;\n    for (int sid : ids) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n        const string& s = uniqStr[sid];\n\n        bool covered = false;\n        for (auto& row : rows) {\n            if (lineContains(row, s)) {\n                covered = true;\n                break;\n            }\n        }\n        if (covered) continue;\n\n        int bestR = -1;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        for (int r = 0; r < SZ; r++) {\n            int ov;\n            string merged;\n            if (rows[r].empty()) {\n                ov = 0;\n                merged = s;\n            } else {\n                merged = mergeLinear(rows[r], s, ov);\n            }\n\n            if (merged.empty() || (int)merged.size() > SZ) continue;\n\n            int score = ov * 1000 + (rows[r].empty() ? 0 : 100) - (int)merged.size();\n            if (score > bestScore) {\n                bestScore = score;\n                bestR = r;\n                bestMerged = merged;\n            }\n        }\n\n        if (bestR != -1) rows[bestR] = bestMerged;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nstruct RowCand {\n    string s;\n    vector<int> contains;\n    int val;\n};\n\nvector<uint8_t> constructCoverRows(const vector<Segment>& segments, Timer& timer, double endTime) {\n    unordered_set<string> seen;\n    seen.reserve(2000);\n    vector<string> candStr;\n\n    auto add = [&](const string& s) {\n        if (s.size() < 2 || s.size() > 20) return;\n        if (seen.insert(s).second) candStr.push_back(s);\n    };\n\n    for (const auto& sg : segments) add(vecToString(sg.ch));\n    for (const auto& s : uniqStr) add(s);\n\n    vector<RowCand> cands;\n    cands.reserve(candStr.size());\n\n    for (auto& cs : candStr) {\n        int val = 0;\n        vector<int> cont;\n        for (int sid = 0; sid < U; sid++) {\n            if (containsInSegment(cs, uniqStr[sid])) {\n                val += W[sid];\n                cont.push_back(sid);\n            }\n        }\n        if (val > 0) cands.push_back({cs, std::move(cont), val});\n    }\n\n    sort(cands.begin(), cands.end(), [](const RowCand& a, const RowCand& b) {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.contains.size() != b.contains.size()) return a.contains.size() > b.contains.size();\n        return a.s.size() > b.s.size();\n    });\n\n    int candLimit = avgLen <= 5.0 ? 700 : 520;\n    if ((int)cands.size() > candLimit) cands.resize(candLimit);\n\n    vector<string> rows(SZ, \"\");\n    vector<char> covered(U, 0);\n\n    int moves = 0;\n    while (timer.elapsed() < endTime && moves < 120) {\n        int bestR = -1;\n        int bestC = -1;\n        int bestGain = 0;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        int iterCnt = 0;\n        for (int ci = 0; ci < (int)cands.size(); ci++) {\n            const auto& cd = cands[ci];\n\n            int approxGain = 0;\n            for (int sid : cd.contains) if (!covered[sid]) approxGain += W[sid];\n            if (approxGain <= 0) continue;\n\n            for (int r = 0; r < SZ; r++) {\n                if (((++iterCnt) & 4095) == 0 && timer.elapsed() > endTime) break;\n\n                if ((int)rows[r].size() == SZ) {\n                    if (lineContains(rows[r], cd.s)) continue;\n                    else continue;\n                }\n\n                int ov = 0;\n                string merged = rows[r].empty() ? cd.s : mergeLinear(rows[r], cd.s, ov);\n                if (merged.empty() || (int)merged.size() > SZ) continue;\n\n                int gain = 0;\n                for (int sid : cd.contains) {\n                    if (!covered[sid]) gain += W[sid];\n                }\n                if (gain <= 0) continue;\n\n                int added = (int)merged.size() - (int)rows[r].size();\n                int score = gain * 100000 + ov * 1800 - added * 120 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestGain = gain;\n                    bestR = r;\n                    bestC = ci;\n                    bestMerged = merged;\n                }\n            }\n            if (timer.elapsed() > endTime) break;\n        }\n\n        if (bestR < 0 || bestGain <= 0 || bestC < 0) break;\n\n        rows[bestR] = bestMerged;\n        for (int sid = 0; sid < U; sid++) {\n            if (!covered[sid] && lineContains(rows[bestR], uniqStr[sid])) {\n                covered[sid] = 1;\n            }\n        }\n        moves++;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nint makePlacementChanges(const State& st, int sid, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    const auto& str = S[sid];\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = str[p];\n        if (st.grid[cell] != ch) {\n            cells[cnt] = cell;\n            vals[cnt] = ch;\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nint makeSequenceChanges(const State& st, const vector<uint8_t>& ch, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    int len = (int)ch.size();\n    for (int p = 0; p < len; p++) {\n        int cell = posCell[pos][p];\n        if (st.grid[cell] != ch[p]) {\n            cells[cnt] = cell;\n            vals[cnt] = ch[p];\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nbool tryInsert(State& st, int sid, int K, int maxChange, bool allowZero, double temp, int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    const int MAXK = 12;\n    K = min(K, MAXK);\n\n    int candPos[MAXK];\n    uint32_t candKey[MAXK];\n    int candN = 0;\n\n    auto updateWorst = [&]() {\n        int wi = 0;\n        for (int i = 1; i < candN; i++) {\n            if (candKey[i] > candKey[wi]) wi = i;\n        }\n        return wi;\n    };\n\n    int base = sid * POS;\n\n    for (int pos = 0; pos < POS; pos++) {\n        int m = st.mism[base + pos];\n        if (m == 0) return false;\n        if (m > maxChange) continue;\n\n        uint32_t key = (uint32_t(m) << 20) | uint32_t(rng.next() & ((1u << 20) - 1));\n        if (candN < K) {\n            candPos[candN] = pos;\n            candKey[candN] = key;\n            candN++;\n        } else {\n            int wi = updateWorst();\n            if (key < candKey[wi]) {\n                candPos[wi] = pos;\n                candKey[wi] = key;\n            }\n        }\n    }\n\n    if (candN == 0) return false;\n\n    int bestD = INT_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (int i = 0; i < candN; i++) {\n        int cnt = makePlacementChanges(st, sid, candPos[i], tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 30) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nvoid shuffleVec(vector<int>& v) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nint softCellSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    static const long long EXACT_BONUS = 3000000LL;\n\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int exactImpTotal = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int changes = 0;\n        int exactImp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            long long bestScore = 0;\n            int bestCh = old;\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                long long sc = st.evalChangesSoft(oneCell, oneVal, 1, EXACT_BONUS);\n                if (sc > bestScore || (sc == bestScore && sc > 0 && rng.randint(2) == 0)) {\n                    bestScore = sc;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestScore > 0) {\n                int before = st.obj;\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                exactImp += st.obj - before;\n                changes++;\n                if (st.obj >= best.obj) best.consider(st);\n                if (st.obj == TOTAL) return exactImpTotal + exactImp;\n            }\n        }\n\n        exactImpTotal += exactImp;\n        if (changes == 0) break;\n    }\n\n    best.consider(st);\n    return exactImpTotal;\n}\n\ninline int maskWeight(const Mask& m) {\n    int sum = 0;\n    for (int w = 0; w < MASK_WORDS; w++) {\n        uint64_t x = m[w];\n        while (x) {\n            int b = __builtin_ctzll(x);\n            int id = w * 64 + b;\n            if (id < U) sum += W[id];\n            x &= x - 1;\n        }\n    }\n    return sum;\n}\n\nvoid buildLossMasks(const State& st, vector<Mask>& masks) {\n    for (auto& m : masks) m.fill(0);\n\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] != 1) continue;\n\n        int base = sid * POS;\n        int exactPos = -1;\n        for (int pos = 0; pos < POS; pos++) {\n            if (st.mism[base + pos] == 0) {\n                exactPos = pos;\n                break;\n            }\n        }\n        if (exactPos < 0) continue;\n\n        int word = sid >> 6;\n        uint64_t bit = 1ULL << (sid & 63);\n\n        for (int p = 0; p < Ls[sid]; p++) {\n            int cell = posCell[exactPos][p];\n            masks[cell][word] |= bit;\n        }\n    }\n}\n\nint approxPlacementLoss(const State& st, const vector<Mask>& masks, int sid, int pos, int& cnt) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = S[sid][p];\n        if (st.grid[cell] == ch) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    tmp[sid >> 6] &= ~(1ULL << (sid & 63));\n    return maskWeight(tmp);\n}\n\nint approxSequenceLoss(const State& st, const vector<Mask>& masks, const vector<uint8_t>& ch,\n                       int pos, int& cnt, const Mask* excludeMask = nullptr) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    int len = (int)ch.size();\n    for (int p = 0; p < len; p++) {\n        int cell = posCell[pos][p];\n        if (st.grid[cell] == ch[p]) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    if (excludeMask) {\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] &= ~((*excludeMask)[w]);\n    }\n\n    return maskWeight(tmp);\n}\n\nbool tryInsertConflict(State& st, int sid, const vector<Mask>& masks,\n                       int kLoss, int kMis, bool allowZero, double temp,\n                       int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 250 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 1200LL - 1LL * c.cnt * 30LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 45) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nbool tryPlaceSequenceConflict(State& st, const vector<uint8_t>& ch, const vector<Mask>& masks,\n                              int kLoss, int kMis, bool allowZero, double temp,\n                              int& appliedDelta, const Mask* excludeMask = nullptr) {\n    appliedDelta = 0;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxSequenceLoss(st, masks, ch, pos, cnt, excludeMask);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 180 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 45 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makeSequenceChanges(st, ch, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 700LL - 1LL * c.cnt * 20LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 35) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nstruct SmallMove {\n    int d = INT_MIN;\n    long long score = LLONG_MIN;\n    int cnt = 0;\n    array<int, 25> cells;\n    array<uint8_t, 25> vals;\n};\n\nbool findBestInsertConflictMove(State& st, int sid, const vector<Mask>& masks,\n                                int kLoss, int kMis, SmallMove& mv) {\n    mv = SmallMove();\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos, loss, cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) if (v[i].key > v[wi].key) wi = i;\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 220 + (rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) if (x.pos == c.pos) return;\n        cand.push_back(c);\n    };\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 700LL - 1LL * c.cnt * 20LL\n                        + (rng.next() & 1023);\n\n        if (d > mv.d || (d == mv.d && score > mv.score)) {\n            mv.d = d;\n            mv.score = score;\n            mv.cnt = cnt;\n            for (int i = 0; i < cnt; i++) {\n                mv.cells[i] = tmpCells[i];\n                mv.vals[i] = tmpVals[i];\n            }\n        }\n    }\n\n    return mv.d != INT_MIN;\n}\n\nbool findBestSequenceConflictMove(State& st, const vector<uint8_t>& ch, const vector<Mask>& masks,\n                                  int kLoss, int kMis, SmallMove& mv,\n                                  const Mask* excludeMask = nullptr) {\n    mv = SmallMove();\n\n    struct Cand {\n        int pos, loss, cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) if (v[i].key > v[wi].key) wi = i;\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxSequenceLoss(st, masks, ch, pos, cnt, excludeMask);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 150 + (rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 40 + (rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) if (x.pos == c.pos) return;\n        cand.push_back(c);\n    };\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makeSequenceChanges(st, ch, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 450LL - 1LL * c.cnt * 15LL\n                        + (rng.next() & 1023);\n\n        if (d > mv.d || (d == mv.d && score > mv.score)) {\n            mv.d = d;\n            mv.score = score;\n            mv.cnt = cnt;\n            for (int i = 0; i < cnt; i++) {\n                mv.cells[i] = tmpCells[i];\n                mv.vals[i] = tmpVals[i];\n            }\n        }\n    }\n\n    return mv.d != INT_MIN;\n}\n\nvoid greedyImproveConflict(State& st, Timer& timer, double endTime, Best& best,\n                           int maxIter, int sampleLimit) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n\n    for (int it = 0; it < maxIter && timer.elapsed() < endTime && st.obj < TOTAL; it++) {\n        buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) if (st.cover[sid] == 0) unc.push_back(sid);\n        if (unc.empty()) break;\n\n        vector<pair<int,int>> order;\n        order.reserve(unc.size());\n\n        for (int sid : unc) {\n            int minM = 13;\n            for (int m = 0; m <= Ls[sid]; m++) {\n                if (st.hist[sid][m] > 0) {\n                    minM = m;\n                    break;\n                }\n            }\n            int key = W[sid] * 200 + Ls[sid] * 80 - minM * 70 + rng.randint(200);\n            order.push_back({-key, sid});\n        }\n\n        sort(order.begin(), order.end());\n        if ((int)order.size() > sampleLimit) order.resize(sampleLimit);\n\n        SmallMove bestMv;\n        int checked = 0;\n\n        for (auto [_, sid] : order) {\n            if (((++checked) & 15) == 0 && timer.elapsed() > endTime) break;\n\n            SmallMove mv;\n            if (!findBestInsertConflictMove(st, sid, masks, 5, 3, mv)) continue;\n\n            if (mv.d > bestMv.d || (mv.d == bestMv.d && mv.score > bestMv.score)) {\n                bestMv = mv;\n            }\n        }\n\n        if (bestMv.d <= 0 || bestMv.d == INT_MIN) break;\n\n        st.applyChanges(bestMv.cells.data(), bestMv.vals.data(), bestMv.cnt);\n        best.consider(st);\n    }\n}\n\nvoid greedyImproveSegments(State& st, Timer& timer, double endTime, Best& best,\n                           const vector<Segment>& segments, int maxIter, int segSample) {\n    if (segments.empty() || st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n\n    for (int it = 0; it < maxIter && timer.elapsed() < endTime && st.obj < TOTAL; it++) {\n        buildLossMasks(st, masks);\n\n        struct Pick {\n            long long key;\n            int idx;\n        };\n\n        vector<Pick> picks;\n        picks.reserve(segments.size());\n\n        for (int i = 0; i < (int)segments.size(); i++) {\n            int gain = 0;\n            for (int sid : segments[i].contains) {\n                if (st.cover[sid] == 0) gain += W[sid];\n            }\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL + 1LL * segments[i].val * 100LL\n                          + 1LL * (int)segments[i].ch.size() * 30LL + (rng.next() & 4095);\n            picks.push_back({key, i});\n        }\n\n        if (picks.empty()) break;\n\n        sort(picks.begin(), picks.end(), [](const Pick& a, const Pick& b) {\n            return a.key > b.key;\n        });\n\n        if ((int)picks.size() > segSample) picks.resize(segSample);\n\n        SmallMove bestMv;\n\n        for (auto& p : picks) {\n            if (timer.elapsed() > endTime) break;\n\n            const Segment& sg = segments[p.idx];\n            SmallMove mv;\n            if (!findBestSequenceConflictMove(st, sg.ch, masks, 5, 3, mv, &sg.mask)) continue;\n\n            if (mv.d > bestMv.d || (mv.d == bestMv.d && mv.score > bestMv.score)) {\n                bestMv = mv;\n            }\n        }\n\n        if (bestMv.d <= 0 || bestMv.d == INT_MIN) break;\n\n        st.applyChanges(bestMv.cells.data(), bestMv.vals.data(), bestMv.cnt);\n        best.consider(st);\n    }\n}\n\nvoid conflictSearch(State& st, Timer& timer, double endTime, Best& best) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 5 == 0) buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) {\n            if (st.cover[sid] == 0) unc.push_back(sid);\n        }\n        if (unc.empty()) break;\n\n        int sid = unc[rng.randint((int)unc.size())];\n\n        int samples = min(26, (int)unc.size());\n        int bestKey = -1;\n        for (int t = 0; t < samples; t++) {\n            int x = unc[rng.randint((int)unc.size())];\n\n            int minM = 13;\n            const auto& hh = st.hist[x];\n            for (int m = 0; m <= Ls[x]; m++) {\n                if (hh[m] > 0) {\n                    minM = m;\n                    break;\n                }\n            }\n\n            int key = Ls[x] * 100 + W[x] * 35 - minM * 30 + rng.randint(120);\n            if (key > bestKey) {\n                bestKey = key;\n                sid = x;\n            }\n        }\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.12 + 1.15 * frac;\n\n        int d;\n        bool ok = tryInsertConflict(st, sid, masks, 9, 5, true, temp, d);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 8);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 150) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n                iter = 0;\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nvoid segmentSearch(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    if (segments.empty() || st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 4 == 0) buildLossMasks(st, masks);\n\n        struct Pick {\n            long long key;\n            int idx;\n            int gain;\n        };\n\n        vector<Pick> top;\n        top.reserve(10);\n\n        auto pushPick = [&](Pick p) {\n            if ((int)top.size() < 10) {\n                top.push_back(p);\n                return;\n            }\n            int wi = 0;\n            for (int i = 1; i < (int)top.size(); i++) {\n                if (top[i].key < top[wi].key) wi = i;\n            }\n            if (p.key > top[wi].key) top[wi] = p;\n        };\n\n        for (int i = 0; i < (int)segments.size(); i++) {\n            int gain = 0;\n            for (int sid : segments[i].contains) {\n                if (st.cover[sid] == 0) gain += W[sid];\n            }\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL\n                          + 1LL * segments[i].val * 120LL\n                          + 1LL * (int)segments[i].ch.size() * 30LL\n                          + (long long)(rng.next() & 4095);\n            pushPick({key, i, gain});\n        }\n\n        if (top.empty()) break;\n\n        int chooseLim = min(5, (int)top.size());\n        nth_element(top.begin(), top.begin() + chooseLim - 1, top.end(),\n                    [](const Pick& a, const Pick& b) { return a.key > b.key; });\n        int idx = top[rng.randint(chooseLim)].idx;\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.10 + 1.05 * frac;\n\n        int d;\n        bool ok = tryPlaceSequenceConflict(st, segments[idx].ch, masks, 11, 6, true, temp, d,\n                                           &segments[idx].mask);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 10);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n\n            if (st.obj < localBestObj - 14) {\n                st.build(localBestGrid);\n                noProgress = 0;\n            }\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 80) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nint repairPass(State& st, Timer& timer, double endTime, int K, int maxChange,\n               bool allowZero, double temp, Best& best) {\n    vector<int> ids;\n    ids.reserve(U);\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] == 0) ids.push_back(sid);\n    }\n    if (ids.empty()) return 0;\n\n    shuffleVec(ids);\n    stable_sort(ids.begin(), ids.end(), [](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int before = st.obj;\n    int applied = 0;\n\n    for (int sid : ids) {\n        if (timer.elapsed() > endTime) break;\n        if (st.cover[sid] > 0) continue;\n\n        int d;\n        if (tryInsert(st, sid, K, maxChange, allowZero, temp, d)) {\n            applied++;\n            if (d > 0 || st.obj == TOTAL) best.consider(st);\n            if (st.obj == TOTAL) break;\n        }\n    }\n\n    best.consider(st);\n    return st.obj - before + applied / 1000000;\n}\n\nvoid fillDots(State& st, Timer& timer, double endTime, Best& best) {\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] != DOT) continue;\n\n        int bestD = INT_MIN;\n        int bestCh = 0;\n        oneCell[0] = cell;\n\n        for (int ch = 0; ch < 8; ch++) {\n            oneVal[0] = (uint8_t)ch;\n            int d = st.evalChanges(oneCell, oneVal, 1);\n            if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n                bestD = d;\n                bestCh = ch;\n            }\n        }\n\n        oneVal[0] = (uint8_t)bestCh;\n        st.applyChanges(oneCell, oneVal, 1);\n        best.consider(st);\n\n        if (st.obj == TOTAL) return;\n    }\n\n    best.consider(st);\n}\n\nint cellHillSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int totalImp = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int imp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            int bestD = 0;\n            int bestCh = old;\n\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                int d = st.evalChanges(oneCell, oneVal, 1);\n                if (d > bestD || (d == bestD && d > 0 && rng.randint(2) == 0)) {\n                    bestD = d;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestD > 0) {\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                imp += bestD;\n                best.consider(st);\n                if (st.obj == TOTAL) return totalImp + imp;\n            }\n        }\n\n        totalImp += imp;\n        if (imp == 0) break;\n    }\n\n    best.consider(st);\n    return totalImp;\n}\n\nvoid voteRefine(State& st, Timer& timer, double endTime, Best& best, int iters) {\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    static int votes[CELLS][8];\n\n    for (int it = 0; it < iters && timer.elapsed() < endTime; it++) {\n        memset(votes, 0, sizeof(votes));\n\n        for (int cell = 0; cell < CELLS; cell++) {\n            int old = st.grid[cell];\n            if (0 <= old && old < 8) votes[cell][old] += 1;\n        }\n\n        for (int sid = 0; sid < U; sid++) {\n            if ((sid & 31) == 0 && timer.elapsed() > endTime) break;\n\n            int base = sid * POS;\n            int bestM = 100;\n            int bestPos = 0;\n            int seen = 0;\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = st.mism[base + pos];\n                if (m < bestM) {\n                    bestM = m;\n                    bestPos = pos;\n                    seen = 1;\n                } else if (m == bestM) {\n                    seen++;\n                    if (rng.randint(seen) == 0) bestPos = pos;\n                }\n            }\n\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[bestPos][p];\n                votes[cell][S[sid][p]] += W[sid];\n            }\n        }\n\n        vector<uint8_t> ng = st.grid;\n\n        for (int cell = 0; cell < CELLS; cell++) {\n            int bestCh = ng[cell];\n            int bestV = -1;\n            for (int ch = 0; ch < 8; ch++) {\n                int v = votes[cell][ch];\n                if (v > bestV || (v == bestV && rng.randint(2) == 0)) {\n                    bestV = v;\n                    bestCh = ch;\n                }\n            }\n            if (bestV > 0) ng[cell] = (uint8_t)bestCh;\n        }\n\n        st.build(ng);\n        best.consider(st);\n\n        if (st.obj > localBestObj) {\n            localBestObj = st.obj;\n            localBestGrid = st.grid;\n        }\n    }\n\n    st.build(localBestGrid);\n    best.consider(st);\n}\n\nbool hasDots(const vector<uint8_t>& g) {\n    for (auto x : g) if (x == DOT) return true;\n    return false;\n}\n\nvoid localSearch(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    best.consider(st);\n    if (st.obj == TOTAL) return;\n\n    int maxChFull = (avgLen >= 8.0 ? 5 : 6);\n\n    if (hasDots(st.grid)) {\n        for (int pass = 0; pass < 2 && timer.elapsed() < endTime; pass++) {\n            int before = st.obj;\n            repairPass(st, timer, endTime, 3, maxLenInput, false, -1.0, best);\n            if (st.obj == TOTAL) return;\n            if (st.obj == before) break;\n        }\n    }\n\n    if (st.obj == TOTAL) return;\n\n    if (hasDots(st.grid)) {\n        fillDots(st, timer, endTime, best);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (avgLen >= 5.5 && timer.elapsed() + 0.07 < endTime) {\n        double vtEnd = min(endTime, timer.elapsed() + 0.10);\n        voteRefine(st, timer, vtEnd, best, 2);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() + 0.05 < endTime && st.obj < TOTAL) {\n        softCellSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n    }\n\n    for (int cyc = 0; cyc < 2 && timer.elapsed() < endTime; cyc++) {\n        int before = st.obj;\n        repairPass(st, timer, endTime, 5, maxChFull, false, -1.0, best);\n        if (st.obj == TOTAL) return;\n\n        cellHillSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n\n        if (st.obj <= before && cyc > 0) break;\n    }\n\n    if (timer.elapsed() + 0.06 < endTime && st.obj < TOTAL) {\n        greedyImproveConflict(st, timer, min(endTime, timer.elapsed() + 0.12), best, 4, 80);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (avgLen >= 5.5 && timer.elapsed() + 0.10 < endTime && st.obj < TOTAL) {\n        greedyImproveSegments(st, timer, min(endTime, timer.elapsed() + 0.10), best, segments, 2, 7);\n        if (st.obj == TOTAL) return;\n\n        double rem = endTime - timer.elapsed();\n        double segEnd = min(endTime, timer.elapsed() + rem * 0.42);\n        segmentSearch(st, timer, segEnd, best, segments);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() < endTime && st.obj < TOTAL) {\n        conflictSearch(st, timer, endTime, best);\n    }\n\n    best.consider(st);\n}\n\nvoid dotMaximize(Best& best, State& st, Timer& timer, double endTime) {\n    if (best.obj < TOTAL) return;\n\n    st.build(best.grid);\n    if (st.obj < TOTAL) return;\n\n    vector<pair<int,int>> order;\n    order.reserve(CELLS);\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (st.grid[cell] == DOT) continue;\n\n        int impact = 0;\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            if (st.grid[cell] == req && st.mism[pid] == 0) {\n                int sid = pid / POS;\n                impact += (st.cover[sid] <= 1 ? 1000 * W[sid] : 1);\n            }\n        }\n        impact = impact * 1024 + rng.randint(1024);\n        order.push_back({impact, cell});\n    }\n\n    sort(order.begin(), order.end());\n\n    int oneCell[1];\n    uint8_t oneVal[1] = {(uint8_t)DOT};\n\n    for (auto [_, cell] : order) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] == DOT) continue;\n\n        oneCell[0] = cell;\n        int d = st.evalChanges(oneCell, oneVal, 1);\n        if (st.obj + d == TOTAL) {\n            st.applyChanges(oneCell, oneVal, 1);\n        }\n    }\n\n    best.consider(st);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin;\n    cin >> Nin >> M_input;\n\n    vector<string> input(M_input);\n    uint64_t h = 1469598103934665603ULL;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M_input * 2);\n\n    int totalLen = 0;\n    for (int i = 0; i < M_input; i++) {\n        cin >> input[i];\n        mp[input[i]]++;\n        totalLen += (int)input[i].size();\n        maxLenInput = max(maxLenInput, (int)input[i].size());\n        for (char c : input[i]) {\n            h ^= (uint64_t)c;\n            h *= 1099511628211ULL;\n        }\n    }\n\n    rng = XorShift(88172645463325252ULL ^ h);\n\n    vector<pair<string,int>> pairs;\n    pairs.reserve(mp.size());\n    for (auto& kv : mp) pairs.push_back(kv);\n    sort(pairs.begin(), pairs.end());\n\n    U = (int)pairs.size();\n    TOTAL = M_input;\n    avgLen = (double)totalLen / M_input;\n\n    uniqStr.reserve(U);\n    S.reserve(U);\n    Ls.reserve(U);\n    W.reserve(U);\n\n    for (auto& kv : pairs) {\n        uniqStr.push_back(kv.first);\n        S.push_back(strToVec(kv.first));\n        Ls.push_back((int)kv.first.size());\n        W.push_back(kv.second);\n    }\n\n    Timer timer;\n\n    initNearVal();\n    initPosCells();\n    buildIncidences();\n\n    vector<Segment> segments = generateSegments();\n\n    State st;\n    st.init();\n\n    Best best;\n\n    vector<int> modes;\n    if (avgLen <= 5.2) {\n        modes = {4, 0, 3, 1};\n    } else if (avgLen <= 6.2) {\n        modes = {1, 4, 0, 3};\n    } else {\n        modes = {1, 0, 3, 2};\n    }\n\n    const double SEARCH_END = 2.62;\n    const double FINAL_END = 2.88;\n\n    for (int r = 0; r < (int)modes.size() && timer.elapsed() < SEARCH_END; r++) {\n        vector<uint8_t> grid;\n\n        if (modes[r] == 3) {\n            grid = constructRowPack(timer, SEARCH_END);\n        } else if (modes[r] == 4) {\n            grid = constructCoverRows(segments, timer, SEARCH_END);\n        } else {\n            grid = constructGreedy(modes[r], segments, timer, SEARCH_END);\n        }\n\n        st.build(grid);\n\n        double rem = SEARCH_END - timer.elapsed();\n        int left = (int)modes.size() - r;\n        double slice = max(0.05, rem / max(1, left));\n        double endTime = min(SEARCH_END, timer.elapsed() + slice);\n\n        localSearch(st, timer, endTime, best, segments);\n\n        if (best.obj == TOTAL) break;\n    }\n\n    if (best.grid.empty()) {\n        vector<uint8_t> g(CELLS);\n        for (int i = 0; i < CELLS; i++) g[i] = rng.randint(8);\n        st.build(g);\n        best.consider(st);\n    }\n\n    if (best.obj == TOTAL) {\n        dotMaximize(best, st, timer, FINAL_END);\n    } else {\n        st.build(best.grid);\n\n        if (hasDots(st.grid)) {\n            fillDots(st, timer, FINAL_END, best);\n        }\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            voteRefine(st, timer, min(FINAL_END, timer.elapsed() + 0.12), best, 2);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            greedyImproveSegments(st, timer, min(FINAL_END, timer.elapsed() + 0.12), best, segments, 3, 8);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            double rem = FINAL_END - timer.elapsed();\n            segmentSearch(st, timer, min(FINAL_END, timer.elapsed() + rem * 0.40), best, segments);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.05 < FINAL_END) {\n            softCellSweep(st, timer, FINAL_END, best, 1);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.06 < FINAL_END) {\n            greedyImproveConflict(st, timer, min(FINAL_END, timer.elapsed() + 0.18), best, 6, 110);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() < FINAL_END) {\n            conflictSearch(st, timer, FINAL_END, best);\n        }\n\n        if (best.obj == TOTAL) {\n            dotMaximize(best, st, timer, FINAL_END);\n        } else {\n            st.build(best.grid);\n            if (hasDots(st.grid)) fillDots(st, timer, FINAL_END, best);\n\n            if (st.obj < TOTAL) {\n                cellHillSweep(st, timer, FINAL_END, best, 3);\n            }\n\n            if (best.obj == TOTAL) {\n                dotMaximize(best, st, timer, FINAL_END);\n            }\n        }\n    }\n\n    if (best.obj < TOTAL) {\n        for (auto& x : best.grid) {\n            if (x == DOT) x = rng.randint(8);\n        }\n    }\n\n    for (int r = 0; r < SZ; r++) {\n        string line;\n        line.reserve(SZ);\n        for (int c = 0; c < SZ; c++) {\n            uint8_t x = best.grid[r * SZ + c];\n            if (x == DOT) line.push_back('.');\n            else line.push_back(char('A' + x));\n        }\n        cout << line << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Dinic {\n    struct Edge {\n        int to, rev;\n        long long cap;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic(int n = 0) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, long long cap) {\n        Edge a{to, (int)g[to].size(), cap};\n        Edge b{fr, (int)g[fr].size(), 0};\n        g[fr].push_back(a);\n        g[to].push_back(b);\n    }\n\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\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return level[t] >= 0;\n    }\n\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n\n        for (int &i = it[v]; i < (int)g[v].size(); i++) {\n            Edge &e = g[v][i];\n\n            if (e.cap <= 0 || level[v] + 1 != level[e.to]) continue;\n\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if (ret > 0) {\n                e.cap -= ret;\n                g[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n\n        return 0;\n    }\n\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        const long long INF = (1LL << 60);\n\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n\n            while (true) {\n                long long f = dfs(s, t, INF);\n                if (!f) break;\n                flow += f;\n            }\n        }\n\n        return flow;\n    }\n\n    vector<int> reachable_from(int s) {\n        vector<int> vis(n, 0);\n        queue<int> q;\n        vis[s] = 1;\n        q.push(s);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return vis;\n    }\n};\n\nstruct Solver {\n    static constexpr int INF16 = 65535;\n\n    Timer timer;\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0, S = 0;\n    vector<vector<int>> id;\n    vector<int> rr, cc, wt;\n    vector<array<int, 4>> nbr;\n\n    vector<uint16_t> distMat, parMat;\n\n    vector<int> hid, vid;\n    vector<vector<int>> hCells, vCells;\n    vector<int> visVal;\n    vector<int> segMinH, segMinV;\n\n    vector<int> bestSafeSeq;\n    vector<int> bestFinalSeq;\n    vector<vector<int>> bestFinalEdges;\n    long long bestSafeCost = (1LL << 60);\n    long long bestFinalCost = (1LL << 60);\n\n    inline int D(int a, int b) const {\n        return distMat[(size_t)a * R + b];\n    }\n\n    inline int Sym(int a, int b) const {\n        return D(a, b) + wt[a];\n    }\n\n    char moveChar(int a, int b) const {\n        if (rr[b] == rr[a] - 1) return 'U';\n        if (rr[b] == rr[a] + 1) return 'D';\n        if (cc[b] == cc[a] - 1) return 'L';\n        return 'R';\n    }\n\n    void readInput() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void buildRoadGraph() {\n        id.assign(N, vector<int>(N, -1));\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    rr.push_back(i);\n                    cc.push_back(j);\n                    wt.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n\n        S = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        int di[4] = {-1, 1, 0, 0};\n        int dj[4] = {0, 0, -1, 1};\n\n        for (int v = 0; v < R; v++) {\n            int i = rr[v], j = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n\n                if (0 <= ni && ni < N && 0 <= nj && nj < N && id[ni][nj] >= 0) {\n                    nbr[v][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void buildSegments() {\n        hid.assign(R, -1);\n        vid.assign(R, -1);\n\n        for (int i = 0; i < N; i++) {\n            int j = 0;\n            while (j < N) {\n                if (id[i][j] < 0) {\n                    j++;\n                    continue;\n                }\n\n                int h = (int)hCells.size();\n                hCells.push_back({});\n\n                while (j < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    hid[v] = h;\n                    hCells.back().push_back(v);\n                    j++;\n                }\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            int i = 0;\n            while (i < N) {\n                if (id[i][j] < 0) {\n                    i++;\n                    continue;\n                }\n\n                int vseg = (int)vCells.size();\n                vCells.push_back({});\n\n                while (i < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    vid[v] = vseg;\n                    vCells.back().push_back(v);\n                    i++;\n                }\n            }\n        }\n\n        visVal.assign(R, 0);\n        for (int v = 0; v < R; v++) {\n            visVal[v] = (int)hCells[hid[v]].size() + (int)vCells[vid[v]].size() - 1;\n        }\n    }\n\n    void computeAPSP() {\n        distMat.assign((size_t)R * R, INF16);\n        parMat.assign((size_t)R * R, 0);\n\n        vector<uint16_t> dist(R), par(R);\n        vector<int> score(R);\n        vector<unsigned char> used(R);\n        vector<vector<int>> buckets(10);\n        for (auto &b : buckets) b.reserve(max(1, R / 2));\n\n        for (int s = 0; s < R; s++) {\n            fill(dist.begin(), dist.end(), (uint16_t)INF16);\n            fill(par.begin(), par.end(), 0);\n            fill(score.begin(), score.end(), -1);\n            fill(used.begin(), used.end(), 0);\n            for (auto &b : buckets) b.clear();\n\n            dist[s] = 0;\n            par[s] = s;\n            score[s] = visVal[s];\n            buckets[0].push_back(s);\n\n            int cur = 0, done = 0;\n\n            while (done < R) {\n                auto &bk = buckets[cur % 10];\n\n                if (bk.empty()) {\n                    cur++;\n                    continue;\n                }\n\n                int v = bk.back();\n                bk.pop_back();\n\n                if (used[v] || dist[v] != cur) continue;\n\n                used[v] = 1;\n                done++;\n\n                for (int k = 0; k < 4; k++) {\n                    int to = nbr[v][k];\n                    if (to < 0 || used[to]) continue;\n\n                    int nd = cur + wt[to];\n                    int ns = score[v] + visVal[to];\n\n                    if (nd < dist[to] || (nd == dist[to] && ns > score[to])) {\n                        dist[to] = (uint16_t)nd;\n                        par[to] = (uint16_t)v;\n                        score[to] = ns;\n                        buckets[nd % 10].push_back(to);\n                    }\n                }\n            }\n\n            memcpy(distMat.data() + (size_t)s * R, dist.data(), sizeof(uint16_t) * R);\n            memcpy(parMat.data() + (size_t)s * R, par.data(), sizeof(uint16_t) * R);\n        }\n    }\n\n    void computeSegmentApprox() {\n        segMinH.assign(hCells.size(), 1e9);\n        segMinV.assign(vCells.size(), 1e9);\n\n        for (int v = 0; v < R; v++) {\n            int rt = D(S, v) + D(v, S);\n            segMinH[hid[v]] = min(segMinH[hid[v]], rt);\n            segMinV[vid[v]] = min(segMinV[vid[v]], rt);\n        }\n    }\n\n    void getPathCellsUnordered(int a, int b, vector<int> &out) const {\n        out.clear();\n        if (a == b) return;\n\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            int p = parMat[(size_t)a * R + cur];\n            cur = p;\n\n            if (++cnt > R + 5) {\n                out.clear();\n                return;\n            }\n        }\n    }\n\n    void getPathCellsOrdered(int a, int b, vector<int> &out) const {\n        getPathCellsUnordered(a, b, out);\n        reverse(out.begin(), out.end());\n    }\n\n    long long routeCost(const vector<int> &seq) const {\n        if (seq.empty()) return (1LL << 60);\n\n        long long ret = 0;\n        int m = (int)seq.size();\n\n        for (int i = 0; i < m; i++) {\n            ret += D(seq[i], seq[(i + 1) % m]);\n        }\n\n        return ret;\n    }\n\n    struct Cover {\n        const Solver *sol = nullptr;\n        vector<int> cntH, cntV;\n        int bad = 0;\n\n        void init(const Solver *s) {\n            sol = s;\n            cntH.assign(sol->hCells.size(), 0);\n            cntV.assign(sol->vCells.size(), 0);\n            bad = sol->R;\n        }\n\n        void addH(int h, int delta) {\n            int old = cntH[h];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad++;\n                }\n            }\n\n            cntH[h] = neu;\n        }\n\n        void addV(int v, int delta) {\n            int old = cntV[v];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad++;\n                }\n            }\n\n            cntV[v] = neu;\n        }\n\n        void addCell(int p, int delta) {\n            addH(sol->hid[p], delta);\n            addV(sol->vid[p], delta);\n        }\n    };\n\n    void applyPath(Cover &cov, const vector<int> &path, int delta) const {\n        for (int p : path) cov.addCell(p, delta);\n    }\n\n    bool checkpointFull(const vector<int> &seq) const {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n\n        return cov.bad == 0;\n    }\n\n    void buildStaticEdges(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        int m = (int)seq.size();\n        edgeCells.assign(m, {});\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, edgeCells[i]);\n        }\n    }\n\n    void ensureEdgeCells(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        if ((int)edgeCells.size() != (int)seq.size()) {\n            buildStaticEdges(seq, edgeCells);\n        }\n    }\n\n    void buildCoverFromEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells, Cover &cov) const {\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            for (int p : edgeCells[i]) cov.addCell(p, +1);\n        }\n    }\n\n    bool actualFullEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (seq.empty()) return false;\n\n        Cover cov;\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                for (int p : edgeCells[i]) cov.addCell(p, +1);\n            }\n        } else {\n            vector<int> path;\n            for (int i = 0; i < m; i++) {\n                int a = seq[i], b = seq[(i + 1) % m];\n                getPathCellsUnordered(a, b, path);\n                for (int p : path) cov.addCell(p, +1);\n            }\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool actualFull(const vector<int> &seq) const {\n        static const vector<vector<int>> emptyEdges;\n        return actualFullEdges(seq, emptyEdges);\n    }\n\n    bool validEdgePaths(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (edgeCells.empty()) return true;\n        int m = (int)seq.size();\n        if ((int)edgeCells.size() != m) return false;\n\n        for (int i = 0; i < m; i++) {\n            int cur = seq[i];\n            int cost = 0;\n\n            for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                int p = edgeCells[i][k];\n                int md = abs(rr[cur] - rr[p]) + abs(cc[cur] - cc[p]);\n                if (md != 1) return false;\n                cost += wt[p];\n                cur = p;\n            }\n\n            if (cur != seq[(i + 1) % m]) return false;\n            if (cost != D(seq[i], seq[(i + 1) % m])) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> constructCellCover(double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<unsigned char> covered(R, 0);\n        vector<int> remH(hCells.size()), remV(vCells.size());\n\n        for (int h = 0; h < (int)hCells.size(); h++) remH[h] = (int)hCells[h].size();\n        for (int v = 0; v < (int)vCells.size(); v++) remV[v] = (int)vCells[v].size();\n\n        int uncovered = R;\n\n        auto mark = [&](int q) {\n            if (!covered[q]) {\n                covered[q] = 1;\n                uncovered--;\n                remH[hid[q]]--;\n                remV[vid[q]]--;\n            }\n        };\n\n        auto addCover = [&](int p) {\n            for (int q : hCells[hid[p]]) mark(q);\n            for (int q : vCells[vid[p]]) mark(q);\n        };\n\n        addCover(S);\n\n        vector<double> gp(R + 1, 1.0);\n        for (int g = 1; g <= R; g++) gp[g] = pow((double)g, alpha);\n\n        while (uncovered > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = remH[hid[p]] + remV[vid[p]] - (covered[p] ? 0 : 1);\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int p = 0; p < R; p++) {\n                    if (!covered[p]) {\n                        bestP = p;\n                        bestPos = 0;\n                        break;\n                    }\n                }\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            addCover(bestP);\n        }\n\n        return seq;\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCoverWeights(const vector<long long> &wH,\n                                                                const vector<long long> &wV) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        long long sumW = 0;\n        for (long long x : wH) sumW += x;\n        for (long long x : wV) sumW += x;\n\n        int SRC = 0;\n        int offH = 1;\n        int offV = offH + nH;\n        int SNK = offV + nV;\n\n        Dinic din(SNK + 1);\n\n        for (int h = 0; h < nH; h++) din.add_edge(SRC, offH + h, wH[h]);\n        for (int v = 0; v < nV; v++) din.add_edge(offV + v, SNK, wV[v]);\n\n        long long INF = sumW + 1;\n\n        for (int p = 0; p < R; p++) {\n            din.add_edge(offH + hid[p], offV + vid[p], INF);\n        }\n\n        din.max_flow(SRC, SNK);\n        vector<int> reach = din.reachable_from(SRC);\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int h = 0; h < nH; h++) selH[h] = !reach[offH + h];\n        for (int v = 0; v < nV; v++) selV[v] = reach[offV + v];\n\n        for (int p = 0; p < R; p++) {\n            if (!selH[hid[p]] && !selV[vid[p]]) selH[hid[p]] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCover(int type) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<long long> wH(nH), wV(nV);\n\n        auto calcW = [&](int minRT, int len, int tp, bool isH) -> long long {\n            len = max(1, len);\n\n            if (tp == 0) return 1;\n            if (tp == 1) return 100 + minRT / 40;\n            if (tp == 2) return 1 + minRT / 20;\n            if (tp == 3) return 1 + minRT / len;\n            if (tp == 4) return 1 + (10LL * minRT) / max(1, len * len);\n            if (tp == 5) return (len <= 1 ? 10000LL + minRT : 1LL + minRT / max(1, 30 * len));\n            if (tp == 6) return max(1LL, 2000LL / len) + minRT / 100;\n            if (tp == 7) {\n                long long base = 1 + minRT / max(1, 18 * len);\n                return isH ? base * 9 : base * 11;\n            }\n\n            return 1 + minRT / max(1, (int)(8.0 * sqrt((double)len)));\n        };\n\n        for (int h = 0; h < nH; h++) {\n            wH[h] = calcW(segMinH[h], (int)hCells[h].size(), type, true);\n        }\n\n        for (int v = 0; v < nV; v++) {\n            wV[v] = calcW(segMinV[v], (int)vCells[v].size(), type, false);\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    pair<vector<char>, vector<char>> preferenceCover(int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int lh = (int)hCells[h].size();\n            int lv = (int)vCells[v].size();\n\n            bool chooseH = true;\n\n            if (mode == 0) {\n                if (lh != lv) chooseH = lh > lv;\n                else chooseH = segMinH[h] <= segMinV[v];\n            } else if (mode == 1) {\n                long long sh = 1000LL * segMinH[h] / max(1, lh);\n                long long sv = 1000LL * segMinV[v] / max(1, lv);\n                chooseH = sh <= sv;\n            } else {\n                long long sh = 100000LL * segMinH[h] / max(1, lh * lh);\n                long long sv = 100000LL * segMinV[v] / max(1, lv * lv);\n                chooseH = sh <= sv;\n            }\n\n            if (chooseH) selH[h] = 1;\n            else selV[v] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> insertionWeightedVertexCover(const vector<int> &base, int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        const int INF = 1e9;\n        vector<int> insH(nH, INF), insV(nV, INF);\n\n        int m = (int)base.size();\n\n        for (int p = 0; p < R; p++) {\n            int best = INF;\n\n            for (int i = 0; i < m; i++) {\n                int a = base[i], b = base[(i + 1) % m];\n                int extra = D(a, p) + D(p, b) - D(a, b);\n                if (extra < best) best = extra;\n            }\n\n            insH[hid[p]] = min(insH[hid[p]], best);\n            insV[vid[p]] = min(insV[vid[p]], best);\n        }\n\n        vector<long long> wH(nH), wV(nV);\n\n        for (int h = 0; h < nH; h++) {\n            int len = max(1, (int)hCells[h].size());\n            int c = insH[h] == INF ? segMinH[h] : insH[h];\n\n            if (mode == 0) wH[h] = 1 + c / len;\n            else wH[h] = 1 + (10LL * c) / max(1, len * len) + segMinH[h] / 250;\n        }\n\n        for (int v = 0; v < nV; v++) {\n            int len = max(1, (int)vCells[v].size());\n            int c = insV[v] == INF ? segMinV[v] : insV[v];\n\n            if (mode == 0) wV[v] = 1 + c / len;\n            else wV[v] = 1 + (10LL * c) / max(1, len * len) + segMinV[v] / 250;\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    vector<int> constructSegmentCover(const vector<char> &selH, const vector<char> &selV,\n                                      double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<char> touchH(hCells.size(), 0), touchV(vCells.size(), 0);\n\n        int remain = 0;\n        for (char x : selH) if (x) remain++;\n        for (char x : selV) if (x) remain++;\n\n        auto touch = [&](int p) {\n            int h = hid[p], v = vid[p];\n\n            if (selH[h] && !touchH[h]) {\n                touchH[h] = 1;\n                remain--;\n            }\n\n            if (selV[v] && !touchV[v]) {\n                touchV[v] = 1;\n                remain--;\n            }\n        };\n\n        touch(S);\n\n        double gp[3] = {1.0, 1.0, pow(2.0, alpha)};\n\n        while (remain > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = 0;\n                if (selH[hid[p]] && !touchH[hid[p]]) gain++;\n                if (selV[vid[p]] && !touchV[vid[p]]) gain++;\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int h = 0; h < (int)selH.size() && bestP < 0; h++) {\n                    if (selH[h] && !touchH[h]) bestP = hCells[h][0];\n                }\n\n                for (int v = 0; v < (int)selV.size() && bestP < 0; v++) {\n                    if (selV[v] && !touchV[v]) bestP = vCells[v][0];\n                }\n\n                bestPos = 0;\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            touch(bestP);\n        }\n\n        return seq;\n    }\n\n    bool twoOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n\n        for (int i = 0; i < m - 1; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            reverse(seq.begin() + bi + 1, seq.begin() + bk + 1);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool orOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        int bestDelta = 0, bi = -1, bj = -1;\n\n        for (int i = 1; i < m; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int removeCost = Sym(prev, x) + Sym(x, next) - Sym(prev, next);\n\n            for (int j = 0; j < m; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j], b = seq[(j + 1) % m];\n                int addCost = Sym(a, x) + Sym(x, b) - Sym(a, b);\n                int delta = addCost - removeCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            int x = seq[bi];\n            seq.erase(seq.begin() + bi);\n\n            int pos;\n            if (bj > bi) pos = bj;\n            else pos = bj + 1;\n\n            seq.insert(seq.begin() + pos, x);\n            return true;\n        }\n\n        return false;\n    }\n\n    void optimizeOrder(vector<int> &seq, double limit) {\n        while (timer.elapsed() < limit) {\n            bool improved = false;\n\n            if (twoOptOnce(seq)) improved = true;\n            if (timer.elapsed() >= limit) break;\n            if (orOptOnce(seq)) improved = true;\n\n            if (!improved) break;\n        }\n    }\n\n    void safeRemove(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n\n            for (int i = 1; i < m; i++) {\n                int x = seq[i];\n\n                cov.addCell(x, -1);\n\n                if (cov.bad == 0) {\n                    int prev = seq[i - 1];\n                    int next = seq[(i + 1) % m];\n                    int save = D(prev, x) + D(x, next) - D(prev, next);\n\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestIdx = i;\n                    }\n                }\n\n                cov.addCell(x, +1);\n            }\n\n            if (bestIdx < 0) break;\n\n            cov.addCell(seq[bestIdx], -1);\n            seq.erase(seq.begin() + bestIdx);\n        }\n    }\n\n    void improveReplace(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                token++;\n                if (token == INT_MAX) {\n                    fill(seen.begin(), seen.end(), 0);\n                    token = 1;\n                }\n\n                cov.addCell(old, -1);\n\n                auto evalCand = [&](int p) {\n                    if (seen[p] == token) return;\n                    seen[p] = token;\n\n                    if (p == old) return;\n\n                    int newCost = D(prev, p) + D(p, next);\n                    int delta = newCost - oldCost;\n\n                    if (delta >= bestDelta) return;\n\n                    cov.addCell(p, +1);\n\n                    if (cov.bad == 0) {\n                        bestDelta = delta;\n                        bestIdx = i;\n                        bestP = p;\n                    }\n\n                    cov.addCell(p, -1);\n                };\n\n                for (int p : hCells[hid[old]]) evalCand(p);\n                for (int p : vCells[vid[old]]) evalCand(p);\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    void improveReplaceCritical(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                cov.addCell(old, -1);\n\n                if (cov.bad > 0) {\n                    int fb = -1;\n                    for (int q = 0; q < R; q++) {\n                        if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                            fb = q;\n                            break;\n                        }\n                    }\n\n                    if (fb >= 0) {\n                        token++;\n                        if (token == INT_MAX) {\n                            fill(seen.begin(), seen.end(), 0);\n                            token = 1;\n                        }\n\n                        auto evalCand = [&](int p) {\n                            if (seen[p] == token) return;\n                            seen[p] = token;\n                            if (p == old) return;\n\n                            int newCost = D(prev, p) + D(p, next);\n                            int delta = newCost - oldCost;\n                            if (delta >= bestDelta) return;\n\n                            cov.addCell(p, +1);\n                            if (cov.bad == 0) {\n                                bestDelta = delta;\n                                bestIdx = i;\n                                bestP = p;\n                            }\n                            cov.addCell(p, -1);\n                        };\n\n                        for (int p : hCells[hid[fb]]) evalCand(p);\n                        for (int p : vCells[vid[fb]]) evalCand(p);\n                    }\n                }\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    vector<int> dynamicShortestPath(int a, int b, const Cover &cov) const {\n        vector<int> fallback;\n        getPathCellsUnordered(a, b, fallback);\n\n        if (a == b) return {};\n\n        int target = D(a, b);\n        if (target >= INF16) return fallback;\n\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<int> badH(nH, 0), badV(nV, 0);\n\n        if (cov.bad > 0) {\n            for (int q = 0; q < R; q++) {\n                if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                    badH[hid[q]]++;\n                    badV[vid[q]]++;\n                }\n            }\n        }\n\n        vector<int> reward(R, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int g = 0;\n\n            if (cov.cntH[h] == 0) g += badH[h];\n            if (cov.cntV[v] == 0) g += badV[v];\n            if (cov.cntH[h] == 0 && cov.cntV[v] == 0) g--;\n\n            reward[p] = g * 10000 + min(visVal[p], 9999);\n        }\n\n        vector<int> nodes;\n        nodes.reserve(R);\n\n        for (int p = 0; p < R; p++) {\n            if (D(a, p) + D(p, b) == target) nodes.push_back(p);\n        }\n\n        sort(nodes.begin(), nodes.end(), [&](int x, int y) {\n            int dx = D(a, x), dy = D(a, y);\n            if (dx != dy) return dx < dy;\n            return x < y;\n        });\n\n        const long long NEG = -(1LL << 60);\n        vector<long long> dp(R, NEG);\n        vector<int> parent(R, -1);\n\n        dp[a] = 0;\n        parent[a] = a;\n\n        for (int v : nodes) {\n            if (dp[v] == NEG) continue;\n\n            int dv = D(a, v);\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n                if (to < 0) continue;\n\n                if (dv + wt[to] != D(a, to)) continue;\n                if (D(a, to) + D(to, b) != target) continue;\n\n                long long ndp = dp[v] + reward[to];\n\n                if (ndp > dp[to]) {\n                    dp[to] = ndp;\n                    parent[to] = v;\n                }\n            }\n        }\n\n        if (parent[b] < 0) return fallback;\n\n        vector<int> out;\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            cur = parent[cur];\n\n            if (cur < 0 || ++cnt > R + 5) return fallback;\n        }\n\n        return out;\n    }\n\n    bool pathRemove(vector<int> &seq, vector<vector<int>> &edgeCells, double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n            vector<int> bestNewPath;\n\n            for (int i = 1; i < m; i++) {\n                int prev = seq[i - 1];\n                int x = seq[i];\n                int next = seq[(i + 1) % m];\n\n                int save = D(prev, x) + D(x, next) - D(prev, next);\n                if (save < bestSave) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n\n                vector<int> np;\n                getPathCellsUnordered(prev, next, np);\n\n                applyPath(cov, np, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand = np;\n\n                applyPath(cov, np, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    vector<int> dp = dynamicShortestPath(prev, next, cov);\n\n                    applyPath(cov, dp, +1);\n\n                    if (cov.bad == 0) {\n                        ok = true;\n                        cand = dp;\n                    }\n\n                    applyPath(cov, dp, -1);\n                }\n\n                if (ok && save > bestSave) {\n                    bestSave = save;\n                    bestIdx = i;\n                    bestNewPath = cand;\n                }\n\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            applyPath(cov, edgeCells[bestIdx - 1], -1);\n            applyPath(cov, edgeCells[bestIdx], -1);\n            applyPath(cov, bestNewPath, +1);\n\n            seq.erase(seq.begin() + bestIdx);\n            edgeCells[bestIdx - 1] = bestNewPath;\n            edgeCells.erase(edgeCells.begin() + bestIdx);\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool pathBlockRemove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                         double limit, int maxLen, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 2) break;\n\n            int bestL = -1, bestR = -1;\n            int bestSave = 0;\n            vector<int> bestPath;\n\n            for (int len = 2; len <= maxLen; len++) {\n                if (len >= m) break;\n\n                for (int l = 1; l + len - 1 < m; l++) {\n                    int r = l + len - 1;\n                    int prev = seq[l - 1];\n                    int next = seq[(r + 1) % m];\n\n                    int oldCost = 0;\n                    for (int e = l - 1; e <= r; e++) {\n                        oldCost += D(seq[e], seq[(e + 1) % m]);\n                    }\n\n                    int save = oldCost - D(prev, next);\n                    if (save <= bestSave) continue;\n\n                    for (int e = l - 1; e <= r; e++) applyPath(cov, edgeCells[e], -1);\n\n                    vector<int> np;\n                    getPathCellsUnordered(prev, next, np);\n                    applyPath(cov, np, +1);\n\n                    bool ok = cov.bad == 0;\n                    vector<int> cand = np;\n\n                    applyPath(cov, np, -1);\n\n                    if (!ok && useDynamic && timer.elapsed() < limit) {\n                        vector<int> dp = dynamicShortestPath(prev, next, cov);\n                        applyPath(cov, dp, +1);\n\n                        if (cov.bad == 0) {\n                            ok = true;\n                            cand = dp;\n                        }\n\n                        applyPath(cov, dp, -1);\n                    }\n\n                    if (ok && save > bestSave) {\n                        bestSave = save;\n                        bestL = l;\n                        bestR = r;\n                        bestPath = cand;\n                    }\n\n                    for (int e = r; e >= l - 1; e--) applyPath(cov, edgeCells[e], +1);\n\n                    if (timer.elapsed() >= limit) break;\n                }\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestL < 0) break;\n\n            for (int e = bestL - 1; e <= bestR; e++) applyPath(cov, edgeCells[e], -1);\n            applyPath(cov, bestPath, +1);\n\n            seq.erase(seq.begin() + bestL, seq.begin() + bestR + 1);\n            edgeCells[bestL - 1] = bestPath;\n            edgeCells.erase(edgeCells.begin() + bestL, edgeCells.begin() + bestR + 1);\n        }\n\n        return cov.bad == 0;\n    }\n\n    vector<int> reverseEdgePath(const vector<int> &oldPath, int oldSource) const {\n        vector<int> ret;\n        if (oldPath.empty()) return ret;\n\n        ret.reserve(oldPath.size());\n        ret.push_back(oldSource);\n\n        for (int i = (int)oldPath.size() - 1; i >= 1; i--) {\n            ret.push_back(oldPath[i]);\n        }\n\n        return ret;\n    }\n\n    bool actualTwoOptOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                          Cover &cov, double limit, bool useDynamic) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n        vector<int> bestP1, bestP2;\n        vector<vector<int>> bestMid;\n\n        for (int i = 0; i < m - 1 && timer.elapsed() < limit; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m && timer.elapsed() < limit; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta >= bestDelta) continue;\n\n                for (int e = i; e <= k; e++) applyPath(cov, edgeCells[e], -1);\n\n                vector<vector<int>> mid;\n                mid.reserve(max(0, k - i - 1));\n\n                for (int ne = i + 1; ne <= k - 1; ne++) {\n                    int oldIdx = i + k - ne;\n                    mid.push_back(reverseEdgePath(edgeCells[oldIdx], seq[oldIdx]));\n                    applyPath(cov, mid.back(), +1);\n                }\n\n                vector<int> p1, p2;\n                getPathCellsUnordered(a, c, p1);\n                getPathCellsUnordered(b, d, p2);\n\n                applyPath(cov, p1, +1);\n                applyPath(cov, p2, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand1 = p1, cand2 = p2;\n\n                applyPath(cov, p2, -1);\n                applyPath(cov, p1, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    cand1 = dynamicShortestPath(a, c, cov);\n                    applyPath(cov, cand1, +1);\n\n                    cand2 = dynamicShortestPath(b, d, cov);\n                    applyPath(cov, cand2, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, cand2, -1);\n                    applyPath(cov, cand1, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                    bestP1 = cand1;\n                    bestP2 = cand2;\n                    bestMid = mid;\n                }\n\n                for (auto &v : mid) applyPath(cov, v, -1);\n                for (int e = k; e >= i; e--) applyPath(cov, edgeCells[e], +1);\n            }\n        }\n\n        if (bi < 0) return false;\n\n        for (int e = bi; e <= bk; e++) applyPath(cov, edgeCells[e], -1);\n        applyPath(cov, bestP1, +1);\n        for (auto &v : bestMid) applyPath(cov, v, +1);\n        applyPath(cov, bestP2, +1);\n\n        vector<int> newSeq = seq;\n        reverse(newSeq.begin() + bi + 1, newSeq.begin() + bk + 1);\n\n        vector<vector<int>> newEdges = edgeCells;\n        newEdges[bi] = bestP1;\n        for (int t = 0; t < (int)bestMid.size(); t++) {\n            newEdges[bi + 1 + t] = bestMid[t];\n        }\n        newEdges[bk] = bestP2;\n\n        seq.swap(newSeq);\n        edgeCells.swap(newEdges);\n\n        return true;\n    }\n\n    bool actualTwoOptImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                             double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        bool any = false;\n\n        while (timer.elapsed() < limit) {\n            bool ok = actualTwoOptOnce(seq, edgeCells, cov, limit, useDynamic);\n            if (!ok) break;\n            any = true;\n        }\n\n        return any && cov.bad == 0;\n    }\n\n    void applyOrOptMove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                        int i, int j,\n                        const vector<int> &pPrevNext,\n                        const vector<int> &pAX,\n                        const vector<int> &pXB) {\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n        int m = (int)oldSeq.size();\n\n        vector<int> ns;\n        vector<vector<int>> ne(m);\n\n        ns.reserve(m);\n\n        if (j < i) {\n            for (int k = 0; k <= j; k++) ns.push_back(oldSeq[k]);\n            ns.push_back(oldSeq[i]);\n            for (int k = j + 1; k <= i - 1; k++) ns.push_back(oldSeq[k]);\n            for (int k = i + 1; k < m; k++) ns.push_back(oldSeq[k]);\n\n            for (int k = 0; k < j; k++) ne[k] = oldEdges[k];\n            ne[j] = pAX;\n            ne[j + 1] = pXB;\n            for (int k = j + 2; k <= i - 1; k++) ne[k] = oldEdges[k - 1];\n            ne[i] = pPrevNext;\n            for (int k = i + 1; k < m; k++) ne[k] = oldEdges[k];\n        } else {\n            for (int k = 0; k <= i - 1; k++) ns.push_back(oldSeq[k]);\n            for (int k = i + 1; k <= j; k++) ns.push_back(oldSeq[k]);\n            ns.push_back(oldSeq[i]);\n            for (int k = j + 1; k < m; k++) ns.push_back(oldSeq[k]);\n\n            for (int k = 0; k <= i - 2; k++) ne[k] = oldEdges[k];\n            ne[i - 1] = pPrevNext;\n            for (int k = i; k <= j - 2; k++) ne[k] = oldEdges[k + 1];\n            ne[j - 1] = pAX;\n            ne[j] = pXB;\n            for (int k = j + 1; k < m; k++) ne[k] = oldEdges[k];\n        }\n\n        if ((int)ns.size() == m && (int)ne.size() == m) {\n            seq.swap(ns);\n            edgeCells.swap(ne);\n        }\n    }\n\n    bool actualOrOptOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                         double limit, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n        vector<int> bestPN, bestAX, bestXB;\n\n        for (int i = 1; i < m && timer.elapsed() < limit; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int oldCost = D(prev, x) + D(x, next);\n\n            for (int j = 0; j < m && timer.elapsed() < limit; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n\n                int delta = D(prev, next) + D(a, x) + D(x, b)\n                          - oldCost - D(a, b);\n\n                if (delta >= bestDelta) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n                applyPath(cov, edgeCells[j], -1);\n\n                vector<int> pn, ax, xb;\n                getPathCellsUnordered(prev, next, pn);\n                getPathCellsUnordered(a, x, ax);\n                getPathCellsUnordered(x, b, xb);\n\n                applyPath(cov, pn, +1);\n                applyPath(cov, ax, +1);\n                applyPath(cov, xb, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> candPN = pn, candAX = ax, candXB = xb;\n\n                applyPath(cov, xb, -1);\n                applyPath(cov, ax, -1);\n                applyPath(cov, pn, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    candPN = dynamicShortestPath(prev, next, cov);\n                    applyPath(cov, candPN, +1);\n                    candAX = dynamicShortestPath(a, x, cov);\n                    applyPath(cov, candAX, +1);\n                    candXB = dynamicShortestPath(x, b, cov);\n                    applyPath(cov, candXB, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, candXB, -1);\n                    applyPath(cov, candAX, -1);\n                    applyPath(cov, candPN, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                    bestPN = candPN;\n                    bestAX = candAX;\n                    bestXB = candXB;\n                }\n\n                applyPath(cov, edgeCells[j], +1);\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n            }\n        }\n\n        if (bestI < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        applyOrOptMove(seq, edgeCells, bestI, bestJ, bestPN, bestAX, bestXB);\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualOrOptImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                            double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualOrOptOnce(seq, edgeCells, limit, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool actualReplaceOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                           double limit, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 2) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestI = -1, bestP = -1;\n        vector<int> bestA, bestB;\n\n        for (int i = 1; i < m && timer.elapsed() < limit; i++) {\n            int old = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int oldCost = D(prev, old) + D(old, next);\n\n            applyPath(cov, edgeCells[i - 1], -1);\n            applyPath(cov, edgeCells[i], -1);\n\n            for (int p = 0; p < R && timer.elapsed() < limit; p++) {\n                if (p == old || p == prev || p == next) continue;\n\n                int delta = D(prev, p) + D(p, next) - oldCost;\n                if (delta >= bestDelta) continue;\n\n                vector<int> pa, pb;\n                getPathCellsUnordered(prev, p, pa);\n                getPathCellsUnordered(p, next, pb);\n\n                applyPath(cov, pa, +1);\n                applyPath(cov, pb, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> ca = pa, cb = pb;\n\n                applyPath(cov, pb, -1);\n                applyPath(cov, pa, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    ca = dynamicShortestPath(prev, p, cov);\n                    applyPath(cov, ca, +1);\n                    cb = dynamicShortestPath(p, next, cov);\n                    applyPath(cov, cb, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, cb, -1);\n                    applyPath(cov, ca, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestP = p;\n                    bestA = ca;\n                    bestB = cb;\n                }\n            }\n\n            applyPath(cov, edgeCells[i], +1);\n            applyPath(cov, edgeCells[i - 1], +1);\n        }\n\n        if (bestI < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        seq[bestI] = bestP;\n        edgeCells[bestI - 1] = bestA;\n        edgeCells[bestI] = bestB;\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualReplaceImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                              double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualReplaceOnce(seq, edgeCells, limit, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool actualBlockReplaceOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                                double limit, int maxLen, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestL = -1, bestR = -1, bestP = -1;\n        vector<int> bestA, bestB;\n\n        for (int len = 2; len <= maxLen && timer.elapsed() < limit; len++) {\n            if (len >= m) break;\n\n            for (int l = 1; l + len - 1 < m && timer.elapsed() < limit; l++) {\n                int r = l + len - 1;\n                int prev = seq[l - 1];\n                int next = seq[(r + 1) % m];\n\n                int oldCost = 0;\n                for (int e = l - 1; e <= r; e++) {\n                    oldCost += D(seq[e], seq[(e + 1) % m]);\n                }\n\n                for (int e = l - 1; e <= r; e++) applyPath(cov, edgeCells[e], -1);\n\n                for (int p = 0; p < R && timer.elapsed() < limit; p++) {\n                    if (p == prev || p == next) continue;\n\n                    int delta = D(prev, p) + D(p, next) - oldCost;\n                    if (delta >= bestDelta) continue;\n\n                    vector<int> pa, pb;\n                    getPathCellsUnordered(prev, p, pa);\n                    getPathCellsUnordered(p, next, pb);\n\n                    applyPath(cov, pa, +1);\n                    applyPath(cov, pb, +1);\n\n                    bool ok = cov.bad == 0;\n                    vector<int> ca = pa, cb = pb;\n\n                    applyPath(cov, pb, -1);\n                    applyPath(cov, pa, -1);\n\n                    if (!ok && useDynamic && timer.elapsed() < limit) {\n                        ca = dynamicShortestPath(prev, p, cov);\n                        applyPath(cov, ca, +1);\n                        cb = dynamicShortestPath(p, next, cov);\n                        applyPath(cov, cb, +1);\n\n                        if (cov.bad == 0) ok = true;\n\n                        applyPath(cov, cb, -1);\n                        applyPath(cov, ca, -1);\n                    }\n\n                    if (ok) {\n                        bestDelta = delta;\n                        bestL = l;\n                        bestR = r;\n                        bestP = p;\n                        bestA = ca;\n                        bestB = cb;\n                    }\n                }\n\n                for (int e = r; e >= l - 1; e--) applyPath(cov, edgeCells[e], +1);\n            }\n        }\n\n        if (bestL < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        seq.erase(seq.begin() + bestL, seq.begin() + bestR + 1);\n        seq.insert(seq.begin() + bestL, bestP);\n\n        edgeCells[bestL - 1] = bestA;\n        edgeCells.erase(edgeCells.begin() + bestL, edgeCells.begin() + bestR + 1);\n        edgeCells.insert(edgeCells.begin() + bestL, bestB);\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualBlockReplaceImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                                   double limit, int maxLen, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualBlockReplaceOnce(seq, edgeCells, limit, maxLen, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    int edgeCellTotal(const vector<vector<int>> &edgeCells) const {\n        int ret = 0;\n        for (auto &v : edgeCells) ret += (int)v.size();\n        return ret;\n    }\n\n    void updateFinalStatic(const vector<int> &seq) {\n        long long c = routeCost(seq);\n\n        if (c < bestFinalCost) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges.clear();\n        }\n    }\n\n    void updateFinalRoute(const vector<int> &seq, const vector<vector<int>> &edgeCells) {\n        long long c = routeCost(seq);\n\n        if (c > bestFinalCost) return;\n        if (!actualFullEdges(seq, edgeCells)) return;\n        if (!edgeCells.empty() && !validEdgePaths(seq, edgeCells)) return;\n\n        bool upd = false;\n\n        if (c < bestFinalCost) {\n            upd = true;\n        } else if (c == bestFinalCost && !edgeCells.empty()) {\n            if (bestFinalEdges.empty() || edgeCellTotal(edgeCells) > edgeCellTotal(bestFinalEdges)) {\n                upd = true;\n            }\n        }\n\n        if (upd) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges = edgeCells;\n        }\n    }\n\n    void updateSafe(const vector<int> &seq) {\n        if (!checkpointFull(seq)) return;\n\n        long long c = routeCost(seq);\n\n        if (c < bestSafeCost) {\n            bestSafeCost = c;\n            bestSafeSeq = seq;\n        }\n\n        updateFinalStatic(seq);\n    }\n\n    void processCandidate(vector<int> seq, bool heavy) {\n        if (seq.empty()) return;\n\n        double lim = min(2.50, timer.elapsed() + (heavy ? 0.22 : 0.08));\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n        if (timer.elapsed() < lim) safeRemove(seq, lim);\n\n        if (heavy && timer.elapsed() < lim) {\n            improveReplace(seq, lim);\n            improveReplaceCritical(seq, lim);\n            safeRemove(seq, lim);\n        }\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.62) {\n            vector<int> pseq = seq;\n            vector<vector<int>> pedges;\n\n            double plim = min(2.67, timer.elapsed() + (heavy ? 0.085 : 0.045));\n            bool dyn = heavy || timer.elapsed() < 1.80;\n\n            if (pathRemove(pseq, pedges, plim, dyn)) {\n                if (heavy && timer.elapsed() < plim) {\n                    pathBlockRemove(pseq, pedges, plim, 2, dyn);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    string buildOutput(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        string ans;\n        ans.reserve(200000);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                int cur = seq[i];\n\n                for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                    int p = edgeCells[i][k];\n                    ans.push_back(moveChar(cur, p));\n                    cur = p;\n                }\n            }\n\n            return ans;\n        }\n\n        vector<int> path;\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsOrdered(a, b, path);\n\n            int cur = a;\n\n            for (int p : path) {\n                ans.push_back(moveChar(cur, p));\n                cur = p;\n            }\n        }\n\n        return ans;\n    }\n\n    string dfsFallback() const {\n        vector<vector<int>> child(R);\n        vector<int> par(R, -1);\n        queue<int> q;\n\n        par[S] = S;\n        q.push(S);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n\n                if (to >= 0 && par[to] < 0) {\n                    par[to] = v;\n                    child[v].push_back(to);\n                    q.push(to);\n                }\n            }\n        }\n\n        string ans;\n        ans.reserve(max(0, 2 * (R - 1)));\n\n        function<void(int)> dfs = [&](int v) {\n            for (int to : child[v]) {\n                ans.push_back(moveChar(v, to));\n                dfs(to);\n                ans.push_back(moveChar(to, v));\n            }\n        };\n\n        dfs(S);\n        return ans;\n    }\n\n    void finalPolish() {\n        if (bestSafeSeq.empty() || timer.elapsed() > 2.76) return;\n\n        vector<int> seq = bestSafeSeq;\n        double lim = 2.84;\n\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n        improveReplace(seq, lim);\n        improveReplaceCritical(seq, lim);\n        safeRemove(seq, lim);\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.86) {\n            vector<int> pseq = seq;\n            vector<vector<int>> pedges;\n\n            if (pathRemove(pseq, pedges, 2.89, true)) {\n                if (timer.elapsed() < 2.895) {\n                    pathBlockRemove(pseq, pedges, 2.908, 3, true);\n                }\n\n                if (timer.elapsed() < 2.908) {\n                    actualBlockReplaceImprove(pseq, pedges, 2.925, 2, false);\n                }\n\n                if (timer.elapsed() < 2.925) {\n                    actualTwoOptImprove(pseq, pedges, 2.938, true);\n                }\n\n                if (timer.elapsed() < 2.938) {\n                    actualOrOptImprove(pseq, pedges, 2.948, false);\n                }\n\n                if (timer.elapsed() < 2.948) {\n                    actualReplaceImprove(pseq, pedges, 2.955, false);\n                }\n\n                if (timer.elapsed() < 2.955) {\n                    pathRemove(pseq, pedges, 2.960, true);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    void finalActualPolish() {\n        if (bestFinalSeq.empty() || timer.elapsed() > 2.91) return;\n\n        vector<int> seq = bestFinalSeq;\n        vector<vector<int>> edges = bestFinalEdges;\n        ensureEdgeCells(seq, edges);\n\n        if (!actualFullEdges(seq, edges)) return;\n\n        if (timer.elapsed() < 2.915) {\n            pathBlockRemove(seq, edges, 2.925, 3, true);\n        }\n\n        if (timer.elapsed() < 2.925) {\n            actualBlockReplaceImprove(seq, edges, 2.940, 2, false);\n        }\n\n        if (timer.elapsed() < 2.940) {\n            actualOrOptImprove(seq, edges, 2.950, false);\n        }\n\n        if (timer.elapsed() < 2.950) {\n            actualReplaceImprove(seq, edges, 2.957, false);\n        }\n\n        if (timer.elapsed() < 2.957) {\n            pathRemove(seq, edges, 2.962, true);\n        }\n\n        updateFinalRoute(seq, edges);\n    }\n\n    void solve() {\n        readInput();\n        buildRoadGraph();\n        buildSegments();\n        computeAPSP();\n        computeSegmentApprox();\n\n        vector<pair<double, double>> cellParams = {\n            {1.25, 0.0},\n            {1.00, 0.0},\n            {1.50, 0.0},\n            {0.75, 0.0},\n            {1.25, 30.0},\n            {1.70, 80.0}\n        };\n\n        for (int i = 0; i < (int)cellParams.size(); i++) {\n            if (i > 0 && timer.elapsed() > 2.18) break;\n\n            auto [a, l] = cellParams[i];\n            vector<int> seq = constructCellCover(a, l);\n            processCandidate(seq, i == 0);\n        }\n\n        vector<int> vcTypes = {0, 2, 3, 1, 5, 4, 6, 7};\n\n        for (int tp : vcTypes) {\n            if (timer.elapsed() > 2.34) break;\n\n            auto [selH, selV] = weightedVertexCover(tp);\n\n            vector<int> seq = constructSegmentCover(selH, selV, 1.0, 25.0);\n            processCandidate(seq, false);\n\n            if (timer.elapsed() > 2.34) break;\n\n            if (tp == 0) {\n                vector<int> seq2 = constructSegmentCover(selH, selV, 1.0, 0.0);\n                processCandidate(seq2, false);\n            }\n        }\n\n        for (int mode = 0; mode < 3; mode++) {\n            if (timer.elapsed() > 2.40) break;\n\n            auto [selH, selV] = preferenceCover(mode);\n            vector<int> seq = constructSegmentCover(selH, selV, 1.2, 10.0);\n            processCandidate(seq, false);\n        }\n\n        if (!bestSafeSeq.empty()) {\n            for (int mode = 0; mode < 2; mode++) {\n                if (timer.elapsed() > 2.43) break;\n\n                auto [selH, selV] = insertionWeightedVertexCover(bestSafeSeq, mode);\n                vector<int> seq = constructSegmentCover(selH, selV, 1.0, 15.0);\n                processCandidate(seq, false);\n            }\n        }\n\n        finalPolish();\n        finalActualPolish();\n\n        if (!bestFinalSeq.empty() &&\n            actualFullEdges(bestFinalSeq, bestFinalEdges) &&\n            validEdgePaths(bestFinalSeq, bestFinalEdges)) {\n            cout << buildOutput(bestFinalSeq, bestFinalEdges) << '\\n';\n        } else if (!bestSafeSeq.empty() && actualFull(bestSafeSeq)) {\n            vector<vector<int>> emptyEdges;\n            cout << buildOutput(bestSafeSeq, emptyEdges) << '\\n';\n        } else {\n            cout << dfsFallback() << '\\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\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconst int MAXN = 1000;\nconst int MAXM = 20;\nconst int MAXK = 20;\nconst int PARTICLES = 128;\n\nint N, M, K, R;\nint reqv[MAXN][MAXK];\n\nvector<int> children_[MAXN];\n\nint statusTask[MAXN]; // 0: unstarted, 1: running, 2: done\nint remDep[MAXN];\nint readyDay[MAXN];\n\nint sumReq[MAXN];\nint descCnt[MAXN];\n\ndouble baseDur[MAXN];\ndouble predDur[MAXM][MAXN];\ndouble sumPred[MAXN];\ndouble upRank_[MAXN];\n\ndouble priorSkill[MAXK];\nint initSkill[MAXK];\nint upperSkill[MAXK];\n\nstatic bitset<MAXN> reachBits[MAXN];\n\nunsigned char particleSkill[PARTICLES][MAXK];\ndouble particlePrior[PARTICLES];\ndouble particleLoss[MAXM][PARTICLES];\n\nstruct Member {\n    int skill[MAXK];\n    vector<int> obsTask;\n    vector<int> obsDur;\n    int task = -1;\n    int startDay = 0;\n};\n\nMember members_[MAXM];\n\ninline double expectedTimeFromW(int w) {\n    if (w <= 0) return 1.0;\n    if (w == 1) return 13.0 / 7.0;\n    if (w == 2) return 17.0 / 7.0;\n    if (w == 3) return 22.0 / 7.0;\n    return (double)w;\n}\n\ninline int calcW(int task, const int skill[]) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        if (reqv[task][k] > skill[k]) {\n            w += reqv[task][k] - skill[k];\n        }\n    }\n    return w;\n}\n\ninline int calcWParticle(int task, int p) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        int s = (int)particleSkill[p][k];\n        if (reqv[task][k] > s) {\n            w += reqv[task][k] - s;\n        }\n    }\n    return w;\n}\n\ninline double durationWithSkill(int task, const int skill[]) {\n    return expectedTimeFromW(calcW(task, skill));\n}\n\ninline double obsLoss(int w, int t) {\n    double p = expectedTimeFromW(w);\n    double diff = p - t;\n    return diff * diff;\n}\n\nconst double PRIOR_W = 0.003;\n\ninline double priorLossComp(int k, int v) {\n    double diff = v - priorSkill[k];\n    return PRIOR_W * diff * diff;\n}\n\nvoid generateParticles() {\n    mt19937 rng(123456789);\n    normal_distribution<double> nd(0.0, 1.0);\n\n    for (int p = 0; p < PARTICLES; p++) {\n        double z[MAXK];\n        double norm = 0.0;\n\n        for (int k = 0; k < K; k++) {\n            z[k] = fabs(nd(rng));\n            norm += z[k] * z[k];\n        }\n\n        norm = sqrt(max(norm, 1e-12));\n\n        // Stratified norm q in [20, 60], matching the generator distribution.\n        double q = 20.0 + 40.0 * ((double)p + 0.5) / (double)PARTICLES;\n\n        particlePrior[p] = 0.0;\n\n        for (int k = 0; k < K; k++) {\n            int v = (int)llround(q * z[k] / norm);\n            v = max(0, min(60, v));\n            particleSkill[p][k] = (unsigned char)v;\n            particlePrior[p] += priorLossComp(k, v);\n        }\n    }\n\n    for (int j = 0; j < MAXM; j++) {\n        for (int p = 0; p < PARTICLES; p++) {\n            particleLoss[j][p] = 0.0;\n        }\n    }\n}\n\nvoid updateParticleLoss(int member, int task, int dur) {\n    for (int p = 0; p < PARTICLES; p++) {\n        int w = calcWParticle(task, p);\n        particleLoss[member][p] += obsLoss(w, dur);\n    }\n}\n\ndouble runCoordinateDescent(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return 0.0;\n\n    vector<int> w(O);\n    for (int i = 0; i < O; i++) {\n        w[i] = calcW(mem.obsTask[i], mem.skill);\n    }\n\n    double curPrior = 0.0;\n    for (int k = 0; k < K; k++) {\n        curPrior += priorLossComp(k, mem.skill[k]);\n    }\n\n    double curObj = curPrior;\n    for (int i = 0; i < O; i++) {\n        curObj += obsLoss(w[i], mem.obsDur[i]);\n    }\n\n    const int MAX_PASS = 4;\n\n    for (int pass = 0; pass < MAX_PASS; pass++) {\n        bool improved = false;\n\n        for (int k = 0; k < K; k++) {\n            int oldVal = mem.skill[k];\n            double priorExcept = curPrior - priorLossComp(k, oldVal);\n\n            int bestVal = oldVal;\n            double bestObj = curObj;\n\n            for (int v = 0; v <= upperSkill[k]; v++) {\n                if (v == oldVal) continue;\n\n                double obj = priorExcept + priorLossComp(k, v);\n\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > v) {\n                        newContrib = reqv[task][k] - v;\n                    }\n\n                    int nw = w[i] - oldContrib + newContrib;\n                    obj += obsLoss(nw, mem.obsDur[i]);\n\n                    if (obj >= bestObj) break;\n                }\n\n                if (obj + 1e-9 < bestObj) {\n                    bestObj = obj;\n                    bestVal = v;\n                }\n            }\n\n            if (bestVal != oldVal) {\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > bestVal) {\n                        newContrib = reqv[task][k] - bestVal;\n                    }\n\n                    w[i] += newContrib - oldContrib;\n                }\n\n                mem.skill[k] = bestVal;\n                curPrior = priorExcept + priorLossComp(k, bestVal);\n                curObj = bestObj;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return curObj;\n}\n\nvoid optimizeMember(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return;\n\n    // Original optimizer first.\n    double obj = runCoordinateDescent(j);\n\n    // Conservative multi-start fallback.\n    // Use it only after enough observations, and only if a sampled realistic skill\n    // vector is already clearly better than the current local optimum.\n    int threshold = max(6, K / 2);\n    if (O >= threshold) {\n        int bestP = -1;\n        double bestObj = 1e100;\n\n        for (int p = 0; p < PARTICLES; p++) {\n            double cand = particleLoss[j][p] + particlePrior[p];\n            if (cand < bestObj) {\n                bestObj = cand;\n                bestP = p;\n            }\n        }\n\n        if (bestP >= 0 && bestObj + 0.5 < obj) {\n            for (int k = 0; k < K; k++) {\n                mem.skill[k] = (int)particleSkill[bestP][k];\n            }\n            runCoordinateDescent(j);\n        }\n    }\n}\n\nvoid updateMemberPredictions(int j) {\n    Member &mem = members_[j];\n\n    double nobs = (double)mem.obsTask.size();\n    double trust = 0.0;\n    if (nobs > 0) trust = nobs / (nobs + 3.0);\n\n    for (int i = 0; i < N; i++) {\n        double pSkill = durationWithSkill(i, mem.skill);\n        double np = trust * pSkill + (1.0 - trust) * baseDur[i];\n\n        sumPred[i] += np - predDur[j][i];\n        predDur[j][i] = np;\n    }\n}\n\nvoid recomputeRanks() {\n    for (int i = N - 1; i >= 0; i--) {\n        if (statusTask[i] == 2) {\n            upRank_[i] = 0.0;\n            continue;\n        }\n\n        double mx = 0.0;\n        for (int v : children_[i]) {\n            if (statusTask[v] != 2) {\n                mx = max(mx, upRank_[v]);\n            }\n        }\n\n        double avg = sumPred[i] / M;\n        upRank_[i] = avg + 0.015 * sumReq[i] + mx;\n    }\n}\n\ndouble taskPriority(int task, int day) {\n    double pr = upRank_[task];\n\n    pr += 0.015 * descCnt[task];\n    pr += 0.25 * (double)children_[task].size();\n\n    int unlock = 0;\n    for (int v : children_[task]) {\n        if (statusTask[v] == 0 && remDep[v] == 1) unlock++;\n    }\n    pr += 2.0 * unlock;\n\n    if (readyDay[task] > 0) {\n        pr += 0.015 * max(0, day - readyDay[task]);\n    }\n\n    return pr;\n}\n\ndouble edgeScore(int member, int task, double prio) {\n    double avg = sumPred[task] / M;\n    double p = predDur[member][task];\n\n    return prio + 0.4 * avg - p;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n\n    int V;\n    vector<vector<Edge>> graph;\n\n    MinCostFlow(int n = 0) {\n        init(n);\n    }\n\n    void init(int n) {\n        V = n;\n        graph.assign(V, {});\n    }\n\n    void addEdge(int fr, int to, int cap, ll cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge r{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(r);\n    }\n\n    pair<int, ll> minCostFlow(int s, int t, int maxf) {\n        const ll INF = (1LL << 62);\n\n        int flow = 0;\n        ll cost = 0;\n\n        vector<ll> h(V, 0), dist(V);\n        vector<int> prevv(V), preve(V);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != cd) continue;\n\n                for (int i = 0; i < (int)graph[v].size(); i++) {\n                    Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n\n                    ll nd = dist[v] + e.cost + h[v] - h[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INF) break;\n\n            for (int v = 0; v < V; v++) {\n                if (dist[v] < INF) h[v] += dist[v];\n            }\n\n            int add = maxf - flow;\n            ll pathCost = 0;\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                add = min(add, e.cap);\n                pathCost += e.cost;\n            }\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= add;\n                graph[v][e.rev].cap += add;\n            }\n\n            flow += add;\n            cost += pathCost * add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> K >> R)) return 0;\n\n    for (int i = 0; i < N; i++) {\n        sumReq[i] = 0;\n        for (int k = 0; k < K; k++) {\n            cin >> reqv[i][k];\n            sumReq[i] += reqv[i][k];\n        }\n    }\n\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u;\n        --v;\n        children_[u].push_back(v);\n        remDep[v]++;\n    }\n\n    double pi = acos(-1.0);\n    double priorComp = 40.0 * sqrt(2.0 / (pi * K));\n\n    for (int k = 0; k < K; k++) {\n        priorSkill[k] = priorComp;\n        initSkill[k] = (int)round(priorComp);\n        initSkill[k] = max(0, min(60, initSkill[k]));\n        upperSkill[k] = 60;\n    }\n\n    generateParticles();\n\n    for (int j = 0; j < M; j++) {\n        for (int k = 0; k < K; k++) {\n            members_[j].skill[k] = initSkill[k];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        baseDur[i] = durationWithSkill(i, initSkill);\n        sumPred[i] = 0.0;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int i = 0; i < N; i++) {\n            predDur[j][i] = baseDur[i];\n            sumPred[i] += predDur[j][i];\n        }\n    }\n\n    for (int i = N - 1; i >= 0; i--) {\n        for (int v : children_[i]) {\n            reachBits[i] |= reachBits[v];\n            reachBits[i].set(v);\n        }\n        descCnt[i] = (int)reachBits[i].count();\n    }\n\n    for (int i = 0; i < N; i++) {\n        statusTask[i] = 0;\n        readyDay[i] = (remDep[i] == 0 ? 1 : -1);\n    }\n\n    static double prioArr[MAXN];\n\n    for (int day = 1;; day++) {\n        recomputeRanks();\n\n        vector<int> idle;\n        for (int j = 0; j < M; j++) {\n            if (members_[j].task < 0) idle.push_back(j);\n        }\n\n        vector<int> readyTasks;\n        for (int i = 0; i < N; i++) {\n            if (statusTask[i] == 0 && remDep[i] == 0) {\n                readyTasks.push_back(i);\n            }\n        }\n\n        vector<pair<int, int>> assignments;\n\n        if (!idle.empty() && !readyTasks.empty()) {\n            for (int task : readyTasks) {\n                prioArr[task] = taskPriority(task, day);\n            }\n\n            vector<int> sortedReady = readyTasks;\n            sort(sortedReady.begin(), sortedReady.end(), [&](int a, int b) {\n                if (prioArr[a] != prioArr[b]) return prioArr[a] > prioArr[b];\n                return a < b;\n            });\n\n            vector<int> candidates;\n            vector<char> inCand(N, 0);\n\n            auto addCandidate = [&](int task) {\n                if (!inCand[task]) {\n                    inCand[task] = 1;\n                    candidates.push_back(task);\n                }\n            };\n\n            int topC = min((int)sortedReady.size(), max(200, (int)idle.size() * 10));\n            for (int i = 0; i < topC; i++) {\n                addCandidate(sortedReady[i]);\n            }\n\n            const int BEST_PER_MEMBER = 10;\n\n            for (int member : idle) {\n                priority_queue<\n                    pair<double, int>,\n                    vector<pair<double, int>>,\n                    greater<pair<double, int>>\n                > pq;\n\n                for (int task : readyTasks) {\n                    double sc = edgeScore(member, task, prioArr[task]);\n                    if ((int)pq.size() < BEST_PER_MEMBER) {\n                        pq.push({sc, task});\n                    } else if (sc > pq.top().first) {\n                        pq.pop();\n                        pq.push({sc, task});\n                    }\n                }\n\n                while (!pq.empty()) {\n                    addCandidate(pq.top().second);\n                    pq.pop();\n                }\n            }\n\n            int I = (int)idle.size();\n            int C = (int)candidates.size();\n            int F = min(I, min(C, (int)readyTasks.size()));\n\n            if (F > 0) {\n                int S = 0;\n                int memberBase = 1;\n                int taskBase = memberBase + I;\n                int T = taskBase + C;\n\n                MinCostFlow mcf(T + 1);\n\n                for (int i = 0; i < I; i++) {\n                    mcf.addEdge(S, memberBase + i, 1, 0);\n                }\n\n                for (int c = 0; c < C; c++) {\n                    mcf.addEdge(taskBase + c, T, 1, 0);\n                }\n\n                const ll SCALE = 1000;\n                const ll OFFSET = 1000000000000000LL;\n\n                for (int i = 0; i < I; i++) {\n                    int member = idle[i];\n                    for (int c = 0; c < C; c++) {\n                        int task = candidates[c];\n                        double sc = edgeScore(member, task, prioArr[task]);\n                        ll isc = llround(sc * SCALE);\n                        ll cost = OFFSET - isc;\n                        if (cost < 0) cost = 0;\n                        mcf.addEdge(memberBase + i, taskBase + c, 1, cost);\n                    }\n                }\n\n                mcf.minCostFlow(S, T, F);\n\n                for (int i = 0; i < I; i++) {\n                    int node = memberBase + i;\n\n                    for (auto &e : mcf.graph[node]) {\n                        if (e.to >= taskBase && e.to < taskBase + C && e.cap == 0) {\n                            int member = idle[i];\n                            int task = candidates[e.to - taskBase];\n\n                            if (members_[member].task < 0 &&\n                                statusTask[task] == 0 &&\n                                remDep[task] == 0) {\n                                assignments.push_back({member, task});\n                            }\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        for (auto [member, task] : assignments) {\n            members_[member].task = task;\n            members_[member].startDay = day;\n            statusTask[task] = 1;\n        }\n\n        cout << assignments.size();\n        for (auto [member, task] : assignments) {\n            cout << ' ' << member + 1 << ' ' << task + 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int nFinished;\n        if (!(cin >> nFinished)) return 0;\n        if (nFinished == -1) return 0;\n\n        for (int x = 0; x < nFinished; x++) {\n            int f;\n            cin >> f;\n            --f;\n\n            int task = members_[f].task;\n            if (task < 0) continue;\n\n            int dur = day - members_[f].startDay + 1;\n\n            statusTask[task] = 2;\n            members_[f].task = -1;\n\n            members_[f].obsTask.push_back(task);\n            members_[f].obsDur.push_back(dur);\n\n            updateParticleLoss(f, task, dur);\n            optimizeMember(f);\n            updateMemberPredictions(f);\n\n            for (int v : children_[task]) {\n                remDep[v]--;\n                if (remDep[v] == 0 && statusTask[v] == 0) {\n                    readyDay[v] = day + 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NORD = 1000;\nstatic constexpr int OFF = 1000;\nstatic constexpr int NID = 2001;\nstatic constexpr int INF = 1e9;\n\nint X[NID], Y[NID];\nint orderCentral[NORD + 1];\nvector<unsigned short> distMat;\n\ninline int distId(int a, int b) {\n    return distMat[a * NID + b];\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int m) {\n        return (int)(next() % (uint64_t)m);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct InsertRes {\n    int delta;\n    int p;\n    int q;\n};\n\nstruct Solution {\n    vector<int> route;\n    bitset<NORD + 1> selected;\n    int len = INF;\n};\n\nint routeCost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distId(route[i], route[i + 1]);\n    }\n    return s;\n}\n\nint selectedCount(const Solution& sol) {\n    return (int)sol.selected.count();\n}\n\nvector<int> selectedList(const Solution& sol) {\n    vector<int> v;\n    v.reserve(50);\n    for (int i = 1; i <= NORD; i++) {\n        if (sol.selected.test(i)) v.push_back(i);\n    }\n    return v;\n}\n\nInsertRes bestInsertion(const vector<int>& route, int oid) {\n    static constexpr int MAXG = 205;\n\n    int G = (int)route.size() - 1;\n    int P = oid;\n    int D = OFF + oid;\n    int pd = distId(P, D);\n\n    int addP[MAXG], addD[MAXG], consec[MAXG];\n    int suf[MAXG + 1], sufIdx[MAXG + 1];\n\n    for (int g = 0; g < G; g++) {\n        int A = route[g];\n        int B = route[g + 1];\n        int base = distId(A, B);\n\n        int dAP = distId(A, P);\n        int dPB = distId(P, B);\n        int dAD = distId(A, D);\n        int dDB = distId(D, B);\n\n        addP[g] = dAP + dPB - base;\n        addD[g] = dAD + dDB - base;\n        consec[g] = dAP + pd + dDB - base;\n    }\n\n    suf[G] = INF;\n    sufIdx[G] = -1;\n    for (int g = G - 1; g >= 0; g--) {\n        if (addD[g] <= suf[g + 1]) {\n            suf[g] = addD[g];\n            sufIdx[g] = g;\n        } else {\n            suf[g] = suf[g + 1];\n            sufIdx[g] = sufIdx[g + 1];\n        }\n    }\n\n    InsertRes best{INF, 0, 0};\n\n    for (int p = 0; p < G; p++) {\n        if (consec[p] < best.delta) {\n            best = {consec[p], p, p};\n        }\n        if (p + 1 < G) {\n            int cost = addP[p] + suf[p + 1];\n            if (cost < best.delta) {\n                best = {cost, p, sufIdx[p + 1]};\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid insertOrder(vector<int>& route, int oid, const InsertRes& res) {\n    int P = oid;\n    int D = OFF + oid;\n\n    if (res.q == res.p) {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.p + 2, D);\n    } else {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.q + 2, D);\n    }\n}\n\nSolution buildGreedy(int seed) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    auto add = [&](int oid, const InsertRes& res) {\n        insertOrder(sol.route, oid, res);\n        sol.selected.set(oid);\n        sol.len += res.delta;\n        cnt++;\n    };\n\n    if (seed > 0) {\n        InsertRes res = bestInsertion(sol.route, seed);\n        add(seed, res);\n    }\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        add(bestOid, best);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildFromPool(const vector<int>& pool) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid : pool) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        if (bestOid == -1) {\n            for (int oid = 1; oid <= NORD; oid++) {\n                if (sol.selected.test(oid)) continue;\n\n                InsertRes res = bestInsertion(sol.route, oid);\n                int tie = orderCentral[oid];\n\n                if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                    best = res;\n                    bestOid = oid;\n                    bestTie = tie;\n                }\n            }\n        }\n\n        insertOrder(sol.route, bestOid, best);\n        sol.selected.set(bestOid);\n        sol.len += best.delta;\n        cnt++;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildRandomizedGreedy(const vector<int>& pool, XorShift& rng, int topR, int bias) {\n    struct Choice {\n        int rank;\n        int oid;\n        InsertRes res;\n    };\n\n    topR = min(topR, 16);\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    for (int cnt = 0; cnt < 50; cnt++) {\n        Choice top[16];\n        int ts = 0;\n\n        auto consider = [&](int oid) {\n            if (sol.selected.test(oid)) return;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rank = res.delta + bias * orderCentral[oid] / 100;\n\n            Choice c{rank, oid, res};\n\n            if (ts < topR) {\n                top[ts++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < ts; i++) {\n                    if (top[i].rank > top[worst].rank) worst = i;\n                }\n                if (c.rank < top[worst].rank) top[worst] = c;\n            }\n        };\n\n        for (int oid : pool) consider(oid);\n\n        if (ts == 0) {\n            for (int oid = 1; oid <= NORD; oid++) consider(oid);\n        }\n\n        sort(top, top + ts, [](const Choice& a, const Choice& b) {\n            if (a.rank != b.rank) return a.rank < b.rank;\n            return a.oid < b.oid;\n        });\n\n        int pick = 0;\n        if (ts > 1) {\n            int r = rng.nextInt(100);\n            if (r < 55) pick = 0;\n            else if (r < 75) pick = min(1, ts - 1);\n            else if (r < 90) pick = min(2, ts - 1);\n            else pick = rng.nextInt(ts);\n        }\n\n        Choice c = top[pick];\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nvector<Solution> buildBeam(const vector<int>& pool, int W, int K, int bias) {\n    struct State {\n        vector<int> route;\n        bitset<NORD + 1> selected;\n        int len;\n    };\n\n    struct Choice {\n        int rank;\n        int len;\n        int oid;\n        InsertRes res;\n    };\n\n    K = min(K, 16);\n\n    vector<State> beam;\n    State init;\n    init.route = {0, 0};\n    init.selected.reset();\n    init.len = 0;\n    beam.push_back(init);\n\n    for (int step = 0; step < 50; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int oid) {\n                if (st.selected.test(oid)) return;\n\n                InsertRes res = bestInsertion(st.route, oid);\n                int nl = st.len + res.delta;\n                int rank = nl + bias * orderCentral[oid] / 100;\n\n                Choice c{rank, nl, oid, res};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int oid : pool) consider(oid);\n\n            if (ts == 0) {\n                for (int oid = 1; oid <= NORD; oid++) consider(oid);\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                if (a.rank != b.rank) return a.rank < b.rank;\n                return a.oid < b.oid;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                insertOrder(ch.route, top[i].oid, top[i].res);\n                ch.selected.set(top[i].oid);\n                ch.len = top[i].len;\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            return a.len < b.len;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    vector<Solution> res;\n    for (auto& st : beam) {\n        if ((int)st.selected.count() != 50) continue;\n\n        Solution sol;\n        sol.route = std::move(st.route);\n        sol.selected = st.selected;\n        sol.len = routeCost(sol.route);\n        res.push_back(std::move(sol));\n    }\n\n    sort(res.begin(), res.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    return res;\n}\n\nvector<int> removeOrderRoute(const vector<int>& route, int oid) {\n    vector<int> nr;\n    nr.reserve(route.size() - 2);\n\n    int P = oid;\n    int D = OFF + oid;\n\n    for (int id : route) {\n        if (id != P && id != D) nr.push_back(id);\n    }\n    return nr;\n}\n\nbool twoOptDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int delPos[NORD + 1];\n        for (int i = 0; i <= NORD; i++) delPos[i] = -1;\n\n        for (int i = 0; i < n; i++) {\n            int id = sol.route[i];\n            if (id > OFF) delPos[id - OFF] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        bool timeout = false;\n\n        for (int l = 1; l <= n - 3; l++) {\n            if ((l & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int minDelivery = INF;\n\n            for (int r = l; r <= n - 2; r++) {\n                int node = sol.route[r];\n\n                if (1 <= node && node <= NORD) {\n                    minDelivery = min(minDelivery, delPos[node]);\n                }\n\n                if (r == l) continue;\n\n                // Invalid iff interval contains pickup and delivery of the same order.\n                if (minDelivery <= r) continue;\n\n                int A = sol.route[l - 1];\n                int B = sol.route[l];\n                int C = sol.route[r];\n                int D = sol.route[r + 1];\n\n                int delta = distId(A, C) + distId(B, D) -\n                            distId(A, B) - distId(C, D);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta < 0) {\n            reverse(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSegmentMoveFast(const vector<int>& route, const int pos[], int l, int r, int k) {\n    int oids[8];\n    int cnt = 0;\n\n    for (int i = l; i <= r; i++) {\n        int id = route[i];\n        int oid = (id <= OFF ? id : id - OFF);\n\n        bool exists = false;\n        for (int j = 0; j < cnt; j++) {\n            if (oids[j] == oid) {\n                exists = true;\n                break;\n            }\n        }\n\n        if (!exists) oids[cnt++] = oid;\n    }\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        bool inP = (l <= pp && pp <= r);\n        bool inD = (l <= dd && dd <= r);\n\n        if (inP && !inD) {\n            if (!(k < dd)) return false;\n        } else if (!inP && inD) {\n            if (!(k >= pp)) return false;\n        }\n    }\n\n    return true;\n}\n\nbool orOptDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        int bestK = -1;\n\n        int checks = 0;\n        bool timeout = false;\n\n        for (int len = 1; len <= maxSegLen; len++) {\n            for (int l = 1; l + len - 1 <= n - 2; l++) {\n                int r = l + len - 1;\n\n                int oldLR = distId(sol.route[l - 1], sol.route[l]) +\n                            distId(sol.route[r], sol.route[r + 1]);\n\n                for (int k = 0; k <= n - 2; k++) {\n                    if (++checks % 8192 == 0 && timer.elapsed() >= deadline) {\n                        timeout = true;\n                        break;\n                    }\n\n                    if (k >= l - 1 && k <= r) continue;\n\n                    int delta =\n                        distId(sol.route[l - 1], sol.route[r + 1]) +\n                        distId(sol.route[k], sol.route[l]) +\n                        distId(sol.route[r], sol.route[k + 1]) -\n                        oldLR -\n                        distId(sol.route[k], sol.route[k + 1]);\n\n                    if (delta >= bestDelta) continue;\n\n                    if (!validSegmentMoveFast(sol.route, pos, l, r, k)) continue;\n\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                    bestK = k;\n                }\n\n                if (timeout) break;\n            }\n            if (timeout) break;\n        }\n\n        if (bestDelta < 0) {\n            int segLen = bestR - bestL + 1;\n            vector<int> seg(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n\n            if (bestK < bestL) {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                sol.route.insert(sol.route.begin() + bestK + 1, seg.begin(), seg.end());\n            } else {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                int ins = bestK - segLen + 1;\n                sol.route.insert(sol.route.begin() + ins, seg.begin(), seg.end());\n            }\n\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSwapFast(const vector<int>& route, const int pos[], int i, int j) {\n    int a = route[i];\n    int b = route[j];\n\n    int oids[2];\n    int cnt = 0;\n\n    auto addOid = [&](int id) {\n        int oid = (id <= OFF ? id : id - OFF);\n        for (int z = 0; z < cnt; z++) {\n            if (oids[z] == oid) return;\n        }\n        oids[cnt++] = oid;\n    };\n\n    addOid(a);\n    addOid(b);\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        if (pp == i) pp = j;\n        else if (pp == j) pp = i;\n\n        if (dd == i) dd = j;\n        else if (dd == j) dd = i;\n\n        if (pp >= dd) return false;\n    }\n\n    return true;\n}\n\nbool swapDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) pos[sol.route[i]] = i;\n\n        int bestDelta = 0;\n        int bestI = -1;\n        int bestJ = -1;\n\n        bool timeout = false;\n\n        for (int i = 1; i <= n - 3; i++) {\n            if ((i & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            for (int j = i + 1; j <= n - 2; j++) {\n                int u = sol.route[i];\n                int v = sol.route[j];\n\n                int delta;\n\n                if (i + 1 == j) {\n                    int A = sol.route[i - 1];\n                    int B = sol.route[j + 1];\n\n                    delta = distId(A, v) + distId(v, u) + distId(u, B)\n                          - distId(A, u) - distId(u, v) - distId(v, B);\n                } else {\n                    int Ai = sol.route[i - 1];\n                    int Bi = sol.route[i + 1];\n                    int Aj = sol.route[j - 1];\n                    int Bj = sol.route[j + 1];\n\n                    delta = distId(Ai, v) + distId(v, Bi) +\n                            distId(Aj, u) + distId(u, Bj) -\n                            distId(Ai, u) - distId(u, Bi) -\n                            distId(Aj, v) - distId(v, Bj);\n                }\n\n                if (delta >= bestDelta) continue;\n                if (!validSwapFast(sol.route, pos, i, j)) continue;\n\n                bestDelta = delta;\n                bestI = i;\n                bestJ = j;\n            }\n        }\n\n        if (bestDelta < 0) {\n            swap(sol.route[bestI], sol.route[bestJ]);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool routeDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen = 3, bool doSwap = false) {\n    bool any = false;\n\n    for (int rep = 0; rep < 5 && timer.elapsed() < deadline; rep++) {\n        bool moved = false;\n\n        if (twoOptDescent(sol, timer, deadline)) moved = true;\n\n        if (timer.elapsed() >= deadline) break;\n\n        if (orOptDescent(sol, timer, deadline, maxSegLen)) moved = true;\n\n        if (doSwap && timer.elapsed() < deadline) {\n            if (swapDescent(sol, timer, deadline)) moved = true;\n        }\n\n        if (!moved) break;\n        any = true;\n    }\n\n    sol.len = routeCost(sol.route);\n    return any;\n}\n\nbool findAndApplyBestPairMove(Solution& sol, Timer& timer, double deadline) {\n    int cur = sol.len;\n    vector<int> sel = selectedList(sol);\n\n    int bestNewLen = cur;\n    int bestRem = -1;\n    int bestIns = -1;\n\n    bool stop = false;\n\n    for (int idx = 0; idx < (int)sel.size(); idx++) {\n        if (timer.elapsed() >= deadline) break;\n\n        int rem = sel[idx];\n        vector<int> tmp = removeOrderRoute(sol.route, rem);\n        int lenTmp = routeCost(tmp);\n\n        {\n            InsertRes res = bestInsertion(tmp, rem);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = rem;\n            }\n        }\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if ((oid & 63) == 0 && timer.elapsed() >= deadline) {\n                stop = true;\n                break;\n            }\n\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(tmp, oid);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = oid;\n            }\n        }\n\n        if (stop) break;\n    }\n\n    if (bestRem == -1) return false;\n\n    vector<int> tmp = removeOrderRoute(sol.route, bestRem);\n\n    if (bestIns != bestRem) {\n        sol.selected.reset(bestRem);\n        sol.selected.set(bestIns);\n    }\n\n    InsertRes res = bestInsertion(tmp, bestIns);\n    insertOrder(tmp, bestIns, res);\n\n    sol.route.swap(tmp);\n    sol.len = routeCost(sol.route);\n\n    return sol.len < cur;\n}\n\nvoid localImprove(Solution& sol, Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 3, false);\n\n        if (timer.elapsed() >= deadline) break;\n\n        bool moved = findAndApplyBestPairMove(sol, timer, deadline);\n        if (!moved) break;\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nSolution rebuildFixedOrder(const Solution& base, vector<int> orders) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    for (int oid : orders) {\n        InsertRes res = bestInsertion(sol.route, oid);\n        insertOrder(sol.route, oid, res);\n        sol.len += res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildFixedGreedy(const Solution& base) {\n    vector<int> orders = selectedList(base);\n    int m = (int)orders.size();\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    vector<char> used(m, 0);\n\n    for (int cnt = 0; cnt < m; cnt++) {\n        int bestIdx = -1;\n        InsertRes best{INF, 0, 0};\n\n        for (int i = 0; i < m; i++) {\n            if (used[i]) continue;\n\n            InsertRes res = bestInsertion(sol.route, orders[i]);\n            if (res.delta < best.delta) {\n                best = res;\n                bestIdx = i;\n            }\n        }\n\n        used[bestIdx] = 1;\n        insertOrder(sol.route, orders[bestIdx], best);\n        sol.len += best.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildSequentialBeam(const Solution& base, int W, int K) {\n    vector<int> orders = selectedList(base);\n    int M = (int)orders.size();\n    if (M != 50) return base;\n\n    struct State {\n        uint64_t picked;\n        uint64_t delivered;\n        int last;\n        int cost;\n        int eval;\n        vector<int> route;\n    };\n\n    struct Choice {\n        int rank;\n        int node;\n        int idx;\n        int type;\n        int add;\n    };\n\n    uint64_t fullMask = (1ULL << M) - 1ULL;\n\n    vector<State> beam;\n    State init;\n    init.picked = 0;\n    init.delivered = 0;\n    init.last = 0;\n    init.cost = 0;\n    init.eval = 0;\n    init.route = {0};\n    beam.push_back(init);\n\n    for (int step = 0; step < 2 * M; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int node, int idx, int type) {\n                int add = distId(st.last, node);\n                int rank = add + distId(node, 0) / 6;\n\n                Choice c{rank, node, idx, type, add};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int j = 0; j < M; j++) {\n                uint64_t bit = 1ULL << j;\n\n                if (!(st.picked & bit)) {\n                    consider(orders[j], j, 0);\n                } else if (!(st.delivered & bit)) {\n                    consider(OFF + orders[j], j, 1);\n                }\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                return a.rank < b.rank;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                uint64_t bit = 1ULL << top[i].idx;\n\n                if (top[i].type == 0) ch.picked |= bit;\n                else ch.delivered |= bit;\n\n                ch.last = top[i].node;\n                ch.cost += top[i].add;\n                ch.eval = ch.cost + distId(ch.last, 0);\n                ch.route.push_back(top[i].node);\n\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    int best = -1;\n    int bestCost = INF;\n\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (beam[i].delivered != fullMask) continue;\n\n        int c = beam[i].cost + distId(beam[i].last, 0);\n        if (c < bestCost) {\n            bestCost = c;\n            best = i;\n        }\n    }\n\n    if (best == -1) return base;\n\n    Solution sol;\n    sol.selected = base.selected;\n    sol.route = std::move(beam[best].route);\n    sol.route.push_back(0);\n    sol.len = routeCost(sol.route);\n\n    return sol;\n}\n\nvoid tryRebuilds(Solution& sol, XorShift& rng, Timer& timer, double deadline) {\n    if (timer.elapsed() >= deadline) return;\n\n    {\n        Solution g = rebuildFixedGreedy(sol);\n        routeDescent(g, timer, min(deadline, timer.elapsed() + 0.030), 2, false);\n        if (g.len < sol.len) sol = std::move(g);\n    }\n\n    if (timer.elapsed() < deadline) {\n        Solution b = rebuildSequentialBeam(sol, 60, 6);\n        routeDescent(b, timer, min(deadline, timer.elapsed() + 0.035), 2, false);\n        if (b.len < sol.len) sol = std::move(b);\n    }\n\n    for (int it = 0; it < 2 && timer.elapsed() < deadline; it++) {\n        vector<int> orders = selectedList(sol);\n\n        for (int i = (int)orders.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(orders[i], orders[j]);\n        }\n\n        Solution r = rebuildFixedOrder(sol, orders);\n        routeDescent(r, timer, min(deadline, timer.elapsed() + 0.025), 2, false);\n\n        if (r.len < sol.len) sol = std::move(r);\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nstruct Cand {\n    int rankCost;\n    int oid;\n    InsertRes res;\n};\n\nSolution ruinRecreate(const Solution& base, int k, XorShift& rng, Timer& timer, double deadline) {\n    Solution sol = base;\n    vector<int> sel = selectedList(base);\n    k = min(k, (int)sel.size());\n\n    vector<char> rem(NORD + 1, 0);\n    vector<int> toRemove;\n\n    int strategy = rng.nextInt(4);\n\n    if (strategy == 0) {\n        vector<pair<int, int>> savings;\n        savings.reserve(sel.size());\n\n        for (int oid : sel) {\n            vector<int> tmp = removeOrderRoute(base.route, oid);\n            int l = routeCost(tmp);\n            savings.push_back({base.len - l, oid});\n        }\n\n        sort(savings.begin(), savings.end(), [](const auto& a, const auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int topLimit = min(25, (int)savings.size());\n\n        while ((int)toRemove.size() < k) {\n            int idx;\n            if (rng.nextInt(100) < 75) idx = rng.nextInt(topLimit);\n            else idx = rng.nextInt((int)savings.size());\n\n            int oid = savings[idx].second;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 1) {\n        while ((int)toRemove.size() < k) {\n            int oid = sel[rng.nextInt((int)sel.size())];\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 2) {\n        int pos[NID];\n        for (int i = 0; i < (int)base.route.size(); i++) {\n            pos[base.route[i]] = i;\n        }\n\n        int seed = sel[rng.nextInt((int)sel.size())];\n        int sp = pos[seed];\n        int sd = pos[OFF + seed];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int pp = pos[oid];\n            int dd = pos[OFF + oid];\n\n            int sc = min({\n                abs(pp - sp),\n                abs(pp - sd),\n                abs(dd - sp),\n                abs(dd - sd)\n            });\n\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else {\n        int seed = sel[rng.nextInt((int)sel.size())];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int sc1 = distId(seed, oid) + distId(OFF + seed, OFF + oid);\n            int sc2 = distId(seed, OFF + oid) + distId(OFF + seed, oid);\n            int sc = min(sc1, sc2);\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    }\n\n    for (int oid : toRemove) {\n        sol.selected.reset(oid);\n    }\n\n    vector<int> nr;\n    nr.reserve(base.route.size());\n\n    for (int id : base.route) {\n        if (id == 0) {\n            nr.push_back(id);\n        } else {\n            int oid = (id <= OFF ? id : id - OFF);\n            if (!rem[oid]) nr.push_back(id);\n        }\n    }\n\n    sol.route.swap(nr);\n    sol.len = routeCost(sol.route);\n\n    int removedPenalty = 8 + rng.nextInt(45);\n\n    for (int t = 0; t < k; t++) {\n        static constexpr int R = 7;\n        Cand top[R];\n        int topSize = 0;\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rankCost = res.delta + (rem[oid] ? removedPenalty : 0) + rng.nextInt(7);\n\n            Cand c{rankCost, oid, res};\n\n            if (topSize < R) {\n                top[topSize++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < R; i++) {\n                    if (top[i].rankCost > top[worst].rankCost) worst = i;\n                }\n                if (c.rankCost < top[worst].rankCost) top[worst] = c;\n            }\n        }\n\n        sort(top, top + topSize, [](const Cand& a, const Cand& b) {\n            return a.rankCost < b.rankCost;\n        });\n\n        int pick = 0;\n        if (topSize > 1) {\n            int roll = rng.nextInt(100);\n            if (roll < 62) pick = 0;\n            else if (roll < 82) pick = min(1, topSize - 1);\n            else if (roll < 93) pick = min(2, topSize - 1);\n            else pick = rng.nextInt(topSize);\n        }\n\n        Cand c = top[pick];\n\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    if (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 2, false);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nbool validate(const Solution& sol) {\n    if (selectedCount(sol) != 50) return false;\n    if (sol.route.empty()) return false;\n    if (sol.route.front() != 0 || sol.route.back() != 0) return false;\n\n    vector<int> pp(NORD + 1, -1), dd(NORD + 1, -1);\n\n    for (int i = 0; i < (int)sol.route.size(); i++) {\n        int id = sol.route[i];\n\n        if (id == 0) continue;\n\n        if (1 <= id && id <= NORD) {\n            pp[id] = i;\n        } else if (OFF < id && id <= OFF + NORD) {\n            dd[id - OFF] = i;\n        } else {\n            return false;\n        }\n    }\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (!sol.selected.test(oid)) continue;\n        if (pp[oid] == -1 || dd[oid] == -1) return false;\n        if (pp[oid] >= dd[oid]) return false;\n    }\n\n    return true;\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    for (int i = 1; i <= NORD; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n\n        X[i] = a;\n        Y[i] = b;\n        X[OFF + i] = c;\n        Y[OFF + i] = d;\n    }\n\n    distMat.assign(NID * NID, 0);\n\n    for (int i = 0; i < NID; i++) {\n        for (int j = 0; j <= i; j++) {\n            int v = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n            distMat[i * NID + j] = distMat[j * NID + i] = (unsigned short)v;\n        }\n    }\n\n    vector<pair<int, int>> firstCost;\n    firstCost.reserve(NORD);\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        int dP = distId(0, oid);\n        int dD = distId(0, OFF + oid);\n        int pd = distId(oid, OFF + oid);\n\n        orderCentral[oid] = dP + dD;\n        firstCost.push_back({dP + pd + dD, oid});\n    }\n\n    sort(firstCost.begin(), firstCost.end());\n\n    Timer timer;\n    XorShift rng(1234567891234567ull);\n\n    vector<int> allIds(NORD);\n    iota(allIds.begin(), allIds.end(), 1);\n\n    vector<Solution> candidates;\n\n    auto addCandidate = [&](Solution sol) {\n        if (selectedCount(sol) == 50) {\n            sol.len = routeCost(sol.route);\n            candidates.push_back(std::move(sol));\n        }\n    };\n\n    addCandidate(buildGreedy(firstCost[0].second));\n\n    const double INIT_DEAD = 0.52;\n\n    for (int idx = 1; idx < 10 && timer.elapsed() < 0.22; idx++) {\n        addCandidate(buildGreedy(firstCost[idx].second));\n    }\n\n    if (timer.elapsed() < 0.32) {\n        auto sols = buildBeam(allIds, 8, 4, 0);\n        for (int i = 0; i < (int)sols.size() && i < 4; i++) {\n            addCandidate(std::move(sols[i]));\n        }\n    }\n\n    vector<vector<int>> sortedModes;\n\n    for (int mode = 0; mode < 8; mode++) {\n        vector<pair<int, int>> score;\n        score.reserve(NORD);\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            int dP = distId(0, oid);\n            int dD = distId(0, OFF + oid);\n            int pd = distId(oid, OFF + oid);\n\n            int linf = max({\n                abs(X[oid] - 400),\n                abs(Y[oid] - 400),\n                abs(X[OFF + oid] - 400),\n                abs(Y[OFF + oid] - 400)\n            });\n\n            int mid = abs(X[oid] + X[OFF + oid] - 800) +\n                      abs(Y[oid] + Y[OFF + oid] - 800);\n\n            int dxSpan = abs(X[oid] - X[OFF + oid]);\n            int dySpan = abs(Y[oid] - Y[OFF + oid]);\n\n            int sc;\n\n            if (mode == 0) {\n                sc = dP + dD;\n            } else if (mode == 1) {\n                sc = max(dP, dD) * 2000 + dP + dD;\n            } else if (mode == 2) {\n                sc = dP + dD + pd;\n            } else if (mode == 3) {\n                sc = linf * 2000 + dP + dD;\n            } else if (mode == 4) {\n                sc = max(dP, dD) * 3 + min(dP, dD);\n            } else if (mode == 5) {\n                sc = dP + dD + mid;\n            } else if (mode == 6) {\n                sc = linf * 3000 + pd;\n            } else {\n                sc = dP + dD + max(dxSpan, dySpan);\n            }\n\n            score.push_back({sc, oid});\n        }\n\n        sort(score.begin(), score.end());\n\n        vector<int> ord;\n        ord.reserve(NORD);\n        for (auto [sc, oid] : score) ord.push_back(oid);\n        sortedModes.push_back(std::move(ord));\n    }\n\n    vector<int> poolSizes = {55, 70, 90, 130, 200, 300};\n\n    for (int mode = 0; mode < (int)sortedModes.size(); mode++) {\n        for (int ps : poolSizes) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            ps = min(ps, (int)sortedModes[mode].size());\n            vector<int> pool(sortedModes[mode].begin(), sortedModes[mode].begin() + ps);\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    // Shifted compact-cluster pools.\n    vector<int> centers = {250, 300, 350, 400, 450, 500, 550};\n\n    for (int cx : centers) {\n        for (int cy : centers) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                int lp = abs(X[oid] - cx) + abs(Y[oid] - cy);\n                int ld = abs(X[OFF + oid] - cx) + abs(Y[OFF + oid] - cy);\n\n                int infp = max(abs(X[oid] - cx), abs(Y[oid] - cy));\n                int infd = max(abs(X[OFF + oid] - cx), abs(Y[OFF + oid] - cy));\n\n                int centerPenalty = abs(cx - 400) + abs(cy - 400);\n                int sc = max(infp, infd) * 3000 + max(lp, ld) * 3 + centerPenalty * 20;\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            int ps = 110;\n            vector<int> pool;\n            pool.reserve(ps);\n            for (int i = 0; i < ps; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    // Directional sector / half-plane pools.\n    for (int sx : {-1, 1}) {\n        for (int sy : {-1, 1}) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                auto outsidePoint = [&](int id) {\n                    int px = sx * (X[id] - 400);\n                    int py = sy * (Y[id] - 400);\n                    return max(0, -px) + max(0, -py);\n                };\n\n                int out = outsidePoint(oid) + outsidePoint(OFF + oid);\n                int far = max(distId(0, oid), distId(0, OFF + oid));\n                int sc = out * 10000 + far * 10 + orderCentral[oid];\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            vector<int> pool;\n            for (int i = 0; i < 130; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    for (int axis = 0; axis < 2; axis++) {\n        for (int sgn : {-1, 1}) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                auto outsidePoint = [&](int id) {\n                    int v = (axis == 0 ? X[id] - 400 : Y[id] - 400);\n                    return max(0, -sgn * v);\n                };\n\n                int out = outsidePoint(oid) + outsidePoint(OFF + oid);\n                int far = max(distId(0, oid), distId(0, OFF + oid));\n                int sc = out * 10000 + far * 10 + orderCentral[oid];\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            vector<int> pool;\n            for (int i = 0; i < 170; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    while (timer.elapsed() < INIT_DEAD && (int)candidates.size() < 65) {\n        if (rng.nextInt(2) == 0) {\n            addCandidate(buildRandomizedGreedy(allIds, rng, 8, 0));\n        } else {\n            int mi = rng.nextInt((int)sortedModes.size());\n            int ps = min(300, (int)sortedModes[mi].size());\n            vector<int> pool(sortedModes[mi].begin(), sortedModes[mi].begin() + ps);\n            addCandidate(buildRandomizedGreedy(pool, rng, 8, 2));\n        }\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    if (candidates.empty()) {\n        candidates.push_back(buildGreedy(firstCost[0].second));\n    }\n\n    const double QUICK_DEAD = 0.72;\n\n    for (int i = 0; i < (int)candidates.size() && i < 14 && timer.elapsed() < QUICK_DEAD; i++) {\n        double sub = min(QUICK_DEAD, timer.elapsed() + 0.020);\n        routeDescent(candidates[i], timer, sub, 2, false);\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    Solution bestOverall = candidates[0];\n\n    const double LOCAL_DEAD = 1.40;\n\n    int starts = min(5, (int)candidates.size());\n\n    for (int i = 0; i < starts && timer.elapsed() < LOCAL_DEAD; i++) {\n        Solution sol = candidates[i];\n\n        double sub = min(LOCAL_DEAD, timer.elapsed() + 0.15);\n        localImprove(sol, timer, sub);\n\n        if (sol.len < bestOverall.len) {\n            bestOverall = std::move(sol);\n        }\n    }\n\n    const double REBUILD_DEAD = 1.48;\n\n    if (timer.elapsed() < REBUILD_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, REBUILD_DEAD);\n        localImprove(bestOverall, timer, REBUILD_DEAD);\n    }\n\n    Solution current = bestOverall;\n\n    const double LNS_DEAD = 1.84;\n\n    while (timer.elapsed() < LNS_DEAD) {\n        if (LNS_DEAD - timer.elapsed() < 0.045) break;\n\n        int roll = rng.nextInt(100);\n        int k;\n\n        if (roll < 58) {\n            k = 3 + rng.nextInt(5);       // 3..7\n        } else if (roll < 90) {\n            k = 8 + rng.nextInt(6);       // 8..13\n        } else {\n            k = 14 + rng.nextInt(7);      // 14..20\n        }\n\n        const Solution& base = (rng.nextInt(5) == 0 ? current : bestOverall);\n\n        Solution cand = ruinRecreate(base, k, rng, timer, LNS_DEAD);\n\n        if (cand.len < bestOverall.len) {\n            bestOverall = std::move(cand);\n\n            double sub = min(LNS_DEAD, timer.elapsed() + 0.08);\n            localImprove(bestOverall, timer, sub);\n\n            if (timer.elapsed() < LNS_DEAD) {\n                tryRebuilds(bestOverall, rng, timer, min(LNS_DEAD, timer.elapsed() + 0.04));\n            }\n\n            current = bestOverall;\n        } else {\n            int diff = cand.len - current.len;\n            double progress = min(1.0, timer.elapsed() / LNS_DEAD);\n            double temp = 45.0 * (1.0 - progress) + 3.0;\n\n            if (diff < 0 || rng.nextDouble() < exp(-(double)diff / temp)) {\n                current = std::move(cand);\n            }\n\n            if (current.len > bestOverall.len + 350) {\n                current = bestOverall;\n            }\n        }\n    }\n\n    const double FINAL_DEAD = 1.90;\n\n    if (timer.elapsed() < FINAL_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, min(FINAL_DEAD, timer.elapsed() + 0.045));\n    }\n\n    routeDescent(bestOverall, timer, FINAL_DEAD, 4, true);\n\n    bestOverall.len = routeCost(bestOverall.route);\n\n    if (!validate(bestOverall)) {\n        bestOverall = buildGreedy(firstCost[0].second);\n    }\n\n    cout << 50;\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (bestOverall.selected.test(oid)) {\n            cout << ' ' << oid;\n        }\n    }\n    cout << '\\n';\n\n    cout << bestOverall.route.size();\n    for (int id : bestOverall.route) {\n        cout << ' ' << X[id] << ' ' << Y[id];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nstatic constexpr int FIRST_SAMPLES = 64;\nstatic constexpr int MAX_SAMPLES = 256;\nstatic constexpr int BLOCK_SIZE = 64;\n\nstatic constexpr int INF = 1e9;\n\nstatic constexpr double BASE_ADAPT_PART = 0.88;\nstatic constexpr double Q_BLEND = 0.12;\n\nstatic constexpr int YMAX = 20000;\n\nstruct DSU {\n    int p[N];\n    int comps;\n\n    void init() {\n        comps = N;\n        for (int i = 0; i < N; i++) p[i] = -1;\n    }\n\n    inline int find(int x) {\n        while (p[x] >= 0) {\n            int y = p[x];\n            if (p[y] >= 0) p[x] = p[y];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n\n    inline bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (p[a] > p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        comps--;\n        return true;\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next() % uint64_t(r - l + 1));\n    }\n};\n\nint X[N], Y[N];\nint U[M], V[M], D[M];\n\nstatic int sampleW[MAX_SAMPLES][M];\nstatic int orderSample[MAX_SAMPLES][M];\nstatic int orderD[M];\n\nstatic double onlineY[YMAX + 1];\n\nstatic inline double online_y_from_offline_mean(double yoff) {\n    if (yoff <= 0.0) return 0.0;\n    if (yoff >= 0.5) return 0.5;\n\n    double k = 1.0 / yoff - 1.0;\n    if (k <= 1.0) return 0.5;\n\n    if (k >= YMAX) {\n        return 2.0 / (k + 3.0);\n    }\n\n    int a = int(floor(k));\n    double f = k - a;\n\n    if (a < 1) return 0.5;\n    if (a + 1 > YMAX) return 2.0 / (k + 3.0);\n\n    return onlineY[a] * (1.0 - f) + onlineY[a + 1] * f;\n}\n\nstatic inline double sample_quantile(const int* vals, int cnt, double p) {\n    static int tmp[MAX_SAMPLES];\n\n    for (int i = 0; i < cnt; i++) tmp[i] = vals[i];\n    sort(tmp, tmp + cnt);\n\n    if (cnt == 1) return tmp[0];\n\n    p = clamp(p, 0.0, 1.0);\n    double pos = p * double(cnt - 1);\n    int a = int(floor(pos));\n    double f = pos - a;\n\n    if (a >= cnt - 1) return tmp[cnt - 1];\n\n    return tmp[a] * (1.0 - f) + tmp[a + 1] * f;\n}\n\nint bottleneck_baseD(int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderD[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return D[e];\n        }\n    }\n\n    return INF;\n}\n\nint bottleneck_sample(int s, int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    const int* ord = orderSample[s];\n    const int* w = sampleW[s];\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = ord[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return w[e];\n        }\n    }\n\n    return INF;\n}\n\ndouble make_threshold(\n    double mc,\n    double lo,\n    int idx,\n    int acceptedEdges,\n    const int* vals,\n    int cnt\n) {\n    double hi = 3.0 * lo;\n    double range = hi - lo;\n    double det = 2.0 * lo;\n\n    if (mc < lo) mc = lo;\n    if (mc > hi) mc = hi;\n\n    double z = (mc - lo) / range;\n    z = clamp(z, 0.0, 1.0);\n\n    double target = double(idx + 1) * double(N - 1) / double(M);\n    double deficit = target - acceptedEdges;\n\n    double threshold;\n\n    if (z < 0.5) {\n        double adapt = BASE_ADAPT_PART;\n\n        // If we are behind the expected acceptance schedule, be slightly less\n        // aggressive. If we are ahead, be slightly more selective.\n        if (deficit > 4.0) {\n            adapt -= min(0.16, 0.012 * (deficit - 4.0));\n        } else if (deficit < -8.0) {\n            adapt += min(0.09, 0.008 * (-deficit - 8.0));\n        }\n\n        adapt = clamp(adapt, 0.70, 0.97);\n\n        double yon = online_y_from_offline_mean(z);\n\n        // Old linear correction in normalized coordinates:\n        // old threshold = mc + 0.22 * (det - mc)\n        // normalized: 0.11 + 0.78*z.\n        double linear = 0.11 + 0.78 * z;\n        if (linear > 0.5) linear = 0.5;\n\n        double tnorm = adapt * yon + (1.0 - adapt) * linear;\n        threshold = lo + range * tnorm;\n\n        // Distribution-shape correction.\n        // For min of k uniform variables, the optimal online threshold is\n        // approximately a high quantile of the offline-min distribution.\n        if (cnt >= 16) {\n            double p;\n\n            if (z <= 1e-12 || yon <= 1e-12) {\n                p = 0.865;\n            } else {\n                double kEff = 1.0 / z - 1.0;\n                if (kEff < 1.0) kEff = 1.0;\n\n                double remBase = max(1e-15, 1.0 - yon);\n                double logRemain = kEff * log(remBase);\n\n                if (logRemain < -50.0) p = 1.0;\n                else p = 1.0 - exp(logRemain);\n\n                p = clamp(p, 0.50, 0.875);\n            }\n\n            double q = sample_quantile(vals, cnt, p);\n\n            double qw = Q_BLEND;\n            if (deficit > 4.0) qw *= 0.55;\n            if (deficit < -8.0) qw = min(0.22, qw * 1.25);\n\n            threshold = threshold * (1.0 - qw) + q * qw;\n        }\n    } else {\n        // Scarce-alternative situation.  The sampled offline marginal is\n        // already high; lowering it tends to reject too much.\n        threshold = mc;\n    }\n\n    // Safety correction against falling too far behind.\n    if (deficit > 8.0) {\n        double mult = 1.0 + 0.0035 * (deficit - 8.0);\n        if (mult > 1.07) mult = 1.07;\n        threshold *= mult;\n    }\n\n    if (threshold < lo) threshold = lo;\n    if (threshold > hi) threshold = hi;\n\n    return threshold;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    onlineY[1] = 0.5;\n    for (int i = 2; i <= YMAX; i++) {\n        onlineY[i] = onlineY[i - 1] - 0.5 * onlineY[i - 1] * onlineY[i - 1];\n    }\n\n    uint64_t seed = 0x123456789abcdefULL;\n\n    auto mix_seed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n        mix_seed(uint64_t(X[i] + 1009));\n        mix_seed(uint64_t(Y[i] + 9176));\n    }\n\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n\n        long long dx = X[U[i]] - X[V[i]];\n        long long dy = Y[U[i]] - Y[V[i]];\n        D[i] = int(sqrt(double(dx * dx + dy * dy)) + 0.5);\n\n        mix_seed(uint64_t(U[i] + 1));\n        mix_seed(uint64_t(V[i] + 1));\n        mix_seed(uint64_t(D[i] + 1));\n    }\n\n    SplitMix64 rng(seed);\n\n    vector<int> perm(BLOCK_SIZE);\n    iota(perm.begin(), perm.end(), 0);\n\n    for (int e = 0; e < M; e++) {\n        int R = 2 * D[e] + 1;\n\n        for (int block = 0; block < MAX_SAMPLES / BLOCK_SIZE; block++) {\n            iota(perm.begin(), perm.end(), 0);\n\n            for (int i = BLOCK_SIZE - 1; i > 0; i--) {\n                int j = rng.randint(0, i);\n                swap(perm[i], perm[j]);\n            }\n\n            for (int s = 0; s < BLOCK_SIZE; s++) {\n                long long numerator = 1LL * (2 * perm[s] + 1) * R;\n                int k = int(numerator / (2LL * BLOCK_SIZE));\n\n                if (k < 0) k = 0;\n                if (k >= R) k = R - 1;\n\n                sampleW[block * BLOCK_SIZE + s][e] = D[e] + k;\n            }\n        }\n    }\n\n    vector<int> ids(M);\n\n    for (int s = 0; s < MAX_SAMPLES; s++) {\n        iota(ids.begin(), ids.end(), 0);\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (sampleW[s][a] != sampleW[s][b]) return sampleW[s][a] < sampleW[s][b];\n            return a < b;\n        });\n\n        for (int i = 0; i < M; i++) orderSample[s][i] = ids[i];\n    }\n\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < M; i++) orderD[i] = ids[i];\n\n    DSU accepted;\n    accepted.init();\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        cin >> l;\n\n        int ans = 0;\n\n        if (!accepted.same(U[i], V[i])) {\n            int base = bottleneck_baseD(i, U[i], V[i], accepted);\n\n            if (base >= INF) {\n                ans = 1;\n            } else {\n                int loInt = base;\n                int hiInt = 3 * base;\n\n                if (l <= loInt) {\n                    ans = 1;\n                } else if (l > hiInt) {\n                    ans = 0;\n                } else {\n                    int vals[MAX_SAMPLES];\n\n                    long long sum = 0;\n                    long long sumsq = 0;\n\n                    for (int s = 0; s < FIRST_SAMPLES; s++) {\n                        int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                        if (b >= INF) b = hiInt;\n\n                        vals[s] = b;\n                        sum += b;\n                        sumsq += 1LL * b * b;\n                    }\n\n                    double mc = double(sum) / FIRST_SAMPLES;\n                    int acceptedEdges = N - accepted.comps;\n\n                    double threshold = make_threshold(\n                        mc,\n                        double(loInt),\n                        i,\n                        acceptedEdges,\n                        vals,\n                        FIRST_SAMPLES\n                    );\n\n                    double var = double(sumsq) / FIRST_SAMPLES - mc * mc;\n                    if (var < 0.0) var = 0.0;\n\n                    double se = sqrt(var / FIRST_SAMPLES);\n\n                    // Use extra samples only when the observed edge length is\n                    // close enough to the threshold to matter.\n                    double margin = max(4.0, 2.4 * se + 0.012 * double(loInt));\n\n                    if (fabs(double(l) - threshold) <= margin) {\n                        for (int s = FIRST_SAMPLES; s < MAX_SAMPLES; s++) {\n                            int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                            if (b >= INF) b = hiInt;\n\n                            vals[s] = b;\n                            sum += b;\n                        }\n\n                        mc = double(sum) / MAX_SAMPLES;\n\n                        threshold = make_threshold(\n                            mc,\n                            double(loInt),\n                            i,\n                            acceptedEdges,\n                            vals,\n                            MAX_SAMPLES\n                        );\n                    }\n\n                    if (double(l) <= threshold) ans = 1;\n                }\n            }\n\n            if (ans) accepted.unite(U[i], V[i]);\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int G = 30;\nconst int INF = 1e9;\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar DIR_CH[4] = {'U', 'D', 'L', 'R'};\n\nint dirId(char ch) {\n    ch = toupper(ch);\n    if (ch == 'U') return 0;\n    if (ch == 'D') return 1;\n    if (ch == 'L') return 2;\n    return 3;\n}\n\nbool inside(int r, int c) {\n    return 0 <= r && r < G && 0 <= c && c < G;\n}\n\nstruct Pet {\n    int r, c, t;\n};\n\npair<int,int> toPhysCoord(int r, int c, int ori) {\n    if (ori == 0) return {r, c};             // corridor = bottom\n    if (ori == 1) return {G - 1 - r, c};     // corridor = top\n    if (ori == 2) return {c, r};             // corridor = right\n    return {c, G - 1 - r};                   // corridor = left\n}\n\npair<int,int> toLogCoord(int pr, int pc, int ori) {\n    if (ori == 0) return {pr, pc};\n    if (ori == 1) return {G - 1 - pr, pc};\n    if (ori == 2) return {pc, pr};\n    return {G - 1 - pc, pr};\n}\n\nint chooseOrientation(const vector<Pet>& petsPhys, const vector<pair<int,int>>& humansPhys) {\n    double best = 1e100;\n    int bestOri = 0;\n\n    for (int ori = 0; ori < 4; ori++) {\n        double cost = 0.0;\n\n        for (auto p : petsPhys) {\n            auto [r, c] = toLogCoord(p.r, p.c, ori);\n            int distCorr = G - 1 - r;\n\n            double w = 1.0;\n            if (p.t == 4) w = 3.0;      // dog\n            else if (p.t == 3) w = 1.5;\n            else if (p.t == 5) w = 1.4;\n            else if (p.t == 2) w = 1.2;\n\n            int near = max(0, 12 - distCorr);\n            cost += w * near * near;\n            if (r >= 28) cost += 100.0 * w;\n        }\n\n        for (auto h : humansPhys) {\n            auto [r, c] = toLogCoord(h.first, h.second, ori);\n            int bestStand = 100;\n            for (int s = 2; s <= 26; s += 4) {\n                bestStand = min(bestStand, abs(c - s));\n            }\n            cost += 0.5 * (G - 1 - r) + 0.2 * bestStand;\n        }\n\n        if (cost < best) {\n            best = cost;\n            bestOri = ori;\n        }\n    }\n\n    return bestOri;\n}\n\nstruct Task {\n    int stand;\n    vector<int> walls;\n    int assigned = -1; // -1: free, >=0: human id, -2: finished\n};\n\nstruct HState {\n    int task = -1;\n    int phase = 0;\n    int wait = 0;\n    int home = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, ori;\n    int turnNo = 0;\n\n    vector<Pet> pets;\n    vector<pair<int,int>> humans;\n\n    bool blocked[G][G]{};\n    bool petOcc[G][G]{};\n    bool humanOcc[G][G]{};\n    bool resBuild[G][G]{};\n    bool resMove[G][G]{};\n\n    vector<Task> tasks;\n    vector<HState> hs;\n\n    char logToPhys[256]{};\n    char physToLog[256]{};\n\n    static constexpr int FREE = 0;\n    static constexpr int GO = 1;\n    static constexpr int UP = 2;\n    static constexpr int DOWN = 3;\n    static constexpr int RET = 4;\n\n    static constexpr int ASSIGN_LIMIT = 190;\n    static constexpr int BUILD_LIMIT = 265;\n    static constexpr int WAIT_UNTIL = 230;\n    static constexpr int WAIT_LIMIT = 2;\n\n    Solver(int n,\n           const vector<Pet>& petsPhys,\n           int m,\n           const vector<pair<int,int>>& humansPhys,\n           int orientation)\n        : N(n), M(m), ori(orientation)\n    {\n        initDirectionMaps();\n\n        pets.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto [r, c] = toLogCoord(petsPhys[i].r, petsPhys[i].c, ori);\n            pets[i] = {r, c, petsPhys[i].t};\n        }\n\n        humans.resize(M);\n        for (int i = 0; i < M; i++) {\n            humans[i] = toLogCoord(humansPhys[i].first, humansPhys[i].second, ori);\n        }\n\n        initTasks();\n\n        hs.resize(M);\n        for (int i = 0; i < M; i++) {\n            hs[i].home = (i + 1) * G / (M + 1);\n        }\n    }\n\n    void initDirectionMaps() {\n        memset(logToPhys, 0, sizeof(logToPhys));\n        memset(physToLog, 0, sizeof(physToLog));\n\n        int br = 15, bc = 15;\n        for (char ch : string(\"UDLR\")) {\n            int d = dirId(ch);\n            auto p1 = toPhysCoord(br, bc, ori);\n            auto p2 = toPhysCoord(br + DR[d], bc + DC[d], ori);\n            int rr = p2.first - p1.first;\n            int cc = p2.second - p1.second;\n\n            char pc = '?';\n            if (rr == -1 && cc == 0) pc = 'U';\n            if (rr == 1 && cc == 0) pc = 'D';\n            if (rr == 0 && cc == -1) pc = 'L';\n            if (rr == 0 && cc == 1) pc = 'R';\n\n            logToPhys[(int)ch] = pc;\n            physToLog[(int)pc] = ch;\n        }\n    }\n\n    void initTasks() {\n        // Logical wall columns: 1,3,5,...,27.\n        // Each task uses an even stand column and builds both adjacent walls.\n        for (int s = 2; s <= 26; s += 4) {\n            Task t;\n            t.stand = s;\n            t.walls = {s - 1, s + 1};\n            tasks.push_back(t);\n        }\n    }\n\n    void buildOcc() {\n        memset(petOcc, 0, sizeof(petOcc));\n        memset(humanOcc, 0, sizeof(humanOcc));\n\n        for (auto &p : pets) {\n            if (inside(p.r, p.c)) petOcc[p.r][p.c] = true;\n        }\n        for (auto &h : humans) {\n            if (inside(h.first, h.second)) humanOcc[h.first][h.second] = true;\n        }\n    }\n\n    void resetReservations() {\n        memset(resBuild, 0, sizeof(resBuild));\n        memset(resMove, 0, sizeof(resMove));\n    }\n\n    bool canBuild(int i, char lowerDir) {\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (petOcc[r][c]) return false;\n        if (humanOcc[r][c]) return false;\n        if (resMove[r][c]) return false;\n\n        for (int k = 0; k < 4; k++) {\n            int nr = r + DR[k], nc = c + DC[k];\n            if (inside(nr, nc) && petOcc[nr][nc]) return false;\n        }\n\n        return true;\n    }\n\n    bool canMove(int i, char upperDir) {\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (blocked[r][c]) return false;\n        if (resBuild[r][c]) return false;\n        return true;\n    }\n\n    bool issueBuild(int i, char lowerDir, vector<char>& act) {\n        lowerDir = tolower(lowerDir);\n        if (!canBuild(i, lowerDir)) return false;\n\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = lowerDir;\n        resBuild[r][c] = true;\n        return true;\n    }\n\n    bool issueMove(int i, char upperDir, vector<char>& act) {\n        upperDir = toupper(upperDir);\n        if (!canMove(i, upperDir)) return false;\n\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = upperDir;\n        resMove[r][c] = true;\n        return true;\n    }\n\n    bool taskComplete(int tid) {\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) return false;\n            }\n        }\n        return true;\n    }\n\n    int countRemainingBuilds(int tid) {\n        int cnt = 0;\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int shortestDist(pair<int,int> st, pair<int,int> goal) {\n        if (!inside(goal.first, goal.second)) return INF;\n        if (blocked[goal.first][goal.second]) return INF;\n\n        int dist[G][G];\n        for (int r = 0; r < G; r++) for (int c = 0; c < G; c++) dist[r][c] = -1;\n\n        queue<pair<int,int>> q;\n        dist[st.first][st.second] = 0;\n        q.push(st);\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            if (r == goal.first && c == goal.second) return dist[r][c];\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (dist[nr][nc] != -1) continue;\n\n                dist[nr][nc] = dist[r][c] + 1;\n                q.push({nr, nc});\n            }\n        }\n\n        return INF;\n    }\n\n    char bfsMove(int i, const vector<pair<int,int>>& goals) {\n        bool goal[G][G]{};\n        int goalCnt = 0;\n\n        for (auto [r, c] : goals) {\n            if (!inside(r, c)) continue;\n            if (blocked[r][c]) continue;\n            if (resBuild[r][c]) continue;\n            if (!goal[r][c]) {\n                goal[r][c] = true;\n                goalCnt++;\n            }\n        }\n\n        if (goalCnt == 0) return '.';\n\n        int sr = humans[i].first;\n        int sc = humans[i].second;\n\n        if (goal[sr][sc]) return '.';\n\n        bool vis[G][G]{};\n        char first[G][G]{};\n\n        queue<pair<int,int>> q;\n        vis[sr][sc] = true;\n        q.push({sr, sc});\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (resBuild[nr][nc]) continue;\n                if (vis[nr][nc]) continue;\n\n                vis[nr][nc] = true;\n                first[nr][nc] = (r == sr && c == sc ? DIR_CH[d] : first[r][c]);\n\n                if (goal[nr][nc]) return first[nr][nc];\n\n                q.push({nr, nc});\n            }\n        }\n\n        return '.';\n    }\n\n    int taskPriority(int tid) {\n        int s = tasks[tid].stand;\n        int pr = 0;\n\n        for (auto &p : pets) {\n            int w = 1;\n            if (p.t == 4) w = 6;\n            else if (p.t == 5) w = 3;\n            else if (p.t == 3) w = 3;\n            else if (p.t == 2) w = 2;\n\n            if (p.r <= 28) {\n                int dc = abs(p.c - s);\n                if (dc <= 2) pr += w * (3 - dc);\n                else if (dc <= 4) pr += 1;\n            } else {\n                if (abs(p.c - s) <= 2) pr += 1;\n            }\n        }\n\n        return pr;\n    }\n\n    void normalizeStates() {\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task == -1) continue;\n\n            int tid = hs[i].task;\n            bool comp = taskComplete(tid);\n\n            if (comp) hs[i].phase = RET;\n            if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n            if (humans[i].first == 29 && hs[i].phase == RET) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n            }\n        }\n    }\n\n    void assignTasks() {\n        if (turnNo > ASSIGN_LIMIT) return;\n\n        while (true) {\n            int bestI = -1, bestT = -1;\n            double bestVal = -1e100;\n\n            for (int i = 0; i < M; i++) {\n                if (hs[i].task != -1) continue;\n\n                for (int tid = 0; tid < (int)tasks.size(); tid++) {\n                    if (tasks[tid].assigned != -1) continue;\n                    if (taskComplete(tid)) continue;\n\n                    int stand = tasks[tid].stand;\n                    if (blocked[28][stand]) continue;\n\n                    int dist = shortestDist(humans[i], {29, stand});\n                    if (dist >= INF) continue;\n\n                    int rem = countRemainingBuilds(tid);\n                    int estimate = dist + rem + 58;\n                    if (turnNo + estimate > BUILD_LIMIT + 8) continue;\n\n                    double val = 50.0 * taskPriority(tid) - dist;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestI = i;\n                        bestT = tid;\n                    }\n                }\n            }\n\n            if (bestI == -1) break;\n\n            hs[bestI].task = bestT;\n            hs[bestI].phase = GO;\n            hs[bestI].wait = 0;\n            tasks[bestT].assigned = bestI;\n        }\n    }\n\n    array<bool, G> computeDoorTargets() {\n        array<bool, G> need;\n        need.fill(false);\n\n        struct Comp {\n            int area = 0;\n            int pets = 0;\n            bool protect = false;\n            vector<int> doors;\n        };\n\n        int compId[G][G];\n        for (int r = 0; r < G; r++) {\n            for (int c = 0; c < G; c++) compId[r][c] = -1;\n        }\n\n        vector<Comp> comps;\n\n        for (int sr = 0; sr <= 28; sr++) {\n            for (int sc = 0; sc < G; sc++) {\n                if (blocked[sr][sc]) continue;\n                if (compId[sr][sc] != -1) continue;\n\n                int id = (int)comps.size();\n                comps.push_back(Comp());\n\n                queue<pair<int,int>> q;\n                compId[sr][sc] = id;\n                q.push({sr, sc});\n\n                while (!q.empty()) {\n                    auto [r, c] = q.front();\n                    q.pop();\n\n                    comps[id].area++;\n\n                    if (r == 28 && !blocked[29][c]) {\n                        comps[id].doors.push_back(c);\n                    }\n\n                    for (int d = 0; d < 4; d++) {\n                        int nr = r + DR[d], nc = c + DC[d];\n                        if (!inside(nr, nc)) continue;\n                        if (nr == 29) continue; // bottom corridor excluded\n                        if (blocked[nr][nc]) continue;\n                        if (compId[nr][nc] != -1) continue;\n\n                        compId[nr][nc] = id;\n                        q.push({nr, nc});\n                    }\n                }\n            }\n        }\n\n        int corridorPets = 0;\n\n        for (auto &p : pets) {\n            if (p.r == 29) {\n                corridorPets++;\n            } else if (0 <= p.r && p.r <= 28) {\n                int id = compId[p.r][p.c];\n                if (id >= 0) comps[id].pets++;\n            }\n        }\n\n        for (auto &h : humans) {\n            if (h.first <= 28) {\n                int id = compId[h.first][h.second];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        // Protect components currently needed by active builders.\n        for (int i = 0; i < M; i++) {\n            int tid = hs[i].task;\n            if (tid == -1) continue;\n            if (hs[i].phase == RET) continue;\n            if (taskComplete(tid)) continue;\n\n            int s = tasks[tid].stand;\n            if (!blocked[28][s]) {\n                int id = compId[28][s];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        int baseArea = 0;\n        for (int c = 0; c < G; c++) {\n            if (!blocked[29][c]) baseArea++;\n        }\n\n        int basePets = corridorPets;\n        (void)basePets; // constant for subset choice\n\n        struct Item {\n            int comp;\n            int area;\n            int pets;\n        };\n\n        vector<Item> items;\n\n        for (int id = 0; id < (int)comps.size(); id++) {\n            auto &cp = comps[id];\n\n            if (cp.doors.empty()) continue; // already isolated from corridor\n\n            if (cp.protect || cp.pets == 0) {\n                baseArea += cp.area;\n                basePets += cp.pets;\n            } else {\n                items.push_back({id, cp.area, cp.pets});\n            }\n        }\n\n        int K = (int)items.size();\n        int maxP = N;\n\n        vector<vector<int>> dp(K + 1, vector<int>(maxP + 1, -INF));\n        vector<vector<int>> pre(K + 1, vector<int>(maxP + 1, -1));\n        vector<vector<char>> take(K + 1, vector<char>(maxP + 1, 0));\n\n        dp[0][0] = baseArea;\n\n        for (int k = 0; k < K; k++) {\n            int a = items[k].area;\n            int p = items[k].pets;\n\n            for (int q = 0; q <= maxP; q++) {\n                if (dp[k][q] < 0) continue;\n\n                // Close this component.\n                if (dp[k][q] > dp[k + 1][q]) {\n                    dp[k + 1][q] = dp[k][q];\n                    pre[k + 1][q] = q;\n                    take[k + 1][q] = 0;\n                }\n\n                // Leave it open.\n                if (q + p <= maxP && dp[k][q] + a > dp[k + 1][q + p]) {\n                    dp[k + 1][q + p] = dp[k][q] + a;\n                    pre[k + 1][q + p] = q;\n                    take[k + 1][q + p] = 1;\n                }\n            }\n        }\n\n        int bestQ = 0;\n        double bestScore = -1.0;\n\n        for (int q = 0; q <= maxP; q++) {\n            if (dp[K][q] < 0) continue;\n            double val = ldexp((double)dp[K][q], -q);\n            if (val > bestScore) {\n                bestScore = val;\n                bestQ = q;\n            }\n        }\n\n        vector<bool> include(K, false);\n        int q = bestQ;\n        for (int k = K; k >= 1; k--) {\n            include[k - 1] = take[k][q];\n            q = pre[k][q];\n            if (q < 0) break;\n        }\n\n        for (int k = 0; k < K; k++) {\n            if (include[k]) continue;\n\n            int id = items[k].comp;\n            for (int c : comps[id].doors) {\n                if (!blocked[28][c]) need[c] = true;\n            }\n        }\n\n        return need;\n    }\n\n    int tryBuildCurrentRow(int i, int tid, vector<char>& act) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (!(0 <= r && r <= 28)) return 0;\n        if (c != stand) return 0;\n\n        bool anyUnbuilt = false;\n\n        for (int wc : tasks[tid].walls) {\n            if (blocked[r][wc]) continue;\n\n            anyUnbuilt = true;\n            char low = (wc < stand ? 'l' : 'r');\n\n            if (!resBuild[r][wc] && canBuild(i, low)) {\n                issueBuild(i, low, act);\n                return 1;\n            }\n        }\n\n        return anyUnbuilt ? -1 : 0;\n    }\n\n    void moveToGoals(int i, const vector<pair<int,int>>& goals, vector<char>& act) {\n        char mv = bfsMove(i, goals);\n        if (mv != '.') issueMove(i, mv, act);\n    }\n\n    void actBuilder(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int tid = hs[i].task;\n\n        if (tid == -1) {\n            actFree(i, act, needDoor);\n            return;\n        }\n\n        bool comp = taskComplete(tid);\n        if (comp) hs[i].phase = RET;\n        if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (hs[i].phase == RET) {\n            if (r == 29) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n                actFree(i, act, needDoor);\n                return;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col = 0; col < G; col++) {\n                if (!blocked[29][col]) goals.push_back({29, col});\n            }\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        if (hs[i].phase == GO) {\n            if (!(r == 29 && c == stand)) {\n                moveToGoals(i, {{29, stand}}, act);\n                return;\n            }\n            hs[i].phase = UP;\n        }\n\n        if (c != stand) {\n            hs[i].phase = GO;\n            moveToGoals(i, {{29, stand}}, act);\n            return;\n        }\n\n        if (hs[i].phase == UP) {\n            if (r == 29) {\n                hs[i].wait = 0;\n                issueMove(i, 'U', act);\n                return;\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r > 0) {\n                issueMove(i, 'U', act);\n                return;\n            } else {\n                hs[i].phase = DOWN;\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n\n        if (hs[i].phase == DOWN) {\n            if (r == 29) {\n                if (taskComplete(tid)) {\n                    hs[i].phase = RET;\n                    actBuilder(i, act, needDoor);\n                    return;\n                } else {\n                    hs[i].phase = UP;\n                    issueMove(i, 'U', act);\n                    return;\n                }\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r < 28) {\n                issueMove(i, 'D', act);\n                return;\n            } else {\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n    }\n\n    void actFree(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n\n        if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c]) {\n            if (canBuild(i, 'u')) {\n                issueBuild(i, 'u', act);\n                return;\n            }\n        }\n\n        vector<int> cols;\n        for (int col = 0; col < G; col++) {\n            if (needDoor[col] && !blocked[28][col] && !resBuild[28][col]) {\n                cols.push_back(col);\n            }\n        }\n\n        if (!cols.empty()) {\n            bool curIllegal = false;\n            if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c] && !canBuild(i, 'u')) {\n                curIllegal = true;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col : cols) {\n                if (curIllegal && col == c && cols.size() >= 2) continue;\n                goals.push_back({29, col});\n            }\n\n            if (goals.empty()) goals.push_back({29, c});\n\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        moveToGoals(i, {{29, hs[i].home}}, act);\n    }\n\n    string decideActions() {\n        buildOcc();\n        resetReservations();\n\n        normalizeStates();\n        assignTasks();\n\n        auto needDoor = computeDoorTargets();\n\n        vector<char> act(M, '.');\n\n        vector<int> order;\n        for (int i = 0; i < M; i++) if (hs[i].task != -1) order.push_back(i);\n        for (int i = 0; i < M; i++) if (hs[i].task == -1) order.push_back(i);\n\n        for (int i : order) {\n            if (hs[i].task != -1) actBuilder(i, act, needDoor);\n            else actFree(i, act, needDoor);\n        }\n\n        string s;\n        s.reserve(M);\n        for (int i = 0; i < M; i++) s.push_back(act[i]);\n        return s;\n    }\n\n    char convertAction(char ch) {\n        if (ch == '.') return '.';\n\n        bool low = islower((unsigned char)ch);\n        char up = toupper(ch);\n        char p = logToPhys[(int)up];\n\n        if (low) p = tolower(p);\n        return p;\n    }\n\n    string toPhysicalOutput(const string& logAct) {\n        string out;\n        out.reserve(logAct.size());\n\n        for (char ch : logAct) {\n            out.push_back(convertAction(ch));\n        }\n\n        return out;\n    }\n\n    void applyActions(const string& logAct) {\n        auto oldHumans = humans;\n        auto newHumans = humans;\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('a' <= a && a <= 'z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) blocked[r][c] = true;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('A' <= a && a <= 'Z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) newHumans[i] = {r, c};\n            }\n        }\n\n        humans = newHumans;\n    }\n\n    bool readPetMovesAndUpdate() {\n        for (int i = 0; i < N; i++) {\n            string s;\n            if (!(cin >> s)) return false;\n\n            if (s == \".\") continue;\n\n            for (char pc : s) {\n                if (pc == '.') continue;\n\n                char lc = physToLog[(int)pc];\n                int d = dirId(lc);\n\n                pets[i].r += DR[d];\n                pets[i].c += DC[d];\n            }\n        }\n\n        return true;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<Pet> petsPhys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> petsPhys[i].r >> petsPhys[i].c >> petsPhys[i].t;\n        petsPhys[i].r--;\n        petsPhys[i].c--;\n    }\n\n    int M;\n    cin >> M;\n\n    vector<pair<int,int>> humansPhys(M);\n    for (int i = 0; i < M; i++) {\n        cin >> humansPhys[i].first >> humansPhys[i].second;\n        humansPhys[i].first--;\n        humansPhys[i].second--;\n    }\n\n    int ori = chooseOrientation(petsPhys, humansPhys);\n    Solver solver(N, petsPhys, M, humansPhys, ori);\n\n    for (int turn = 0; turn < 300; turn++) {\n        solver.turnNo = turn;\n\n        string logAct = solver.decideActions();\n        string out = solver.toPhysicalOutput(logAct);\n\n        cout << out << endl;\n        cout.flush();\n\n        solver.applyActions(logAct);\n\n        if (!solver.readPetMovesAndUpdate()) return 0;\n    }\n\n    return 0;\n}","ahc009":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 20;\nstatic constexpr int W = 20;\nstatic constexpr int N = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr int MAXD = 400;\n\nint si_, sj_, ti_, tj_;\nint SID, TID;\ndouble pForget, qRemember;\n\nstring hwall[H], vwall[H - 1];\n\nint goTo[4][N]; // U D L R\nint distT[N], distS[N];\n\ndouble pot[MAXL + 1][MAXD + 1];\ndouble adaptVal[MAXL + 1][N];\n\ndouble pref[MAXL + 1][N];\ndouble suff[MAXL + 1][N];\ndouble prefScore[MAXL + 1];\n\nchrono::steady_clock::time_point startTime;\n\nconst double HARD_LIMIT = 1.88;\nconst double EPS = 1e-10;\nconst string DIRS = \"UDLR\";\n\nenum FillMode {\n    F_LAST = 0,\n    F_GREEDY = 1\n};\n\ninline int id(int i, int j) {\n    return i * W + j;\n}\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n}\n\nvoid buildGo() {\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x = id(i, j);\n            goTo[0][x] = (i > 0 && vwall[i - 1][j] == '0') ? id(i - 1, j) : x;\n            goTo[1][x] = (i + 1 < H && vwall[i][j] == '0') ? id(i + 1, j) : x;\n            goTo[2][x] = (j > 0 && hwall[i][j - 1] == '0') ? id(i, j - 1) : x;\n            goTo[3][x] = (j + 1 < W && hwall[i][j] == '0') ? id(i, j + 1) : x;\n        }\n    }\n}\n\nvoid bfsDistFrom(int st, int* dist) {\n    fill(dist, dist + N, -1);\n    queue<int> que;\n    dist[st] = 0;\n    que.push(st);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n            if (dist[y] == -1) {\n                dist[y] = dist[x] + 1;\n                que.push(y);\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (dist[i] < 0) dist[i] = MAXD;\n    }\n}\n\nvoid buildPotential() {\n    for (int d = 0; d <= MAXD; d++) pot[MAXL][d] = 0.0;\n    pot[MAXL][0] = 401 - MAXL;\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        pot[l][0] = 401 - l;\n        for (int d = 1; d <= MAXD; d++) {\n            pot[l][d] = qRemember * pot[l + 1][d - 1] + pForget * pot[l + 1][d];\n        }\n    }\n}\n\nvoid buildAdaptiveValue() {\n    fill(adaptVal[MAXL], adaptVal[MAXL] + N, 0.0);\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        double reward = 400 - l;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                adaptVal[l][v] = 0.0;\n                continue;\n            }\n\n            double best = 0.0;\n\n            for (int a = 0; a < 4; a++) {\n                int u = goTo[a][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * adaptVal[l + 1][v];\n                } else if (u == v) {\n                    val = adaptVal[l + 1][v];\n                } else {\n                    val = pForget * adaptVal[l + 1][v] + qRemember * adaptVal[l + 1][u];\n                }\n\n                best = max(best, val);\n            }\n\n            adaptVal[l][v] = best;\n        }\n    }\n}\n\ndouble evaluate(const vector<int>& seq) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    double score = 0.0;\n    int L = (int)seq.size();\n\n    for (int k = 0; k < L; k++) {\n        fill(ndp, ndp + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = dp[v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                ndp[v] += m * pForget;\n            } else if (u == v) {\n                ndp[v] += m;\n            } else {\n                ndp[v] += m * pForget;\n                ndp[u] += m * qRemember;\n            }\n        }\n\n        score += reward * hit;\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return score;\n}\n\nvoid applyActionDist(const double* dp, double* ndp, int a) {\n    fill(ndp, ndp + N, 0.0);\n\n    for (int v = 0; v < N; v++) {\n        double m = dp[v];\n        if (m == 0.0) continue;\n\n        int u = goTo[a][v];\n\n        if (u == TID) {\n            ndp[v] += m * pForget;\n        } else if (u == v) {\n            ndp[v] += m;\n        } else {\n            ndp[v] += m * pForget;\n            ndp[u] += m * qRemember;\n        }\n    }\n}\n\nvoid computePrefixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(pref[0], pref[0] + N, 0.0);\n    pref[0][SID] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int k = 0; k < L; k++) {\n        fill(pref[k + 1], pref[k + 1] + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = pref[k][v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                pref[k + 1][v] += m * pForget;\n            } else if (u == v) {\n                pref[k + 1][v] += m;\n            } else {\n                pref[k + 1][v] += m * pForget;\n                pref[k + 1][u] += m * qRemember;\n            }\n        }\n\n        prefScore[k + 1] = prefScore[k] + reward * hit;\n    }\n}\n\nvoid computeSuffixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(suff[L], suff[L] + N, 0.0);\n\n    for (int k = L - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                suff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                suff[k][v] = qRemember * reward + pForget * suff[k + 1][v];\n            } else if (u == v) {\n                suff[k][v] = suff[k + 1][v];\n            } else {\n                suff[k][v] = pForget * suff[k + 1][v] + qRemember * suff[k + 1][u];\n            }\n        }\n    }\n}\n\nvoid computePrefixSuffix(const vector<int>& seq) {\n    computePrefixOnly(seq);\n    computeSuffixOnly(seq);\n}\n\ninline double heuristicFuture(int mode, int pos, int state) {\n    if (mode == 0) return adaptVal[pos][state];\n    if (mode == 1) return pot[pos][distT[state]];\n    return 0.55 * adaptVal[pos][state] + 0.45 * pot[pos][distT[state]];\n}\n\nvoid completeGreedy(vector<int>& seq) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n    if ((int)seq.size() == MAXL) return;\n\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    int len = (int)seq.size();\n\n    for (int k = 0; k < len; k++) {\n        applyActionDist(dp, ndp, seq[k]);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    for (int k = len; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * adaptVal[k + 1][v]);\n                } else if (u == v) {\n                    val += m * adaptVal[k + 1][v];\n                } else {\n                    val += m * (pForget * adaptVal[k + 1][v] + qRemember * adaptVal[k + 1][u]);\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n}\n\nvector<int> greedySequenceMode(int mode) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    vector<int> seq;\n    seq.reserve(MAXL);\n\n    for (int k = 0; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * heuristicFuture(mode, k + 1, v));\n                } else if (u == v) {\n                    val += m * heuristicFuture(mode, k + 1, v);\n                } else {\n                    val += m * (pForget * heuristicFuture(mode, k + 1, v) + qRemember * heuristicFuture(mode, k + 1, u));\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return seq;\n}\n\nstruct Candidate {\n    vector<int> seq;\n    double score;\n};\n\nvoid fillLast(vector<int>& seq) {\n    if (seq.empty()) seq.push_back(1);\n    while ((int)seq.size() < MAXL) seq.push_back(seq.back());\n}\n\nvoid addCandidate(vector<Candidate>& cands, vector<int> seq, int mode = F_GREEDY) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n\n    if ((int)seq.size() < MAXL) {\n        if (mode == F_GREEDY) completeGreedy(seq);\n        else fillLast(seq);\n    }\n\n    for (const auto& c : cands) {\n        if (c.seq == seq) return;\n    }\n\n    double sc = evaluate(seq);\n    cands.push_back({move(seq), sc});\n}\n\nvoid pruneCands(vector<Candidate>& cands, int limit) {\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        return a.score > b.score;\n    });\n\n    if ((int)cands.size() > limit) cands.resize(limit);\n}\n\nint repCost(int d, double z) {\n    if (d <= 0) return 0;\n\n    double val = d / qRemember + z * sqrt(max(0.0, d * pForget)) / qRemember;\n    int r = (int)ceil(val - 1e-9);\n\n    r = max(r, d);\n    r = max(r, 1);\n\n    return r;\n}\n\nint cappedRep(int d, double z) {\n    if (d <= 0) return 0;\n    return min(18, repCost(d, z));\n}\n\nvoid appendRun(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt && (int)s.size() < MAXL; i++) {\n        s.push_back(a);\n    }\n}\n\nvoid appendRunRaw(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt; i++) s.push_back(a);\n}\n\nvector<int> bfsPath(int start, int goal, const array<int, 4>& order) {\n    if (start == goal) return {};\n\n    vector<int> par(N, -1), parA(N, -1);\n    queue<int> que;\n\n    par[start] = start;\n    que.push(start);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        if (x == goal) break;\n\n        for (int a : order) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            if (par[y] == -1) {\n                par[y] = x;\n                parA[y] = a;\n                que.push(y);\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != start) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> randomPathTo(int goal, int seed, int noise, int biasAway) {\n    mt19937 rng(seed);\n\n    int wgt[4][N];\n\n    for (int a = 0; a < 4; a++) {\n        for (int v = 0; v < N; v++) {\n            if (goTo[a][v] == v) {\n                wgt[a][v] = INT_MAX / 4;\n            } else {\n                int pen = (a == 0 || a == 2) ? biasAway : 0;\n                wgt[a][v] = 1000 + pen + (int)(rng() % max(1, noise));\n            }\n        }\n    }\n\n    const int INF = 1 << 29;\n    vector<int> dist(N, INF), par(N, -1), parA(N, -1);\n    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n    dist[SID] = 0;\n    pq.push({0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd != dist[x]) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            int nd = cd + wgt[a][x];\n            if (nd < dist[y]) {\n                dist[y] = nd;\n                par[y] = x;\n                parA[y] = a;\n                pq.push({nd, y});\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != SID) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> makeCyclePath(const vector<int>& path) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    s.reserve(MAXL);\n    for (int i = 0; i < MAXL; i++) {\n        s.push_back(path[i % path.size()]);\n    }\n\n    return s;\n}\n\nvector<int> repeatEachPathOriginal(const vector<int>& path, int rep) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    for (int a : path) {\n        for (int r = 0; r < rep && (int)s.size() < MAXL; r++) {\n            s.push_back(a);\n        }\n\n        if ((int)s.size() >= MAXL) break;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(path[ptr % path.size()]);\n        ptr++;\n    }\n\n    return s;\n}\n\nvector<int> syncRunPath(const vector<int>& path, double z, int extraUnsynced = 0) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    int cell = SID;\n\n    for (int i = 0; i < (int)path.size();) {\n        int a = path[i];\n        int j = i;\n\n        while (j < (int)path.size() && path[j] == a) j++;\n\n        int d = j - i;\n        int end = cell;\n\n        for (int k = 0; k < d; k++) {\n            end = goTo[a][end];\n        }\n\n        bool synced = (end == TID || goTo[a][end] == end);\n        int r = synced ? repCost(d, z) : d + extraUnsynced;\n        r = max(r, d);\n\n        appendRun(s, a, r);\n\n        cell = end;\n\n        if ((int)s.size() >= MAXL) break;\n\n        i = j;\n    }\n\n    return s;\n}\n\npair<int, int> slideResult(int cell, int a) {\n    int c = cell;\n    int d = 0;\n\n    while (true) {\n        int u = goTo[a][c];\n        if (u == c) break;\n\n        c = u;\n        d++;\n\n        if (c == TID) break;\n    }\n\n    return {c, d};\n}\n\nvector<int> slidePathToGoal(int goal, double z) {\n    if (goal == SID) return {};\n\n    const double INF = 1e100;\n\n    vector<double> dc(N, INF);\n    vector<int> pre(N, -1), preA(N, -1), preD(N, 0);\n\n    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n\n    dc[SID] = 0.0;\n    pq.push({0.0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd > dc[x] + 1e-9) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            auto [to, d] = slideResult(x, a);\n            if (d == 0) continue;\n\n            double nd = cd + repCost(d, z);\n\n            if (nd < dc[to]) {\n                dc[to] = nd;\n                pre[to] = x;\n                preA[to] = a;\n                preD[to] = d;\n                pq.push({nd, to});\n            }\n        }\n    }\n\n    if (pre[goal] == -1) return {};\n\n    vector<pair<int, int>> segs;\n\n    int x = goal;\n    while (x != SID) {\n        segs.push_back({preA[x], preD[x]});\n        x = pre[x];\n    }\n\n    reverse(segs.begin(), segs.end());\n\n    vector<int> seq;\n\n    for (auto [a, d] : segs) {\n        appendRun(seq, a, repCost(d, z));\n        if ((int)seq.size() >= MAXL) break;\n    }\n\n    return seq;\n}\n\nvector<int> slideCandidate(double z) {\n    return slidePathToGoal(TID, z);\n}\n\nvoid addPathCandidatesOriginal(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, F_LAST);\n    addCandidate(cands, makeCyclePath(path), F_LAST);\n\n    for (int rep : {2, 3, 4}) {\n        addCandidate(cands, repeatEachPathOriginal(path, rep), F_LAST);\n    }\n}\n\nvoid addLightPathCandidates(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, F_GREEDY);\n    addCandidate(cands, makeCyclePath(path), F_LAST);\n    addCandidate(cands, syncRunPath(path, 0.9, 0), F_GREEDY);\n\n    int r = max(2, (int)ceil(1.0 / qRemember));\n    addCandidate(cands, repeatEachPathOriginal(path, r), F_GREEDY);\n}\n\nvector<int> patternFromRuns(const vector<pair<int, int>>& runs) {\n    vector<int> pat;\n\n    for (auto [a, c] : runs) {\n        if (c <= 0) continue;\n        appendRunRaw(pat, a, c);\n    }\n\n    return pat;\n}\n\nvoid addPatternCandidate(vector<Candidate>& cands, const vector<int>& prefix, const vector<int>& pattern) {\n    vector<int> s = prefix;\n\n    if ((int)s.size() > MAXL) s.resize(MAXL);\n\n    if (pattern.empty()) {\n        addCandidate(cands, s, F_GREEDY);\n        return;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(pattern[ptr]);\n        ptr++;\n        if (ptr == (int)pattern.size()) ptr = 0;\n    }\n\n    addCandidate(cands, s, F_LAST);\n}\n\nvoid addLineCandidates(vector<Candidate>& cands, int goal, int toward, int back, int offset) {\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<vector<int>> prefixes;\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPath(SID, goal, ord);\n        if (goal != SID && path.empty()) continue;\n\n        prefixes.push_back(path);\n\n        vector<int> sp = syncRunPath(path, 0.8, 0);\n        prefixes.push_back(sp);\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    if (offset == 0) {\n        for (auto& pre : prefixes) {\n            addCandidate(cands, pre, F_GREEDY);\n        }\n        return;\n    }\n\n    vector<int> counts = {\n        offset,\n        max(offset, (int)ceil(offset / qRemember)),\n        cappedRep(offset, 0.7),\n        min(18, max(offset, 5))\n    };\n\n    sort(counts.begin(), counts.end());\n    counts.erase(unique(counts.begin(), counts.end()), counts.end());\n\n    for (auto& pre : prefixes) {\n        for (int c : counts) {\n            vector<int> pat = patternFromRuns({{toward, c}, {back, c}});\n            addPatternCandidate(cands, pre, pat);\n        }\n    }\n}\n\nvoid addSweepCandidates(vector<Candidate>& cands) {\n    vector<vector<int>> patterns;\n\n    vector<int> cs = {\n        4,\n        max(4, (int)round(4.0 / qRemember)),\n        min(14, repCost(4, 0.7)),\n        min(18, repCost(4, 1.4))\n    };\n\n    sort(cs.begin(), cs.end());\n    cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n    for (int c : cs) {\n        patterns.push_back(patternFromRuns({{0, c}, {2, c}, {1, c}, {3, c}}));\n        patterns.push_back(patternFromRuns({{2, c}, {0, c}, {3, c}, {1, c}}));\n    }\n\n    int up = 19 - ti_;\n    int left = 19 - tj_;\n\n    for (double z : {0.0, 0.8, 1.5}) {\n        int ru = cappedRep(up, z);\n        int rl = cappedRep(left, z);\n\n        if (ru + rl > 0) {\n            patterns.push_back(patternFromRuns({{0, ru}, {2, rl}, {1, ru}, {3, rl}}));\n            patterns.push_back(patternFromRuns({{2, rl}, {0, ru}, {3, rl}, {1, ru}}));\n        }\n    }\n\n    vector<vector<int>> prefixes;\n\n    for (double z : {0.0, 1.0}) {\n        int big = min(75, repCost(19, z));\n\n        vector<int> s1;\n        appendRun(s1, 1, big);\n        appendRun(s1, 3, big);\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        appendRun(s2, 3, big);\n        appendRun(s2, 1, big);\n        prefixes.push_back(s2);\n    }\n\n    for (int chunk : {max(5, (int)round(7.0 / qRemember)), max(8, (int)round(11.0 / qRemember))}) {\n        vector<int> s1;\n        while ((int)s1.size() < 115) {\n            appendRun(s1, 1, chunk);\n            appendRun(s1, 3, chunk);\n        }\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        while ((int)s2.size() < 115) {\n            appendRun(s2, 3, chunk);\n            appendRun(s2, 1, chunk);\n        }\n        prefixes.push_back(s2);\n    }\n\n    array<int, 4> drOrder{1, 3, 0, 2};\n    vector<int> cornerPath = bfsPath(SID, id(19, 19), drOrder);\n\n    if (!cornerPath.empty()) {\n        prefixes.push_back(cornerPath);\n        prefixes.push_back(syncRunPath(cornerPath, 0.8, 0));\n        prefixes.push_back(syncRunPath(cornerPath, 1.6, 0));\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    int used = 0;\n\n    for (auto& pre : prefixes) {\n        for (auto& pat : patterns) {\n            addPatternCandidate(cands, pre, pat);\n            used++;\n            if (used >= 60) break;\n        }\n        if (used >= 60) break;\n    }\n\n    addLineCandidates(cands, id(ti_, 19), 2, 3, 19 - tj_);\n    addLineCandidates(cands, id(19, tj_), 0, 1, 19 - ti_);\n}\n\nvoid addNearTargetCandidates(vector<Candidate>& cands) {\n    vector<int> cells;\n\n    for (int v = 0; v < N; v++) {\n        if (v == TID) continue;\n        if (distT[v] <= 4) cells.push_back(v);\n    }\n\n    sort(cells.begin(), cells.end(), [&](int a, int b) {\n        int ca = distS[a] + 5 * distT[a];\n        int cb = distS[b] + 5 * distT[b];\n        return ca < cb;\n    });\n\n    if ((int)cells.size() > 10) cells.resize(10);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    for (int v : cells) {\n        for (auto ord : orders) {\n            vector<int> path = bfsPath(SID, v, ord);\n            if (v != SID && path.empty()) continue;\n\n            addCandidate(cands, path, F_GREEDY);\n\n            vector<int> sp = syncRunPath(path, 0.8, 0);\n            addCandidate(cands, sp, F_GREEDY);\n        }\n    }\n}\n\nstruct RayInfo {\n    int cell;\n    int action;\n    int d;\n    int rank;\n};\n\nvoid addTargetRayCandidates(vector<Candidate>& cands) {\n    vector<RayInfo> rays;\n\n    for (int a = 0; a < 4; a++) {\n        for (int c = 0; c < N; c++) {\n            if (c == TID) continue;\n\n            int x = c;\n\n            for (int d = 1; d <= 25; d++) {\n                int y = goTo[a][x];\n                if (y == x) break;\n\n                x = y;\n\n                if (x == TID) {\n                    int rank = distS[c] + repCost(d, 1.0);\n                    rays.push_back({c, a, d, rank});\n                    break;\n                }\n            }\n        }\n    }\n\n    sort(rays.begin(), rays.end(), [](const RayInfo& a, const RayInfo& b) {\n        if (a.rank != b.rank) return a.rank < b.rank;\n        return a.d < b.d;\n    });\n\n    if ((int)rays.size() > 16) rays.resize(16);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<double> zs = {0.0, 1.0};\n    if (pForget >= 0.25) zs.push_back(1.8);\n\n    for (const auto& r : rays) {\n        for (auto ord : orders) {\n            vector<int> path = bfsPath(SID, r.cell, ord);\n            if (r.cell != SID && path.empty()) continue;\n\n            vector<vector<int>> prefixes;\n            prefixes.push_back(path);\n            prefixes.push_back(syncRunPath(path, 0.8, 0));\n\n            sort(prefixes.begin(), prefixes.end());\n            prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n            for (auto pre : prefixes) {\n                for (double z : zs) {\n                    vector<int> s = pre;\n                    appendRun(s, r.action, repCost(r.d, z));\n                    addCandidate(cands, s, F_GREEDY);\n                }\n            }\n        }\n\n        for (double pz : {0.5, 1.2}) {\n            vector<int> pre = slidePathToGoal(r.cell, pz);\n            if (r.cell != SID && pre.empty()) continue;\n\n            for (double z : zs) {\n                vector<int> s = pre;\n                appendRun(s, r.action, repCost(r.d, z));\n                addCandidate(cands, s, F_GREEDY);\n            }\n        }\n    }\n}\n\nstruct BeamNode {\n    float prob[N];\n    double score;\n    double est;\n    unsigned char seq[MAXL];\n\n    BeamNode() {}\n};\n\n// mode 0: original distance potential\n// mode 1: mixed adaptive + distance potential\nvector<vector<int>> beamSearchMode(int topCount, int initialWidth, int mode) {\n    int width = initialWidth;\n\n    vector<BeamNode> cur, nxt, selected;\n    vector<int> idx;\n\n    cur.reserve(initialWidth);\n    nxt.reserve(initialWidth * 4);\n    selected.reserve(initialWidth);\n    idx.reserve(initialWidth * 4);\n\n    BeamNode root;\n    fill(root.prob, root.prob + N, 0.0f);\n    root.prob[SID] = 1.0f;\n    root.score = 0.0;\n\n    if (mode == 0) {\n        root.est = pot[0][distT[SID]];\n    } else {\n        root.est = 0.75 * adaptVal[0][SID] + 0.25 * pot[0][distT[SID]];\n    }\n\n    cur.push_back(root);\n\n    for (int l = 0; l < MAXL; l++) {\n        if ((l % 5) == 0) {\n            double e = elapsedSec();\n\n            if (e > 1.55) width = min(width, 35);\n            else if (e > 1.42) width = min(width, 70);\n            else if (e > 1.28) width = min(width, 120);\n            else if (e > 1.12 && mode != 0) width = min(width, 120);\n        }\n\n        nxt.clear();\n\n        for (const BeamNode& par : cur) {\n            for (int a = 0; a < 4; a++) {\n                BeamNode& ch = nxt.emplace_back();\n\n                fill(ch.prob, ch.prob + N, 0.0f);\n\n                if (l > 0) memcpy(ch.seq, par.seq, l * sizeof(unsigned char));\n                ch.seq[l] = (unsigned char)a;\n\n                double hit = 0.0;\n                double future = 0.0;\n                const double* drow = pot[l + 1];\n                const double* vrow = adaptVal[l + 1];\n\n                for (int v = 0; v < N; v++) {\n                    float mf = par.prob[v];\n                    if (mf == 0.0f) continue;\n\n                    double m = mf;\n                    int u = goTo[a][v];\n\n                    auto addFuture = [&](int state, double mass) {\n                        if (mode == 0) {\n                            future += mass * drow[distT[state]];\n                        } else {\n                            future += mass * (0.75 * vrow[state] + 0.25 * drow[distT[state]]);\n                        }\n                    };\n\n                    if (u == TID) {\n                        double stay = m * pForget;\n                        hit += m * qRemember;\n                        ch.prob[v] += (float)stay;\n                        addFuture(v, stay);\n                    } else if (u == v) {\n                        ch.prob[v] += mf;\n                        addFuture(v, m);\n                    } else {\n                        double stay = m * pForget;\n                        double mv = m * qRemember;\n\n                        ch.prob[v] += (float)stay;\n                        ch.prob[u] += (float)mv;\n\n                        addFuture(v, stay);\n                        addFuture(u, mv);\n                    }\n                }\n\n                ch.score = par.score + (400 - l) * hit;\n                ch.est = ch.score + future;\n            }\n        }\n\n        int n = (int)nxt.size();\n\n        if (n > width) {\n            idx.resize(n);\n            iota(idx.begin(), idx.end(), 0);\n\n            auto cmp = [&](int x, int y) {\n                if (nxt[x].est != nxt[y].est) return nxt[x].est > nxt[y].est;\n                return nxt[x].score > nxt[y].score;\n            };\n\n            nth_element(idx.begin(), idx.begin() + width, idx.end(), cmp);\n\n            selected.clear();\n\n            for (int i = 0; i < width; i++) {\n                selected.push_back(nxt[idx[i]]);\n            }\n\n            cur.swap(selected);\n        } else {\n            cur.swap(nxt);\n        }\n    }\n\n    vector<vector<int>> res;\n    int n = (int)cur.size();\n\n    idx.resize(n);\n    iota(idx.begin(), idx.end(), 0);\n\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        return cur[x].score > cur[y].score;\n    });\n\n    int take = min(topCount, n);\n\n    for (int r = 0; r < take; r++) {\n        vector<int> s(MAXL);\n        const BeamNode& node = cur[idx[r]];\n\n        for (int k = 0; k < MAXL; k++) {\n            s[k] = node.seq[k];\n        }\n\n        res.push_back(move(s));\n    }\n\n    return res;\n}\n\nvector<int> bestCrossoverSeq(const vector<int>& A, const vector<int>& B) {\n    computeSuffixOnly(B);\n    computePrefixOnly(A);\n\n    double best = -1.0;\n    int bestK = 0;\n\n    for (int k = 0; k <= MAXL; k++) {\n        double total = prefScore[k];\n\n        for (int v = 0; v < N; v++) {\n            total += pref[k][v] * suff[k][v];\n        }\n\n        if (total > best) {\n            best = total;\n            bestK = k;\n        }\n    }\n\n    vector<int> s;\n    s.reserve(MAXL);\n\n    for (int i = 0; i < bestK; i++) s.push_back(A[i]);\n    for (int i = bestK; i < MAXL; i++) s.push_back(B[i]);\n\n    return s;\n}\n\nvoid addCrossovers(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>(cands.size(), 14));\n\n    int m = min<int>(8, cands.size());\n    vector<vector<int>> top;\n\n    for (int i = 0; i < m; i++) top.push_back(cands[i].seq);\n\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < m; j++) {\n            if (i == j) continue;\n\n            if (elapsedSec() > 1.60) return;\n\n            vector<int> s = bestCrossoverSeq(top[i], top[j]);\n            addCandidate(cands, s, F_LAST);\n        }\n    }\n}\n\nvoid addGreedyTailCandidates(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>(cands.size(), 12));\n\n    vector<vector<int>> top;\n    int m = min<int>(6, cands.size());\n\n    for (int i = 0; i < m; i++) top.push_back(cands[i].seq);\n\n    vector<int> cuts = {0, 25, 50, 75, 100, 125, 150, 175};\n\n    for (auto& base : top) {\n        for (int k : cuts) {\n            if (elapsedSec() > 1.55) return;\n\n            vector<int> s(base.begin(), base.begin() + k);\n            addCandidate(cands, s, F_GREEDY);\n        }\n    }\n}\n\nbool tryWindow(vector<int>& seq, int win, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    int masks = 1 << (2 * win);\n\n    static double buf1[N], buf2[N];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 3) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        for (int mask = 0; mask < masks; mask++) {\n            if (mask == curMask) continue;\n\n            memcpy(buf1, pref[k], sizeof(double) * N);\n\n            double* dp = buf1;\n            double* ndp = buf2;\n            double sc = prefScore[k];\n\n            int mm = mask;\n\n            for (int r = 0; r < win; r++) {\n                int a = mm & 3;\n                mm >>= 2;\n\n                fill(ndp, ndp + N, 0.0);\n\n                double hit = 0.0;\n                double reward = 400 - (k + r);\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        ndp[v] += m * pForget;\n                    } else if (u == v) {\n                        ndp[v] += m;\n                    } else {\n                        ndp[v] += m * pForget;\n                        ndp[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp, ndp);\n            }\n\n            double total = sc;\n            const double* sw = suff[k + win];\n\n            for (int v = 0; v < N; v++) {\n                total += dp[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = mask;\n            }\n        }\n    }\n\n    if (bestK != -1) {\n        int mm = bestMask;\n\n        for (int r = 0; r < win; r++) {\n            seq[bestK + r] = mm & 3;\n            mm >>= 2;\n        }\n\n        newScore = best;\n        return true;\n    }\n\n    return false;\n}\n\nbool tryShiftDP(vector<int>& seq, double currentScore, double& newScore) {\n    int L = (int)seq.size();\n    if (L != MAXL) return false;\n\n    static double insSuff[MAXL + 1][N];\n    static double delSuff[4][MAXL + 1][N];\n\n    fill(insSuff[L - 1], insSuff[L - 1] + N, 0.0);\n\n    for (int k = L - 2; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 399 - k;\n        const double* nxt = insSuff[k + 1];\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                insSuff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                insSuff[k][v] = qRemember * reward + pForget * nxt[v];\n            } else if (u == v) {\n                insSuff[k][v] = nxt[v];\n            } else {\n                insSuff[k][v] = pForget * nxt[v] + qRemember * nxt[u];\n            }\n        }\n    }\n\n    double finalReward = 400 - (L - 1);\n\n    for (int c = 0; c < 4; c++) {\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                delSuff[c][L][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[c][v];\n            delSuff[c][L][v] = (u == TID ? qRemember * finalReward : 0.0);\n        }\n\n        for (int k = L - 1; k >= 1; k--) {\n            int a = seq[k];\n            double reward = 401 - k;\n            const double* nxt = delSuff[c][k + 1];\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    delSuff[c][k][v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    delSuff[c][k][v] = qRemember * reward + pForget * nxt[v];\n                } else if (u == v) {\n                    delSuff[c][k][v] = nxt[v];\n                } else {\n                    delSuff[c][k][v] = pForget * nxt[v] + qRemember * nxt[u];\n                }\n            }\n        }\n    }\n\n    double best = currentScore;\n    int bestType = -1;\n    int bestI = -1;\n    int bestC = -1;\n\n    // Insert command at i and drop last.\n    for (int i = 0; i < L; i++) {\n        const double* row = pref[i];\n        double base = prefScore[i];\n        double reward = 400 - i;\n        const double* tail = insSuff[i];\n\n        for (int c = 0; c < 4; c++) {\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                double m = row[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[c][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * tail[v];\n                } else if (u == v) {\n                    val = tail[v];\n                } else {\n                    val = pForget * tail[v] + qRemember * tail[u];\n                }\n\n                total += m * val;\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 0;\n                bestI = i;\n                bestC = c;\n            }\n        }\n    }\n\n    // Delete command at i and append c.\n    for (int i = 0; i < L; i++) {\n        const double* row = pref[i];\n        double base = prefScore[i];\n\n        for (int c = 0; c < 4; c++) {\n            const double* tail = delSuff[c][i + 1];\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                total += row[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 1;\n                bestI = i;\n                bestC = c;\n            }\n        }\n    }\n\n    if (bestType == -1) return false;\n\n    vector<int> ns(L);\n\n    if (bestType == 0) {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n        ns[bestI] = bestC;\n        for (int k = bestI + 1; k < L; k++) ns[k] = seq[k - 1];\n    } else {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n        for (int k = bestI; k < L - 1; k++) ns[k] = seq[k + 1];\n        ns[L - 1] = bestC;\n    }\n\n    seq.swap(ns);\n    newScore = best;\n    return true;\n}\n\nstruct BlockNode {\n    double prob[N];\n    double sc;\n    double key;\n    int mask;\n};\n\nbool tryWindowBeam(vector<int>& seq, int win, int beamW, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    if (win <= 0 || win > 10) return false;\n\n    beamW = min(beamW, 30);\n\n    static BlockNode cur[32], nxt[128], sel[32];\n    static int idx[128];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 1) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        int curN = 1;\n        memcpy(cur[0].prob, pref[k], sizeof(double) * N);\n        cur[0].sc = 0.0;\n        cur[0].key = 0.0;\n        cur[0].mask = 0;\n\n        for (int r = 0; r < win; r++) {\n            int nn = 0;\n            int pos = k + r;\n            double reward = 400 - pos;\n            const double* vrow = adaptVal[pos + 1];\n            const double* drow = pot[pos + 1];\n\n            for (int bi = 0; bi < curN; bi++) {\n                const BlockNode& par = cur[bi];\n\n                for (int a = 0; a < 4; a++) {\n                    BlockNode& ch = nxt[nn++];\n                    fill(ch.prob, ch.prob + N, 0.0);\n\n                    double hit = 0.0;\n                    double future = 0.0;\n\n                    for (int v = 0; v < N; v++) {\n                        double m = par.prob[v];\n                        if (m == 0.0) continue;\n\n                        int u = goTo[a][v];\n\n                        if (u == TID) {\n                            double stay = m * pForget;\n                            hit += m * qRemember;\n                            ch.prob[v] += stay;\n                            future += stay * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                        } else if (u == v) {\n                            ch.prob[v] += m;\n                            future += m * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                        } else {\n                            double stay = m * pForget;\n                            double mv = m * qRemember;\n                            ch.prob[v] += stay;\n                            ch.prob[u] += mv;\n                            future += stay * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                            future += mv * (0.65 * vrow[u] + 0.35 * drow[distT[u]]);\n                        }\n                    }\n\n                    ch.sc = par.sc + reward * hit;\n                    ch.key = ch.sc + future;\n                    ch.mask = par.mask | (a << (2 * r));\n                }\n            }\n\n            if (nn > beamW) {\n                iota(idx, idx + nn, 0);\n                nth_element(idx, idx + beamW, idx + nn, [&](int x, int y) {\n                    return nxt[x].key > nxt[y].key;\n                });\n\n                for (int i = 0; i < beamW; i++) {\n                    sel[i] = nxt[idx[i]];\n                }\n\n                curN = beamW;\n                for (int i = 0; i < curN; i++) {\n                    cur[i] = sel[i];\n                }\n            } else {\n                curN = nn;\n                for (int i = 0; i < curN; i++) {\n                    cur[i] = nxt[i];\n                }\n            }\n        }\n\n        const double* sw = suff[k + win];\n\n        for (int bi = 0; bi < curN; bi++) {\n            if (cur[bi].mask == curMask) continue;\n\n            double total = prefScore[k] + cur[bi].sc;\n\n            for (int v = 0; v < N; v++) {\n                total += cur[bi].prob[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = cur[bi].mask;\n            }\n        }\n    }\n\n    if (bestK == -1) return false;\n\n    int mm = bestMask;\n    for (int r = 0; r < win; r++) {\n        seq[bestK + r] = mm & 3;\n        mm >>= 2;\n    }\n\n    newScore = best;\n    return true;\n}\n\ndouble improve(vector<int>& seq, double deadline, int maxWindow, bool useShift, bool useLarge) {\n    int L = (int)seq.size();\n    double curScore = evaluate(seq);\n\n    while (elapsedSec() < deadline) {\n        computePrefixSuffix(seq);\n        curScore = prefScore[L];\n\n        double bestScore = curScore;\n        int bestK = -1;\n        int bestC = -1;\n\n        for (int k = 0; k < L; k++) {\n            const double* row = pref[k];\n            const double* sw = suff[k + 1];\n            double base = prefScore[k];\n            double reward = 400 - k;\n\n            for (int c = 0; c < 4; c++) {\n                if (c == seq[k]) continue;\n\n                double total = base;\n\n                for (int v = 0; v < N; v++) {\n                    double m = row[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[c][v];\n                    double val;\n\n                    if (u == TID) {\n                        val = qRemember * reward + pForget * sw[v];\n                    } else if (u == v) {\n                        val = sw[v];\n                    } else {\n                        val = pForget * sw[v] + qRemember * sw[u];\n                    }\n\n                    total += m * val;\n                }\n\n                if (total > bestScore + EPS) {\n                    bestScore = total;\n                    bestK = k;\n                    bestC = c;\n                }\n            }\n        }\n\n        if (bestK != -1) {\n            seq[bestK] = bestC;\n            curScore = bestScore;\n            continue;\n        }\n\n        bool changed = false;\n\n        for (int w = 2; w <= maxWindow; w++) {\n            if (elapsedSec() > deadline - 0.01) break;\n\n            double ns;\n            if (tryWindow(seq, w, curScore, deadline, ns)) {\n                curScore = ns;\n                changed = true;\n                break;\n            }\n        }\n\n        if (changed) continue;\n\n        if (useShift && elapsedSec() < deadline - 0.005) {\n            double ns;\n            if (tryShiftDP(seq, curScore, ns)) {\n                curScore = ns;\n                continue;\n            }\n        }\n\n        if (useLarge && elapsedSec() < deadline - 0.05) {\n            double ns;\n            int bw = (pForget >= 0.35 ? 14 : 12);\n\n            if (tryWindowBeam(seq, 7, bw, curScore, deadline, ns)) {\n                curScore = ns;\n                continue;\n            }\n\n            if (elapsedSec() < deadline - 0.06 && tryWindowBeam(seq, 10, 8, curScore, deadline, ns)) {\n                curScore = ns;\n                continue;\n            }\n        }\n\n        break;\n    }\n\n    return evaluate(seq);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si_ >> sj_ >> ti_ >> tj_ >> pForget;\n    qRemember = 1.0 - pForget;\n\n    for (int i = 0; i < H; i++) cin >> hwall[i];\n    for (int i = 0; i < H - 1; i++) cin >> vwall[i];\n\n    SID = id(si_, sj_);\n    TID = id(ti_, tj_);\n\n    startTime = chrono::steady_clock::now();\n\n    buildGo();\n    bfsDistFrom(TID, distT);\n    bfsDistFrom(SID, distS);\n    buildPotential();\n    buildAdaptiveValue();\n\n    vector<Candidate> cands;\n\n    addCandidate(cands, vector<int>{}, F_GREEDY);\n\n    for (int mode = 0; mode < 3; mode++) {\n        addCandidate(cands, greedySequenceMode(mode), F_LAST);\n    }\n\n    array<int, 4> originalOrder{0, 1, 2, 3};\n    vector<int> spOriginal = bfsPath(SID, TID, originalOrder);\n    addPathCandidatesOriginal(cands, spOriginal);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2},\n        array<int, 4>{1, 3, 2, 0},\n        array<int, 4>{3, 1, 2, 0},\n        array<int, 4>{0, 1, 3, 2},\n        array<int, 4>{2, 3, 1, 0}\n    };\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPath(SID, TID, ord);\n        addLightPathCandidates(cands, path);\n    }\n\n    for (int r = 0; r < 4; r++) {\n        int noise = 350 + 100 * r;\n        int bias = (r % 2 == 0 ? 120 : 0);\n        addLightPathCandidates(cands, randomPathTo(TID, 10000 + r * 97, noise, bias));\n    }\n\n    addNearTargetCandidates(cands);\n    addTargetRayCandidates(cands);\n    addSweepCandidates(cands);\n\n    for (double z : {0.0, 0.5, 1.0, 1.5, 2.2}) {\n        vector<int> s = slideCandidate(z);\n        if (!s.empty()) {\n            addCandidate(cands, s, F_LAST);\n            addCandidate(cands, s, F_GREEDY);\n        }\n    }\n\n    pruneCands(cands, 90);\n\n    vector<vector<int>> distBeamSeqs;\n    distBeamSeqs = beamSearchMode(8, 430, 0);\n\n    for (auto& s : distBeamSeqs) {\n        addCandidate(cands, s, F_LAST);\n    }\n\n    if (elapsedSec() < 1.20) {\n        vector<vector<int>> adapBeamSeqs = beamSearchMode(5, 170, 1);\n        for (auto& s : adapBeamSeqs) {\n            addCandidate(cands, s, F_LAST);\n        }\n    }\n\n    pruneCands(cands, 100);\n\n    if (elapsedSec() < 1.45) {\n        addGreedyTailCandidates(cands);\n    }\n\n    if (elapsedSec() < 1.50) {\n        addCrossovers(cands);\n    }\n\n    if (cands.empty()) {\n        addCandidate(cands, vector<int>{}, F_GREEDY);\n    }\n\n    pruneCands(cands, 100);\n\n    vector<int> bestSeq = cands[0].seq;\n    double bestScore = cands[0].score;\n\n    vector<vector<int>> localStarts;\n\n    auto addStart = [&](const vector<int>& s) {\n        if ((int)s.size() != MAXL) return;\n\n        for (auto& t : localStarts) {\n            if (t == s) return;\n        }\n\n        localStarts.push_back(s);\n    };\n\n    addStart(cands[0].seq);\n\n    if (!distBeamSeqs.empty()) {\n        addStart(distBeamSeqs[0]);\n        if ((int)distBeamSeqs.size() >= 2) addStart(distBeamSeqs[1]);\n    }\n\n    int topStarts = min<int>(8, cands.size());\n    for (int i = 1; i < topStarts; i++) {\n        addStart(cands[i].seq);\n    }\n\n    for (int i = 0; i < (int)localStarts.size(); i++) {\n        if (elapsedSec() > HARD_LIMIT - 0.22) break;\n\n        vector<int> seq = localStarts[i];\n\n        double budget;\n        if (i == 0) budget = 0.22;\n        else if (i <= 2) budget = 0.20;\n        else budget = 0.10;\n\n        double dl = min(HARD_LIMIT - 0.12, elapsedSec() + budget);\n        if (dl <= elapsedSec() + 0.01) break;\n\n        int mw = (i <= 2 ? 3 : 2);\n        bool useShift = (i <= 3);\n        double sc = improve(seq, dl, mw, useShift, false);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    if (elapsedSec() < HARD_LIMIT - 0.04) {\n        vector<int> seq = bestSeq;\n        double sc = improve(seq, HARD_LIMIT, 4, true, true);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    if ((int)bestSeq.size() > MAXL) bestSeq.resize(MAXL);\n    if ((int)bestSeq.size() < MAXL) completeGreedy(bestSeq);\n\n    string out;\n    out.reserve(MAXL);\n\n    for (int a : bestSeq) {\n        out.push_back(DIRS[a]);\n    }\n\n    cout << out << '\\n';\n\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int CELLS = N * N;\nconstexpr int PORTS = CELLS * 4;\nconstexpr int MAXLEN = 1800;\nconstexpr int MAXCOMP = 4005;\nconstexpr int BITWORDS = (CELLS + 63) / 64;\n\nusing StateArr = array<unsigned char, CELLS>;\n\nint pairDir[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\nint maskState[8];\nint segCnt[8];\nint segA[8][2], segB[8][2];\n\nint adjPort[PORTS];\nint neighCell[CELLS][4];\n\nint baseTile[CELLS];\nint optCnt[CELLS];\nint optState[CELLS][4];\n\nint moveCnt[PORTS];\nint moveNextState[PORTS][2];\nvector<int> validMoveStates;\n\nint di[4] = {0, -1, 0, 1};\nint dj[4] = {-1, 0, 1, 0};\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = seed ? seed : 88172645463325252ULL;\n        for (int i = 0; i < 20; i++) next();\n    }\n    inline uint64_t next() {\n        x ^= x << 13;\n        x ^= x >> 7;\n        x ^= x << 17;\n        return x;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct BIT {\n    int bit[MAXLEN + 2];\n    int total;\n\n    void reset() {\n        memset(bit, 0, sizeof(bit));\n        total = 0;\n    }\n\n    void add(int idx, int delta) {\n        if (idx <= 0) return;\n        total += delta;\n        for (int i = idx; i <= MAXLEN; i += i & -i) bit[i] += delta;\n    }\n\n    int kth(int k) const {\n        int idx = 0;\n        for (int pw = 2048; pw; pw >>= 1) {\n            int ni = idx + pw;\n            if (ni <= MAXLEN && bit[ni] < k) {\n                idx = ni;\n                k -= bit[ni];\n            }\n        }\n        return idx + 1;\n    }\n};\n\nstruct Stats {\n    int l1 = 0, l2 = 0;\n    int c1 = 0, c2 = 0;\n    int loops = 0;\n    int broken = 0;\n    long long score = 0;\n    long long loopSq = 0;\n};\n\nstruct Manager {\n    unsigned char st[CELLS];\n\n    int comp[PORTS];\n    vector<int> ports[MAXCOMP];\n    bool alive[MAXCOMP];\n    int compLen[MAXCOMP];\n    int compBroken[MAXCOMP];\n\n    int nextId = 0;\n    vector<int> freeIds;\n\n    BIT compBIT, loopBIT;\n    long long loopSq = 0;\n    int brokenTotal = 0;\n\n    int stackBuf[PORTS];\n\n    Manager() {\n        freeIds.reserve(MAXCOMP);\n        memset(alive, 0, sizeof(alive));\n    }\n\n    inline bool active(int p) const {\n        return pairDir[st[p >> 2]][p & 3] >= 0;\n    }\n\n    inline int internalPort(int p) const {\n        return (p & ~3) | pairDir[st[p >> 2]][p & 3];\n    }\n\n    int allocId() {\n        int id;\n        if (!freeIds.empty()) {\n            id = freeIds.back();\n            freeIds.pop_back();\n        } else {\n            id = nextId++;\n        }\n        alive[id] = true;\n        ports[id].clear();\n        return id;\n    }\n\n    void addStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, 1);\n        brokenTotal += br;\n\n        if (br == 0) {\n            loopBIT.add(len, 1);\n            loopSq += 1LL * len * len;\n        }\n    }\n\n    void removeStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, -1);\n        brokenTotal -= br;\n\n        if (br == 0) {\n            loopBIT.add(len, -1);\n            loopSq -= 1LL * len * len;\n        }\n    }\n\n    void removeComp(int id) {\n        if (id < 0 || !alive[id]) return;\n\n        removeStats(id);\n\n        for (int p : ports[id]) comp[p] = -1;\n        ports[id].clear();\n        alive[id] = false;\n        freeIds.push_back(id);\n    }\n\n    void addComponent(int start) {\n        int id = allocId();\n\n        int top = 0;\n        stackBuf[top++] = start;\n        comp[start] = id;\n        ports[id].push_back(start);\n\n        int broken = 0;\n\n        while (top) {\n            int p = stackBuf[--top];\n\n            int q = internalPort(p);\n            if (comp[q] == -1) {\n                comp[q] = id;\n                ports[id].push_back(q);\n                stackBuf[top++] = q;\n            }\n\n            int e = adjPort[p];\n            if (e != -1 && active(e)) {\n                if (comp[e] == -1) {\n                    comp[e] = id;\n                    ports[id].push_back(e);\n                    stackBuf[top++] = e;\n                }\n            } else {\n                broken++;\n            }\n        }\n\n        compLen[id] = (int)ports[id].size() / 2;\n        compBroken[id] = broken;\n        addStats(id);\n    }\n\n    void build(const StateArr &arr) {\n        for (int i = 0; i < nextId; i++) {\n            ports[i].clear();\n            alive[i] = false;\n        }\n\n        nextId = 0;\n        freeIds.clear();\n\n        compBIT.reset();\n        loopBIT.reset();\n        loopSq = 0;\n        brokenTotal = 0;\n\n        for (int i = 0; i < CELLS; i++) st[i] = arr[i];\n        fill(comp, comp + PORTS, -1);\n\n        for (int p = 0; p < PORTS; p++) {\n            if (active(p) && comp[p] == -1) addComponent(p);\n        }\n    }\n\n    void updateCell(int cell, int newState) {\n        if (st[cell] == newState) return;\n\n        int ids[20];\n        int cnt = 0;\n\n        auto addId = [&](int id) {\n            if (id < 0 || !alive[id]) return;\n            for (int k = 0; k < cnt; k++) {\n                if (ids[k] == id) return;\n            }\n            ids[cnt++] = id;\n        };\n\n        int base = cell * 4;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            addId(comp[p]);\n            int e = adjPort[p];\n            if (e != -1) addId(comp[e]);\n        }\n\n        for (int k = 0; k < cnt; k++) removeComp(ids[k]);\n\n        st[cell] = (unsigned char)newState;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            if (active(p) && comp[p] == -1) addComponent(p);\n\n            int e = adjPort[p];\n            if (e != -1 && active(e) && comp[e] == -1) addComponent(e);\n        }\n    }\n\n    Stats getStats() const {\n        Stats s;\n\n        s.loops = loopBIT.total;\n\n        if (loopBIT.total >= 1) s.l1 = loopBIT.kth(loopBIT.total);\n        if (loopBIT.total >= 2) s.l2 = loopBIT.kth(loopBIT.total - 1);\n\n        if (compBIT.total >= 1) s.c1 = compBIT.kth(compBIT.total);\n        if (compBIT.total >= 2) s.c2 = compBIT.kth(compBIT.total - 1);\n\n        s.score = 1LL * s.l1 * s.l2;\n        s.loopSq = loopSq;\n        s.broken = brokenTotal;\n\n        return s;\n    }\n\n    void exportState(StateArr &out) const {\n        for (int i = 0; i < CELLS; i++) out[i] = st[i];\n    }\n};\n\nvoid initGlobals() {\n    for (int t = 0; t < 8; t++) {\n        maskState[t] = 0;\n        segCnt[t] = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (pairDir[t][d] != -1) maskState[t] |= 1 << d;\n        }\n\n        for (int d = 0; d < 4; d++) {\n            int e = pairDir[t][d];\n            if (e != -1 && d < e) {\n                int k = segCnt[t]++;\n                segA[t][k] = d;\n                segB[t][k] = e;\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                    neighCell[id][d] = -1;\n                    adjPort[id * 4 + d] = -1;\n                } else {\n                    int nb = ni * N + nj;\n                    neighCell[id][d] = nb;\n                    adjPort[id * 4 + d] = nb * 4 + (d ^ 2);\n                }\n            }\n        }\n    }\n}\n\nvoid buildMoveTransitions() {\n    validMoveStates.clear();\n\n    for (int s = 0; s < PORTS; s++) {\n        moveCnt[s] = 0;\n\n        int c = s >> 2;\n        int d = s & 3;\n\n        if (neighCell[c][d] == -1) continue;\n\n        if (baseTile[c] >= 6) {\n            int out = d ^ 2;\n            int nb = neighCell[c][out];\n            if (nb != -1) {\n                moveNextState[s][moveCnt[s]++] = nb * 4 + (out ^ 2);\n            }\n        } else {\n            int out1 = (d + 1) & 3;\n            int out2 = (d + 3) & 3;\n\n            int nb1 = neighCell[c][out1];\n            if (nb1 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb1 * 4 + (out1 ^ 2);\n            }\n\n            int nb2 = neighCell[c][out2];\n            if (nb2 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb2 * 4 + (out2 ^ 2);\n            }\n        }\n\n        if (moveCnt[s] > 0) validMoveStates.push_back(s);\n    }\n}\n\nint stateForPair(int base, int a, int b) {\n    if (a > b) swap(a, b);\n\n    if (base < 4) {\n        if (a == 0 && b == 1) return 0;\n        if (a == 0 && b == 3) return 1;\n        if (a == 2 && b == 3) return 2;\n        if (a == 1 && b == 2) return 3;\n        return -1;\n    } else if (base < 6) {\n        if ((a == 0 && b == 1) || (a == 2 && b == 3)) return 4;\n        if ((a == 0 && b == 3) || (a == 1 && b == 2)) return 5;\n        return -1;\n    } else {\n        if (a == 0 && b == 2) return 6;\n        if (a == 1 && b == 3) return 7;\n        return -1;\n    }\n}\n\nint localQuality(const unsigned char *arr, int id, int candState) {\n    bool nbAct[4];\n\n    for (int d = 0; d < 4; d++) {\n        int nb = neighCell[id][d];\n        nbAct[d] = false;\n\n        if (nb != -1) {\n            int ns = arr[nb];\n            nbAct[d] = (maskState[ns] >> (d ^ 2)) & 1;\n        }\n    }\n\n    int cm = maskState[candState];\n    int q = 0;\n\n    for (int d = 0; d < 4; d++) {\n        bool ca = (cm >> d) & 1;\n        bool na = nbAct[d];\n\n        if (ca && na) q += 6;\n        else if (ca || na) q -= 4;\n    }\n\n    for (int k = 0; k < segCnt[candState]; k++) {\n        int a = segA[candState][k];\n        int b = segB[candState][k];\n\n        int c = (nbAct[a] ? 1 : 0) + (nbAct[b] ? 1 : 0);\n\n        if (c == 2) q += 20;\n        else if (c == 1) q -= 3;\n        else q -= 8;\n    }\n\n    return q;\n}\n\nvoid greedyImprove(StateArr &cand, RNG &rng, int sweeps, const char *fixed = nullptr) {\n    int steps = sweeps * CELLS;\n\n    for (int it = 0; it < steps; it++) {\n        int id = rng.nextInt(CELLS);\n        if (fixed && fixed[id]) continue;\n\n        int bestSt = cand[id];\n        int bestQ = -1000000000;\n        int ties = 0;\n\n        for (int k = 0; k < optCnt[id]; k++) {\n            int s = optState[id][k];\n            int q = localQuality(cand.data(), id, s);\n\n            if (q > bestQ) {\n                bestQ = q;\n                bestSt = s;\n                ties = 1;\n            } else if (q == bestQ) {\n                ties++;\n                if (rng.nextInt(ties) == 0) bestSt = s;\n            }\n        }\n\n        cand[id] = (unsigned char)bestSt;\n    }\n}\n\nlong long startValue(const Stats &s) {\n    long long compProd = 1LL * s.c1 * s.c2;\n    return s.score * 1500LL + s.loopSq * 25LL + compProd * 6LL - 120LL * s.broken;\n}\n\nlong long energyValue(const Stats &s, double progress) {\n    long long compProd = 1LL * s.c1 * s.c2;\n\n    if (progress < 0.60) {\n        return s.score * 500LL\n             + s.loopSq * 30LL\n             + compProd * 8LL\n             + 1LL * s.l1 * s.l1 * 10LL\n             + 1LL * s.l2 * s.l2 * 10LL\n             - 110LL * s.broken;\n    } else {\n        return s.score * 2500LL\n             + s.loopSq * 5LL\n             + 1LL * s.l1 * s.l1 * 3LL\n             + 1LL * s.l2 * s.l2 * 3LL\n             + compProd / 3LL\n             - 4LL * s.broken;\n    }\n}\n\nlong long finalValue(const Stats &s) {\n    return s.score * 1000000LL\n         + 1LL * s.l1 * 2000LL\n         + 1LL * s.l2 * 1000LL\n         + s.loopSq\n         - 10LL * s.broken;\n}\n\nbool betterStats(const Stats &s, long long bestScore, int bestL1, int bestL2) {\n    if (s.score != bestScore) return s.score > bestScore;\n    return s.l1 + s.l2 > bestL1 + bestL2;\n}\n\nvoid updateBestWithState(\n    const StateArr &arr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        bestState = arr;\n    }\n}\n\nvoid updateBestWithManager(\n    const Manager &mgr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        mgr.exportState(bestState);\n    }\n}\n\nstruct Cycle {\n    int len = 0;\n    uint64_t hash = 0;\n    array<uint64_t, BITWORDS> bits{};\n    array<unsigned char, CELLS> pmask{};\n    array<unsigned char, CELLS> cstate{};\n    vector<int> cells;\n    vector<unsigned char> states;\n    vector<unsigned char> masks;\n};\n\nbool incompatibleCycle(const Cycle &a, const Cycle &b) {\n    for (int w = 0; w < BITWORDS; w++) {\n        uint64_t x = a.bits[w] & b.bits[w];\n\n        while (x) {\n            int bit = __builtin_ctzll(x);\n            int c = w * 64 + bit;\n            x &= x - 1;\n\n            if (c >= CELLS) continue;\n\n            if (!(baseTile[c] >= 4 && baseTile[c] < 6)) return true;\n            if (a.cstate[c] != b.cstate[c]) return true;\n            if (a.pmask[c] & b.pmask[c]) return true;\n        }\n    }\n\n    return false;\n}\n\nstruct CycleSampler {\n    static constexpr int MIN_LEN = 16;\n    static constexpr int KEEP = 1300;\n\n    vector<Cycle> cycles;\n\n    int stateSeen[PORTS];\n    int statePos[PORTS];\n\n    int cellSeen[CELLS];\n    int cellCnt[CELLS];\n\n    int tmpSeen[CELLS];\n    unsigned char tmpState[CELLS];\n    unsigned char tmpMask[CELLS];\n\n    int stamp = 1;\n    int tmpStamp = 1;\n    int minStored = MIN_LEN;\n\n    vector<int> path;\n    vector<int> tmpCells;\n\n    CycleSampler() {\n        memset(stateSeen, 0, sizeof(stateSeen));\n        memset(cellSeen, 0, sizeof(cellSeen));\n        memset(tmpSeen, 0, sizeof(tmpSeen));\n        cycles.reserve(KEEP);\n        path.reserve(PORTS);\n        tmpCells.reserve(MAXLEN);\n    }\n\n    void markState(int s) {\n        int pos = (int)path.size();\n        path.push_back(s);\n\n        stateSeen[s] = stamp;\n        statePos[s] = pos;\n\n        int c = s >> 2;\n        if (cellSeen[c] != stamp) {\n            cellSeen[c] = stamp;\n            cellCnt[c] = 0;\n        }\n        cellCnt[c]++;\n    }\n\n    bool canVisitState(int s) const {\n        if (stateSeen[s] == stamp) return false;\n\n        int c = s >> 2;\n\n        if (cellSeen[c] != stamp) return true;\n\n        return baseTile[c] >= 4 && baseTile[c] < 6 && cellCnt[c] < 2;\n    }\n\n    void recomputeMin() {\n        if ((int)cycles.size() < KEEP) {\n            minStored = MIN_LEN;\n            return;\n        }\n\n        minStored = 1000000;\n        for (const auto &c : cycles) minStored = min(minStored, c.len);\n    }\n\n    uint64_t calcHash(const Cycle &cy) {\n        uint64_t h = 1469598103934665603ULL ^ (uint64_t)cy.len;\n\n        for (uint64_t x : cy.bits) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n\n        for (int i = 0; i < (int)cy.cells.size(); i++) {\n            uint64_t v = (uint64_t)cy.cells[i] * 1315423911ULL\n                       + (uint64_t)cy.states[i] * 911382323ULL\n                       + (uint64_t)cy.masks[i] * 972663749ULL;\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n\n        return h;\n    }\n\n    void storeCycle(Cycle &&cy) {\n        for (const auto &ex : cycles) {\n            if (ex.len != cy.len || ex.hash != cy.hash) continue;\n            if (ex.cells == cy.cells && ex.states == cy.states && ex.masks == cy.masks) {\n                return;\n            }\n        }\n\n        if ((int)cycles.size() < KEEP) {\n            cycles.push_back(std::move(cy));\n            if ((int)cycles.size() == KEEP) recomputeMin();\n            return;\n        }\n\n        int mi = 0;\n        for (int i = 1; i < KEEP; i++) {\n            if (cycles[i].len < cycles[mi].len) mi = i;\n        }\n\n        if (cy.len > cycles[mi].len) {\n            cycles[mi] = std::move(cy);\n            recomputeMin();\n        }\n    }\n\n    void addCycle(int idx) {\n        int end = (int)path.size();\n        int len = end - idx;\n\n        if (len < MIN_LEN || len > MAXLEN) return;\n        if ((int)cycles.size() >= KEEP && len < minStored) return;\n\n        tmpStamp++;\n        if (tmpStamp == INT_MAX) {\n            memset(tmpSeen, 0, sizeof(tmpSeen));\n            tmpStamp = 1;\n        }\n\n        tmpCells.clear();\n\n        for (int p = idx; p < end; p++) {\n            int s = path[p];\n            int nxt = (p + 1 < end ? path[p + 1] : path[idx]);\n\n            int c = s >> 2;\n            int in = s & 3;\n            int out = (nxt & 3) ^ 2;\n\n            int st = stateForPair(baseTile[c], in, out);\n            if (st < 0) return;\n\n            unsigned char pm = (unsigned char)((1 << in) | (1 << out));\n\n            if (tmpSeen[c] != tmpStamp) {\n                tmpSeen[c] = tmpStamp;\n                tmpState[c] = (unsigned char)st;\n                tmpMask[c] = pm;\n                tmpCells.push_back(c);\n            } else {\n                if (!(baseTile[c] >= 4 && baseTile[c] < 6)) return;\n                if (tmpState[c] != st) return;\n                if (tmpMask[c] & pm) return;\n                tmpMask[c] |= pm;\n            }\n        }\n\n        Cycle cy;\n        cy.len = len;\n        cy.bits.fill(0);\n        cy.pmask.fill(0);\n        cy.cstate.fill((unsigned char)255);\n\n        sort(tmpCells.begin(), tmpCells.end());\n\n        cy.cells.reserve(tmpCells.size());\n        cy.states.reserve(tmpCells.size());\n        cy.masks.reserve(tmpCells.size());\n\n        for (int c : tmpCells) {\n            cy.bits[c >> 6] |= 1ULL << (c & 63);\n            cy.pmask[c] = tmpMask[c];\n            cy.cstate[c] = tmpState[c];\n\n            cy.cells.push_back(c);\n            cy.states.push_back(tmpState[c]);\n            cy.masks.push_back(tmpMask[c]);\n        }\n\n        cy.hash = calcHash(cy);\n        storeCycle(std::move(cy));\n    }\n\n    int onwardDegree(int ns) {\n        int deg = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) deg++;\n            } else if (canVisitState(nn)) {\n                deg++;\n            }\n        }\n\n        return deg;\n    }\n\n    int onwardScore(int ns, RNG &rng) {\n        int sc = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) sc += 20 + min(50, len / 8);\n            } else if (canVisitState(nn)) {\n                sc += 3;\n            }\n        }\n\n        int c = ns >> 2;\n        int i = c / N;\n        int j = c % N;\n        int border = min(min(i, N - 1 - i), min(j, N - 1 - j));\n        sc += border / 4;\n\n        return sc + rng.nextInt(4);\n    }\n\n    void sample(Timer &timer, double endTime, RNG &rng) {\n        if (validMoveStates.empty()) return;\n\n        while (timer.elapsed() < endTime) {\n            stamp++;\n\n            if (stamp == INT_MAX) {\n                memset(stateSeen, 0, sizeof(stateSeen));\n                memset(cellSeen, 0, sizeof(cellSeen));\n                stamp = 1;\n            }\n\n            path.clear();\n\n            int start = validMoveStates[rng.nextInt((int)validMoveStates.size())];\n            markState(start);\n\n            int mode = rng.nextInt(3);\n            int inner = 0;\n\n            while ((int)path.size() < MAXLEN) {\n                int cur = path.back();\n                int cnt = moveCnt[cur];\n\n                if (cnt == 0) break;\n\n                int cont[2];\n                int cc = 0;\n\n                for (int k = 0; k < cnt; k++) {\n                    int ns = moveNextState[cur][k];\n\n                    if (stateSeen[ns] == stamp) {\n                        int idx = statePos[ns];\n                        int len = (int)path.size() - idx;\n                        if (len >= MIN_LEN) addCycle(idx);\n                    } else if (canVisitState(ns)) {\n                        cont[cc++] = ns;\n                    }\n                }\n\n                if (cc == 0) break;\n\n                int chosen;\n\n                if (cc == 1) {\n                    chosen = cont[0];\n                } else if (mode == 2) {\n                    chosen = cont[rng.nextInt(2)];\n                } else if (mode == 1) {\n                    int d0 = onwardDegree(cont[0]);\n                    int d1 = onwardDegree(cont[1]);\n\n                    if (d0 == 0 && d1 > 0) {\n                        chosen = cont[1];\n                    } else if (d1 == 0 && d0 > 0) {\n                        chosen = cont[0];\n                    } else if (d0 == d1) {\n                        chosen = cont[rng.nextInt(2)];\n                    } else if (d0 < d1) {\n                        chosen = (rng.nextInt(4) ? cont[0] : cont[1]);\n                    } else {\n                        chosen = (rng.nextInt(4) ? cont[1] : cont[0]);\n                    }\n                } else {\n                    int s0 = onwardScore(cont[0], rng);\n                    int s1 = onwardScore(cont[1], rng);\n\n                    if (s0 == s1) {\n                        chosen = cont[rng.nextInt(2)];\n                    } else if (s0 > s1) {\n                        chosen = (rng.nextInt(5) ? cont[0] : cont[1]);\n                    } else {\n                        chosen = (rng.nextInt(5) ? cont[1] : cont[0]);\n                    }\n                }\n\n                markState(chosen);\n\n                inner++;\n                if ((inner & 255) == 0 && timer.elapsed() >= endTime) break;\n            }\n        }\n    }\n};\n\nvoid runSA(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    double startTime = timer.elapsed();\n    if (endTime - startTime < 0.01) return;\n\n    Stats initS = mgr.getStats();\n    updateBestWithManager(mgr, initS, bestState, bestScore, bestL1, bestL2);\n\n    int iter = 0;\n    double now = startTime;\n    double progress = 0.0;\n    double temp = 6e6;\n\n    while (true) {\n        if ((iter & 127) == 0) {\n            now = timer.elapsed();\n            if (now >= endTime) break;\n\n            progress = (now - startTime) / (endTime - startTime);\n            progress = min(1.0, max(0.0, progress));\n            temp = 6e6 * pow(2000.0 / 6e6, progress);\n        }\n\n        int ids[4];\n        int oldSt[4];\n        int newSt[4];\n        int m = 1;\n\n        int rr = rng.nextInt(100);\n\n        if (progress < 0.65 && rr < 6) {\n            m = 4;\n            int i = rng.nextInt(N - 1);\n            int j = rng.nextInt(N - 1);\n\n            ids[0] = i * N + j;\n            ids[1] = i * N + j + 1;\n            ids[2] = (i + 1) * N + j;\n            ids[3] = (i + 1) * N + j + 1;\n        } else if (progress < 0.85 && rr < 22) {\n            m = 2;\n            ids[0] = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int nb = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[ids[0]][d] != -1) {\n                    nb = neighCell[ids[0]][d];\n                    break;\n                }\n            }\n\n            ids[1] = nb;\n        } else {\n            m = 1;\n            ids[0] = rng.nextInt(CELLS);\n        }\n\n        bool changed = false;\n\n        for (int x = 0; x < m; x++) {\n            int id = ids[x];\n            int cur = mgr.st[id];\n            oldSt[x] = cur;\n\n            int ns = cur;\n\n            int smartProb = (m == 1 ? 25 : 45);\n\n            if (rng.nextInt(100) < smartProb) {\n                int bestQ = -1000000000;\n                int ties = 0;\n\n                for (int k = 0; k < optCnt[id]; k++) {\n                    int s = optState[id][k];\n                    if (s == cur) continue;\n\n                    int q = localQuality(mgr.st, id, s);\n\n                    if (q > bestQ) {\n                        bestQ = q;\n                        ns = s;\n                        ties = 1;\n                    } else if (q == bestQ) {\n                        ties++;\n                        if (rng.nextInt(ties) == 0) ns = s;\n                    }\n                }\n            } else {\n                do {\n                    ns = optState[id][rng.nextInt(optCnt[id])];\n                } while (ns == cur);\n            }\n\n            newSt[x] = ns;\n            if (ns != cur) changed = true;\n        }\n\n        if (!changed) {\n            iter++;\n            continue;\n        }\n\n        Stats oldS = mgr.getStats();\n        long long oldE = energyValue(oldS, progress);\n\n        for (int x = 0; x < m; x++) mgr.updateCell(ids[x], newSt[x]);\n\n        Stats newS = mgr.getStats();\n        long long newE = energyValue(newS, progress);\n\n        updateBestWithManager(mgr, newS, bestState, bestScore, bestL1, bestL2);\n\n        long long diff = newE - oldE;\n\n        bool accept = false;\n\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            double x = (double)diff / temp;\n            if (x > -30.0 && rng.nextDouble() < exp(x)) accept = true;\n        }\n\n        if (!accept) {\n            for (int x = m - 1; x >= 0; x--) mgr.updateCell(ids[x], oldSt[x]);\n        }\n\n        iter++;\n    }\n}\n\nvoid runHillClimb(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    mgr.build(bestState);\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 7) == 0) {\n            if (timer.elapsed() >= endTime) break;\n        }\n\n        bool pairMove = rng.nextInt(100) < 35;\n\n        if (!pairMove) {\n            int id = rng.nextInt(CELLS);\n            int cur = mgr.st[id];\n\n            Stats baseS = mgr.getStats();\n            long long bestVal = finalValue(baseS);\n            int bestSt = cur;\n\n            for (int k = 0; k < optCnt[id]; k++) {\n                int s = optState[id][k];\n                if (s == cur) continue;\n\n                mgr.updateCell(id, s);\n                Stats ns = mgr.getStats();\n                long long v = finalValue(ns);\n                mgr.updateCell(id, cur);\n\n                if (v > bestVal) {\n                    bestVal = v;\n                    bestSt = s;\n                }\n            }\n\n            if (bestSt != cur) {\n                mgr.updateCell(id, bestSt);\n                Stats s = mgr.getStats();\n                updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n            }\n        } else {\n            int id1 = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int id2 = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[id1][d] != -1) {\n                    id2 = neighCell[id1][d];\n                    break;\n                }\n            }\n\n            if (id2 == -1) {\n                iter++;\n                continue;\n            }\n\n            int old1 = mgr.st[id1];\n            int old2 = mgr.st[id2];\n\n            Stats baseS = mgr.getStats();\n            long long bestVal = finalValue(baseS);\n            int best1 = old1;\n            int best2 = old2;\n\n            for (int a = 0; a < optCnt[id1]; a++) {\n                int s1 = optState[id1][a];\n\n                for (int b = 0; b < optCnt[id2]; b++) {\n                    int s2 = optState[id2][b];\n\n                    if (s1 == old1 && s2 == old2) continue;\n\n                    mgr.updateCell(id1, s1);\n                    mgr.updateCell(id2, s2);\n\n                    Stats ns = mgr.getStats();\n                    long long v = finalValue(ns);\n\n                    mgr.updateCell(id2, old2);\n                    mgr.updateCell(id1, old1);\n\n                    if (v > bestVal) {\n                        bestVal = v;\n                        best1 = s1;\n                        best2 = s2;\n                    }\n                }\n            }\n\n            if (best1 != old1 || best2 != old2) {\n                mgr.updateCell(id1, best1);\n                mgr.updateCell(id2, best2);\n\n                Stats s = mgr.getStats();\n                updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n            }\n        }\n\n        iter++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initGlobals();\n\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        string row;\n        cin >> row;\n\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            int t = row[j] - '0';\n\n            baseTile[id] = t;\n            seed = seed * 1000003ULL + (uint64_t)(t + 17);\n        }\n    }\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n\n        if (b < 4) {\n            optCnt[id] = 4;\n            for (int k = 0; k < 4; k++) optState[id][k] = k;\n        } else if (b < 6) {\n            optCnt[id] = 2;\n            optState[id][0] = 4;\n            optState[id][1] = 5;\n        } else {\n            optCnt[id] = 2;\n            optState[id][0] = 6;\n            optState[id][1] = 7;\n        }\n    }\n\n    buildMoveTransitions();\n\n    Timer timer;\n    RNG rng(seed);\n\n    Manager mgr;\n\n    StateArr bestState{};\n    long long bestScore = -1;\n    int bestL1 = 0;\n    int bestL2 = 0;\n\n    vector<pair<long long, StateArr>> topStarts;\n\n    auto insertTop = [&](long long val, const StateArr &s) {\n        topStarts.push_back({val, s});\n\n        sort(topStarts.begin(), topStarts.end(),\n             [](const auto &a, const auto &b) {\n                 return a.first > b.first;\n             });\n\n        if ((int)topStarts.size() > 10) topStarts.pop_back();\n    };\n\n    auto evalCandidate = [&](const StateArr &cand) {\n        mgr.build(cand);\n        Stats s = mgr.getStats();\n\n        updateBestWithState(cand, s, bestState, bestScore, bestL1, bestL2);\n        insertTop(startValue(s), cand);\n    };\n\n    StateArr baseArr;\n    for (int id = 0; id < CELLS; id++) baseArr[id] = baseTile[id];\n    evalCandidate(baseArr);\n\n    CycleSampler sampler;\n    sampler.sample(timer, 0.30, rng);\n\n    auto &cycles = sampler.cycles;\n\n    sort(cycles.begin(), cycles.end(),\n         [](const Cycle &a, const Cycle &b) {\n             return a.len > b.len;\n         });\n\n    vector<tuple<long long, int, int>> topPairs;\n\n    auto insertPair = [&](long long prod, int a, int b) {\n        topPairs.emplace_back(prod, a, b);\n\n        sort(topPairs.begin(), topPairs.end(),\n             [](const auto &x, const auto &y) {\n                 return get<0>(x) > get<0>(y);\n             });\n\n        if ((int)topPairs.size() > 10) topPairs.pop_back();\n    };\n\n    int C = (int)cycles.size();\n    int I = min(C, 350);\n    int J = min(C, 1000);\n\n    for (int i = 0; i < I; i++) {\n        for (int j = i + 1; j < J; j++) {\n            long long prod = 1LL * cycles[i].len * cycles[j].len;\n\n            if ((int)topPairs.size() >= 10 && prod <= get<0>(topPairs.back())) {\n                break;\n            }\n\n            if (!incompatibleCycle(cycles[i], cycles[j])) {\n                insertPair(prod, i, j);\n            }\n        }\n    }\n\n    auto applyCycle = [&](const Cycle &cy, StateArr &cand, array<char, CELLS> &fixed) {\n        for (int c : cy.cells) {\n            cand[c] = cy.cstate[c];\n            fixed[c] = 1;\n        }\n    };\n\n    for (int p = 0; p < (int)topPairs.size(); p++) {\n        if (timer.elapsed() > 0.45) break;\n\n        int a = get<1>(topPairs[p]);\n        int b = get<2>(topPairs[p]);\n\n        for (int var = 0; var < 2; var++) {\n            if (timer.elapsed() > 0.48) break;\n\n            StateArr cand;\n            array<char, CELLS> fixed{};\n            fixed.fill(0);\n\n            if (var == 0) {\n                for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n            } else {\n                for (int id = 0; id < CELLS; id++) {\n                    cand[id] = optState[id][rng.nextInt(optCnt[id])];\n                }\n            }\n\n            applyCycle(cycles[a], cand, fixed);\n            applyCycle(cycles[b], cand, fixed);\n\n            greedyImprove(cand, rng, 7 + var, fixed.data());\n            evalCandidate(cand);\n        }\n    }\n\n    for (int sidx = 0; sidx < min(5, C); sidx++) {\n        if (timer.elapsed() > 0.49) break;\n\n        StateArr cand;\n        array<char, CELLS> fixed{};\n        fixed.fill(0);\n\n        for (int id = 0; id < CELLS; id++) {\n            cand[id] = optState[id][rng.nextInt(optCnt[id])];\n        }\n\n        applyCycle(cycles[sidx], cand, fixed);\n        greedyImprove(cand, rng, 7, fixed.data());\n        evalCandidate(cand);\n    }\n\n    constexpr int CAND_LIMIT = 55;\n    constexpr double START_END = 0.52;\n\n    for (int c = 0; c < CAND_LIMIT; c++) {\n        if (c > 4 && timer.elapsed() > START_END) break;\n\n        StateArr cand;\n\n        if (c == 0) {\n            for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n        } else {\n            for (int id = 0; id < CELLS; id++) {\n                cand[id] = optState[id][rng.nextInt(optCnt[id])];\n            }\n        }\n\n        int sweeps = 7 + (c % 4);\n        greedyImprove(cand, rng, sweeps);\n\n        evalCandidate(cand);\n    }\n\n    vector<StateArr> starts;\n\n    auto addUniqueStart = [&](const StateArr &s) {\n        for (const auto &t : starts) {\n            if (t == s) return;\n        }\n        starts.push_back(s);\n    };\n\n    addUniqueStart(bestState);\n\n    for (auto &p : topStarts) addUniqueStart(p.second);\n\n    if (starts.empty()) {\n        StateArr init;\n        for (int id = 0; id < CELLS; id++) init[id] = baseTile[id];\n        starts.push_back(init);\n        bestState = init;\n    }\n\n    double SA_END = 1.70;\n    double HILL_END = 1.92;\n\n    int runs = min(4, (int)starts.size());\n\n    for (int r = 0; r < runs; r++) {\n        double now = timer.elapsed();\n\n        if (now >= SA_END) break;\n\n        double endTime = now + (SA_END - now) / (runs - r);\n\n        mgr.build(starts[r]);\n        runSA(mgr, timer, endTime, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    if (timer.elapsed() < HILL_END) {\n        runHillClimb(mgr, timer, HILL_END, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    string ans;\n    ans.reserve(CELLS);\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n        int f = bestState[id];\n        int r;\n\n        if (b < 4) {\n            r = (f - b + 4) % 4;\n        } else {\n            r = (f == b ? 0 : 1);\n        }\n\n        ans.push_back(char('0' + r));\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#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\nint N, T, NN, M;\nvector<int> initBoard;\nint initBlank;\nint invCnt[16];\nint nbCell[105][4];\nint nearDistMask[16][105];\n\nconst int DR[4] = {-1, 1, 0, 0};\nconst int DC[4] = {0, 0, -1, 1};\nconst char DCH[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\nint hexVal(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return c - 'a' + 10;\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\nint bitForDir(int d) {\n    if (d == 0) return 2;\n    if (d == 1) return 8;\n    if (d == 2) return 1;\n    return 4;\n}\n\nbool inRegionCell(int id, int B) {\n    int r = id / N, c = id % N;\n    return !(r >= N - B && c >= N - B);\n}\n\nstruct FastDSU {\n    int p[105], sz[105];\n\n    void init(int n) {\n        for (int i = 0; i < n; i++) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\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\n    void unite(int a, int b) {\n        a = find(a);\n        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 Eval {\n    int S;\n    int edges;\n    int maxComp;\n};\n\nEval evalBoard(const vector<int>& bd) {\n    FastDSU dsu;\n    dsu.init(NN);\n\n    pair<int, int> edges[220];\n    int ec = 0;\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            int v = bd[id];\n            if (v == 0) continue;\n\n            if (c + 1 < N) {\n                int j = id + 1;\n                if (bd[j] != 0 && (v & 4) && (bd[j] & 1)) {\n                    dsu.unite(id, j);\n                    edges[ec++] = {id, j};\n                }\n            }\n\n            if (r + 1 < N) {\n                int j = id + N;\n                if (bd[j] != 0 && (v & 8) && (bd[j] & 2)) {\n                    dsu.unite(id, j);\n                    edges[ec++] = {id, j};\n                }\n            }\n        }\n    }\n\n    int vcnt[105] = {};\n    int ecnt[105] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (bd[i] != 0) vcnt[dsu.find(i)]++;\n    }\n    for (int i = 0; i < ec; i++) {\n        ecnt[dsu.find(edges[i].first)]++;\n    }\n\n    int best = 0;\n    int mx = 0;\n\n    for (int i = 0; i < NN; i++) {\n        if (dsu.find(i) == i && vcnt[i] > 0) {\n            mx = max(mx, vcnt[i]);\n            if (ecnt[i] == vcnt[i] - 1) {\n                best = max(best, vcnt[i]);\n            }\n        }\n    }\n\n    return {best, ec, mx};\n}\n\nlong long scoreFromEval(const Eval& e, int K) {\n    if (e.S == M) {\n        return llround(500000.0 * (2.0 - (double)K / T));\n    } else {\n        return llround(500000.0 * (double)e.S / M);\n    }\n}\n\nbool applyDir(vector<int>& bd, int& blank, int d) {\n    int nb = nbCell[blank][d];\n    if (nb < 0) return false;\n    swap(bd[blank], bd[nb]);\n    blank = nb;\n    return true;\n}\n\nvector<int> simulateMoves(const string& moves) {\n    vector<int> bd = initBoard;\n    int blank = initBlank;\n\n    for (char ch : moves) {\n        int d = dirIndex(ch);\n        if (!applyDir(bd, blank, d)) break;\n    }\n\n    return bd;\n}\n\nstring simplifyMoves(const string& s) {\n    string res;\n\n    for (char ch : s) {\n        int d = dirIndex(ch);\n        if (!res.empty() && dirIndex(res.back()) == OPP[d]) {\n            res.pop_back();\n        } else {\n            res.push_back(ch);\n        }\n    }\n\n    return res;\n}\n\nstruct BestAns {\n    string moves;\n    long long score = -1;\n    int S = 0;\n};\n\nvoid updateBestKnownBoard(BestAns& best, const string& mv0, const vector<int>& bd) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nvoid updateBest(BestAns& best, const string& mv0) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n\n    vector<int> bd = simulateMoves(mv);\n    updateBestKnownBoard(best, mv, bd);\n}\n\nuint64_t hashRegionMask(const vector<int>& mask, int B) {\n    uint64_t h = 1469598103934665603ULL ^ (uint64_t)B;\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, B)) {\n            h ^= (uint64_t)(mask[i] + 17);\n            h *= 1099511628211ULL;\n        }\n    }\n\n    return h;\n}\n\nint rectHungarian(const vector<int>& targets, const vector<int>& sources) {\n    int n = (int)targets.size();\n    int m = (int)sources.size();\n\n    if (n == 0) return 0;\n    if (n > m) return 1000000000;\n\n    const int INF = 1000000000;\n    vector<vector<int>> cost(n, vector<int>(m));\n\n    for (int i = 0; i < n; i++) {\n        int tr = targets[i] / N;\n        int tc = targets[i] % N;\n\n        for (int j = 0; j < m; j++) {\n            int sr = sources[j] / N;\n            int sc = sources[j] % N;\n            cost[i][j] = abs(tr - sr) + abs(tc - sc);\n        }\n    }\n\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\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n\n        do {\n            used[j0] = true;\n            int i0 = p[j0];\n            int delta = INF;\n            int j1 = 0;\n\n            for (int j = 1; j <= m; j++) {\n                if (used[j]) continue;\n\n                int cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\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\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);\n    }\n\n    return -v[0];\n}\n\nint partialMatchingCost(const vector<int>& target, int B) {\n    int total = 0;\n\n    for (int m = 1; m < 16; m++) {\n        vector<int> A;\n        vector<int> S;\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, B) && target[i] == m) A.push_back(i);\n            if (initBoard[i] == m) S.push_back(i);\n        }\n\n        if (A.size() > S.size()) return 1000000000;\n        total += rectHungarian(A, S);\n    }\n\n    return total;\n}\n\nstruct Candidate {\n    vector<int> target;\n    int B;\n    int expectedS;\n    int estCost;\n    uint64_t hash;\n};\n\nlong long candidateValue(const Candidate& c) {\n    return (long long)c.expectedS * 1000000LL - (long long)c.estCost * 1200LL - c.B * 1000LL;\n}\n\nvoid addPartialCandidate(vector<Candidate>& cands, const vector<int>& regionMask, int B) {\n    int cnt[16] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (!inRegionCell(i, B)) continue;\n        int m = regionMask[i];\n        if (m <= 0 || m >= 16) return;\n        cnt[m]++;\n    }\n\n    for (int m = 0; m < 16; m++) {\n        if (cnt[m] > invCnt[m]) return;\n    }\n\n    vector<int> freeCells;\n\n    for (int r = N - B; r < N; r++) {\n        for (int c = N - B; c < N; c++) {\n            freeCells.push_back(r * N + c);\n        }\n    }\n\n    vector<int> target(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, B)) target[i] = regionMask[i];\n    }\n\n    int blankCell = (N - 1) * N + (N - 1);\n    target[blankCell] = 0;\n\n    vector<int> remCnt(16);\n    int remSum = 0;\n\n    for (int m = 1; m < 16; m++) {\n        remCnt[m] = invCnt[m] - cnt[m];\n        remSum += remCnt[m];\n    }\n\n    if (remSum != (int)freeCells.size() - 1) return;\n\n    int ptr = 1;\n\n    for (int id : freeCells) {\n        if (id == blankCell) continue;\n\n        while (ptr < 16 && remCnt[ptr] == 0) ptr++;\n        if (ptr >= 16) return;\n\n        target[id] = ptr;\n        remCnt[ptr]--;\n    }\n\n    vector<int> ideal(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, B)) ideal[i] = regionMask[i];\n    }\n\n    Eval e = evalBoard(ideal);\n    int est = partialMatchingCost(target, B);\n\n    if (est >= 1000000000) return;\n\n    uint64_t h = hashRegionMask(regionMask, B);\n\n    for (const auto& c : cands) {\n        if (c.hash == h && c.B == B) return;\n    }\n\n    Candidate nc{target, B, e.S, est, h};\n\n    const int MAX_CANDS = 260;\n\n    if ((int)cands.size() < MAX_CANDS) {\n        cands.push_back(nc);\n    } else {\n        int worst = 0;\n\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (candidateValue(cands[i]) < candidateValue(cands[worst])) {\n                worst = i;\n            }\n        }\n\n        if (candidateValue(nc) > candidateValue(cands[worst])) {\n            cands[worst] = nc;\n        }\n    }\n}\n\nint outwardToFreeBits(int id, int B) {\n    int bits = 0;\n\n    for (int d = 0; d < 4; d++) {\n        int nb = nbCell[id][d];\n\n        if (nb >= 0 && !inRegionCell(nb, B)) {\n            bits |= bitForDir(d);\n        }\n    }\n\n    return bits;\n}\n\nvoid adjustAndAddCandidate(vector<Candidate>& cands, vector<int> regMask, int B) {\n    int cnt[16] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, B)) cnt[regMask[i]]++;\n    }\n\n    vector<int> cur(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, B)) cur[i] = regMask[i];\n    }\n\n    int guard = 0;\n\n    while (guard++ < 240) {\n        int over = -1;\n\n        for (int m = 1; m < 16; m++) {\n            if (cnt[m] > invCnt[m]) {\n                over = m;\n                break;\n            }\n        }\n\n        if (over == -1) break;\n\n        vector<int> deficits;\n\n        for (int m = 1; m < 16; m++) {\n            if (cnt[m] < invCnt[m]) deficits.push_back(m);\n        }\n\n        if (deficits.empty()) break;\n\n        int bestCell = -1;\n        int bestNew = -1;\n        long long bestVal = LLONG_MIN;\n\n        for (int id = 0; id < NN; id++) {\n            if (!inRegionCell(id, B) || cur[id] != over) continue;\n\n            int old = cur[id];\n\n            for (int nm : deficits) {\n                cur[id] = nm;\n                Eval e = evalBoard(cur);\n\n                int outPenalty = __builtin_popcount((unsigned)(nm & outwardToFreeBits(id, B)));\n\n                long long val =\n                    (long long)e.S * 1000000LL +\n                    (long long)e.maxComp * 5000LL +\n                    (long long)e.edges * 100LL -\n                    (long long)outPenalty * 200000LL -\n                    (long long)nearDistMask[nm][id] * 220LL -\n                    (long long)__builtin_popcount((unsigned)(nm ^ old)) * 60LL;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestCell = id;\n                    bestNew = nm;\n                }\n            }\n\n            cur[id] = old;\n        }\n\n        if (bestCell < 0) break;\n\n        int old = cur[bestCell];\n        cur[bestCell] = bestNew;\n        cnt[old]--;\n        cnt[bestNew]++;\n    }\n\n    for (int m = 0; m < 16; m++) {\n        if (cnt[m] > invCnt[m]) return;\n    }\n\n    addPartialCandidate(cands, cur, B);\n}\n\nvector<int> canonicalTreeMask(int B) {\n    vector<int> mask(NN, 0);\n    int root = 0;\n\n    for (int id = 0; id < NN; id++) {\n        if (!inRegionCell(id, B) || id == root) continue;\n\n        int r = id / N;\n        int c = id % N;\n        int parent = -1;\n\n        if (r > 0 && inRegionCell(id - N, B)) {\n            parent = id - N;\n        } else if (c > 0 && inRegionCell(id - 1, B)) {\n            parent = id - 1;\n        }\n\n        if (parent < 0) continue;\n\n        if (parent == id - N) {\n            mask[id] |= 2;\n            mask[parent] |= 8;\n        } else {\n            mask[id] |= 1;\n            mask[parent] |= 4;\n        }\n    }\n\n    return mask;\n}\n\nstruct Edge {\n    int a, b;\n    int ba, bb;\n};\n\nconst int OVER_W = 120000;\nconst int DIST_W = 95;\nconst int POS_W = 12;\n\nstruct Change {\n    int vc = 0;\n    int verts[4];\n    int oldm[4];\n    int newm[4];\n    int dcnt[16];\n    int overD = 0;\n    int distD = 0;\n    int posD = 0;\n    int energyD = 0;\n};\n\nstruct RegionTreeState {\n    int B;\n    vector<char> inReg;\n    vector<int> verts;\n    vector<Edge> edges;\n    int E;\n\n    vector<char> inTree;\n    vector<vector<int>> adj;\n    vector<int> mask;\n\n    int cnt[16];\n    int overflow = 0;\n    int distCost = 0;\n    int posCost = 0;\n\n    vector<int> par;\n    vector<int> pare;\n    vector<int> qbuf;\n    vector<int> path;\n\n    RegionTreeState(int B_) : B(B_) {\n        inReg.assign(NN, 0);\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, B)) {\n                inReg[i] = 1;\n                verts.push_back(i);\n            }\n        }\n\n        for (int id : verts) {\n            int r = id / N;\n            int c = id % N;\n\n            if (c + 1 < N) {\n                int j = id + 1;\n                if (inReg[j]) edges.push_back({id, j, 4, 1});\n            }\n\n            if (r + 1 < N) {\n                int j = id + N;\n                if (inReg[j]) edges.push_back({id, j, 8, 2});\n            }\n        }\n\n        E = (int)edges.size();\n\n        inTree.assign(E, 0);\n        adj.assign(NN, {});\n        mask.assign(NN, 0);\n\n        par.resize(NN);\n        pare.resize(NN);\n        qbuf.reserve(NN);\n        path.reserve(NN);\n    }\n\n    int other(int eid, int v) const {\n        const Edge& e = edges[eid];\n        return e.a == v ? e.b : e.a;\n    }\n\n    void addInitialEdge(int eid) {\n        const Edge& e = edges[eid];\n\n        inTree[eid] = 1;\n        adj[e.a].push_back(eid);\n        adj[e.b].push_back(eid);\n        mask[e.a] |= e.ba;\n        mask[e.b] |= e.bb;\n    }\n\n    int calcOverflow() const {\n        int ov = 0;\n\n        for (int m = 0; m < 16; m++) {\n            ov += max(0, cnt[m] - invCnt[m]);\n        }\n\n        return ov;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(inTree.begin(), inTree.end(), 0);\n\n        for (auto& a : adj) a.clear();\n\n        fill(mask.begin(), mask.end(), 0);\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(E);\n\n        for (int i = 0; i < E; i++) {\n            const Edge& e = edges[i];\n            int w = 0;\n\n            if (mode > 0) {\n                if (initBoard[e.a] & e.ba) w += 4;\n                else w -= 1;\n\n                if (initBoard[e.b] & e.bb) w += 4;\n                else w -= 1;\n\n                if (nearDistMask[e.ba][e.a] == 0) w++;\n                if (nearDistMask[e.bb][e.b] == 0) w++;\n\n                if (mode == 2) w += (int)(rng() % 7) - 3;\n            }\n\n            long long noise = ((long long)rng() << 32) ^ rng();\n            long long key = noise - (long long)w * (mode == 1 ? 950000000LL : 260000000LL);\n\n            if (mode == 0) key = noise;\n\n            ord.push_back({key, i});\n        }\n\n        sort(ord.begin(), ord.end());\n\n        FastDSU dsu;\n        dsu.init(NN);\n\n        int selected = 0;\n\n        for (auto [key, id] : ord) {\n            (void)key;\n\n            const Edge& e = edges[id];\n\n            if (dsu.find(e.a) != dsu.find(e.b)) {\n                dsu.unite(e.a, e.b);\n                addInitialEdge(id);\n                selected++;\n\n                if (selected == (int)verts.size() - 1) break;\n            }\n        }\n\n        memset(cnt, 0, sizeof(cnt));\n\n        overflow = 0;\n        distCost = 0;\n        posCost = 0;\n\n        for (int v : verts) {\n            cnt[mask[v]]++;\n            distCost += nearDistMask[mask[v]][v];\n            posCost += __builtin_popcount((unsigned)(mask[v] ^ initBoard[v]));\n        }\n\n        overflow = calcOverflow();\n    }\n\n    void getPath(int s, int t) {\n        fill(par.begin(), par.end(), -1);\n        qbuf.clear();\n        path.clear();\n\n        int head = 0;\n        par[s] = s;\n        qbuf.push_back(s);\n\n        while (head < (int)qbuf.size()) {\n            int v = qbuf[head++];\n\n            if (v == t) break;\n\n            for (int eid : adj[v]) {\n                if (!inTree[eid]) continue;\n\n                int u = other(eid, v);\n\n                if (par[u] == -1) {\n                    par[u] = v;\n                    pare[u] = eid;\n                    qbuf.push_back(u);\n                }\n            }\n        }\n\n        if (par[t] == -1) return;\n\n        int cur = t;\n\n        while (cur != s) {\n            path.push_back(pare[cur]);\n            cur = par[cur];\n        }\n    }\n\n    Change makeChange(int addId, int remId) const {\n        Change ch;\n        memset(ch.dcnt, 0, sizeof(ch.dcnt));\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < ch.vc; i++) {\n                if (ch.verts[i] == v) return i;\n            }\n\n            int idx = ch.vc++;\n            ch.verts[idx] = v;\n            ch.oldm[idx] = mask[v];\n            ch.newm[idx] = mask[v];\n            return idx;\n        };\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        int ia = getIdx(ea.a);\n        ch.newm[ia] |= ea.ba;\n\n        int ib = getIdx(ea.b);\n        ch.newm[ib] |= ea.bb;\n\n        int ra = getIdx(er.a);\n        ch.newm[ra] &= ~er.ba;\n\n        int rb = getIdx(er.b);\n        ch.newm[rb] &= ~er.bb;\n\n        for (int i = 0; i < ch.vc; i++) {\n            if (ch.oldm[i] == ch.newm[i]) continue;\n\n            int v = ch.verts[i];\n\n            ch.dcnt[ch.oldm[i]]--;\n            ch.dcnt[ch.newm[i]]++;\n\n            ch.distD += nearDistMask[ch.newm[i]][v] - nearDistMask[ch.oldm[i]][v];\n\n            ch.posD += __builtin_popcount((unsigned)(ch.newm[i] ^ initBoard[v]))\n                     - __builtin_popcount((unsigned)(ch.oldm[i] ^ initBoard[v]));\n        }\n\n        for (int m = 0; m < 16; m++) {\n            if (ch.dcnt[m]) {\n                ch.overD += max(0, cnt[m] + ch.dcnt[m] - invCnt[m])\n                          - max(0, cnt[m] - invCnt[m]);\n            }\n        }\n\n        ch.energyD = ch.overD * OVER_W + ch.distD * DIST_W + ch.posD * POS_W;\n        return ch;\n    }\n\n    void removeAdj(int v, int eid) {\n        auto& a = adj[v];\n\n        for (int i = 0; i < (int)a.size(); i++) {\n            if (a[i] == eid) {\n                a[i] = a.back();\n                a.pop_back();\n                return;\n            }\n        }\n    }\n\n    void applySwap(int addId, int remId, const Change& ch) {\n        for (int m = 0; m < 16; m++) {\n            cnt[m] += ch.dcnt[m];\n        }\n\n        overflow += ch.overD;\n        distCost += ch.distD;\n        posCost += ch.posD;\n\n        for (int i = 0; i < ch.vc; i++) {\n            mask[ch.verts[i]] = ch.newm[i];\n        }\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        inTree[addId] = 1;\n        inTree[remId] = 0;\n\n        adj[ea.a].push_back(addId);\n        adj[ea.b].push_back(addId);\n\n        removeAdj(er.a, remId);\n        removeAdj(er.b, remId);\n    }\n\n    void step(mt19937& rng, double temp) {\n        int addId;\n\n        do {\n            addId = (int)(rng() % E);\n        } while (inTree[addId]);\n\n        const Edge& e = edges[addId];\n\n        getPath(e.a, e.b);\n\n        if (path.empty()) return;\n\n        int remId = -1;\n        Change bestCh;\n        int bestDelta = INT_MAX;\n\n        bool chooseBest = (rng() % 100) < 90;\n\n        if (chooseBest) {\n            for (int pe : path) {\n                Change ch = makeChange(addId, pe);\n\n                if (ch.energyD < bestDelta) {\n                    bestDelta = ch.energyD;\n                    bestCh = ch;\n                    remId = pe;\n                }\n            }\n        } else {\n            remId = path[rng() % path.size()];\n            bestCh = makeChange(addId, remId);\n            bestDelta = bestCh.energyD;\n        }\n\n        bool accept = false;\n\n        if (bestDelta <= 0) {\n            accept = true;\n        } else if (bestDelta < temp * 70.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-(double)bestDelta / temp);\n        }\n\n        if (accept) {\n            applySwap(addId, remId, bestCh);\n        }\n    }\n};\n\nvoid runPartialSearch(int B, double endTime, Timer& timer, mt19937& rng, vector<Candidate>& cands) {\n    int bestOver = INT_MAX;\n    int bestDist = INT_MAX;\n    vector<int> bestMask;\n\n    int restart = 0;\n\n    while (timer.elapsed() < endTime) {\n        RegionTreeState st(B);\n\n        int mode = restart % 3;\n        st.initRandom(mode, rng);\n\n        if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n            bestOver = st.overflow;\n            bestDist = st.distCost;\n            bestMask = st.mask;\n        }\n\n        if (st.overflow == 0) {\n            addPartialCandidate(cands, st.mask, B);\n        }\n\n        int maxIter = 22000 + N * 1500;\n\n        if (B >= 5) maxIter = 18000 + N * 1200;\n\n        int bestZeroDist = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n\n            double p = (double)it / maxIter;\n            double temp = 90000.0 * pow(80.0 / 90000.0, p);\n\n            st.step(rng, temp);\n\n            if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n                bestOver = st.overflow;\n                bestDist = st.distCost;\n                bestMask = st.mask;\n            }\n\n            if (st.overflow == 0) {\n                if (st.distCost + 4 < bestZeroDist || (it & 4095) == 0) {\n                    addPartialCandidate(cands, st.mask, B);\n                    bestZeroDist = min(bestZeroDist, st.distCost);\n                }\n            }\n        }\n\n        if (st.overflow == 0) {\n            addPartialCandidate(cands, st.mask, B);\n        }\n\n        restart++;\n    }\n\n    if (!bestMask.empty()) {\n        adjustAndAddCandidate(cands, bestMask, B);\n    }\n}\n\nstruct SolveResult {\n    string bestMoves;\n    int bestS;\n    bool completed;\n};\n\nstruct PathRes {\n    bool ok;\n    vector<int> path;\n};\n\nstruct SlidingSolver {\n    vector<int> board;\n    vector<int> target;\n    vector<char> fixed;\n    string ops;\n\n    int blank;\n    int B;\n    int variant;\n    int baseVar;\n    bool adaptive;\n\n    Timer& timer;\n    double timeLimit;\n    int cap;\n\n    string localBestMoves;\n    long long localBestScore = -1;\n    int localBestS = 0;\n\n    vector<int> dirOrder;\n    vector<int> parent;\n    vector<unsigned char> pdir;\n    vector<int> que;\n\n    SlidingSolver(const vector<int>& tgt, int B_, int var, Timer& tm, double lim, int cp)\n        : board(initBoard),\n          target(tgt),\n          fixed(NN, 0),\n          blank(initBlank),\n          B(B_),\n          variant(var),\n          baseVar(var & 15),\n          adaptive((var & 16) != 0),\n          timer(tm),\n          timeLimit(lim),\n          cap(cp) {\n        static const int perms[8][4] = {\n            {0, 1, 2, 3},\n            {2, 3, 0, 1},\n            {1, 0, 3, 2},\n            {3, 2, 1, 0},\n            {0, 2, 1, 3},\n            {2, 0, 3, 1},\n            {1, 3, 0, 2},\n            {3, 1, 2, 0},\n        };\n\n        int pm = baseVar % 8;\n        dirOrder.assign(perms[pm], perms[pm] + 4);\n\n        parent.resize(NN * NN);\n        pdir.resize(NN * NN);\n        que.reserve(NN * NN);\n    }\n\n    void considerLocal() {\n        if ((int)ops.size() > T) return;\n\n        Eval e = evalBoard(board);\n        long long sc = scoreFromEval(e, (int)ops.size());\n\n        if (sc > localBestScore || (sc == localBestScore && ops.size() < localBestMoves.size())) {\n            localBestScore = sc;\n            localBestMoves = ops;\n            localBestS = e.S;\n        }\n    }\n\n    bool doDir(int d) {\n        int nb = nbCell[blank][d];\n\n        if (nb < 0) return false;\n\n        swap(board[blank], board[nb]);\n        blank = nb;\n        ops.push_back(DCH[d]);\n        return true;\n    }\n\n    PathRes findPathTo(int qcell) {\n        int desired = target[qcell];\n\n        if (desired == 0) return {false, {}};\n\n        fill(parent.begin(), parent.end(), -1);\n        que.clear();\n\n        int goal = -1;\n\n        for (int i = 0; i < NN; i++) {\n            if (!fixed[i] && i != blank && board[i] == desired) {\n                int id = i * NN + blank;\n\n                if (parent[id] == -1) {\n                    parent[id] = -2;\n                    que.push_back(id);\n\n                    if (i == qcell) {\n                        goal = id;\n                    }\n                }\n            }\n        }\n\n        if (que.empty()) return {false, {}};\n\n        int head = 0;\n\n        while (goal == -1 && head < (int)que.size()) {\n            int id = que[head++];\n            int tile = id / NN;\n            int emp = id % NN;\n\n            for (int d : dirOrder) {\n                int nb = nbCell[emp][d];\n\n                if (nb < 0 || fixed[nb]) continue;\n\n                int ntile = tile;\n                int nemp = nb;\n\n                if (nb == tile) {\n                    ntile = emp;\n                    nemp = nb;\n                }\n\n                int nid = ntile * NN + nemp;\n\n                if (parent[nid] != -1) continue;\n\n                parent[nid] = id;\n                pdir[nid] = (unsigned char)d;\n\n                if (ntile == qcell) {\n                    goal = nid;\n                    break;\n                }\n\n                que.push_back(nid);\n            }\n        }\n\n        if (goal == -1) return {false, {}};\n\n        vector<int> path;\n\n        for (int cur = goal; parent[cur] != -2; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n\n        reverse(path.begin(), path.end());\n        return {true, path};\n    }\n\n    bool executePath(const vector<int>& path) {\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            if (!doDir(d)) return false;\n        }\n\n        return true;\n    }\n\n    bool placeTile(int qcell) {\n        PathRes res = findPathTo(qcell);\n\n        if (!res.ok) return false;\n        if (!executePath(res.path)) return false;\n\n        if (board[qcell] != target[qcell]) return false;\n\n        fixed[qcell] = 1;\n        return true;\n    }\n\n    bool readyAdaptiveCell(int id) const {\n        int r = id / N;\n        int c = id % N;\n\n        if (r > 0) {\n            int u = id - N;\n\n            if (inRegionCell(u, B) && !fixed[u]) return false;\n        }\n\n        if (c > 0) {\n            int l = id - 1;\n\n            if (inRegionCell(l, B) && !fixed[l]) return false;\n        }\n\n        return true;\n    }\n\n    SolveResult runAdaptive() {\n        considerLocal();\n\n        int total = 0;\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, B) && target[i] != 0) total++;\n        }\n\n        bool completed = true;\n\n        for (int placed = 0; placed < total; placed++) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                completed = false;\n                break;\n            }\n\n            int bestQ = -1;\n            int bestKey = INT_MAX;\n            vector<int> bestPath;\n\n            for (int q = 0; q < NN; q++) {\n                if (!inRegionCell(q, B) || fixed[q] || target[q] == 0) continue;\n                if (!readyAdaptiveCell(q)) continue;\n\n                PathRes res = findPathTo(q);\n\n                if (!res.ok) continue;\n\n                int key = (int)res.path.size() * 100;\n\n                if (board[q] == target[q]) key -= 80;\n                key += nearDistMask[target[q]][q];\n\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestQ = q;\n                    bestPath = std::move(res.path);\n                }\n            }\n\n            if (bestQ < 0) {\n                completed = false;\n                break;\n            }\n\n            if (!executePath(bestPath)) {\n                completed = false;\n                break;\n            }\n\n            if (board[bestQ] != target[bestQ]) {\n                completed = false;\n                break;\n            }\n\n            fixed[bestQ] = 1;\n            considerLocal();\n        }\n\n        considerLocal();\n        return {localBestMoves, localBestS, completed};\n    }\n\n    SolveResult runStatic() {\n        considerLocal();\n\n        int rowMode = baseVar % 3;\n        int colMode = (baseVar / 3) % 4;\n\n        vector<int> order;\n        order.reserve(NN);\n\n        for (int r = 0; r < N - B; r++) {\n            bool rev = false;\n\n            if (rowMode == 1) rev = true;\n            if (rowMode == 2 && (r & 1)) rev = true;\n\n            if (!rev) {\n                for (int c = 0; c < N; c++) order.push_back(r * N + c);\n            } else {\n                for (int c = N - 1; c >= 0; c--) order.push_back(r * N + c);\n            }\n        }\n\n        for (int c = 0; c < N - B; c++) {\n            vector<int> rows;\n\n            for (int r = N - B; r < N; r++) {\n                rows.push_back(r);\n            }\n\n            if (colMode == 1) {\n                reverse(rows.begin(), rows.end());\n            } else if (colMode == 2 && (c & 1)) {\n                reverse(rows.begin(), rows.end());\n            } else if (colMode == 3 && B > 1) {\n                rotate(rows.begin(), rows.begin() + (baseVar % B), rows.end());\n            }\n\n            for (int r : rows) order.push_back(r * N + c);\n        }\n\n        bool completed = true;\n\n        for (int q : order) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                completed = false;\n                break;\n            }\n\n            if (target[q] == 0) continue;\n\n            if (!placeTile(q)) {\n                completed = false;\n                break;\n            }\n\n            considerLocal();\n        }\n\n        considerLocal();\n        return {localBestMoves, localBestS, completed};\n    }\n\n    SolveResult run() {\n        if (adaptive) {\n            return runAdaptive();\n        } else {\n            return runStatic();\n        }\n    }\n};\n\nSolveResult solveCandidate(const Candidate& cand, int variant, Timer& timer, double limit) {\n    SlidingSolver solver(cand.target, cand.B, variant, timer, limit, T);\n    return solver.run();\n}\n\nvoid greedyImprove(BestAns& best, double endTime, Timer& timer, mt19937& rng) {\n    while (timer.elapsed() < endTime) {\n        vector<int> bd = initBoard;\n        int blank = initBlank;\n        string mv;\n        int last = -1;\n\n        for (int step = 0; step < T && timer.elapsed() < endTime; step++) {\n            vector<int> opts;\n\n            for (int d = 0; d < 4; d++) {\n                if (nbCell[blank][d] >= 0 && (last == -1 || d != OPP[last])) {\n                    opts.push_back(d);\n                }\n            }\n\n            if (opts.empty()) {\n                for (int d = 0; d < 4; d++) {\n                    if (nbCell[blank][d] >= 0) opts.push_back(d);\n                }\n            }\n\n            int bestD = opts[0];\n            long long bestVal = LLONG_MIN;\n            Eval chosenEval{0, 0, 0};\n\n            for (int d : opts) {\n                int oldBlank = blank;\n                int nb = nbCell[blank][d];\n\n                swap(bd[blank], bd[nb]);\n                blank = nb;\n\n                Eval e = evalBoard(bd);\n\n                long long val =\n                    (long long)e.S * 1000000LL +\n                    (long long)e.maxComp * 8000LL +\n                    (long long)e.edges * 300LL +\n                    (long long)(rng() % 1000);\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestD = d;\n                    chosenEval = e;\n                }\n\n                swap(bd[oldBlank], bd[blank]);\n                blank = oldBlank;\n            }\n\n            applyDir(bd, blank, bestD);\n            mv.push_back(DCH[bestD]);\n            last = bestD;\n\n            if (chosenEval.S >= best.S || (step & 15) == 0) {\n                updateBestKnownBoard(best, mv, bd);\n            }\n        }\n\n        updateBestKnownBoard(best, mv, bd);\n    }\n}\n\nvector<int> preferredBOrder(int maxB) {\n    vector<int> res;\n\n    auto add = [&](int b) {\n        if (2 <= b && b <= maxB && find(res.begin(), res.end(), b) == res.end()) {\n            res.push_back(b);\n        }\n    };\n\n    if (N == 6) {\n        add(3);\n        add(2);\n        add(4);\n        add(5);\n    } else if (N == 7) {\n        add(4);\n        add(3);\n        add(2);\n        add(5);\n        add(6);\n    } else if (N == 8) {\n        add(5);\n        add(4);\n        add(3);\n        add(2);\n        add(6);\n    } else if (N == 9) {\n        add(5);\n        add(4);\n        add(6);\n        add(3);\n        add(2);\n    } else {\n        add(6);\n        add(5);\n        add(4);\n        add(3);\n        add(2);\n    }\n\n    for (int b = 2; b <= maxB; b++) add(b);\n\n    return res;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n\n    NN = N * N;\n    M = NN - 1;\n\n    initBoard.assign(NN, 0);\n    memset(invCnt, 0, sizeof(invCnt));\n\n    for (int r = 0; r < N; r++) {\n        string s;\n        cin >> s;\n\n        for (int c = 0; c < N; c++) {\n            int v = hexVal(s[c]);\n            int id = r * N + c;\n\n            initBoard[id] = v;\n\n            if (v == 0) {\n                initBlank = id;\n            } else {\n                invCnt[v]++;\n            }\n        }\n    }\n\n    for (int id = 0; id < NN; id++) {\n        int r = id / N;\n        int c = id % N;\n\n        for (int d = 0; d < 4; d++) {\n            int nr = r + DR[d];\n            int nc = c + DC[d];\n\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                nbCell[id][d] = -1;\n            } else {\n                nbCell[id][d] = nr * N + nc;\n            }\n        }\n    }\n\n    for (int m = 0; m < 16; m++) {\n        for (int v = 0; v < NN; v++) {\n            nearDistMask[m][v] = 2 * N + 5;\n        }\n    }\n\n    for (int v = 0; v < NN; v++) {\n        nearDistMask[0][v] = 0;\n    }\n\n    for (int m = 1; m < 16; m++) {\n        vector<int> pos;\n\n        for (int i = 0; i < NN; i++) {\n            if (initBoard[i] == m) pos.push_back(i);\n        }\n\n        if (pos.empty()) continue;\n\n        for (int v = 0; v < NN; v++) {\n            int vr = v / N;\n            int vc = v % N;\n            int best = 2 * N + 5;\n\n            for (int p : pos) {\n                int pr = p / N;\n                int pc = p % N;\n                best = min(best, abs(vr - pr) + abs(vc - pc));\n            }\n\n            nearDistMask[m][v] = best;\n        }\n    }\n\n    Timer timer;\n\n    uint64_t seed = 88172645463393265ULL;\n\n    for (int x : initBoard) {\n        seed = seed * 1315423911ULL + x + 1;\n    }\n\n    seed ^= (uint64_t)N * 1000003ULL;\n\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n    BestAns best;\n    updateBest(best, \"\");\n\n    if (best.S == M) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<Candidate> cands;\n\n    int maxB = min(6, N - 1);\n\n    for (int B = 2; B <= maxB; B++) {\n        vector<int> can = canonicalTreeMask(B);\n        adjustAndAddCandidate(cands, can, B);\n    }\n\n    auto runB = [&](int B, double until) {\n        if (2 <= B && B <= maxB && timer.elapsed() < until) {\n            runPartialSearch(B, until, timer, rng, cands);\n        }\n    };\n\n    if (N == 6) {\n        runB(3, 0.55);\n        runB(2, 1.05);\n        runB(4, 1.25);\n    } else if (N == 7) {\n        runB(4, 0.45);\n        runB(3, 1.05);\n        runB(2, 1.35);\n    } else if (N == 8) {\n        runB(5, 0.35);\n        runB(4, 1.05);\n        runB(3, 1.38);\n    } else if (N == 9) {\n        runB(5, 0.65);\n        runB(4, 1.15);\n        runB(6, 1.35);\n    } else {\n        runB(6, 0.65);\n        runB(5, 1.15);\n        runB(4, 1.50);\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.expectedS != b.expectedS) return a.expectedS > b.expectedS;\n        if (a.estCost != b.estCost) return a.estCost < b.estCost;\n        return a.B < b.B;\n    });\n\n    vector<int> prefs = preferredBOrder(maxB);\n    vector<int> orderIdx;\n    vector<char> used(cands.size(), 0);\n\n    for (int pi = 0; pi < (int)prefs.size(); pi++) {\n        int B = prefs[pi];\n        int takeLimit = (pi == 0 ? 10 : 7);\n        int take = 0;\n\n        for (int i = 0; i < (int)cands.size() && take < takeLimit; i++) {\n            if (!used[i] && cands[i].B == B) {\n                orderIdx.push_back(i);\n                used[i] = 1;\n                take++;\n            }\n        }\n    }\n\n    for (int i = 0; i < (int)cands.size(); i++) {\n        if (!used[i]) orderIdx.push_back(i);\n    }\n\n    int attemptRank = 0;\n\n    for (int idx : orderIdx) {\n        if (timer.elapsed() > 2.82) break;\n\n        const Candidate& cand = cands[idx];\n\n        if (cand.expectedS + 1 <= best.S) continue;\n\n        vector<int> vars;\n\n        if (attemptRank < 5) {\n            vars = {16, 17, 18, 19, 20, 21, 22, 23, 0, 1, 2, 3};\n        } else if (attemptRank < 16) {\n            vars = {16, 17, 0, 1, 18, 2};\n        } else {\n            vars = {16, 0};\n        }\n\n        for (int v : vars) {\n            if (timer.elapsed() > 2.84) break;\n\n            SolveResult res = solveCandidate(cand, v, timer, 2.86);\n            updateBest(best, res.bestMoves);\n\n            if (best.S >= cand.expectedS) break;\n            if (best.S == M) break;\n        }\n\n        attemptRank++;\n\n        if (best.S == M) break;\n    }\n\n    if (best.S < NN - 9 && timer.elapsed() < 2.87) {\n        greedyImprove(best, 2.88, timer, rng);\n    }\n\n    if ((int)best.moves.size() > T) {\n        best.moves.resize(T);\n    }\n\n    cout << best.moves << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint N, K_input, MAX_CUTS;\nint targetA[11];\nvector<int> Xs, Ys;\nint M_attendees;\n\nchrono::steady_clock::time_point START_TIME;\nconst double STOP_START_TIME = 2.50;\nconst double HARD_TIME_LIMIT = 2.86;\n\ndouble elapsed_time() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t state = 1;\n    uint64_t next() {\n        uint64_t z = (state += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) {\n        if (l > r) swap(l, r);\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\nRNG rng;\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key& o) const {\n        return lo == o.lo && hi == o.hi;\n    }\n};\n\nstruct KeyHash {\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    size_t operator()(const Key& k) const {\n        return (size_t)(splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1));\n    }\n};\n\nstruct Proj {\n    ll s;\n    int idx;\n    bool operator<(const Proj& o) const {\n        if (s != o.s) return s < o.s;\n        return idx < o.idx;\n    }\n};\n\nstruct Line {\n    ll A, B, C; // A*x+B*y=C\n    shared_ptr<vector<Proj>> ord;\n};\n\nstruct LineOut {\n    ll A, B, C;\n};\n\nvector<LineOut> bestLines;\nint bestScore = -1;\nll bestValue = LLONG_MIN;\n\ninline bool getBit(const Key& k, int j) {\n    if (j < 64) return (k.lo >> j) & 1ULL;\n    return (k.hi >> (j - 64)) & 1ULL;\n}\n\ninline void flipBit(Key& k, int j) {\n    if (j < 64) k.lo ^= (1ULL << j);\n    else k.hi ^= (1ULL << (j - 64));\n}\n\nshared_ptr<vector<Proj>> computeOrder(ll A, ll B) {\n    auto ord = make_shared<vector<Proj>>();\n    ord->reserve(N);\n    for (int i = 0; i < N; i++) {\n        ll s = A * (ll)Xs[i] + B * (ll)Ys[i];\n        ord->push_back({s, i});\n    }\n    sort(ord->begin(), ord->end());\n    return ord;\n}\n\nll thresholdAtRank(const vector<Proj>& ord, int rank) {\n    int n = (int)ord.size();\n    if (rank <= 0) return ord[0].s - 1;\n    if (rank >= n) return ord[n - 1].s + 1;\n\n    for (int d = 0; d <= n; d++) {\n        int b = rank - d;\n        if (0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n        b = rank + d;\n        if (d != 0 && 0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n    }\n    return (rank < n / 2 ? ord[0].s - 1 : ord[n - 1].s + 1);\n}\n\npair<ll,ll> primitive(ll A, ll B) {\n    if (A == 0 && B == 0) return {1, 0};\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) g = 1;\n    A /= g;\n    B /= g;\n    return {A, B};\n}\n\npair<ll,ll> normalFromAngle(long double theta) {\n    static const long double PI = acosl(-1.0L);\n    theta = fmodl(theta, PI);\n    if (theta < 0) theta += PI;\n\n    const long double S = 1000000.0L;\n    ll A = llround(cosl(theta) * S);\n    ll B = llround(sinl(theta) * S);\n    if (A == 0 && B == 0) A = 1;\n    return primitive(A, B);\n}\n\nlong long cellCountFormula(const vector<int>& c) {\n    long long cells = 1;\n    int sum = 0;\n    for (int x : c) sum += x;\n    cells += sum;\n    for (int i = 0; i < (int)c.size(); i++) {\n        for (int j = i + 1; j < (int)c.size(); j++) {\n            cells += 1LL * c[i] * c[j];\n        }\n    }\n    return cells;\n}\n\nvector<int> bestCounts(int G, int T) {\n    vector<int> best(G, 0), cur(G, 0);\n    long long bestCost = LLONG_MAX;\n\n    auto eval = [&]() {\n        int sum = 0, mn = 1e9, mx = -1;\n        for (int x : cur) {\n            sum += x;\n            mn = min(mn, x);\n            mx = max(mx, x);\n        }\n        if (sum > MAX_CUTS) return;\n        long long cells = cellCountFormula(cur);\n        long long diff = llabs(cells - T);\n        long long cost = diff * 100000LL + (cells < T ? 1000LL : 0LL)\n                       + (mx - mn) * 100LL + sum;\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = cur;\n        }\n    };\n\n    if (G == 2) {\n        for (int a = 0; a <= MAX_CUTS; a++) {\n            for (int b = 0; a + b <= MAX_CUTS; b++) {\n                cur[0] = a;\n                cur[1] = b;\n                eval();\n            }\n        }\n        return best;\n    }\n\n    if (G <= 4) {\n        long double denom = max(1, G * (G - 1));\n        int base = (int)round(sqrt((2.0L * T) / denom));\n        int R = (G == 4 ? 10 : 12);\n        int lo = max(0, base - R);\n        int hi = min(MAX_CUTS, base + R);\n\n        function<void(int,int)> dfs = [&](int pos, int sum) {\n            if (pos == G) {\n                eval();\n                return;\n            }\n            for (int v = lo; v <= hi; v++) {\n                if (sum + v <= MAX_CUTS) {\n                    cur[pos] = v;\n                    dfs(pos + 1, sum + v);\n                }\n            }\n        };\n        dfs(0, 0);\n    } else {\n        for (int sum = 0; sum <= MAX_CUTS; sum++) {\n            int q = sum / G;\n            int r = sum % G;\n            for (int i = 0; i < G; i++) cur[i] = q + (i < r);\n            eval();\n        }\n    }\n\n    if (bestCost == LLONG_MAX) {\n        int v = min(MAX_CUTS / G, 1);\n        fill(best.begin(), best.end(), v);\n    }\n    return best;\n}\n\nvector<Line> makeGroup(int G, const vector<int>& counts, long double baseAngle, int initMode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n\n    for (int g = 0; g < G; g++) {\n        int m = counts[g];\n        if (m <= 0) continue;\n\n        auto [A, B] = normalFromAngle(baseAngle + PI * g / G);\n        auto ord = computeOrder(A, B);\n\n        vector<int> ranks;\n        ranks.reserve(m);\n\n        if (initMode == 0) {\n            for (int t = 1; t <= m; t++) {\n                ranks.push_back((int)((long long)t * N / (m + 1)));\n            }\n        } else if (initMode == 1) {\n            int low = N / 20;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            for (int t = 0; t < m; t++) ranks.push_back(rng.nextInt(low, high));\n            sort(ranks.begin(), ranks.end());\n        } else {\n            for (int t = 1; t <= m; t++) {\n                long double u = (long double)t + (rng.nextDouble() - 0.5L) * 0.9L;\n                int rank = (int)llround(u * N / (m + 1));\n                rank = max(0, min(N, rank));\n                ranks.push_back(rank);\n            }\n            sort(ranks.begin(), ranks.end());\n        }\n\n        for (int rank : ranks) {\n            Line L;\n            L.A = A;\n            L.B = B;\n            L.ord = ord;\n            L.C = thresholdAtRank(*L.ord, rank);\n            res.push_back(std::move(L));\n        }\n    }\n\n    if ((int)res.size() > MAX_CUTS) res.resize(MAX_CUTS);\n    return res;\n}\n\nint kForCells(int T) {\n    for (int k = 0; k <= MAX_CUTS; k++) {\n        if (1LL + 1LL * k * (k + 1) / 2 >= T) return k;\n    }\n    return MAX_CUTS;\n}\n\nvector<Line> makeGeneral(int k, int mode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n    res.reserve(k);\n\n    long double base = (k > 0 ? rng.nextDouble() * PI / k : 0);\n\n    for (int i = 0; i < k; i++) {\n        long double theta;\n        if (mode == 0) {\n            theta = base + ((long double)i + 0.5L + (rng.nextDouble() - 0.5L) * 0.8L) * PI / k;\n        } else {\n            theta = rng.nextDouble() * PI;\n        }\n\n        auto [A, B] = normalFromAngle(theta);\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n\n        int low = N / 20;\n        int high = N - low;\n        if (low > high) {\n            low = 0;\n            high = N;\n        }\n        int rank = rng.nextInt(low, high);\n        L.C = thresholdAtRank(*L.ord, rank);\n\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nstruct Config {\n    int k;\n    vector<Line> lines;\n    vector<Key> pat;\n    unordered_map<Key, int, KeyHash> mp;\n    int hist[11];\n    int overStraw = 0;\n\n    Config(vector<Line>&& ls) : k((int)ls.size()), lines(std::move(ls)), pat(N) {\n        memset(hist, 0, sizeof(hist));\n    }\n\n    inline void removeEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]--;\n        else if (c > 10) overStraw -= c;\n    }\n\n    inline void addEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]++;\n        else if (c > 10) overStraw += c;\n    }\n\n    void build() {\n        mp.clear();\n        mp.reserve(N * 4 + 100);\n        mp.max_load_factor(0.7);\n        memset(hist, 0, sizeof(hist));\n        overStraw = 0;\n\n        for (int i = 0; i < N; i++) {\n            Key key{0, 0};\n            for (int j = 0; j < k; j++) {\n                ll s = lines[j].A * (ll)Xs[i] + lines[j].B * (ll)Ys[i];\n                if (s > lines[j].C) {\n                    if (j < 64) key.lo |= (1ULL << j);\n                    else key.hi |= (1ULL << (j - 64));\n                }\n            }\n            pat[i] = key;\n            mp[key]++;\n        }\n\n        for (auto& kv : mp) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) hist[c]++;\n            else if (c > 10) overStraw += c;\n        }\n    }\n\n    void decKey(const Key& key) {\n        auto it = mp.find(key);\n        int old = it->second;\n        removeEffect(old);\n        int nw = old - 1;\n        addEffect(nw);\n        if (nw == 0) mp.erase(it);\n        else it->second = nw;\n    }\n\n    void incKey(const Key& key) {\n        auto it = mp.find(key);\n        if (it == mp.end()) {\n            addEffect(1);\n            mp.emplace(key, 1);\n        } else {\n            int old = it->second;\n            removeEffect(old);\n            int nw = old + 1;\n            addEffect(nw);\n            it->second = nw;\n        }\n    }\n\n    inline void flipPoint(int idx, int j) {\n        Key old = pat[idx];\n        Key nw = old;\n        flipBit(nw, j);\n        decKey(old);\n        incKey(nw);\n        pat[idx] = nw;\n    }\n\n    int score() const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], hist[d]);\n        return sc;\n    }\n\n    int surplus() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (hist[d] > targetA[d]) s += hist[d] - targetA[d];\n        }\n        return s;\n    }\n\n    ll value() const {\n        const ll SCORE_W = 1000000000000LL;\n        const ll OVER_W = 5000LL;\n        const ll SURPLUS_W = 10000LL;\n        return (ll)score() * SCORE_W - (ll)overStraw * OVER_W - (ll)surplus() * SURPLUS_W;\n    }\n\n    int rankForC(int j) const {\n        const auto& ord = *lines[j].ord;\n        int l = 0, r = N;\n        ll C = lines[j].C;\n        while (l < r) {\n            int m = (l + r) >> 1;\n            if (ord[m].s <= C) l = m + 1;\n            else r = m;\n        }\n        return l;\n    }\n\n    void sweepLine(int j) {\n        const auto& ord = *lines[j].ord;\n\n        ll origVal = value();\n        int bestIdx = rankForC(j);\n        ll bestC = lines[j].C;\n        ll bestVal = origVal;\n\n        for (int i = 0; i < N; i++) {\n            if (!getBit(pat[i], j)) flipPoint(i, j);\n        }\n\n        ll valAll = value();\n        if (valAll > bestVal) {\n            bestVal = valAll;\n            bestIdx = 0;\n            bestC = ord[0].s - 1;\n        }\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = ord[idx].s;\n            while (idx < N && ord[idx].s == v) {\n                flipPoint(ord[idx].idx, j);\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = ord[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = value();\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestIdx = idx;\n                    bestC = candC;\n                }\n            }\n        }\n\n        for (int t = bestIdx; t < N; t++) {\n            flipPoint(ord[t].idx, j);\n        }\n        lines[j].C = bestC;\n    }\n\n    void optimize(int passes) {\n        if (k == 0) return;\n        vector<int> order(k);\n        iota(order.begin(), order.end(), 0);\n\n        for (int p = 0; p < passes; p++) {\n            for (int i = k - 1; i > 0; i--) {\n                int j = rng.nextInt(0, i);\n                swap(order[i], order[j]);\n            }\n\n            ll before = value();\n\n            for (int t = 0; t < k; t++) {\n                sweepLine(order[t]);\n                if ((t & 7) == 0 && elapsed_time() > HARD_TIME_LIMIT) return;\n            }\n\n            if (value() <= before) break;\n        }\n    }\n\n    int cellBadScore(int c) const {\n        if (c <= 1) return 0;\n\n        int def[11];\n        for (int d = 1; d <= 10; d++) def[d] = max(0, targetA[d] - hist[d]);\n\n        int loss = 0;\n        if (1 <= c && c <= 10 && hist[c] <= targetA[c]) loss = 1;\n\n        int best = -loss;\n\n        auto evalSplit = [&](int t) {\n            if (t <= 0 || t >= c) return;\n            int u = c - t;\n            int cnt[11] = {};\n            if (1 <= t && t <= 10) cnt[t]++;\n            if (1 <= u && u <= 10) cnt[u]++;\n            int gain = -loss;\n            for (int d = 1; d <= 10; d++) gain += min(cnt[d], def[d]);\n            best = max(best, gain);\n        };\n\n        for (int t = 1; t <= min(c - 1, 10); t++) evalSplit(t);\n        for (int t = max(1, c - 10); t <= c - 1; t++) evalSplit(t);\n\n        if (best > 0) return 100 * best + min(c, 50);\n        if (c > 10) return 15 + min(c, 40);\n        if (hist[c] > targetA[c]) return 8 + min(hist[c] - targetA[c], 20);\n        return 0;\n    }\n\n    long double targetedTheta() const {\n        static const long double PI = acosl(-1.0L);\n\n        Key chosen{0, 0};\n        bool has = false;\n        double total = 0.0;\n\n        for (const auto& kv : mp) {\n            int w = cellBadScore(kv.second);\n            if (w <= 0) continue;\n            double dw = (double)w;\n            total += dw;\n            if (rng.nextDouble() * total < dw) {\n                chosen = kv.first;\n                has = true;\n            }\n        }\n\n        if (!has) {\n            for (int attempt = 0; attempt < 10; attempt++) {\n                int i = rng.nextInt(0, N - 1);\n                auto it = mp.find(pat[i]);\n                if (it != mp.end() && it->second >= 2) {\n                    chosen = pat[i];\n                    has = true;\n                    break;\n                }\n            }\n        }\n\n        if (!has) return rng.nextDouble() * PI;\n\n        vector<int> pts;\n        pts.reserve(64);\n        for (int i = 0; i < N; i++) {\n            if (pat[i] == chosen) pts.push_back(i);\n        }\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        int bestA = pts[0], bestB = pts[1];\n        ll bestD = -1;\n        int samples = min(40, max(8, (int)pts.size() * 2));\n        for (int s = 0; s < samples; s++) {\n            int a = pts[rng.nextInt(0, (int)pts.size() - 1)];\n            int b = pts[rng.nextInt(0, (int)pts.size() - 1)];\n            if (a == b) continue;\n            ll dx = (ll)Xs[a] - Xs[b];\n            ll dy = (ll)Ys[a] - Ys[b];\n            ll dist = dx * dx + dy * dy;\n            if (dist > bestD) {\n                bestD = dist;\n                bestA = a;\n                bestB = b;\n            }\n        }\n\n        long double dx = (long double)Xs[bestA] - Xs[bestB];\n        long double dy = (long double)Ys[bestA] - Ys[bestB];\n        if (dx == 0 && dy == 0) return rng.nextDouble() * PI;\n\n        long double th = atan2l(dy, dx);\n        th += (rng.nextDouble() - 0.5L) * 0.32L;\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    void replaceLineAllZero(int j, Line&& L) {\n        for (int i = 0; i < N; i++) {\n            if (getBit(pat[i], j)) flipPoint(i, j);\n        }\n        lines[j] = std::move(L);\n    }\n\n    long double lineTheta(int j) const {\n        static const long double PI = acosl(-1.0L);\n        long double th = atan2l((long double)lines[j].B, (long double)lines[j].A);\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    bool tryReplaceLineTheta(int j, long double theta) {\n        if (elapsed_time() > HARD_TIME_LIMIT - 0.02) return false;\n\n        auto [A, B] = normalFromAngle(theta);\n        if (A == lines[j].A && B == lines[j].B) return false;\n\n        ll oldVal = value();\n\n        vector<Key> oldPat = pat;\n        auto oldMp = mp;\n        int oldHist[11];\n        memcpy(oldHist, hist, sizeof(hist));\n        int oldOver = overStraw;\n        Line oldLine = lines[j];\n\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n        L.C = L.ord->back().s + 1;\n\n        replaceLineAllZero(j, std::move(L));\n        sweepLine(j);\n\n        if (value() > oldVal) return true;\n\n        pat = std::move(oldPat);\n        mp = std::move(oldMp);\n        memcpy(hist, oldHist, sizeof(hist));\n        overStraw = oldOver;\n        lines[j] = std::move(oldLine);\n        return false;\n    }\n\n    bool tryAddLineTheta(long double theta) {\n        if (k >= MAX_CUTS) return false;\n        if (elapsed_time() > HARD_TIME_LIMIT - 0.02) return false;\n\n        auto [A, B] = normalFromAngle(theta);\n        ll oldVal = value();\n\n        vector<Key> oldPat = pat;\n        auto oldMp = mp;\n        int oldHist[11];\n        memcpy(oldHist, hist, sizeof(hist));\n        int oldOver = overStraw;\n        int oldK = k;\n\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n        L.C = L.ord->back().s + 1;\n\n        lines.push_back(std::move(L));\n        k++;\n\n        sweepLine(k - 1);\n\n        if (value() > oldVal) return true;\n\n        pat = std::move(oldPat);\n        mp = std::move(oldMp);\n        memcpy(hist, oldHist, sizeof(hist));\n        overStraw = oldOver;\n        k = oldK;\n        lines.resize(oldK);\n        return false;\n    }\n\n    int addLineSearch(int trials, int maxAccept) {\n        static const long double PI = acosl(-1.0L);\n        int acc = 0;\n        for (int t = 0; t < trials && acc < maxAccept && k < MAX_CUTS; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n            long double theta;\n            if (rng.nextDouble() < 0.78) theta = targetedTheta();\n            else theta = rng.nextDouble() * PI;\n\n            if (tryAddLineTheta(theta)) acc++;\n        }\n        return acc;\n    }\n\n    int chooseReplaceLine() const {\n        if (k <= 0) return -1;\n        if (rng.nextDouble() < 0.28) {\n            vector<int> cand;\n            cand.reserve(k);\n            for (int i = 0; i < k; i++) {\n                int r = rankForC(i);\n                if (r == 0 || r == N) cand.push_back(i);\n            }\n            if (!cand.empty()) return cand[rng.nextInt(0, (int)cand.size() - 1)];\n        }\n        return rng.nextInt(0, k - 1);\n    }\n\n    int angleOptimize(int trials) {\n        static const long double PI = acosl(-1.0L);\n        if (k == 0) return 0;\n        int acc = 0;\n\n        for (int t = 0; t < trials; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n\n            int j = chooseReplaceLine();\n            if (j < 0) break;\n\n            long double theta;\n            double r = rng.nextDouble();\n\n            if (r < 0.45) {\n                long double scale = 0.04L + 0.32L * rng.nextDouble();\n                theta = lineTheta(j) + (rng.nextDouble() * 2.0L - 1.0L) * scale;\n            } else if (r < 0.83) {\n                theta = targetedTheta();\n            } else {\n                theta = rng.nextDouble() * PI;\n            }\n\n            if (tryReplaceLineTheta(j, theta)) acc++;\n        }\n\n        return acc;\n    }\n};\n\nvoid updateBest(const Config& cfg) {\n    int sc = cfg.score();\n    ll val = cfg.value();\n    if (sc > bestScore || (sc == bestScore && val > bestValue)) {\n        bestScore = sc;\n        bestValue = val;\n        bestLines.clear();\n        for (const auto& L : cfg.lines) {\n            bestLines.push_back({L.A, L.B, L.C});\n        }\n    }\n}\n\nvoid runCandidate(vector<Line> lines, int passes) {\n    if ((int)lines.size() > MAX_CUTS) lines.resize(MAX_CUTS);\n    if (elapsed_time() > STOP_START_TIME) return;\n\n    Config cfg(std::move(lines));\n    cfg.build();\n    cfg.optimize(passes);\n    updateBest(cfg);\n}\n\nvector<Line> rebuildLinesFromOut(const vector<LineOut>& outs) {\n    vector<Line> res;\n    res.reserve(outs.size());\n    for (auto O : outs) {\n        Line L;\n        L.A = O.A;\n        L.B = O.B;\n        L.C = O.C;\n        L.ord = computeOrder(L.A, L.B);\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nvoid finalPolish() {\n    if (bestLines.empty()) return;\n    if (elapsed_time() > HARD_TIME_LIMIT - 0.08) return;\n\n    auto ls = rebuildLinesFromOut(bestLines);\n    Config cfg(std::move(ls));\n    cfg.build();\n\n    cfg.optimize(5);\n    updateBest(cfg);\n\n    int loops = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.06 && cfg.score() < M_attendees) {\n        cfg.addLineSearch(14, 3);\n        cfg.angleOptimize(16);\n        cfg.optimize(1);\n        updateBest(cfg);\n        loops++;\n        if (loops > 45) break;\n    }\n\n    int shakeAttempts = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.04 && shakeAttempts < 8) {\n        vector<Line> sl = cfg.lines;\n        if (sl.empty()) break;\n\n        int changes = max(1, (int)sl.size() / 6);\n        for (int c = 0; c < changes; c++) {\n            int j = rng.nextInt(0, (int)sl.size() - 1);\n            int low = N / 25;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            int rank = rng.nextInt(low, high);\n            sl[j].C = thresholdAtRank(*sl[j].ord, rank);\n        }\n\n        Config tmp(std::move(sl));\n        tmp.build();\n        tmp.optimize(2);\n        tmp.addLineSearch(4, 1);\n        tmp.angleOptimize(4);\n        tmp.optimize(1);\n        updateBest(tmp);\n\n        if (tmp.value() > cfg.value()) {\n            cfg = std::move(tmp);\n        }\n\n        shakeAttempts++;\n    }\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = 1;\n        y = 0;\n        return a;\n    }\n    ll x1, y1;\n    ll g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<ll,4> fallbackLine() {\n    return {1000000000LL, 1000000000LL, 999999999LL, 1000000000LL};\n}\n\narray<ll,4> endpoints(LineOut L) {\n    ll A = L.A, B = L.B, C = L.C;\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) return fallbackLine();\n    if (C % g != 0) return fallbackLine();\n    A /= g;\n    B /= g;\n    C /= g;\n\n    auto inside = [](ll v) {\n        return -1000000000LL <= v && v <= 1000000000LL;\n    };\n\n    if (B == 0) {\n        if (A == 0 || C % A != 0) return fallbackLine();\n        ll x = C / A;\n        if (!inside(x)) return fallbackLine();\n        return {x, 0, x, 1};\n    }\n    if (A == 0) {\n        if (B == 0 || C % B != 0) return fallbackLine();\n        ll y = C / B;\n        if (!inside(y)) return fallbackLine();\n        return {0, y, 1, y};\n    }\n\n    ll xg, yg;\n    extgcd(llabs(A), llabs(B), xg, yg);\n\n    __int128 x0 = (__int128)xg * (A >= 0 ? 1 : -1) * C;\n    __int128 y0 = (__int128)yg * (B >= 0 ? 1 : -1) * C;\n\n    ll dx = B;\n    ll dy = -A;\n\n    long double dot = (long double)x0 * (long double)dx + (long double)y0 * (long double)dy;\n    long double den = (long double)dx * dx + (long double)dy * dy;\n    ll t0 = llround(-dot / den);\n\n    __int128 bestNorm = -1;\n    __int128 bx = x0, by = y0;\n\n    for (ll dt = -6; dt <= 6; dt++) {\n        ll t = t0 + dt;\n        __int128 x = x0 + (__int128)dx * t;\n        __int128 y = y0 + (__int128)dy * t;\n        __int128 norm = x * x + y * y;\n        if (bestNorm < 0 || norm < bestNorm) {\n            bestNorm = norm;\n            bx = x;\n            by = y;\n        }\n    }\n\n    __int128 qx = bx + dx;\n    __int128 qy = by + dy;\n\n    if (bx < -1000000000LL || bx > 1000000000LL ||\n        by < -1000000000LL || by > 1000000000LL ||\n        qx < -1000000000LL || qx > 1000000000LL ||\n        qy < -1000000000LL || qy > 1000000000LL) {\n        return fallbackLine();\n    }\n\n    ll px = (ll)bx, py = (ll)by;\n    ll rx = (ll)qx, ry = (ll)qy;\n    if (px == rx && py == ry) return fallbackLine();\n    return {px, py, rx, ry};\n}\n\nLineOut canonical(LineOut L) {\n    ll g = std::gcd(llabs(L.A), llabs(L.B));\n    if (g > 0 && L.C % g == 0) {\n        L.A /= g;\n        L.B /= g;\n        L.C /= g;\n    }\n    if (L.A < 0 || (L.A == 0 && L.B < 0)) {\n        L.A = -L.A;\n        L.B = -L.B;\n        L.C = -L.C;\n    }\n    return L;\n}\n\ndouble clampd(double x, double l, double r) {\n    return max(l, min(r, x));\n}\n\ndouble poissonFactorEstimate() {\n    int maxCells = min(5051, max(50, (int)ceil(M_attendees * 4.0)));\n    int minCells = max(20, (int)floor(M_attendees * 0.40));\n\n    double bestVal = -1e100;\n    int bestT = max(1, M_attendees);\n\n    for (int T = minCells; T <= maxCells; T++) {\n        double lambda = (double)N / T;\n        double p = exp(-lambda);\n        double approx = 0.0;\n        for (int d = 1; d <= 10; d++) {\n            p *= lambda / d;\n            double bd = T * p;\n            approx += min((double)targetA[d], bd);\n        }\n\n        double factor = (double)T / max(1, M_attendees);\n        double penalty = 0.04 * abs(factor - 1.25);\n        double val = approx - penalty;\n        if (val > bestVal) {\n            bestVal = val;\n            bestT = T;\n        }\n    }\n\n    return (double)bestT / max(1, M_attendees);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K_input;\n    MAX_CUTS = min(K_input, 100);\n\n    M_attendees = 0;\n    for (int d = 1; d <= 10; d++) {\n        cin >> targetA[d];\n        M_attendees += targetA[d];\n    }\n\n    Xs.resize(N);\n    Ys.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xs[i] >> Ys[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    auto mixSeed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed(N);\n    mixSeed(K_input);\n    for (int d = 1; d <= 10; d++) mixSeed(targetA[d]);\n    for (int i = 0; i < N; i++) {\n        mixSeed((uint64_t)(Xs[i] + 20000) * 40009ULL + (uint64_t)(Ys[i] + 20000));\n    }\n    rng.state = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    double avgD = (double)N / max(1, M_attendees);\n    double smallRatio = (targetA[1] + targetA[2] + targetA[3]) / (double)M_attendees;\n    double largeRatio = (targetA[8] + targetA[9] + targetA[10]) / (double)M_attendees;\n\n    double centerFactor = 1.25 + 0.95 * (smallRatio - largeRatio) + 0.10 * (5.5 - avgD);\n    centerFactor = clampd(centerFactor, 0.70, 2.05);\n\n    double poissonFactor = poissonFactorEstimate();\n    poissonFactor = clampd(poissonFactor, 0.55, 3.20);\n\n    auto normFactor = [&](double f) {\n        return clampd(f, 0.45, 4.00);\n    };\n\n    auto tryGroup = [&](int G, double factor, int initMode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        auto counts = bestCounts(G, T);\n        long double PI = acosl(-1.0L);\n        long double base = rng.nextDouble() * PI / G;\n        auto lines = makeGroup(G, counts, base, initMode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    auto tryGeneral = [&](double factor, int mode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        int k = kForCells(T);\n        auto lines = makeGeneral(k, mode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    // Preserve the previously strong deterministic wave.\n    tryGroup(2, centerFactor, 0, 4);\n    tryGroup(3, centerFactor, 0, 4);\n    tryGroup(4, centerFactor, 0, 3);\n    tryGroup(5, centerFactor, 0, 3);\n    tryGeneral(centerFactor, 0, 3);\n\n    tryGroup(2, centerFactor * 1.28, 2, 3);\n    tryGroup(3, centerFactor * 0.88, 2, 3);\n    tryGroup(4, centerFactor * 1.18, 2, 3);\n    tryGroup(6, centerFactor * 1.05, 0, 3);\n    tryGeneral(centerFactor * 1.28, 1, 3);\n\n    // Additional density/direction diversity.\n    tryGroup(2, poissonFactor, 0, 3);\n    tryGroup(3, poissonFactor * 1.05, 2, 3);\n    tryGroup(7, (centerFactor + poissonFactor) * 0.5, 0, 2);\n    tryGeneral(poissonFactor, 0, 2);\n\n    int iter = 0;\n    while (elapsed_time() < STOP_START_TIME) {\n        int typ = iter % 8;\n\n        double baseF;\n        double rbase = rng.nextDouble();\n        if (rbase < 0.45) baseF = centerFactor;\n        else if (rbase < 0.80) baseF = poissonFactor;\n        else baseF = 0.5 * (centerFactor + poissonFactor);\n\n        double mult;\n        if (rng.nextDouble() < 0.16) mult = 0.50 + 2.15 * rng.nextDouble();\n        else mult = 0.68 + 1.05 * rng.nextDouble();\n\n        double factor = normFactor(baseF * mult);\n        int initMode = rng.nextInt(0, 2);\n\n        if (typ == 0) tryGroup(2, factor, initMode, 2);\n        else if (typ == 1) tryGroup(3, factor, initMode, 2);\n        else if (typ == 2) tryGroup(4, factor, initMode, 2);\n        else if (typ == 3) tryGroup(5, factor, initMode, 2);\n        else if (typ == 4) tryGroup(6, factor, initMode, 2);\n        else if (typ == 5) tryGroup(7, factor, initMode, 2);\n        else tryGeneral(factor, rng.nextInt(0, 1), 2);\n\n        iter++;\n    }\n\n    finalPolish();\n\n    vector<LineOut> outputLines;\n    vector<LineOut> seen;\n    for (auto L : bestLines) {\n        LineOut C = canonical(L);\n        bool dup = false;\n        for (auto S : seen) {\n            if (S.A == C.A && S.B == C.B && S.C == C.C) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) {\n            seen.push_back(C);\n            outputLines.push_back(L);\n        }\n        if ((int)outputLines.size() == MAX_CUTS) break;\n    }\n\n    cout << outputLines.size() << '\\n';\n    for (auto L : outputLines) {\n        auto e = endpoints(L);\n        cout << e[0] << ' ' << e[1] << ' ' << e[2] << ' ' << e[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#pragma GCC optimize(\"O3,unroll-loops\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAXN = 61;\nconst int MAXC = MAXN * MAXN;\nconst int MAXTOP = 128;\n\nint N, M, C;\nint PX[MAXC], PY[MAXC];\nint WT[MAXC];\nint maxWeight = 0;\nunsigned char initDot[MAXC];\ndouble priorityVal[MAXC];\nlong long initialSum = 0;\n\nint initMinX, initMaxX, initMinY, initMaxY;\n\nconst int DX[8] = {1, 0, -1, 0, 1, -1, -1, 1};\nconst int DY[8] = {0, 1, 0, -1, 1, 1, -1, -1};\n\n// E,N / N,W / W,S / S,E and NE,NW / NW,SW / SW,SE / SE,NE\nconst int PA[8] = {0, 1, 2, 3, 4, 5, 6, 7};\nconst int PB[8] = {1, 2, 3, 0, 5, 6, 7, 4};\n\ninline int pid(int x, int y) {\n    return x * N + y;\n}\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y < N;\n}\n\ninline uint64_t rangeMask(int l, int r) {\n    int len = r - l;\n    if (len <= 0) return 0ULL;\n    return ((1ULL << len) - 1ULL) << l;\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 RNG {\n    uint64_t x;\n\n    RNG(uint64_t seed = 1) {\n        x = splitmix64(seed);\n        if (x == 0) x = 88172645463325252ULL;\n    }\n\n    inline uint64_t next() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    inline double nextSigned() {\n        return nextDouble() * 2.0 - 1.0;\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n\n    Timer() {\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\nstruct Op {\n    int p1, p2, p3, p4;\n};\n\nstruct Candidate {\n    int p1, p2, p3, p4;\n    int lenSum;\n    int area;\n};\n\nstruct Node {\n    double key;\n    Candidate cand;\n};\n\ninline void heapSiftUp(Node h[], int i) {\n    while (i > 0) {\n        int p = (i - 1) >> 1;\n        if (h[p].key <= h[i].key) break;\n        swap(h[p], h[i]);\n        i = p;\n    }\n}\n\ninline void heapSiftDown(Node h[], int n, int i = 0) {\n    while (true) {\n        int l = i * 2 + 1;\n        int r = l + 1;\n        int m = i;\n\n        if (l < n && h[l].key < h[m].key) m = l;\n        if (r < n && h[r].key < h[m].key) m = r;\n\n        if (m == i) break;\n\n        swap(h[i], h[m]);\n        i = m;\n    }\n}\n\ninline void heapPushTop(Node h[], int& n, int K, const Node& nd) {\n    if (n < K) {\n        h[n] = nd;\n        heapSiftUp(h, n);\n        ++n;\n    } else if (nd.key > h[0].key) {\n        h[0] = nd;\n        heapSiftDown(h, n, 0);\n    }\n}\n\nstruct Params {\n    double wcoef;\n    double perim;\n    double area;\n    double outAvg;\n    double outOpp;\n    double frontier;\n    int topK;\n    double rankPower;\n    double noise;\n};\n\nstruct State {\n    unsigned char dot[MAXC];\n    int nearestDot[8][MAXC];\n\n    // Used elementary edge masks.\n    // H[y]: horizontal segment bit x: (x,y)-(x+1,y)\n    // V[x]: vertical segment bit y: (x,y)-(x,y+1)\n    // DPm[x-y+N-1]: diagonal + segment bit x: (x,y)-(x+1,y+1)\n    // DMm[x+y]: diagonal - segment bit x: (x,y)-(x+1,y-1)\n    uint64_t H[MAXN], V[MAXN], DPm[2 * MAXN], DMm[2 * MAXN];\n\n    vector<Op> ops;\n    long long sumW = 0;\n    bool dirtyNearest = true;\n\n    int minX, maxX, minY, maxY;\n\n    void reset() {\n        memcpy(dot, initDot, C * sizeof(unsigned char));\n\n        fill(H, H + MAXN, 0ULL);\n        fill(V, V + MAXN, 0ULL);\n        fill(DPm, DPm + 2 * MAXN, 0ULL);\n        fill(DMm, DMm + 2 * MAXN, 0ULL);\n\n        ops.clear();\n        sumW = initialSum;\n        dirtyNearest = true;\n\n        minX = initMinX;\n        maxX = initMaxX;\n        minY = initMinY;\n        maxY = initMaxY;\n    }\n\n    void buildNearest() {\n        for (int d = 0; d < 8; ++d) {\n            int dx = DX[d];\n            int dy = DY[d];\n\n            for (int sx = 0; sx < N; ++sx) {\n                for (int sy = 0; sy < N; ++sy) {\n                    int nx = sx + dx;\n                    int ny = sy + dy;\n                    if (inside(nx, ny)) continue;\n\n                    int cur = -1;\n                    int x = sx;\n                    int y = sy;\n\n                    while (inside(x, y)) {\n                        int p = pid(x, y);\n                        nearestDot[d][p] = cur;\n\n                        if (dot[p]) cur = p;\n\n                        x -= dx;\n                        y -= dy;\n                    }\n                }\n            }\n        }\n\n        dirtyNearest = false;\n    }\n\n    void updateNearestAfterAdd(int p) {\n        for (int d = 0; d < 8; ++d) {\n            int x = PX[p] - DX[d];\n            int y = PY[p] - DY[d];\n\n            while (inside(x, y)) {\n                int q = pid(x, y);\n                nearestDot[d][q] = p;\n\n                if (dot[q]) break;\n\n                x -= DX[d];\n                y -= DY[d];\n            }\n        }\n    }\n\n    bool sideFree(int a, int b) const {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            uint64_t m = rangeMask(y1, y2);\n            return (V[x1] & m) == 0;\n        }\n\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            uint64_t m = rangeMask(x1, x2);\n            return (H[y1] & m) == 0;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (abs(dx) != abs(dy)) return false;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 - y1 + N - 1;\n            uint64_t m = rangeMask(x1, x2);\n            return (DPm[line] & m) == 0;\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 + y1;\n            uint64_t m = rangeMask(x1, x2);\n            return (DMm[line] & m) == 0;\n        }\n    }\n\n    void markSide(int a, int b) {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            V[x1] |= rangeMask(y1, y2);\n            return;\n        }\n\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            H[y1] |= rangeMask(x1, x2);\n            return;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 - y1 + N - 1;\n            DPm[line] |= rangeMask(x1, x2);\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 + y1;\n            DMm[line] |= rangeMask(x1, x2);\n        }\n    }\n\n    void applyOp(const Op& op, bool updateNearest) {\n        markSide(op.p1, op.p2);\n        markSide(op.p2, op.p3);\n        markSide(op.p3, op.p4);\n        markSide(op.p4, op.p1);\n\n        dot[op.p1] = 1;\n        sumW += WT[op.p1];\n        ops.push_back(op);\n\n        int x = PX[op.p1];\n        int y = PY[op.p1];\n\n        if (x < minX) minX = x;\n        if (x > maxX) maxX = x;\n        if (y < minY) minY = y;\n        if (y > maxY) maxY = y;\n\n        if (updateNearest && !dirtyNearest) {\n            updateNearestAfterAdd(op.p1);\n        } else {\n            dirtyNearest = true;\n        }\n    }\n\n    inline bool canReplay(const Op& op) const {\n        return !dot[op.p1] && dot[op.p2] && dot[op.p3] && dot[op.p4];\n    }\n\n    bool chooseCandidate(const Params& par, RNG& rng, Candidate& res) {\n        if (dirtyNearest) buildNearest();\n\n        int K = par.topK;\n        if (K < 1) K = 1;\n        if (K > MAXTOP) K = MAXTOP;\n\n        bool found = false;\n        double bestKey = -1e100;\n        int bestLen = INT_MAX;\n        Candidate bestCand{};\n\n        Node heap[MAXTOP];\n        int hsz = 0;\n\n        for (int p1 = 0; p1 < C; ++p1) {\n            if (dot[p1]) continue;\n\n            int x1 = PX[p1];\n            int y1 = PY[p1];\n\n            int ext = 0;\n\n            if (x1 < minX) ext += minX - x1;\n            else if (x1 > maxX) ext += x1 - maxX;\n\n            if (y1 < minY) ext += minY - y1;\n            else if (y1 > maxY) ext += y1 - maxY;\n\n            for (int t = 0; t < 8; ++t) {\n                int d1 = PA[t];\n                int d2 = PB[t];\n\n                int p2 = nearestDot[d1][p1];\n                if (p2 < 0) continue;\n\n                int p4 = nearestDot[d2][p1];\n                if (p4 < 0) continue;\n\n                int x3 = PX[p2] + PX[p4] - x1;\n                int y3 = PY[p2] + PY[p4] - y1;\n\n                if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n\n                int p3 = pid(x3, y3);\n                if (!dot[p3]) continue;\n\n                if (nearestDot[d2][p2] != p3) continue;\n                if (nearestDot[d1][p4] != p3) continue;\n\n                if (!sideFree(p1, p2)) continue;\n                if (!sideFree(p2, p3)) continue;\n                if (!sideFree(p3, p4)) continue;\n                if (!sideFree(p4, p1)) continue;\n\n                int len1 = max(abs(PX[p2] - x1), abs(PY[p2] - y1));\n                int len2 = max(abs(PX[p4] - x1), abs(PY[p4] - y1));\n                int lenSum = len1 + len2;\n                int area = len1 * len2;\n\n                double avgOther = (WT[p2] + WT[p3] + WT[p4]) / 3.0;\n\n                double key =\n                    priorityVal[p1]\n                    + par.outAvg * (WT[p1] - avgOther)\n                    + par.outOpp * (WT[p1] - WT[p3])\n                    + par.frontier * ext\n                    - par.perim * lenSum\n                    - par.area * area;\n\n                Candidate cand{p1, p2, p3, p4, lenSum, area};\n\n                if (K == 1) {\n                    if (!found || key > bestKey + 1e-12 ||\n                        (fabs(key - bestKey) <= 1e-12 && lenSum < bestLen)) {\n                        found = true;\n                        bestKey = key;\n                        bestLen = lenSum;\n                        bestCand = cand;\n                    }\n                } else {\n                    Node nd{key, cand};\n                    heapPushTop(heap, hsz, K, nd);\n                }\n            }\n        }\n\n        if (K == 1) {\n            if (!found) return false;\n            res = bestCand;\n            return true;\n        } else {\n            if (hsz == 0) return false;\n\n            sort(heap, heap + hsz, [](const Node& a, const Node& b) {\n                return a.key > b.key;\n            });\n\n            int idx = 0;\n\n            if (hsz > 1) {\n                if (par.rankPower <= 0.0) {\n                    idx = rng.nextInt(hsz);\n                } else {\n                    double z = pow(rng.nextDouble(), par.rankPower);\n                    idx = (int)(z * hsz);\n                    if (idx >= hsz) idx = hsz - 1;\n                }\n            }\n\n            res = heap[idx].cand;\n            return true;\n        }\n    }\n};\n\nParams randomParam(RNG& rng) {\n    static const double wcoefs[] = {\n        0.0, 0.15, 0.35, 0.65, 0.9, 1.0, 1.0, 1.25, 1.6, 2.1\n    };\n\n    static const double perims[] = {\n        -1.4, -0.8, -0.4, -0.1, 0.0, 0.4, 0.9, 1.6, 2.7, 4.2, 6.5, 9.0\n    };\n\n    static const double areas[] = {\n        -0.025, -0.010, -0.003, 0.0, 0.0, 0.006, 0.016, 0.035, 0.070\n    };\n\n    Params p;\n\n    p.wcoef = wcoefs[rng.nextInt((int)(sizeof(wcoefs) / sizeof(wcoefs[0])))];\n\n    p.perim = perims[rng.nextInt((int)(sizeof(perims) / sizeof(perims[0])))]\n              + (rng.nextDouble() - 0.5) * 0.45;\n\n    p.area = areas[rng.nextInt((int)(sizeof(areas) / sizeof(areas[0])))];\n\n    p.outAvg = 0.0;\n    p.outOpp = 0.0;\n\n    if (rng.nextInt(100) < 60) p.outAvg = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 50) p.outOpp = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 10) p.outOpp += rng.nextDouble() * 1.8;\n\n    p.frontier = 0.0;\n\n    if (rng.nextInt(100) < 45) p.frontier = rng.nextDouble() * 35.0;\n\n    // Sparse instances often need larger jumps.\n    // Dense instances often benefit from shorter scaffolding moves.\n    if (M < 2 * N && rng.nextInt(100) < 35) {\n        p.perim -= 1.0 + rng.nextDouble() * 2.0;\n        p.area -= rng.nextDouble() * 0.025;\n        p.frontier += rng.nextDouble() * 25.0;\n    }\n\n    if (M > N * N / 18 && rng.nextInt(100) < 35) {\n        p.perim += rng.nextDouble() * 4.0;\n        p.area += rng.nextDouble() * 0.040;\n        p.wcoef *= 0.7;\n    }\n\n    int r = rng.nextInt(100);\n\n    if (r < 18) {\n        p.topK = 1;\n    } else if (r < 72) {\n        p.topK = 3 + rng.nextInt(25);\n    } else {\n        p.topK = 30 + rng.nextInt(90);\n    }\n\n    if (p.topK > MAXTOP) p.topK = MAXTOP;\n\n    if (p.topK == 1) {\n        p.rankPower = 1.0;\n    } else {\n        int q = rng.nextInt(100);\n\n        if (q < 18) p.rankPower = 1.0;\n        else if (q < 84) p.rankPower = 1.5 + rng.nextDouble() * 3.2;\n        else p.rankPower = 0.45 + rng.nextDouble() * 0.65;\n    }\n\n    if (rng.nextInt(100) < 50) p.noise = rng.nextDouble() * 0.14;\n    else p.noise = rng.nextDouble() * 0.38;\n\n    if (rng.nextInt(100) < 5) p.noise = rng.nextDouble() * 0.75;\n\n    return p;\n}\n\nvoid preparePriority(const Params& par, RNG& rng) {\n    double amp = par.noise * maxWeight;\n\n    for (int i = 0; i < C; ++i) {\n        priorityVal[i] = par.wcoef * WT[i];\n\n        if (amp > 1e-12) {\n            priorityVal[i] += amp * rng.nextSigned();\n        }\n    }\n}\n\nvoid runGreedy(State& st, const Params& par, RNG& rng, const Timer& timer, double TL) {\n    Candidate cand;\n\n    while (timer.elapsed() < TL) {\n        if (!st.chooseCandidate(par, rng, cand)) break;\n\n        Op op{cand.p1, cand.p2, cand.p3, cand.p4};\n        st.applyOp(op, true);\n    }\n}\n\nvoid replayDestroyed(State& st, const vector<Op>& base, RNG& rng) {\n    st.reset();\n\n    int K = (int)base.size();\n    if (K == 0) return;\n\n    int mode = rng.nextInt(100);\n\n    int cut = K;\n    int l = 0, r = 0;\n    int cx = 0, cy = 0, rad2 = 0, rx = 0, ry = 0;\n    bool circle = true;\n    double pdrop = 0.0, extra = 0.0;\n    bool dropLow = true;\n\n    if (mode < 20) {\n        int lim = min(K, 50 + rng.nextInt(950));\n        int drop = 1 + rng.nextInt(lim);\n        cut = K - drop;\n    } else if (mode < 45) {\n        pdrop = 0.01 + pow(rng.nextDouble(), 2.0) * 0.30;\n\n        if (rng.nextInt(100) < 10) {\n            pdrop = 0.30 + rng.nextDouble() * 0.35;\n        }\n    } else if (mode < 65) {\n        double frac = 0.02 + 0.55 * rng.nextDouble() * rng.nextDouble();\n        int maxLen = max(1, min(K, 1 + (int)(K * frac)));\n        int len = 1 + rng.nextInt(maxLen);\n\n        l = rng.nextInt(K - len + 1);\n        r = l + len;\n    } else if (mode < 85) {\n        const Op& op = base[rng.nextInt(K)];\n\n        cx = PX[op.p1];\n        cy = PY[op.p1];\n\n        circle = rng.nextInt(2) == 0;\n\n        if (circle) {\n            int rad = 2 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            rad2 = rad * rad;\n        } else {\n            rx = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            ry = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n        }\n    } else {\n        pdrop = 0.01 + rng.nextDouble() * 0.08;\n        extra = 0.05 + rng.nextDouble() * 0.32;\n        dropLow = rng.nextInt(2) == 0;\n    }\n\n    for (int i = 0; i < K; ++i) {\n        const Op& op = base[i];\n        bool keep = true;\n\n        if (mode < 20) {\n            keep = i < cut;\n        } else if (mode < 45) {\n            keep = rng.nextDouble() >= pdrop;\n        } else if (mode < 65) {\n            keep = !(l <= i && i < r);\n        } else if (mode < 85) {\n            int x = PX[op.p1];\n            int y = PY[op.p1];\n\n            bool inRegion;\n\n            if (circle) {\n                int dx = x - cx;\n                int dy = y - cy;\n                inRegion = dx * dx + dy * dy <= rad2;\n            } else {\n                inRegion = abs(x - cx) <= rx && abs(y - cy) <= ry;\n            }\n\n            keep = !inRegion;\n        } else {\n            double norm = (double)WT[op.p1] / maxWeight;\n            double pd = pdrop + extra * (dropLow ? (1.0 - norm) : norm);\n\n            if (pd > 0.80) pd = 0.80;\n\n            keep = rng.nextDouble() >= pd;\n        }\n\n        if (keep && st.canReplay(op)) {\n            st.applyOp(op, false);\n        }\n    }\n}\n\nstruct Solution {\n    long long sum;\n    vector<Op> ops;\n};\n\nvoid considerSolution(\n    const State& st,\n    vector<Solution>& pool,\n    vector<Op>& bestOps,\n    long long& bestSum\n) {\n    if (st.sumW > bestSum) {\n        bestSum = st.sumW;\n        bestOps = st.ops;\n    }\n\n    const int POOL_SIZE = 10;\n\n    if ((int)pool.size() >= POOL_SIZE && st.sumW <= pool.back().sum) return;\n\n    for (const auto& s : pool) {\n        if (s.sum == st.sumW && s.ops.size() == st.ops.size()) return;\n    }\n\n    Solution sol;\n    sol.sum = st.sumW;\n    sol.ops = st.ops;\n\n    pool.push_back(move(sol));\n\n    sort(pool.begin(), pool.end(), [](const Solution& a, const Solution& b) {\n        if (a.sum != b.sum) return a.sum > b.sum;\n        return a.ops.size() > b.ops.size();\n    });\n\n    if ((int)pool.size() > POOL_SIZE) pool.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    C = N * N;\n\n    fill(initDot, initDot + MAXC, 0);\n\n    int c = N / 2;\n\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y < N; ++y) {\n            int p = pid(x, y);\n            PX[p] = x;\n            PY[p] = y;\n\n            int dx = x - c;\n            int dy = y - c;\n\n            WT[p] = dx * dx + dy * dy + 1;\n            maxWeight = max(maxWeight, WT[p]);\n        }\n    }\n\n    initMinX = N;\n    initMaxX = -1;\n    initMinY = N;\n    initMaxY = -1;\n\n    uint64_t seed = splitmix64(((uint64_t)N << 32) ^ (uint64_t)M);\n\n    for (int i = 0; i < M; ++i) {\n        int x, y;\n        cin >> x >> y;\n\n        int p = pid(x, y);\n        initDot[p] = 1;\n\n        initMinX = min(initMinX, x);\n        initMaxX = max(initMaxX, x);\n        initMinY = min(initMinY, y);\n        initMaxY = max(initMaxY, y);\n\n        seed ^= splitmix64(((uint64_t)(i + 1) << 40) ^ ((uint64_t)x << 20) ^ (uint64_t)y);\n    }\n\n    initialSum = 0;\n\n    for (int p = 0; p < C; ++p) {\n        if (initDot[p]) initialSum += WT[p];\n    }\n\n    RNG rng(seed);\n\n    vector<Params> presets = {\n        {1.0,  0.0,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  0.6,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  2.8,  0.015, 0.8, 0.2,  0.0,  1, 1.0, 0.00},\n        {1.0, -0.4, -0.004, 0.4, 0.0,  0.0,  8, 2.0, 0.00},\n        {1.0,  0.5,  0.000, 1.0, 0.0,  0.0, 16, 1.7, 0.00},\n        {1.0,  4.5,  0.050, 0.0, 0.0,  0.0, 24, 2.5, 0.00},\n        {0.0,  6.0,  0.040, 0.0, 0.0,  0.0,  8, 2.2, 0.01},\n        {0.25, 3.5,  0.020, 0.2, 0.0,  0.0, 12, 2.0, 0.02},\n        {0.8,  0.0,  0.000, 0.0, 0.8, 25.0, 20, 2.2, 0.04}\n    };\n\n    State st;\n    st.ops.reserve(C);\n\n    vector<Op> bestOps;\n    bestOps.reserve(C);\n\n    long long bestSum = initialSum;\n\n    vector<Solution> pool;\n    pool.reserve(12);\n\n    Timer timer;\n\n    // Previous stable version used about 4.75s.\n    // This version keeps the same algorithmic core and safely uses a bit more time.\n    const double TL = 4.86;\n\n    int trial = 0;\n\n    while (timer.elapsed() < TL) {\n        Params par;\n        bool useLNS = false;\n\n        if (trial < (int)presets.size()) {\n            par = presets[trial];\n        } else {\n            par = randomParam(rng);\n\n            if (!pool.empty() && rng.nextInt(100) < 78) {\n                useLNS = true;\n            }\n        }\n\n        preparePriority(par, rng);\n\n        if (useLNS) {\n            int ps = (int)pool.size();\n            double u = rng.nextDouble();\n            int idx = (int)(u * u * ps);\n\n            if (idx >= ps) idx = ps - 1;\n\n            replayDestroyed(st, pool[idx].ops, rng);\n        } else {\n            st.reset();\n        }\n\n        runGreedy(st, par, rng, timer, TL);\n        considerSolution(st, pool, bestOps, bestSum);\n\n        ++trial;\n    }\n\n    cout << bestOps.size() << '\\n';\n\n    for (const auto& op : bestOps) {\n        cout << PX[op.p1] << ' ' << PY[op.p1] << ' '\n             << PX[op.p2] << ' ' << PY[op.p2] << ' '\n             << PX[op.p3] << ' ' << PY[op.p3] << ' '\n             << PX[op.p4] << ' ' << PY[op.p4] << '\\n';\n    }\n\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint flav[100];\nint totalCnt[4];\nint remAfter[100][4];\n\nint neighs[100][4], degs_[100];\nint rightCell[100], downCell[100];\nuint8_t manhDist[100][100];\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Board {\n    uint8_t a[100];\n    int n;\n\n    Board() { clear(); }\n\n    void clear() {\n        memset(a, 0, sizeof(a));\n        n = 0;\n    }\n\n    void placeRank(int rk, int fl) {\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) {\n                if (rk == 0) {\n                    a[i] = (uint8_t)fl;\n                    n++;\n                    return;\n                }\n                rk--;\n            }\n        }\n    }\n\n    void placeCell(int pos, int fl) {\n        a[pos] = (uint8_t)fl;\n        n++;\n    }\n\n    int getEmpties(int emp[]) const {\n        int m = 0;\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) emp[m++] = i;\n        }\n        return m;\n    }\n\n    void tilt(int dir) {\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; c++) {\n                int w = 0;\n                for (int r = 0; r < 10; r++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w++ * 10 + c] = v;\n                }\n                for (int r = w; r < 10; r++) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; c++) {\n                int w = 9;\n                for (int r = 9; r >= 0; r--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w-- * 10 + c] = v;\n                }\n                for (int r = w; r >= 0; r--) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; r++) {\n                int w = 0;\n                for (int c = 0; c < 10; c++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w++] = v;\n                }\n                for (int c = w; c < 10; c++) a[r * 10 + c] = 0;\n            }\n        } else { // R\n            for (int r = 0; r < 10; r++) {\n                int w = 9;\n                for (int c = 9; c >= 0; c--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w--] = v;\n                }\n                for (int c = w; c >= 0; c--) a[r * 10 + c] = 0;\n            }\n        }\n    }\n};\n\nstruct Layout {\n    uint8_t target[100];\n    uint8_t dist[4][100];\n};\n\nvector<Layout> layouts;\nunordered_set<string> seenLayouts;\n\nvoid initTables() {\n    for (int i = 0; i < 100; i++) {\n        degs_[i] = 0;\n        rightCell[i] = downCell[i] = -1;\n    }\n\n    for (int r = 0; r < 10; r++) {\n        for (int c = 0; c < 10; c++) {\n            int id = r * 10 + c;\n            if (r > 0) neighs[id][degs_[id]++] = (r - 1) * 10 + c;\n            if (r < 9) neighs[id][degs_[id]++] = (r + 1) * 10 + c;\n            if (c > 0) neighs[id][degs_[id]++] = r * 10 + c - 1;\n            if (c < 9) neighs[id][degs_[id]++] = r * 10 + c + 1;\n\n            if (c < 9) rightCell[id] = id + 1;\n            if (r < 9) downCell[id] = id + 10;\n        }\n    }\n\n    for (int i = 0; i < 100; i++) {\n        int r1 = i / 10, c1 = i % 10;\n        for (int j = 0; j < 100; j++) {\n            int r2 = j / 10, c2 = j % 10;\n            manhDist[i][j] = (uint8_t)(abs(r1 - r2) + abs(c1 - c2));\n        }\n    }\n}\n\nll finalScoreNum(const Board& b) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    ll res = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        res += 1LL * sz * sz;\n    }\n\n    return res;\n}\n\nll evalBoard(const Board& b, int step, const Layout& L) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    int maxComp[4] = {};\n    int sumSq = 0;\n    int comps = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        comps++;\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        sumSq += sz * sz;\n        maxComp[fl] = max(maxComp[fl], sz);\n    }\n\n    int adj = 0;\n    int distCost = 0;\n    int match = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int v = b.a[i];\n        if (!v) continue;\n\n        int r = rightCell[i];\n        if (r != -1 && b.a[r] == v) adj++;\n\n        int d = downCell[i];\n        if (d != -1 && b.a[d] == v) adj++;\n\n        distCost += L.dist[v][i];\n        if (L.target[i] == v) match++;\n    }\n\n    // Optimistic future-aware component potential:\n    // If all future candies of a flavor join its largest current component,\n    // contribution is sumSq + 2 * maxComponent * remaining + constant.\n    ll compPot = sumSq;\n    for (int f = 1; f <= 3; f++) {\n        compPot += 2LL * maxComp[f] * remAfter[step][f];\n    }\n\n    int future = 99 - step;\n\n    ll val = 0;\n    val += compPot * 1000LL;\n    val += adj * 200LL;\n    val -= comps * 50LL;\n    val += match * (30LL + future);\n    val -= distCost * (20LL + 3LL * future);\n\n    return val;\n}\n\nint greedyDir(const Board& b, int step, const Layout& L) {\n    int offset = ((step + 1) * 17 + flav[step] * 31) & 3;\n\n    int bestD = 0;\n    ll bestV = LLONG_MIN;\n\n    for (int k = 0; k < 4; k++) {\n        int d = (offset + k) & 3;\n        Board nb = b;\n        nb.tilt(d);\n        ll v = evalBoard(nb, step, L);\n        if (v > bestV) {\n            bestV = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nvoid computeLayoutDist(Layout& L) {\n    for (int f = 0; f < 4; f++) {\n        for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n    }\n\n    for (int f = 1; f <= 3; f++) {\n        vector<int> cells;\n        for (int i = 0; i < 100; i++) {\n            if (L.target[i] == f) cells.push_back(i);\n        }\n\n        if (cells.empty()) {\n            for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n            continue;\n        }\n\n        for (int i = 0; i < 100; i++) {\n            int best = 100;\n            for (int p : cells) {\n                best = min(best, (int)manhDist[i][p]);\n            }\n            L.dist[f][i] = (uint8_t)best;\n        }\n    }\n}\n\nvoid addLayout(const array<uint8_t, 100>& tar) {\n    string key;\n    key.resize(100);\n    for (int i = 0; i < 100; i++) key[i] = char('0' + tar[i]);\n\n    if (!seenLayouts.insert(key).second) return;\n\n    Layout L;\n    memset(&L, 0, sizeof(L));\n    for (int i = 0; i < 100; i++) L.target[i] = tar[i];\n    computeLayoutDist(L);\n    layouts.push_back(L);\n}\n\npair<int, int> transformCoord(int r, int c, int s) {\n    if (s == 0) return {r, c};\n    if (s == 1) return {r, 9 - c};\n    if (s == 2) return {9 - r, c};\n    if (s == 3) return {9 - r, 9 - c};\n    if (s == 4) return {c, r};\n    if (s == 5) return {c, 9 - r};\n    if (s == 6) return {9 - c, r};\n    return {9 - c, 9 - r};\n}\n\nstruct PQNode {\n    int dist;\n    int tie;\n    int f;\n    int pos;\n};\n\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        if (a.dist != b.dist) return a.dist > b.dist;\n        if (a.tie != b.tie) return a.tie > b.tie;\n        return a.f > b.f;\n    }\n};\n\nint tieValue(int pos, int f, int seed) {\n    return (pos * 37 + f * 101 + seed * 17) & 1023;\n}\n\narray<uint8_t, 100> makeCornerLayout(const int seeds[4]) {\n    array<uint8_t, 100> tar;\n    tar.fill(0);\n\n    int cap[4];\n    for (int f = 1; f <= 3; f++) cap[f] = totalCnt[f];\n\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq;\n\n    for (int f = 1; f <= 3; f++) {\n        if (cap[f] > 0) {\n            int p = seeds[f];\n            pq.push({0, tieValue(p, f, seeds[f]), f, p});\n        }\n    }\n\n    int assigned = 0;\n\n    while (assigned < 100 && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n\n        int f = cur.f;\n        int p = cur.pos;\n\n        if (cap[f] <= 0 || tar[p] != 0) continue;\n\n        tar[p] = (uint8_t)f;\n        cap[f]--;\n        assigned++;\n\n        if (cap[f] > 0) {\n            for (int k = 0; k < degs_[p]; k++) {\n                int to = neighs[p][k];\n                if (tar[to] == 0) {\n                    pq.push({cur.dist + 1, tieValue(to, f, seeds[f]), f, to});\n                }\n            }\n        }\n    }\n\n    // Fallback, rarely used.\n    if (assigned < 100) {\n        for (int p = 0; p < 100; p++) {\n            if (tar[p] != 0) continue;\n\n            int bestF = -1;\n            int bestCost = 1e9;\n\n            for (int f = 1; f <= 3; f++) {\n                if (cap[f] <= 0) continue;\n\n                int cost = manhDist[p][seeds[f]];\n                bool adj = false;\n                for (int k = 0; k < degs_[p]; k++) {\n                    if (tar[neighs[p][k]] == f) adj = true;\n                }\n                if (adj) cost -= 20;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestF = f;\n                }\n            }\n\n            if (bestF == -1) {\n                for (int f = 1; f <= 3; f++) {\n                    if (cap[f] > 0) {\n                        bestF = f;\n                        break;\n                    }\n                }\n            }\n\n            tar[p] = (uint8_t)bestF;\n            cap[bestF]--;\n            assigned++;\n        }\n    }\n\n    return tar;\n}\n\nvoid generateLayouts() {\n    layouts.clear();\n    seenLayouts.clear();\n    layouts.reserve(128);\n    seenLayouts.reserve(256);\n\n    // Neutral layout: target term disabled.\n    {\n        Layout neutral;\n        memset(&neutral, 0, sizeof(neutral));\n        layouts.push_back(neutral);\n        seenLayouts.insert(string(100, '0'));\n    }\n\n    // Snake/band layouts.\n    vector<int> basePath;\n    basePath.reserve(100);\n\n    for (int r = 0; r < 10; r++) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < 10; c++) basePath.push_back(r * 10 + c);\n        } else {\n            for (int c = 9; c >= 0; c--) basePath.push_back(r * 10 + c);\n        }\n    }\n\n    for (int sym = 0; sym < 8; sym++) {\n        vector<int> path;\n        path.reserve(100);\n        bool used[100] = {};\n        bool ok = true;\n\n        for (int id : basePath) {\n            int r = id / 10, c = id % 10;\n            auto [nr, nc] = transformCoord(r, c, sym);\n            int p = nr * 10 + nc;\n            if (used[p]) ok = false;\n            used[p] = true;\n            path.push_back(p);\n        }\n\n        if (!ok) continue;\n\n        array<int, 3> perm = {1, 2, 3};\n        do {\n            array<uint8_t, 100> tar;\n            tar.fill(0);\n\n            int idx = 0;\n            for (int k = 0; k < 3; k++) {\n                int f = perm[k];\n                for (int cnt = 0; cnt < totalCnt[f]; cnt++) {\n                    tar[path[idx++]] = (uint8_t)f;\n                }\n            }\n\n            addLayout(tar);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    // Three-corner growing layouts.\n    int corners[4] = {0, 9, 90, 99};\n    for (int a = 0; a < 4; a++) {\n        for (int b = 0; b < 4; b++) if (b != a) {\n            for (int c = 0; c < 4; c++) if (c != a && c != b) {\n                int seeds[4] = {};\n                seeds[1] = corners[a];\n                seeds[2] = corners[b];\n                seeds[3] = corners[c];\n\n                auto tar = makeCornerLayout(seeds);\n                addLayout(tar);\n            }\n        }\n    }\n}\n\nint chooseLayout() {\n    constexpr int K = 3;\n\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 100; i++) {\n        seed = seed * 1000003ULL + flav[i] * 97ULL + i;\n    }\n\n    RNG rng(seed);\n    uint8_t ranks[K][100];\n\n    for (int k = 0; k < K; k++) {\n        for (int s = 0; s < 100; s++) {\n            ranks[k][s] = (uint8_t)rng.nextInt(100 - s);\n        }\n    }\n\n    int bestIdx = 0;\n    ll bestScore = LLONG_MIN;\n\n    for (int li = 0; li < (int)layouts.size(); li++) {\n        ll total = 0;\n\n        for (int k = 0; k < K; k++) {\n            Board b;\n\n            for (int s = 0; s < 100; s++) {\n                b.placeRank(ranks[k][s], flav[s]);\n\n                if (s == 99) break;\n\n                int d = greedyDir(b, s, layouts[li]);\n                b.tilt(d);\n            }\n\n            total += finalScoreNum(b);\n        }\n\n        if (total > bestScore) {\n            bestScore = total;\n            bestIdx = li;\n        }\n    }\n\n    return bestIdx;\n}\n\ndouble exactValue(const Board& b, int step);\n\ndouble exactDirValue(const Board& b, int step, int dir) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    Board bb = b;\n    bb.tilt(dir);\n\n    int emp[100];\n    int m = bb.getEmpties(emp);\n\n    if (m == 0) return (double)finalScoreNum(bb);\n\n    double sum = 0.0;\n\n    for (int i = 0; i < m; i++) {\n        Board nb = bb;\n        nb.placeCell(emp[i], flav[step + 1]);\n        sum += exactValue(nb, step + 1);\n    }\n\n    return sum / m;\n}\n\ndouble exactValue(const Board& b, int step) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        best = max(best, exactDirValue(b, step, d));\n    }\n\n    return best;\n}\n\nint exactBestDir(const Board& b, int step) {\n    int bestD = 0;\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        double v = exactDirValue(b, step, d);\n        if (v > best) {\n            best = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nstruct BeamNode {\n    Board b;\n    ll val;\n};\n\nvoid addBeamCandidate(BeamNode next[], int& cnt, int BW, const Board& b, ll val) {\n    if (cnt < BW) {\n        next[cnt].b = b;\n        next[cnt].val = val;\n        cnt++;\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < BW; i++) {\n        if (next[i].val < next[worst].val) worst = i;\n    }\n\n    if (val > next[worst].val) {\n        next[worst].b = b;\n        next[worst].val = val;\n    }\n}\n\nll simulateBeam(const Board& start, int step, const uint8_t ranks[], const Layout& L, int BW) {\n    BeamNode beam[2], nxt[2];\n\n    int bc = 1;\n    beam[0].b = start;\n    beam[0].val = 0;\n\n    for (int s = step + 1; s < 100; s++) {\n        int nc = 0;\n        ll bestFinal = -1;\n\n        for (int i = 0; i < bc; i++) {\n            Board placed = beam[i].b;\n            placed.placeRank(ranks[s], flav[s]);\n\n            if (s == 99) {\n                bestFinal = max(bestFinal, finalScoreNum(placed));\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    Board nb = placed;\n                    nb.tilt(d);\n                    ll v = evalBoard(nb, s, L);\n                    addBeamCandidate(nxt, nc, BW, nb, v);\n                }\n            }\n        }\n\n        if (s == 99) return bestFinal;\n\n        bc = nc;\n        for (int i = 0; i < bc; i++) beam[i] = nxt[i];\n    }\n\n    return finalScoreNum(start);\n}\n\nint decideMove(const Board& b, int step, const Layout& L, RNG& rng) {\n    if (step >= 99) return 0;\n\n    int rem = 99 - step;\n    double el = elapsedSec();\n\n    // Exact expectimax for the last few moves.\n    if (rem <= 5 && el < 1.72) {\n        return exactBestDir(b, step);\n    }\n\n    if (el > 1.84) {\n        return greedyDir(b, step, L);\n    }\n\n    Board first[4];\n    for (int d = 0; d < 4; d++) {\n        first[d] = b;\n        first[d].tilt(d);\n    }\n\n    int BW = (rem <= 25 ? 2 : 1);\n    int work = (BW == 1 ? 520 : 360);\n    int R = max(4, min(60, work / max(1, rem)));\n\n    if (el > 1.70) R = max(2, R / 3);\n    else if (el > 1.50) R = max(3, R / 2);\n\n    ll scores[4] = {};\n    uint8_t ranks[100];\n\n    int done = 0;\n\n    for (int it = 0; it < R; it++) {\n        if (it > 0 && (it & 3) == 0 && elapsedSec() > 1.86) break;\n\n        for (int s = step + 1; s < 100; s++) {\n            ranks[s] = (uint8_t)rng.nextInt(100 - s);\n        }\n\n        for (int d = 0; d < 4; d++) {\n            scores[d] += simulateBeam(first[d], step, ranks, L, BW);\n        }\n\n        done++;\n    }\n\n    if (done == 0) {\n        return greedyDir(b, step, L);\n    }\n\n    int bestD = 0;\n    ll bestScore = LLONG_MIN;\n    ll bestHeur = LLONG_MIN;\n\n    for (int d = 0; d < 4; d++) {\n        ll h = evalBoard(first[d], step, L);\n\n        if (scores[d] > bestScore || (scores[d] == bestScore && h > bestHeur)) {\n            bestScore = scores[d];\n            bestHeur = h;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    initTables();\n\n    for (int i = 0; i < 100; i++) {\n        if (!(cin >> flav[i])) return 0;\n        totalCnt[flav[i]]++;\n    }\n\n    int suf[4] = {};\n    for (int i = 99; i >= 0; i--) {\n        for (int f = 1; f <= 3; f++) remAfter[i][f] = suf[f];\n        suf[flav[i]]++;\n    }\n\n    generateLayouts();\n    int layoutIdx = chooseLayout();\n    Layout layout = layouts[layoutIdx];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < 100; i++) {\n        seed ^= (uint64_t)(flav[i] + 1237 * i);\n        seed *= 0xbf58476d1ce4e5b9ULL;\n    }\n\n    RNG rng(seed ^ 0xdeadbeefcafebabeULL);\n\n    Board board;\n    const char dc[4] = {'F', 'B', 'L', 'R'};\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        board.placeRank(p - 1, flav[t]);\n\n        int dir;\n        if (t == 99) {\n            dir = 0;\n        } else {\n            dir = decideMove(board, t, layout, rng);\n        }\n\n        board.tilt(dir);\n\n        cout << dc[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nconst int MAXN = 100;\nusing Row = array<ull, 2>;\n\nint M;\ndouble EPS, QV;\n\nint Ncur, Bcur, Lcur, Fcur;\nint POSBIN[MAXN];\nint FIDX[10][10];\nvector<int> PAIRCNT;\n\ndouble PMF[MAXN][MAXN];\ndouble NEGLOGP[MAXN][MAXN];\ndouble edgePenalty = 0.0;\n\nstruct Candidate {\n    uint32_t mask;\n    array<unsigned char, MAXN> deg;\n    int sum;\n};\n\nstruct Codeword {\n    uint32_t mask;\n    array<unsigned char, MAXN> deg;\n    vector<Row> rows;\n    array<double, MAXN> mixNeg;\n    vector<int> blockCnt;\n};\n\nstruct QueryFeat {\n    array<int, MAXN> degSorted;\n    array<int, MAXN> hist;\n    vector<Row> rows;\n    vector<int> blockCnt;\n};\n\nstruct Config {\n    double alpha; // sorted degree NLL weight\n    double wb;    // block edge feature weight\n    double we;    // aligned edge hamming weight\n};\n\nstruct TrainResult {\n    Config cfg;\n    int err;\n    int samples;\n};\n\nvector<Codeword> codes;\nConfig bestCfg{0.5, 0.0, 0.0};\n\ninline int thresholdBit(uint32_t mask, int idx, int B, int N) {\n    int b = (long long)idx * B / N;\n    return (mask >> b) & 1u;\n}\n\ninline void setEdge(vector<Row>& rows, int i, int j) {\n    rows[i][j >> 6] |= 1ULL << (j & 63);\n    rows[j][i >> 6] |= 1ULL << (i & 63);\n}\n\ninline bool getEdge(const vector<Row>& rows, int i, int j) {\n    return (rows[i][j >> 6] >> (j & 63)) & 1ULL;\n}\n\ninline double rnd01(mt19937_64& rng) {\n    return (rng() >> 11) * (1.0 / 9007199254740992.0);\n}\n\nvoid thresholdDegrees(uint32_t mask, int B, int N, array<int, MAXN>& degOrig) {\n    int cnt = 0;\n    for (int i = N - 1; i >= 0; --i) {\n        int bit = thresholdBit(mask, i, B, N);\n        if (bit) degOrig[i] = i + cnt;\n        else degOrig[i] = cnt;\n        if (bit) cnt++;\n    }\n}\n\nvector<Candidate> buildPool(int N, int B) {\n    vector<Candidate> pool;\n    int total = 1 << B;\n    pool.reserve(total);\n\n    unordered_set<string> seen;\n    seen.reserve(total * 2);\n\n    for (uint32_t mask = 0; mask < (uint32_t)total; ++mask) {\n        array<int, MAXN> dorig{};\n        thresholdDegrees(mask, B, N, dorig);\n\n        Candidate c;\n        c.mask = mask;\n        c.deg.fill(0);\n        c.sum = 0;\n        for (int i = 0; i < N; ++i) {\n            c.deg[i] = (unsigned char)dorig[i];\n            c.sum += dorig[i];\n        }\n        sort(c.deg.begin(), c.deg.begin() + N);\n\n        string key;\n        key.resize(N);\n        for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n        if (seen.insert(key).second) {\n            pool.push_back(c);\n        }\n    }\n    return pool;\n}\n\ninline int dist2Deg(const array<unsigned char, MAXN>& a,\n                    const array<unsigned char, MAXN>& b,\n                    int N) {\n    int s = 0;\n    for (int i = 0; i < N; ++i) {\n        int d = (int)a[i] - (int)b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstruct Selection {\n    vector<int> idx;\n    int minD2;\n};\n\nSelection selectFarthest(const vector<Candidate>& pool, int N, int m, int improveIters) {\n    int P = (int)pool.size();\n    Selection res;\n    res.minD2 = 0;\n    if (P < m) return res;\n\n    vector<int> selected;\n    vector<int> minDist(P, INT_MAX);\n    vector<char> used(P, 0);\n\n    int start = 0;\n    for (int i = 1; i < P; ++i) {\n        if (pool[i].sum < pool[start].sum) start = i;\n    }\n\n    for (int it = 0; it < m; ++it) {\n        int id;\n        if (it == 0) {\n            id = start;\n        } else {\n            id = -1;\n            int best = -1;\n            for (int i = 0; i < P; ++i) {\n                if (!used[i] && minDist[i] > best) {\n                    best = minDist[i];\n                    id = i;\n                }\n            }\n        }\n\n        used[id] = 1;\n        selected.push_back(id);\n\n        for (int i = 0; i < P; ++i) {\n            if (!used[i]) {\n                int d = dist2Deg(pool[i].deg, pool[id].deg, N);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    for (int rep = 0; rep < improveIters; ++rep) {\n        vector<int> near(m, INT_MAX);\n        int curMin = INT_MAX;\n        int worstPos = -1;\n\n        for (int i = 0; i < m; ++i) {\n            for (int j = 0; j < m; ++j) if (i != j) {\n                int d = dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N);\n                near[i] = min(near[i], d);\n            }\n            if (near[i] < curMin) {\n                curMin = near[i];\n                worstPos = i;\n            }\n        }\n\n        int bestP = -1;\n        int bestMd = curMin;\n\n        for (int p = 0; p < P; ++p) if (!used[p]) {\n            int md = INT_MAX;\n            for (int i = 0; i < m; ++i) {\n                if (i == worstPos) continue;\n                int d = dist2Deg(pool[p].deg, pool[selected[i]].deg, N);\n                md = min(md, d);\n                if (md <= curMin) break;\n            }\n            if (md > bestMd) {\n                bestMd = md;\n                bestP = p;\n            }\n        }\n\n        if (bestP == -1) break;\n\n        used[selected[worstPos]] = 0;\n        selected[worstPos] = bestP;\n        used[bestP] = 1;\n    }\n\n    int md2 = INT_MAX;\n    for (int i = 0; i < m; ++i) {\n        for (int j = i + 1; j < m; ++j) {\n            md2 = min(md2, dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N));\n        }\n    }\n\n    res.idx = selected;\n    res.minD2 = md2;\n    return res;\n}\n\nvoid setupBlocks(int N) {\n    Lcur = min(10, N);\n    Fcur = 0;\n    for (int i = 0; i < 10; ++i) for (int j = 0; j < 10; ++j) FIDX[i][j] = -1;\n\n    for (int a = 0; a < Lcur; ++a) {\n        for (int b = a; b < Lcur; ++b) {\n            FIDX[a][b] = FIDX[b][a] = Fcur++;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        POSBIN[i] = (long long)i * Lcur / N;\n        if (POSBIN[i] >= Lcur) POSBIN[i] = Lcur - 1;\n    }\n\n    PAIRCNT.assign(Fcur, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            int f = FIDX[POSBIN[i]][POSBIN[j]];\n            PAIRCNT[f]++;\n        }\n    }\n}\n\nvector<int> computeBlockCounts(const vector<Row>& rows) {\n    vector<int> cnt(Fcur, 0);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, i, j)) {\n                int f = FIDX[POSBIN[i]][POSBIN[j]];\n                cnt[f]++;\n            }\n        }\n    }\n    return cnt;\n}\n\nvector<double> binomDist(int n, double p) {\n    vector<double> d(n + 1, 0.0);\n    if (n == 0) {\n        d[0] = 1.0;\n        return d;\n    }\n    double q = 1.0 - p;\n    d[0] = pow(q, n);\n    for (int k = 0; k < n; ++k) {\n        if (q == 0.0) {\n            d[k + 1] = (k + 1 == n ? 1.0 : 0.0);\n        } else {\n            d[k + 1] = d[k] * (double)(n - k) / (double)(k + 1) * p / q;\n        }\n    }\n    return d;\n}\n\nvoid setupPMF(int N) {\n    vector<vector<double>> keep(N), flip(N);\n    for (int n = 0; n <= N - 1; ++n) {\n        keep[n] = binomDist(n, 1.0 - EPS);\n        flip[n] = binomDist(n, EPS);\n    }\n\n    for (int d = 0; d <= N - 1; ++d) {\n        for (int x = 0; x <= N - 1; ++x) PMF[d][x] = 0.0;\n\n        int absent = N - 1 - d;\n        for (int y = 0; y <= d; ++y) {\n            for (int z = 0; z <= absent; ++z) {\n                PMF[d][y + z] += keep[d][y] * flip[absent][z];\n            }\n        }\n\n        for (int x = 0; x <= N - 1; ++x) {\n            double p = max(PMF[d][x], 1e-300);\n            NEGLOGP[d][x] = -log(p);\n        }\n    }\n}\n\nCodeword buildCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = cand.mask;\n    c.deg = cand.deg;\n    c.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : c.rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> dorig{};\n    thresholdDegrees(c.mask, Bcur, Ncur, dorig);\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (dorig[a] != dorig[b]) return dorig[a] < dorig[b];\n        return a < b;\n    });\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            int u = ord[a], v = ord[b];\n            int later = max(u, v);\n            if (thresholdBit(c.mask, later, Bcur, Ncur)) {\n                setEdge(c.rows, a, b);\n            }\n        }\n    }\n\n    c.mixNeg.fill(0.0);\n    for (int x = 0; x < Ncur; ++x) {\n        double p = 0.0;\n        for (int i = 0; i < Ncur; ++i) {\n            p += PMF[c.deg[i]][x];\n        }\n        p /= Ncur;\n        c.mixNeg[x] = -log(max(p, 1e-300));\n    }\n\n    c.blockCnt = computeBlockCounts(c.rows);\n    return c;\n}\n\nQueryFeat makeFeatureFromRows(const vector<Row>& rowsIn, const array<int, MAXN>& deg) {\n    QueryFeat q;\n    q.hist.fill(0);\n    q.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : q.rows) r = {0ULL, 0ULL};\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < Ncur; ++i) {\n        q.degSorted[i] = deg[ord[i]];\n        q.hist[q.degSorted[i]]++;\n    }\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            if (getEdge(rowsIn, ord[a], ord[b])) {\n                setEdge(q.rows, a, b);\n            }\n        }\n    }\n\n    q.blockCnt = computeBlockCounts(q.rows);\n    return q;\n}\n\nQueryFeat featureFromString(const string& s) {\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    int pos = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (s[pos++] == '1') {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    return makeFeatureFromRows(rows, deg);\n}\n\nQueryFeat simulateQuery(int k, mt19937_64& rng) {\n    const Codeword& cw = codes[k];\n\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            int g = thresholdBit(cw.mask, j, Bcur, Ncur);\n            int h = g;\n            if (rnd01(rng) < EPS) h ^= 1;\n            if (h) {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    array<int, MAXN> perm{};\n    for (int i = 0; i < Ncur; ++i) perm[i] = i;\n    for (int i = Ncur - 1; i >= 1; --i) {\n        int r = rng() % (i + 1);\n        swap(perm[i], perm[r]);\n    }\n\n    vector<Row> shuf(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : shuf) r = {0ULL, 0ULL};\n    array<int, MAXN> deg2{};\n    deg2.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        deg2[i] = deg[perm[i]];\n    }\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, perm[i], perm[j])) {\n                setEdge(shuf, i, j);\n            }\n        }\n    }\n\n    return makeFeatureFromRows(shuf, deg2);\n}\n\nint edgeMismatch(const vector<Row>& A, const vector<Row>& B) {\n    int s = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        s += __builtin_popcountll(A[i][0] ^ B[i][0]);\n        if (Ncur > 64) s += __builtin_popcountll(A[i][1] ^ B[i][1]);\n    }\n    return s / 2;\n}\n\nstruct Components {\n    double sortedCost;\n    double mixCost;\n    double blockCost;\n    int edgeMis;\n};\n\nComponents computeComponents(const QueryFeat& q, const Codeword& c) {\n    Components comp{0.0, 0.0, 0.0, 0};\n\n    for (int i = 0; i < Ncur; ++i) {\n        comp.sortedCost += NEGLOGP[c.deg[i]][q.degSorted[i]];\n    }\n\n    for (int x = 0; x < Ncur; ++x) {\n        if (q.hist[x]) comp.mixCost += q.hist[x] * c.mixNeg[x];\n    }\n\n    for (int f = 0; f < Fcur; ++f) {\n        int pairs = PAIRCNT[f];\n        if (pairs <= 0) continue;\n        double mu = EPS * pairs + QV * c.blockCnt[f];\n        double var = pairs * EPS * (1.0 - EPS) + 1.0;\n        double diff = q.blockCnt[f] - mu;\n        comp.blockCost += diff * diff / (2.0 * var);\n    }\n\n    comp.edgeMis = edgeMismatch(q.rows, c.rows);\n    return comp;\n}\n\ninline double scoreWithConfig(const Components& comp, const Config& cfg) {\n    double degCost = cfg.alpha * comp.sortedCost + (1.0 - cfg.alpha) * comp.mixCost;\n    return degCost + cfg.wb * comp.blockCost + cfg.we * edgePenalty * comp.edgeMis;\n}\n\nvector<Config> buildConfigs() {\n    vector<Config> cfgs;\n    cfgs.push_back({0.5, 0.0, 0.0}); // conservative default\n\n    vector<double> alphas = {0.0, 0.25, 0.5, 0.75, 1.0};\n    vector<double> wbs = {0.0, 0.2, 0.5, 1.0, 2.0};\n    vector<double> wes = {0.0, 0.02, 0.05, 0.1, 0.2};\n\n    for (double a : alphas) {\n        for (double wb : wbs) {\n            for (double we : wes) {\n                cfgs.push_back({a, wb, we});\n            }\n        }\n    }\n    return cfgs;\n}\n\nTrainResult trainDecoder() {\n    vector<Config> cfgs = buildConfigs();\n    int C = cfgs.size();\n\n    int R = 3;\n    if (EPS > 0.25) R = 5;\n    else if (EPS > 0.12) R = 4;\n    if (M <= 20) R += 4;\n    else if (M <= 50) R += 1;\n\n    int samples = M * R;\n    vector<int> errs(C, 0);\n\n    mt19937_64 rng(1234567ULL + (uint64_t)M * 1009ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 9176ULL\n                   + (uint64_t)Ncur * 1000003ULL);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n\n            vector<double> best(C, 1e300);\n            vector<int> bestId(C, -1);\n\n            for (int k = 0; k < M; ++k) {\n                Components comp = computeComponents(q, codes[k]);\n                for (int ci = 0; ci < C; ++ci) {\n                    double sc = scoreWithConfig(comp, cfgs[ci]);\n                    if (sc < best[ci]) {\n                        best[ci] = sc;\n                        bestId[ci] = k;\n                    }\n                }\n            }\n\n            for (int ci = 0; ci < C; ++ci) {\n                if (bestId[ci] != trueId) errs[ci]++;\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int ci = 1; ci < C; ++ci) {\n        if (errs[ci] < errs[bestC]) bestC = ci;\n    }\n\n    return {cfgs[bestC], errs[bestC], samples};\n}\n\nint predict(const QueryFeat& q) {\n    double best = 1e300;\n    int ans = 0;\n\n    for (int k = 0; k < M; ++k) {\n        Components comp = computeComponents(q, codes[k]);\n        double sc = scoreWithConfig(comp, bestCfg);\n        if (sc < best) {\n            best = sc;\n            ans = k;\n        }\n    }\n    return ans;\n}\n\nstring graphString(uint32_t mask) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(thresholdBit(mask, j, Bcur, Ncur) ? '1' : '0');\n        }\n    }\n    return s;\n}\n\nint chooseN() {\n    int minN = 4;\n    while (minN < 100 && (1LL << (minN - 1)) < M) minN++;\n\n    double r = sqrt(EPS * (1.0 - EPS)) / QV;\n    int nest = (int)ceil(4.0 + 38.0 * r * sqrt(M / 100.0) + 0.03 * M);\n    nest = max(minN, min(100, nest));\n\n    int start, end;\n    if (EPS < 0.05) {\n        start = minN;\n        end = min(100, max(nest + 15, minN + 8));\n    } else {\n        start = max(minN, nest - 20);\n        end = min(100, nest + 25);\n        if (EPS > 0.34) end = 100;\n    }\n\n    vector<int> ns;\n    for (int n = start; n <= end;) {\n        ns.push_back(n);\n        if (n < 35) n++;\n        else if (n < 75) n += 2;\n        else n += 4;\n    }\n    ns.push_back(minN);\n    ns.push_back(nest);\n    ns.push_back(100);\n    sort(ns.begin(), ns.end());\n    ns.erase(unique(ns.begin(), ns.end()), ns.end());\n\n    double target = 3.25 + 0.12 * log((double)M);\n    if (EPS > 0.25) target += 0.15;\n    if (EPS < 0.03) target -= 0.75;\n    else if (EPS < 0.07) target -= 0.30;\n    if (M <= 20) target -= 0.15;\n    target = max(2.4, target);\n\n    for (int n : ns) {\n        if (n < minN || n > 100) continue;\n        int Bs = min(n, (n >= 80 ? 12 : 11));\n        vector<Candidate> pool = buildPool(n, Bs);\n        if ((int)pool.size() < M) continue;\n\n        Selection sel = selectFarthest(pool, n, M, 0);\n        if (sel.idx.empty()) continue;\n\n        double sigma = sqrt((n - 1) * EPS * (1.0 - EPS));\n        double z = QV * sqrt((double)sel.minD2) / (2.0 * sigma);\n        if (z >= target) return n;\n    }\n\n    return 100;\n}\n\nvoid buildThresholdSolution(int initialN) {\n    int chosenN = initialN;\n    int attempts = 0;\n\n    while (true) {\n        Ncur = chosenN;\n        Bcur = min(Ncur, (Ncur >= 70 ? 14 : (Ncur >= 35 ? 13 : 12)));\n\n        vector<Candidate> pool = buildPool(Ncur, Bcur);\n        if ((int)pool.size() < M) {\n            chosenN++;\n            continue;\n        }\n\n        Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n        setupBlocks(Ncur);\n        setupPMF(Ncur);\n        edgePenalty = log((1.0 - EPS) / EPS);\n\n        codes.clear();\n        codes.reserve(M);\n        for (int id : sel.idx) {\n            codes.push_back(buildCodeword(pool[id]));\n        }\n\n        TrainResult tr = trainDecoder();\n        bestCfg = tr.cfg;\n\n        int allowed;\n        if (EPS < 0.05) allowed = max(4, tr.samples / 50);\n        else allowed = max(3, tr.samples / 100);\n\n        if (tr.err > allowed && chosenN < 100 && attempts < 3) {\n            int inc = (chosenN < 50 ? 10 : 6);\n            if (EPS > 0.3) inc = max(inc, 8);\n            chosenN = min(100, chosenN + inc);\n            attempts++;\n            continue;\n        }\n\n        break;\n    }\n}\n\n// Exact solver for epsilon = 0\nstruct ExactSolver {\n    int n, T;\n    vector<string> reps;\n    vector<int> cmap;\n    vector<array<int, 15>> trans;\n\n    int pairPos[6][6];\n\n    void prepareTrans(int n_) {\n        n = n_;\n        T = n * (n - 1) / 2;\n        for (int i = 0; i < 6; ++i) for (int j = 0; j < 6; ++j) pairPos[i][j] = -1;\n\n        int p = 0;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                pairPos[i][j] = pairPos[j][i] = p++;\n            }\n        }\n\n        vector<int> perm(n);\n        iota(perm.begin(), perm.end(), 0);\n        trans.clear();\n\n        do {\n            array<int, 15> tr{};\n            int pos = 0;\n            for (int i = 0; i < n; ++i) {\n                for (int j = i + 1; j < n; ++j) {\n                    int a = perm[i], b = perm[j];\n                    tr[pos++] = pairPos[a][b];\n                }\n            }\n            trans.push_back(tr);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    int canonicalMask(int mask) const {\n        int best = INT_MAX;\n        for (const auto& tr : trans) {\n            int val = 0;\n            for (int i = 0; i < T; ++i) {\n                val = (val << 1) | ((mask >> tr[i]) & 1);\n            }\n            if (val < best) best = val;\n        }\n        return best;\n    }\n\n    string maskToString(int mask) const {\n        string s;\n        s.resize(T);\n        for (int i = 0; i < T; ++i) {\n            s[i] = ((mask >> i) & 1) ? '1' : '0';\n        }\n        return s;\n    }\n\n    int stringToMask(const string& s) const {\n        int mask = 0;\n        for (int i = 0; i < T; ++i) {\n            if (s[i] == '1') mask |= 1 << i;\n        }\n        return mask;\n    }\n\n    void generate(int M) {\n        for (int nn = 4; nn <= 6; ++nn) {\n            prepareTrans(nn);\n            reps.clear();\n            cmap.assign(1 << T, -1);\n\n            for (int mask = 0; mask < (1 << T); ++mask) {\n                int c = canonicalMask(mask);\n                if (cmap[c] == -1) {\n                    int id = (int)reps.size();\n                    cmap[c] = id;\n                    reps.push_back(maskToString(mask));\n                    if ((int)reps.size() == M) return;\n                }\n            }\n        }\n    }\n\n    int decode(const string& s) const {\n        int mask = stringToMask(s);\n        int c = canonicalMask(mask);\n        if (0 <= c && c < (int)cmap.size() && cmap[c] != -1) return cmap[c];\n        return 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> M >> EPS;\n    QV = 1.0 - 2.0 * EPS;\n\n    if (EPS < 1e-12) {\n        ExactSolver ex;\n        ex.generate(M);\n\n        cout << ex.n << '\\n';\n        for (int i = 0; i < M; ++i) {\n            cout << ex.reps[i] << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            cin >> H;\n            int ans = ex.decode(H);\n            cout << ans << '\\n';\n            cout.flush();\n        }\n        return 0;\n    }\n\n    int initialN = chooseN();\n    buildThresholdSolution(initialN);\n\n    cout << Ncur << '\\n';\n    for (int i = 0; i < M; ++i) {\n        cout << graphString(codes[i].mask) << '\\n';\n    }\n    cout.flush();\n\n    for (int q = 0; q < 100; ++q) {\n        string H;\n        cin >> H;\n        QueryFeat feat = featureFromString(H);\n        int ans = predict(feat);\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#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() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    static constexpr int INF = 1100000000;\n    static constexpr int UNREACH = 1000000000;\n    static constexpr long long DISCONN_SCORE = 4000000000000000LL;\n\n    struct Edge {\n        int u, v, w;\n        int cell;\n        uint32_t key;\n    };\n    struct Arc {\n        int to, w, id;\n    };\n    struct ScoreRes {\n        long long total;\n        vector<long long> day;\n    };\n    struct State {\n        vector<int> assign;\n        vector<int> count;\n        vector<vector<int>> dayEdges;\n        vector<int> pos;\n        vector<int> inc;\n        vector<double> dayImp;\n        vector<int> cellCnt;\n        vector<int> cutCnt;\n        vector<long long> dayScore;\n        long long totalScore = 0;\n    };\n    struct Cand {\n        int type = 0; // 1: move, 2: swap\n        int e = -1, f = -1;\n        double cheap = 1e100;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Arc>> adj;\n    vector<int> xs, ys;\n    vector<int> origDist;\n    vector<long long> load;\n    vector<vector<int>> cutAdj;\n    vector<double> stretch;\n    vector<double> impNorm;\n    vector<int> target;\n    vector<int> optSources;\n\n    static constexpr int G = 16;\n    static constexpr int C = G * G;\n    vector<vector<int>> neighCells;\n    vector<unsigned char> nearCell;\n\n    RNG rng;\n    chrono::steady_clock::time_point startTime;\n    double localEndTime = 5.65;\n\n    vector<pair<int, int>> heapBuf;\n    vector<int> distBuf;\n    vector<int> bfsVis, bfsQ;\n    int bfsStamp = 1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static uint64_t mix64(uint64_t z) {\n        z += 0x9e3779b97f4a7c15ull;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n\n    uint32_t zOrder(int x, int y) const {\n        uint32_t r = 0;\n        for (int b = 0; b < 11; b++) {\n            r |= ((x >> b) & 1u) << (2 * b);\n            r |= ((y >> b) & 1u) << (2 * b + 1);\n        }\n        return r;\n    }\n\n    int edgeCellFromSum(int sx, int sy) const {\n        int cx = min(G - 1, (sx * G) / 2001);\n        int cy = min(G - 1, (sy * G) / 2001);\n        return cx * G + cy;\n    }\n\n    void setupCells() {\n        neighCells.assign(C, {});\n        nearCell.assign(C * C, 0);\n        for (int cx = 0; cx < G; cx++) {\n            for (int cy = 0; cy < G; cy++) {\n                int c = cx * G + cy;\n                for (int dx = -1; dx <= 1; dx++) {\n                    for (int dy = -1; dy <= 1; dy++) {\n                        int nx = cx + dx, ny = cy + dy;\n                        if (0 <= nx && nx < G && 0 <= ny && ny < G) {\n                            int nc = nx * G + ny;\n                            neighCells[c].push_back(nc);\n                            nearCell[c * C + nc] = 1;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    void readInput() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        adj.assign(N, {});\n        uint64_t seed = 123456789;\n\n        for (int i = 0; i < M; i++) {\n            int u, v, w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i].u = u;\n            edges[i].v = v;\n            edges[i].w = w;\n            edges[i].cell = 0;\n            edges[i].key = 0;\n            adj[u].push_back({v, w, i});\n            adj[v].push_back({u, w, i});\n            seed ^= mix64((uint64_t)(u + 1) * 1000003ull + (uint64_t)(v + 1) * 1009ull + w);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> xs[i] >> ys[i];\n            seed ^= mix64((uint64_t)(xs[i] + 1) * 10007ull + ys[i] + i * 97ull);\n        }\n        rng.x = seed ? seed : 88172645463325252ull;\n\n        setupCells();\n\n        for (int i = 0; i < M; i++) {\n            int u = edges[i].u, v = edges[i].v;\n            int sx = xs[u] + xs[v];\n            int sy = ys[u] + ys[v];\n            edges[i].cell = edgeCellFromSum(sx, sy);\n            int hx = min(2047, (sx * 2047) / 2000);\n            int hy = min(2047, (sy * 2047) / 2000);\n            edges[i].key = zOrder(hx, hy);\n        }\n\n        target.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) target[d]++;\n\n        distBuf.assign(N, INF);\n        bfsVis.assign(N, 0);\n        bfsQ.assign(N, 0);\n        heapBuf.reserve(max(10000, 4 * M + 2 * N));\n    }\n\n    void heapPush(int d, int v) {\n        pair<int, int> val = {d, v};\n        int i = (int)heapBuf.size();\n        heapBuf.push_back(val);\n        while (i > 0) {\n            int p = (i - 1) >> 1;\n            if (heapBuf[p].first <= val.first) break;\n            heapBuf[i] = heapBuf[p];\n            i = p;\n        }\n        heapBuf[i] = val;\n    }\n\n    pair<int, int> heapPop() {\n        pair<int, int> res = heapBuf[0];\n        pair<int, int> val = heapBuf.back();\n        heapBuf.pop_back();\n        if (!heapBuf.empty()) {\n            int i = 0;\n            int n = (int)heapBuf.size();\n            while (true) {\n                int l = i * 2 + 1;\n                if (l >= n) break;\n                int r = l + 1;\n                int c = l;\n                if (r < n && heapBuf[r].first < heapBuf[l].first) c = r;\n                if (heapBuf[c].first >= val.first) break;\n                heapBuf[i] = heapBuf[c];\n                i = c;\n            }\n            heapBuf[i] = val;\n        }\n        return res;\n    }\n\n    void dijkstraOriginalParent(\n        int src,\n        vector<int>& dist,\n        vector<int>& parV,\n        vector<int>& parE,\n        vector<int>& order\n    ) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        order.clear();\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            order.push_back(v);\n            for (const auto& a : adj[v]) {\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    parV[a.to] = v;\n                    parE[a.to] = a.id;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    void dijkstraDaySource(int src, int day, const vector<int>& assign, vector<int>& dist) {\n        fill(dist.begin(), dist.end(), INF);\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            for (const auto& a : adj[v]) {\n                if (assign[a.id] == day) continue;\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    int dijkstraBetweenSkipEdge(int src, int dst, int banned) {\n        fill(distBuf.begin(), distBuf.end(), INF);\n        heapBuf.clear();\n\n        distBuf[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != distBuf[v]) continue;\n            if (v == dst) return du;\n            for (const auto& a : adj[v]) {\n                if (a.id == banned) continue;\n                int nd = du + a.w;\n                if (nd < distBuf[a.to]) {\n                    distBuf[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n        return INF;\n    }\n\n    void computeOriginalAndLoad() {\n        origDist.assign(N * N, INF);\n        load.assign(M, 0);\n\n        vector<int> dist(N), parV(N), parE(N), order;\n        vector<int> sub(N);\n\n        for (int s = 0; s < N; s++) {\n            dijkstraOriginalParent(s, dist, parV, parE, order);\n            memcpy(&origDist[s * N], dist.data(), sizeof(int) * N);\n\n            fill(sub.begin(), sub.end(), 1);\n            for (int ii = (int)order.size() - 1; ii >= 0; ii--) {\n                int v = order[ii];\n                int e = parE[v];\n                if (e != -1) {\n                    load[e] += sub[v];\n                    sub[parV[v]] += sub[v];\n                }\n            }\n        }\n    }\n\n    void detectTwoEdgeCuts() {\n        cutAdj.assign(M, {});\n        vector<int> tin(N), low(N);\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), 0);\n            fill(low.begin(), low.end(), 0);\n            int timer = 0;\n\n            auto dfs = [&](auto&& self, int v, int pe) -> void {\n                tin[v] = low[v] = ++timer;\n                for (const auto& a : adj[v]) {\n                    if (a.id == banned || a.id == pe) continue;\n                    int to = a.to;\n                    if (!tin[to]) {\n                        self(self, to, a.id);\n                        low[v] = min(low[v], low[to]);\n                        if (low[to] > tin[v]) {\n                            int f = a.id;\n                            if (banned < f) {\n                                cutAdj[banned].push_back(f);\n                                cutAdj[f].push_back(banned);\n                            }\n                        }\n                    } else {\n                        low[v] = min(low[v], tin[to]);\n                    }\n                }\n            };\n\n            dfs(dfs, 0, -1);\n        }\n\n        for (auto& v : cutAdj) {\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n    }\n\n    void computeStretch() {\n        stretch.assign(M, 0.0);\n        const double deadline = 1.35;\n\n        for (int e = 0; e < M; e++) {\n            if (elapsed() > deadline) break;\n            int u = edges[e].u;\n            int v = edges[e].v;\n            int repl = dijkstraBetweenSkipEdge(u, v, e);\n            int base = origDist[u * N + v];\n            if (repl >= INF) {\n                stretch[e] = 5.0;\n            } else {\n                stretch[e] = max(0.0, (double)(repl - base) / max(1, base));\n                stretch[e] = min(stretch[e], 8.0);\n            }\n        }\n    }\n\n    void computeImportance() {\n        double sumLoad = 0.0;\n        for (auto x : load) sumLoad += (double)x;\n        double meanLoad = max(1.0, sumLoad / max(1, M));\n\n        double avgW = 0.0;\n        for (const auto& e : edges) avgW += e.w;\n        avgW /= max(1, M);\n\n        vector<double> raw(M);\n        double sumRaw = 0.0;\n\n        for (int e = 0; e < M; e++) {\n            double r = (double)load[e] + 0.05 * meanLoad + 1.0;\n            r *= 1.0 + 0.7 * min(5.0, stretch[e]);\n            r *= 1.0 + 0.03 * min(50, (int)cutAdj[e].size());\n            r *= 0.75 + 0.25 * sqrt(max(0.1, edges[e].w / avgW));\n            raw[e] = r;\n            sumRaw += r;\n        }\n\n        double meanRaw = max(1e-9, sumRaw / max(1, M));\n        impNorm.assign(M, 1.0);\n        for (int e = 0; e < M; e++) {\n            impNorm[e] = raw[e] / meanRaw;\n            impNorm[e] = min(60.0, max(0.03, impNorm[e]));\n        }\n    }\n\n    vector<int> selectSources(int P) {\n        P = min(P, N);\n        vector<pair<uint32_t, int>> ord;\n        ord.reserve(N);\n        for (int i = 0; i < N; i++) {\n            int hx = xs[i] * 2047 / 1000;\n            int hy = ys[i] * 2047 / 1000;\n            ord.push_back({zOrder(hx, hy), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        vector<int> res;\n        vector<char> used(N, 0);\n        for (int t = 0; t < P; t++) {\n            int idx = (int)(((long long)(2 * t + 1) * N) / (2 * P));\n            idx = min(idx, N - 1);\n            int v = ord[idx].second;\n            if (used[v]) {\n                for (int k = 0; k < N; k++) {\n                    int nv = ord[(idx + k) % N].second;\n                    if (!used[nv]) {\n                        v = nv;\n                        break;\n                    }\n                }\n            }\n            used[v] = 1;\n            res.push_back(v);\n        }\n        return res;\n    }\n\n    bool isConnectedSkip(const vector<int>& assign, int day, int extraSkip = -1) {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            fill(bfsVis.begin(), bfsVis.end(), 0);\n            bfsStamp = 1;\n        }\n\n        int head = 0, tail = 0;\n        bfsVis[0] = bfsStamp;\n        bfsQ[tail++] = 0;\n        int seen = 1;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            for (const auto& a : adj[v]) {\n                if (a.id == extraSkip) continue;\n                if (assign[a.id] == day) continue;\n                int to = a.to;\n                if (bfsVis[to] == bfsStamp) continue;\n                bfsVis[to] = bfsStamp;\n                bfsQ[tail++] = to;\n                seen++;\n            }\n        }\n        return seen == N;\n    }\n\n    long long computeDayScore(\n        const vector<int>& assign,\n        int day,\n        const vector<int>& sources,\n        int removedCount,\n        bool checkConn\n    ) {\n        if (removedCount == 0) return 0;\n        if (checkConn && !isConnectedSkip(assign, day, -1)) return DISCONN_SCORE;\n\n        long long sum = 0;\n        for (int s : sources) {\n            dijkstraDaySource(s, day, assign, distBuf);\n            int base = s * N;\n            for (int v = 0; v < N; v++) {\n                int d = distBuf[v];\n                int dd = (d >= INF ? UNREACH : d);\n                int diff = dd - origDist[base + v];\n                if (diff > 0) sum += diff;\n            }\n        }\n        return sum;\n    }\n\n    ScoreRes scoreAll(const vector<int>& assign, const vector<int>& sources) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n            cnt[assign[e]]++;\n        }\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] > K) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n        }\n\n        ScoreRes r;\n        r.total = 0;\n        r.day.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            r.day[d] = computeDayScore(assign, d, sources, cnt[d], true);\n            r.total += r.day[d];\n        }\n        return r;\n    }\n\n    void shuffleVec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int localCellCount(const vector<int>& cellCnt, int day, int cell) const {\n        int s = 0;\n        int base = day * C;\n        for (int nb : neighCells[cell]) s += cellCnt[base + nb];\n        return s;\n    }\n\n    vector<int> buildHilbertLike(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0 || variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                int ax = xs[edges[a].u] + xs[edges[a].v];\n                int bx = xs[edges[b].u] + xs[edges[b].v];\n                if (ax != bx) return ax < bx;\n                int ay = ys[edges[a].u] + ys[edges[a].v];\n                int by = ys[edges[b].u] + ys[edges[b].v];\n                return ay < by;\n            });\n        }\n\n        vector<int> assign(M, 0);\n        vector<int> perm(D);\n        for (int b = 0; b < M; b += D) {\n            iota(perm.begin(), perm.end(), 0);\n            if (variant == 0) {\n                rotate(perm.begin(), perm.begin() + ((b / D) % D), perm.end());\n            } else {\n                shuffleVec(perm);\n            }\n            for (int i = 0; i < D && b + i < M; i++) {\n                assign[order[b + i]] = perm[i];\n            }\n        }\n        return assign;\n    }\n\n    vector<int> buildRandomBalanced() {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffleVec(order);\n\n        vector<int> days;\n        days.reserve(M);\n        for (int d = 0; d < D; d++) {\n            for (int i = 0; i < target[d]; i++) days.push_back(d);\n        }\n        shuffleVec(days);\n\n        vector<int> assign(M);\n        for (int i = 0; i < M; i++) assign[order[i]] = days[i];\n        return assign;\n    }\n\n    vector<int> buildGreedy(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (impNorm[a] != impNorm[b]) return impNorm[a] > impNorm[b];\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (cutAdj[a].size() != cutAdj[b].size()) return cutAdj[a].size() > cutAdj[b].size();\n                return impNorm[a] > impNorm[b];\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 3) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            vector<double> key(M);\n            for (int e = 0; e < M; e++) key[e] = impNorm[e] * (0.6 + 0.8 * rng.nextDouble());\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        }\n\n        vector<int> assign(M, -1);\n        vector<int> count(D, 0);\n        vector<int> inc(N * D, 0);\n        vector<double> dayImp(D, 0.0);\n        vector<int> cellCnt(D * C, 0);\n        vector<int> cutCnt(M * D, 0);\n\n        for (int e : order) {\n            int u = edges[e].u, v = edges[e].v;\n            int cell = edges[e].cell;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(D);\n\n            for (int d = 0; d < D; d++) {\n                if (count[d] >= K) continue;\n\n                int adjCnt = inc[u * D + d] + inc[v * D + d];\n                int loc = localCellCount(cellCnt, d, cell);\n                int cut = cutCnt[e * D + d];\n\n                double over = max(0, count[d] + 1 - target[d]);\n                double cost = 100000000.0 * cut;\n                cost += 25.0 * adjCnt;\n                cost += 2.0 * loc;\n                cost += 4.0 * impNorm[e] * (dayImp[d] / max(1, target[d]));\n                if (count[d] >= target[d]) cost += 600.0 * over * over;\n                else cost += 0.1 * (double)count[d] / max(1, target[d]);\n                cost += 0.01 * rng.nextDouble();\n\n                cand.push_back({cost, d});\n            }\n\n            if (cand.empty()) {\n                int best = min_element(count.begin(), count.end()) - count.begin();\n                cand.push_back({0.0, best});\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int chosen = -1;\n            for (auto [cost, d] : cand) {\n                if (isConnectedSkip(assign, d, e)) {\n                    chosen = d;\n                    break;\n                }\n            }\n            if (chosen == -1) chosen = cand[0].second;\n\n            assign[e] = chosen;\n            count[chosen]++;\n            inc[u * D + chosen]++;\n            inc[v * D + chosen]++;\n            dayImp[chosen] += impNorm[e];\n            cellCnt[chosen * C + cell]++;\n            for (int g : cutAdj[e]) cutCnt[g * D + chosen]++;\n        }\n\n        return assign;\n    }\n\n    State buildState(const vector<int>& assign, const vector<int>& sources) {\n        State st;\n        st.assign = assign;\n        st.count.assign(D, 0);\n        st.dayEdges.assign(D, {});\n        st.pos.assign(M, -1);\n        st.inc.assign(N * D, 0);\n        st.dayImp.assign(D, 0.0);\n        st.cellCnt.assign(D * C, 0);\n        st.cutCnt.assign(M * D, 0);\n        st.dayScore.assign(D, 0);\n        st.totalScore = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            st.pos[e] = (int)st.dayEdges[d].size();\n            st.dayEdges[d].push_back(e);\n            st.count[d]++;\n            st.inc[edges[e].u * D + d]++;\n            st.inc[edges[e].v * D + d]++;\n            st.dayImp[d] += impNorm[e];\n            st.cellCnt[d * C + edges[e].cell]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            for (int g : cutAdj[e]) {\n                st.cutCnt[g * D + d]++;\n            }\n        }\n\n        for (int d = 0; d < D; d++) {\n            st.dayScore[d] = computeDayScore(st.assign, d, sources, st.count[d], true);\n            st.totalScore += st.dayScore[d];\n        }\n\n        return st;\n    }\n\n    bool isCutPair(int a, int b) const {\n        const auto& v = cutAdj[a];\n        return binary_search(v.begin(), v.end(), b);\n    }\n\n    int shareCount(int a, int b) const {\n        int c = 0;\n        if (edges[a].u == edges[b].u || edges[a].u == edges[b].v) c++;\n        if (edges[a].v == edges[b].u || edges[a].v == edges[b].v) c++;\n        return c;\n    }\n\n    double placeCost(const State& st, int e, int d, int removeY) {\n        bool inD = (st.assign[e] == d);\n        int u = edges[e].u, v = edges[e].v;\n        int adjCnt = st.inc[u * D + d] + st.inc[v * D + d];\n        if (inD) adjCnt -= 2;\n        if (removeY >= 0 && st.assign[removeY] == d) {\n            adjCnt -= shareCount(e, removeY);\n        }\n        adjCnt = max(0, adjCnt);\n\n        int cut = st.cutCnt[e * D + d];\n        if (removeY >= 0 && st.assign[removeY] == d && isCutPair(e, removeY)) cut--;\n        cut = max(0, cut);\n\n        int loc = localCellCount(st.cellCnt, d, edges[e].cell);\n        if (inD) loc--;\n        if (removeY >= 0 && st.assign[removeY] == d &&\n            nearCell[edges[e].cell * C + edges[removeY].cell]) {\n            loc--;\n        }\n        loc = max(0, loc);\n\n        double impSum = st.dayImp[d];\n        if (inD) impSum -= impNorm[e];\n        if (removeY >= 0 && st.assign[removeY] == d) impSum -= impNorm[removeY];\n        impSum = max(0.0, impSum);\n\n        double cost = 1000000.0 * cut;\n        cost += 10.0 * adjCnt;\n        cost += 1.5 * loc;\n        cost += 2.0 * impNorm[e] * (impSum / max(1, target[d]));\n        return cost;\n    }\n\n    double edgeBadness(const State& st, int e, int d) {\n        return placeCost(st, e, d, -1) + 0.5 * impNorm[e];\n    }\n\n    int randomNonemptyDay(const State& st, int exclude = -1) {\n        for (int t = 0; t < 50; t++) {\n            int d = rng.nextInt(D);\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        for (int d = 0; d < D; d++) {\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        return -1;\n    }\n\n    int argMaxDay(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int d = 0; d < D; d++) {\n            if (st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int argMinDay(const State& st, int exclude = -1, bool requireNonempty = true) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int d = 0; d < D; d++) {\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int tournamentHigh(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int i = 0; i < 5; i++) {\n            int d = randomNonemptyDay(st);\n            if (d == -1) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMaxDay(st);\n        return best;\n    }\n\n    int tournamentLow(const State& st, int exclude, bool requireNonempty) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int i = 0; i < 5; i++) {\n            int d = rng.nextInt(D);\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMinDay(st, exclude, requireNonempty);\n        return best;\n    }\n\n    int selectEdge(const State& st, int day, bool bad) {\n        const auto& v = st.dayEdges[day];\n        if (v.empty()) return -1;\n\n        int best = v[rng.nextInt((int)v.size())];\n        double bv = edgeBadness(st, best, day);\n\n        int samples = min(7, (int)v.size());\n        for (int i = 1; i < samples; i++) {\n            int e = v[rng.nextInt((int)v.size())];\n            double val = edgeBadness(st, e, day);\n            if ((bad && val > bv) || (!bad && val < bv)) {\n                bv = val;\n                best = e;\n            }\n        }\n        return best;\n    }\n\n    double cheapDeltaSwap(const State& st, int e, int f) {\n        int a = st.assign[e], b = st.assign[f];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1) + placeCost(st, f, b, -1);\n        double after = placeCost(st, e, b, f) + placeCost(st, f, a, e);\n        return after - before;\n    }\n\n    double cheapDeltaMove(const State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1);\n        double after = placeCost(st, e, b, -1);\n        return after - before;\n    }\n\n    Cand proposeSwap(const State& st) {\n        Cand best;\n        best.type = 2;\n\n        for (int t = 0; t < 14; t++) {\n            int a, b;\n            int mode = rng.nextInt(100);\n\n            if (mode < 45) {\n                a = argMaxDay(st);\n                b = argMinDay(st, a, true);\n            } else if (mode < 80) {\n                a = tournamentHigh(st);\n                b = tournamentLow(st, a, true);\n            } else {\n                a = randomNonemptyDay(st);\n                b = randomNonemptyDay(st, a);\n            }\n\n            if (a < 0 || b < 0 || a == b) continue;\n\n            int e = selectEdge(st, a, true);\n            int f = selectEdge(st, b, false);\n            if (e < 0 || f < 0) continue;\n\n            double cd = cheapDeltaSwap(st, e, f);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = f;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    Cand proposeMove(const State& st) {\n        Cand best;\n        best.type = 1;\n\n        int lowBound = max(0, M / D - 2);\n        int highBound = min(K, (M + D - 1) / D + 2);\n\n        for (int t = 0; t < 12; t++) {\n            int a = -1;\n            long long av = LLONG_MIN;\n\n            if (rng.nextInt(100) < 60) {\n                for (int d = 0; d < D; d++) {\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            } else {\n                for (int k = 0; k < 8; k++) {\n                    int d = rng.nextInt(D);\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            }\n\n            if (a < 0) continue;\n\n            int b = -1;\n            long long bv = LLONG_MAX;\n            for (int k = 0; k < 8; k++) {\n                int d = rng.nextInt(D);\n                if (d == a) continue;\n                if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                if (st.dayScore[d] < bv) {\n                    bv = st.dayScore[d];\n                    b = d;\n                }\n            }\n            if (b < 0) {\n                for (int d = 0; d < D; d++) {\n                    if (d == a) continue;\n                    if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                    if (st.dayScore[d] < bv) {\n                        bv = st.dayScore[d];\n                        b = d;\n                    }\n                }\n            }\n            if (b < 0) continue;\n\n            int e = selectEdge(st, a, true);\n            if (e < 0) continue;\n\n            double cd = cheapDeltaMove(st, e, b);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = b;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    bool acceptDelta(const State& st, long long delta, bool isMove) {\n        if (delta <= 0) return true;\n\n        double avg = max(1.0, st.totalScore / (double)max(1, D));\n        double prog = min(1.0, elapsed() / localEndTime);\n        double factor = isMove ? 0.004 : 0.008;\n        double T = avg * (factor * (1.0 - prog) + 0.00002);\n\n        if (T <= 1.0) return false;\n        if ((double)delta > T * 20.0) return false;\n        return rng.nextDouble() < exp(-(double)delta / T);\n    }\n\n    void applySwap(State& st, int e, int f, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e], pf = st.pos[f];\n        st.dayEdges[a][pe] = f;\n        st.dayEdges[b][pf] = e;\n        st.pos[f] = pe;\n        st.pos[e] = pf;\n\n        auto decEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]--;\n            st.inc[edges[x].v * D + d]--;\n            st.dayImp[d] -= impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]--;\n        };\n        auto incEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]++;\n            st.inc[edges[x].v * D + d]++;\n            st.dayImp[d] += impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]++;\n        };\n\n        decEdge(e, a); incEdge(e, b);\n        decEdge(f, b); incEdge(f, a);\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n        for (int g : cutAdj[f]) {\n            st.cutCnt[g * D + b]--;\n            st.cutCnt[g * D + a]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    void applyMove(State& st, int e, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e];\n        int last = st.dayEdges[a].back();\n        st.dayEdges[a][pe] = last;\n        st.pos[last] = pe;\n        st.dayEdges[a].pop_back();\n\n        st.pos[e] = (int)st.dayEdges[b].size();\n        st.dayEdges[b].push_back(e);\n\n        st.count[a]--;\n        st.count[b]++;\n\n        st.inc[edges[e].u * D + a]--;\n        st.inc[edges[e].v * D + a]--;\n        st.inc[edges[e].u * D + b]++;\n        st.inc[edges[e].v * D + b]++;\n\n        st.dayImp[a] -= impNorm[e];\n        st.dayImp[b] += impNorm[e];\n\n        st.cellCnt[a * C + edges[e].cell]--;\n        st.cellCnt[b * C + edges[e].cell]++;\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    bool trySwap(State& st, int e, int f) {\n        int a = st.assign[e];\n        int b = st.assign[f];\n        if (a == b) return false;\n\n        st.assign[e] = b;\n        st.assign[f] = a;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a], false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b], false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, false);\n\n        if (acc) {\n            applySwap(st, e, f, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            st.assign[f] = b;\n            return false;\n        }\n    }\n\n    bool tryMove(State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return false;\n        if (st.count[b] >= K) return false;\n\n        st.assign[e] = b;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a] - 1, false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b] + 1, false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, true);\n\n        if (acc) {\n            applyMove(st, e, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            return false;\n        }\n    }\n\n    void ensureLegal(vector<int>& assign) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) assign[e] = 0;\n            cnt[assign[e]]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            if (cnt[d] <= K) continue;\n            int b = -1;\n            for (int j = 0; j < D; j++) {\n                if (cnt[j] < K) {\n                    b = j;\n                    break;\n                }\n            }\n            if (b == -1) break;\n            cnt[d]--;\n            assign[e] = b;\n            cnt[b]++;\n        }\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        readInput();\n\n        computeOriginalAndLoad();\n        detectTwoEdgeCuts();\n        computeStretch();\n        computeImportance();\n\n        int P = 24;\n        if (D <= 10) P += 8;\n        else if (D <= 18) P += 4;\n        if (M <= 1200) P += 8;\n        else if (M <= 2000) P += 4;\n        if (N <= 700) P += 4;\n        P = min({P, N, 52});\n        optSources = selectSources(P);\n\n        vector<int> bestAssign;\n        long long bestScore = LLONG_MAX;\n\n        auto consider = [&](const vector<int>& assign) {\n            ScoreRes sc = scoreAll(assign, optSources);\n            if (sc.total < bestScore) {\n                bestScore = sc.total;\n                bestAssign = assign;\n            }\n        };\n\n        consider(buildHilbertLike(0));\n        consider(buildGreedy(0));\n\n        const double initDeadline = 2.25;\n        if (elapsed() < initDeadline) consider(buildGreedy(1));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(1));\n        if (elapsed() < initDeadline) consider(buildGreedy(2));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(2));\n        if (elapsed() < initDeadline) consider(buildGreedy(4));\n        if (elapsed() < initDeadline) consider(buildRandomBalanced());\n\n        if (bestAssign.empty()) bestAssign = buildRandomBalanced();\n\n        State st = buildState(bestAssign, optSources);\n        vector<int> bestLocal = st.assign;\n        long long bestLocalScore = st.totalScore;\n\n        localEndTime = 5.65;\n        while (elapsed() < localEndTime) {\n            Cand cand;\n            if (rng.nextInt(100) < 18) cand = proposeMove(st);\n            if (cand.type == 0) cand = proposeSwap(st);\n\n            bool accepted = false;\n            if (cand.type == 1) {\n                accepted = tryMove(st, cand.e, cand.f);\n            } else if (cand.type == 2) {\n                accepted = trySwap(st, cand.e, cand.f);\n            }\n\n            if (accepted && st.totalScore < bestLocalScore) {\n                bestLocalScore = st.totalScore;\n                bestLocal = st.assign;\n            }\n        }\n\n        ensureLegal(bestLocal);\n\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << bestLocal[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    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct I3 {\n        short x, y, z;\n    };\n    struct Rot {\n        int perm[3];\n        int sign[3];\n    };\n    struct AlignCand {\n        long long key;\n        int ori, tid, cnt, w;\n    };\n    struct AlignMinCmp {\n        bool operator()(const AlignCand& a, const AlignCand& b) const {\n            return a.key > b.key;\n        }\n    };\n    struct CompCand {\n        bool valid = false;\n        double score = -1e100;\n        int size = 0;\n        int cov = 0;\n        int ori = 0;\n        int tx = 0, ty = 0, tz = 0;\n        vector<int> cells;\n    };\n    struct Box {\n        int x = 0, y = 0, z = 0;\n        int lx = 0, ly = 0, lz = 0;\n        int cov = -1;\n        int vol = 0;\n        bool valid = false;\n    };\n    struct BoxCand {\n        bool valid = false;\n        Box b0, b1;\n        int vol = 0;\n        int cov = 0;\n        double score = -1;\n    };\n    struct Bar {\n        int x = 0, y = 0, z = 0;\n        int dir = 0;\n        int len = 0;\n        int cov = 0;\n        bool valid = false;\n        array<int, 15> nf{};\n        array<int, 15> nr{};\n    };\n    struct BarCand {\n        bool valid = false;\n        Bar b0, b1;\n        int len = 0;\n        int cov = 0;\n        double score = -1e100;\n    };\n    struct SimpleBox {\n        int x = 0, y = 0, z = 0;\n        int lx = 0, ly = 0, lz = 0;\n        int vol = 0;\n        bool valid = false;\n    };\n    struct PoolBoxCand {\n        bool valid = false;\n        SimpleBox b0, b1;\n        int vol = 0;\n    };\n\n    int D, D2, N;\n    int rangeT, offsetT, Tcnt;\n    array<vector<string>, 2> F, Rt;\n\n    array<vector<char>, 2> allowed, rem, covF, covR;\n    array<vector<int>, 2> ans;\n    array<vector<unsigned char>, 2> aw;\n\n    vector<int> xs, ys, zs;\n    vector<array<int, 6>> neigh;\n\n    vector<Rot> rots;\n    vector<vector<I3>> rotp;\n\n    int unF[2][15];\n    int unR[2][15];\n\n    int allowedCount[2] = {0, 0};\n    int remCnt[2] = {0, 0};\n    int minAllowed = 0;\n    int totalUncov = 0;\n\n    int label = 0;\n    int commonVol = 0;\n    int uniqueVol[2] = {0, 0};\n    double commonCost = 0.0;\n\n    vector<int> cnt, wcnt;\n    vector<int> mark, vis, qmap;\n    int markToken = 1, visToken = 1;\n    array<vector<int>, 2> tmpF, tmpR;\n    int pixToken = 1;\n\n    vector<int> startTid, curTid, entries;\n\n    array<vector<vector<int>>, 2> blk;\n    vector<char> activeLab;\n\n    chrono::steady_clock::time_point startTime;\n\n    Solver(int D_, const array<vector<string>, 2>& F_, const array<vector<string>, 2>& Rt_)\n        : D(D_), F(F_), Rt(Rt_) {\n        D2 = D * D;\n        N = D * D * D;\n        rangeT = 3 * D - 2;\n        offsetT = D - 1;\n        Tcnt = rangeT * rangeT * rangeT;\n\n        memset(unF, 0, sizeof(unF));\n        memset(unR, 0, sizeof(unR));\n\n        for (int s = 0; s < 2; s++) {\n            allowed[s].assign(N, 0);\n            rem[s].assign(N, 0);\n            covF[s].assign(D2, 0);\n            covR[s].assign(D2, 0);\n            ans[s].assign(N, 0);\n            aw[s].assign(N, 0);\n            tmpF[s].assign(D2, 0);\n            tmpR[s].assign(D2, 0);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        zs.resize(N);\n        neigh.resize(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 v = id(x, y, z);\n                    xs[v] = x;\n                    ys[v] = y;\n                    zs[v] = z;\n                }\n            }\n        }\n\n        for (int v = 0; v < N; v++) {\n            int x = xs[v], y = ys[v], z = zs[v];\n            array<int, 6> nb;\n            nb.fill(-1);\n            if (x > 0) nb[0] = id(x - 1, y, z);\n            if (x + 1 < D) nb[1] = id(x + 1, y, z);\n            if (y > 0) nb[2] = id(x, y - 1, z);\n            if (y + 1 < D) nb[3] = id(x, y + 1, z);\n            if (z > 0) nb[4] = id(x, y, z - 1);\n            if (z + 1 < D) nb[5] = id(x, y, z + 1);\n            neigh[v] = nb;\n        }\n\n        for (int s = 0; s < 2; s++) {\n            for (int z = 0; z < D; z++) {\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1') {\n                        unF[s][z]++;\n                        totalUncov++;\n                    }\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1') {\n                        unR[s][z]++;\n                        totalUncov++;\n                    }\n                }\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                        if (F[s][z][x] == '1' && Rt[s][z][y] == '1') {\n                            int v = id(x, y, z);\n                            allowed[s][v] = 1;\n                            rem[s][v] = 1;\n                            allowedCount[s]++;\n                        }\n                    }\n                }\n            }\n            remCnt[s] = allowedCount[s];\n        }\n\n        minAllowed = min(allowedCount[0], allowedCount[1]);\n\n        generateRotations();\n        rotp.assign(rots.size(), vector<I3>(N));\n        for (int ri = 0; ri < (int)rots.size(); ri++) {\n            for (int v = 0; v < N; v++) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) {\n                    q[a] = rots[ri].sign[a] * p[rots[ri].perm[a]];\n                }\n                rotp[ri][v] = I3{(short)q[0], (short)q[1], (short)q[2]};\n            }\n        }\n\n        cnt.assign(Tcnt, 0);\n        wcnt.assign(Tcnt, 0);\n        startTid.assign(Tcnt, 0);\n        curTid.assign(Tcnt, 0);\n        mark.assign(N, 0);\n        vis.assign(N, 0);\n        qmap.assign(N, -1);\n    }\n\n    inline int id(int x, int y, int z) const {\n        return (x * D + y) * D + z;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void generateRotations() {\n        array<int, 3> p = {0, 1, 2};\n        sort(p.begin(), p.end());\n        do {\n            int inv = 0;\n            for (int i = 0; i < 3; i++) {\n                for (int j = i + 1; j < 3; j++) {\n                    if (p[i] > p[j]) inv++;\n                }\n            }\n            int parity = (inv % 2 == 0 ? 1 : -1);\n            for (int sx : {-1, 1}) {\n                for (int sy : {-1, 1}) {\n                    for (int sz : {-1, 1}) {\n                        if (parity * sx * sy * sz == 1) {\n                            Rot r;\n                            r.perm[0] = p[0];\n                            r.perm[1] = p[1];\n                            r.perm[2] = p[2];\n                            r.sign[0] = sx;\n                            r.sign[1] = sy;\n                            r.sign[2] = sz;\n                            rots.push_back(r);\n                        }\n                    }\n                }\n            }\n        } while (next_permutation(p.begin(), p.end()));\n    }\n\n    inline int activeWeight(int s, int v) const {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int w = 0;\n        if (!covF[s][z * D + x]) w++;\n        if (!covR[s][z * D + y]) w++;\n        return w;\n    }\n\n    void coverCell(int s, int v) {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int fid = z * D + x;\n        int rid = z * D + y;\n\n        if (F[s][z][x] == '1' && !covF[s][fid]) {\n            covF[s][fid] = 1;\n            unF[s][z]--;\n            totalUncov--;\n        }\n        if (Rt[s][z][y] == '1' && !covR[s][rid]) {\n            covR[s][rid] = 1;\n            unR[s][z]--;\n            totalUncov--;\n        }\n    }\n\n    int calcLBNow(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += max(unF[s][z], unR[s][z]);\n        return res;\n    }\n\n    int currentDeficit() const {\n        return max(0, max(calcLBNow(0), calcLBNow(1)) - min(remCnt[0], remCnt[1]));\n    }\n\n    int calcLBAfter(int s, const int* nf, const int* nr) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) {\n            int a = unF[s][z] - nf[z];\n            int b = unR[s][z] - nr[z];\n            if (a < 0) a = 0;\n            if (b < 0) b = 0;\n            res += max(a, b);\n        }\n        return res;\n    }\n\n    void decodeTid(int tid, int& tx, int& ty, int& tz) const {\n        tz = tid % rangeT;\n        tid /= rangeT;\n        ty = tid % rangeT;\n        tx = tid / rangeT;\n        tx -= offsetT;\n        ty -= offsetT;\n        tz -= offsetT;\n    }\n\n    void evalAlignment(int ori, int tid, const vector<int>& list0, CompCand& best) {\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        int inter = 0;\n\n        for (int p : list0) {\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            if (0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D) {\n                int q = id(qx, qy, qz);\n                if (rem[1][q]) {\n                    mark[p] = mt;\n                    qmap[p] = q;\n                    inter++;\n                }\n            }\n        }\n        if (inter == 0) return;\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(inter);\n        comp.reserve(inter);\n\n        int curDef = currentDeficit();\n\n        for (int st : list0) {\n            if (mark[st] != mt || vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int v : comp) {\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n            }\n\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int remCap = min(remCnt[0], remCnt[1]) - sz;\n            int def = max(0, max(lb0, lb1) - remCap);\n            int incDef = max(0, def - curDef);\n\n            double score = (double)cov * sz;\n            score /= (1.0 + 0.18 * incDef);\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponent(int topK, double timeLimit) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if (list0.empty() || list1.empty()) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        priority_queue<AlignCand, vector<AlignCand>, AlignMinCmp> pq1, pq2;\n\n        auto consider = [&](auto& pq, const AlignCand& a) {\n            if ((int)pq.size() < topK) {\n                pq.push(a);\n            } else if (a.key > pq.top().key) {\n                pq.pop();\n                pq.push(a);\n            }\n        };\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int awp = aw[0][p];\n                for (int j = 0; j < n1; j++) {\n                    int tx = qx[j] - rp.x + offsetT;\n                    int ty = qy[j] - rp.y + offsetT;\n                    int tz = qz[j] - rp.z + offsetT;\n                    int tid = (tx * rangeT + ty) * rangeT + tz;\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            for (int tid = 0; tid < Tcnt; tid++) {\n                if (wcnt[tid] == 0) continue;\n                int c = cnt[tid];\n                int w = wcnt[tid];\n                consider(pq1, AlignCand{1LL * c * (w + 1), oi, tid, c, w});\n                consider(pq2, AlignCand{1LL * c * c, oi, tid, c, w});\n            }\n\n            if (elapsed() > timeLimit) break;\n        }\n\n        vector<AlignCand> aligns;\n        while (!pq1.empty()) {\n            aligns.push_back(pq1.top());\n            pq1.pop();\n        }\n        while (!pq2.empty()) {\n            aligns.push_back(pq2.top());\n            pq2.pop();\n        }\n\n        sort(aligns.begin(), aligns.end(), [](const AlignCand& a, const AlignCand& b) {\n            return a.key > b.key;\n        });\n\n        unordered_set<long long> seen;\n        seen.reserve(aligns.size() * 2 + 1);\n\n        int evalCnt = 0;\n        for (const auto& a : aligns) {\n            long long code = 1LL * a.ori * Tcnt + a.tid;\n            if (!seen.insert(code).second) continue;\n            evalAlignment(a.ori, a.tid, list0, best);\n            evalCnt++;\n            if (evalCnt >= topK) break;\n            if (elapsed() > timeLimit) break;\n        }\n\n        return best;\n    }\n\n    void evalBucketAlignment(int ori, int tid, int l, int r, int minSize, int oldNeed, CompCand& best) {\n        if (r - l < minSize) return;\n\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        for (int idx = l; idx < r; idx++) {\n            int p = entries[idx];\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            mark[p] = mt;\n            qmap[p] = id(qx, qy, qz);\n        }\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(r - l);\n        comp.reserve(r - l);\n\n        int curDef = currentDeficit();\n\n        for (int idx = l; idx < r; idx++) {\n            int st = entries[idx];\n            if (vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            if (sz < minSize) continue;\n\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int v : comp) {\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n            }\n\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int newNeed = max(lb0, lb1);\n            int gainNeed = max(0, oldNeed - newNeed);\n            int cap = min(remCnt[0], remCnt[1]) - sz;\n            int def = max(0, newNeed - cap);\n            int incDef = max(0, def - curDef);\n\n            double score =\n                10.0 * gainNeed\n                + 1.0 * cov\n                + 0.7 * log((double)sz + 1.0)\n                + 0.3 * (1.0 - 1.0 / sz)\n                - 4.0 * incDef\n                + 0.0001 * sz;\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponentExhaustive(double deadline, int minSize) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if ((int)list0.size() < minSize || (int)list1.size() < minSize) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        int oldNeed = max(calcLBNow(0), calcLBNow(1));\n        vector<int> activeTids;\n        activeTids.reserve(Tcnt);\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            if (elapsed() > deadline) break;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n            activeTids.clear();\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n                int awp = aw[0][p];\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    if (cnt[tid] == 0) activeTids.push_back(tid);\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            int total = 0;\n            for (int tid : activeTids) {\n                startTid[tid] = total;\n                curTid[tid] = total;\n                total += cnt[tid];\n            }\n\n            entries.resize(total);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    entries[curTid[tid]++] = p;\n                }\n            }\n\n            for (int tid : activeTids) {\n                if (wcnt[tid] == 0 || cnt[tid] < minSize) continue;\n                evalBucketAlignment(oi, tid, startTid[tid], startTid[tid] + cnt[tid], minSize, oldNeed, best);\n                if (elapsed() > deadline) break;\n            }\n        }\n\n        return best;\n    }\n\n    void placeCommonMapped(const CompCand& c) {\n        int lab = ++label;\n        int sz = (int)c.cells.size();\n\n        for (int p : c.cells) {\n            I3 rp = rotp[c.ori][p];\n            int qx = rp.x + c.tx;\n            int qy = rp.y + c.ty;\n            int qz = rp.z + c.tz;\n            int q = id(qx, qy, qz);\n\n            ans[0][p] = lab;\n            rem[0][p] = 0;\n            coverCell(0, p);\n\n            ans[1][q] = lab;\n            rem[1][q] = 0;\n            coverCell(1, q);\n        }\n\n        remCnt[0] -= sz;\n        remCnt[1] -= sz;\n        commonVol += sz;\n        commonCost += 1.0 / sz;\n    }\n\n    inline int p3id(int x, int y, int z) const {\n        int P = D + 1;\n        return (x * P + y) * P + z;\n    }\n\n    inline int p2id(int a, int b) const {\n        int P = D + 1;\n        return a * P + b;\n    }\n\n    int query3(const vector<int>& ps, int x0, int x1, int y0, int y1, int z0, int z1) const {\n        return ps[p3id(x1, y1, z1)]\n             - ps[p3id(x0, y1, z1)]\n             - ps[p3id(x1, y0, z1)]\n             - ps[p3id(x1, y1, z0)]\n             + ps[p3id(x0, y0, z1)]\n             + ps[p3id(x0, y1, z0)]\n             + ps[p3id(x1, y0, z0)]\n             - ps[p3id(x0, y0, z0)];\n    }\n\n    int query2(const vector<int>& ps, int a0, int a1, int b0, int b1) const {\n        return ps[p2id(a1, b1)]\n             - ps[p2id(a0, b1)]\n             - ps[p2id(a1, b0)]\n             + ps[p2id(a0, b0)];\n    }\n\n    void buildPrefix3(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P * P, 0);\n        for (int x = 1; x <= D; x++) {\n            for (int y = 1; y <= D; y++) {\n                for (int z = 1; z <= D; z++) {\n                    int val = rem[s][id(x - 1, y - 1, z - 1)] ? 1 : 0;\n                    ps[p3id(x, y, z)] =\n                        val\n                        + ps[p3id(x - 1, y, z)]\n                        + ps[p3id(x, y - 1, z)]\n                        + ps[p3id(x, y, z - 1)]\n                        - ps[p3id(x - 1, y - 1, z)]\n                        - ps[p3id(x - 1, y, z - 1)]\n                        - ps[p3id(x, y - 1, z - 1)]\n                        + ps[p3id(x - 1, y - 1, z - 1)];\n                }\n            }\n        }\n    }\n\n    void buildPrefix2F(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int x = 1; x <= D; x++) {\n                int val = (F[s][z - 1][x - 1] == '1' && !covF[s][(z - 1) * D + (x - 1)]) ? 1 : 0;\n                ps[p2id(z, x)] =\n                    val + ps[p2id(z - 1, x)] + ps[p2id(z, x - 1)] - ps[p2id(z - 1, x - 1)];\n            }\n        }\n    }\n\n    void buildPrefix2R(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int y = 1; y <= D; y++) {\n                int val = (Rt[s][z - 1][y - 1] == '1' && !covR[s][(z - 1) * D + (y - 1)]) ? 1 : 0;\n                ps[p2id(z, y)] =\n                    val + ps[p2id(z - 1, y)] + ps[p2id(z, y - 1)] - ps[p2id(z - 1, y - 1)];\n            }\n        }\n    }\n\n    int shapeKey(int a, int b, int c) const {\n        if (a > b) swap(a, b);\n        if (b > c) swap(b, c);\n        if (a > b) swap(a, b);\n        return (a * 15 + b) * 15 + c;\n    }\n\n    void enumerateBoxesSide(int s, vector<Box>& best, double timeLimit) {\n        vector<int> ps3, psF, psR;\n        buildPrefix3(s, ps3);\n        buildPrefix2F(s, psF);\n        buildPrefix2R(s, psR);\n\n        for (int x0 = 0; x0 < D; x0++) {\n            if (elapsed() > timeLimit) return;\n            for (int x1 = x0 + 1; x1 <= D; x1++) {\n                int lx = x1 - x0;\n                for (int y0 = 0; y0 < D; y0++) {\n                    for (int y1 = y0 + 1; y1 <= D; y1++) {\n                        int ly = y1 - y0;\n                        for (int z0 = 0; z0 < D; z0++) {\n                            for (int z1 = z0 + 1; z1 <= D; z1++) {\n                                int lz = z1 - z0;\n                                int vol = lx * ly * lz;\n                                if (vol < 2) continue;\n\n                                if (query3(ps3, x0, x1, y0, y1, z0, z1) != vol) continue;\n\n                                int cov =\n                                    query2(psF, z0, z1, x0, x1)\n                                    + query2(psR, z0, z1, y0, y1);\n\n                                int key = shapeKey(lx, ly, lz);\n                                if (!best[key].valid || cov > best[key].cov) {\n                                    Box b;\n                                    b.x = x0;\n                                    b.y = y0;\n                                    b.z = z0;\n                                    b.lx = lx;\n                                    b.ly = ly;\n                                    b.lz = lz;\n                                    b.cov = cov;\n                                    b.vol = vol;\n                                    b.valid = true;\n                                    best[key] = b;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    BoxCand findBestCuboid(double timeLimit) {\n        const int KEY = 15 * 15 * 15;\n        vector<Box> best0(KEY), best1(KEY);\n\n        enumerateBoxesSide(0, best0, timeLimit);\n        if (elapsed() > timeLimit) return BoxCand();\n        enumerateBoxesSide(1, best1, timeLimit);\n\n        BoxCand res;\n        for (int k = 0; k < KEY; k++) {\n            if (!best0[k].valid || !best1[k].valid) continue;\n            int cov = best0[k].cov + best1[k].cov;\n            if (cov <= 0) continue;\n            int vol = best0[k].vol;\n            double score = (double)cov * vol;\n            if (!res.valid || score > res.score || (abs(score - res.score) < 1e-9 && vol > res.vol)) {\n                res.valid = true;\n                res.b0 = best0[k];\n                res.b1 = best1[k];\n                res.vol = vol;\n                res.cov = cov;\n                res.score = score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBox(const Box& b0, const Box& b1) {\n        int lab = ++label;\n        int vol = b0.vol;\n\n        auto put = [&](int s, const Box& b) {\n            for (int x = b.x; x < b.x + b.lx; x++) {\n                for (int y = b.y; y < b.y + b.ly; y++) {\n                    for (int z = b.z; z < b.z + b.lz; z++) {\n                        int v = id(x, y, z);\n                        ans[s][v] = lab;\n                        rem[s][v] = 0;\n                        coverCell(s, v);\n                    }\n                }\n            }\n        };\n\n        put(0, b0);\n        put(1, b1);\n\n        remCnt[0] -= vol;\n        remCnt[1] -= vol;\n        commonVol += vol;\n        commonCost += 1.0 / vol;\n    }\n\n    void considerBar(vector<Bar>& best, const Bar& b) {\n        if (b.len < 2 || b.cov <= 0) return;\n        if (!best[b.len].valid || b.cov > best[b.len].cov) best[b.len] = b;\n    }\n\n    void enumerateBarsSide(int s, vector<Bar>& best, double deadline) {\n        for (int z = 0; z < D; z++) {\n            for (int y = 0; y < D; y++) {\n                for (int x0 = 0; x0 < D; x0++) {\n                    if (elapsed() > deadline) return;\n                    if (!rem[s][id(x0, y, z)]) continue;\n                    Bar b;\n                    b.x = x0; b.y = y; b.z = z; b.dir = 0;\n                    b.nf.fill(0); b.nr.fill(0);\n                    int cov = 0;\n                    if (!covR[s][z * D + y]) {\n                        b.nr[z] = 1;\n                        cov++;\n                    }\n                    for (int x = x0; x < D && rem[s][id(x, y, z)]; x++) {\n                        if (!covF[s][z * D + x]) {\n                            b.nf[z]++;\n                            cov++;\n                        }\n                        b.len = x - x0 + 1;\n                        b.cov = cov;\n                        b.valid = true;\n                        considerBar(best, b);\n                    }\n                }\n            }\n        }\n\n        for (int z = 0; z < D; z++) {\n            for (int x = 0; x < D; x++) {\n                for (int y0 = 0; y0 < D; y0++) {\n                    if (elapsed() > deadline) return;\n                    if (!rem[s][id(x, y0, z)]) continue;\n                    Bar b;\n                    b.x = x; b.y = y0; b.z = z; b.dir = 1;\n                    b.nf.fill(0); b.nr.fill(0);\n                    int cov = 0;\n                    if (!covF[s][z * D + x]) {\n                        b.nf[z] = 1;\n                        cov++;\n                    }\n                    for (int y = y0; y < D && rem[s][id(x, y, z)]; y++) {\n                        if (!covR[s][z * D + y]) {\n                            b.nr[z]++;\n                            cov++;\n                        }\n                        b.len = y - y0 + 1;\n                        b.cov = cov;\n                        b.valid = true;\n                        considerBar(best, b);\n                    }\n                }\n            }\n        }\n\n        for (int x = 0; x < D; x++) {\n            for (int y = 0; y < D; y++) {\n                for (int z0 = 0; z0 < D; z0++) {\n                    if (elapsed() > deadline) return;\n                    if (!rem[s][id(x, y, z0)]) continue;\n                    Bar b;\n                    b.x = x; b.y = y; b.z = z0; b.dir = 2;\n                    b.nf.fill(0); b.nr.fill(0);\n                    int cov = 0;\n                    for (int z = z0; z < D && rem[s][id(x, y, z)]; z++) {\n                        if (!covF[s][z * D + x]) {\n                            b.nf[z]++;\n                            cov++;\n                        }\n                        if (!covR[s][z * D + y]) {\n                            b.nr[z]++;\n                            cov++;\n                        }\n                        b.len = z - z0 + 1;\n                        b.cov = cov;\n                        b.valid = true;\n                        considerBar(best, b);\n                    }\n                }\n            }\n        }\n    }\n\n    BarCand findBestBar(double deadline) {\n        vector<Bar> best0(D + 1), best1(D + 1);\n        enumerateBarsSide(0, best0, deadline);\n        if (elapsed() > deadline) return BarCand();\n        enumerateBarsSide(1, best1, deadline);\n\n        BarCand res;\n        int curDef = currentDeficit();\n\n        for (int L = 2; L <= D; L++) {\n            if (!best0[L].valid || !best1[L].valid) continue;\n            int cov = best0[L].cov + best1[L].cov;\n            if (cov <= 0) continue;\n\n            int lb0 = calcLBAfter(0, best0[L].nf.data(), best0[L].nr.data());\n            int lb1 = calcLBAfter(1, best1[L].nf.data(), best1[L].nr.data());\n            int newDef = max(0, max(lb0, lb1) - (min(remCnt[0], remCnt[1]) - L));\n            int incDef = max(0, newDef - curDef);\n\n            double score = (double)cov * L + 0.05 * L;\n            score /= (1.0 + 0.8 * incDef);\n\n            if (!res.valid || score > res.score) {\n                res.valid = true;\n                res.b0 = best0[L];\n                res.b1 = best1[L];\n                res.len = L;\n                res.cov = cov;\n                res.score = score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBar(const Bar& b0, const Bar& b1) {\n        int lab = ++label;\n        int len = b0.len;\n\n        auto put = [&](int s, const Bar& b) {\n            for (int t = 0; t < b.len; t++) {\n                int x = b.x + (b.dir == 0 ? t : 0);\n                int y = b.y + (b.dir == 1 ? t : 0);\n                int z = b.z + (b.dir == 2 ? t : 0);\n                int v = id(x, y, z);\n                ans[s][v] = lab;\n                rem[s][v] = 0;\n                coverCell(s, v);\n            }\n        };\n\n        put(0, b0);\n        put(1, b1);\n\n        remCnt[0] -= len;\n        remCnt[1] -= len;\n        commonVol += len;\n        commonCost += 1.0 / len;\n    }\n\n    int findBestCell(int s, bool needActive) const {\n        int best = -1;\n        int bestW = needActive ? 0 : 100;\n        for (int v = 0; v < N; v++) {\n            if (!rem[s][v]) continue;\n            int w = activeWeight(s, v);\n            if (needActive) {\n                if (w > bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            } else {\n                if (best == -1 || w < bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            }\n        }\n        return best;\n    }\n\n    void placeCommonUnit(int a, int b) {\n        int lab = ++label;\n        ans[0][a] = lab;\n        rem[0][a] = 0;\n        coverCell(0, a);\n\n        ans[1][b] = lab;\n        rem[1][b] = 0;\n        coverCell(1, b);\n\n        remCnt[0]--;\n        remCnt[1]--;\n        commonVol += 1;\n        commonCost += 1.0;\n    }\n\n    bool placeUniqueCell(int s, int v) {\n        if (v < 0 || !rem[s][v]) return false;\n        int lab = ++label;\n        ans[s][v] = lab;\n        rem[s][v] = 0;\n        coverCell(s, v);\n        remCnt[s]--;\n        uniqueVol[s]++;\n        return true;\n    }\n\n    void placeCommonUnits() {\n        while (totalUncov > 0) {\n            int a0 = findBestCell(0, true);\n            int a1 = findBestCell(1, true);\n\n            if (a0 == -1 && a1 == -1) break;\n\n            if (a0 != -1 && a1 != -1) {\n                placeCommonUnit(a0, a1);\n            } else if (a0 != -1) {\n                int b = findBestCell(1, false);\n                if (b == -1) break;\n                placeCommonUnit(a0, b);\n            } else {\n                int a = findBestCell(0, false);\n                if (a == -1) break;\n                placeCommonUnit(a, a1);\n            }\n        }\n    }\n\n    int sideUncovered(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += unF[s][z] + unR[s][z];\n        return res;\n    }\n\n    int chooseCell(int s, int z, int x, int y) const {\n        if (x >= 0 && y >= 0) {\n            int v = id(x, y, z);\n            if (rem[s][v]) return v;\n        }\n        if (x >= 0) {\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] == '1') {\n                    int v = id(x, yy, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        if (y >= 0) {\n            for (int xx = 0; xx < D; xx++) {\n                if (F[s][z][xx] == '1') {\n                    int v = id(xx, y, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        for (int xx = 0; xx < D; xx++) {\n            if (F[s][z][xx] != '1') continue;\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] != '1') continue;\n                int v = id(xx, yy, z);\n                if (rem[s][v]) return v;\n            }\n        }\n        return -1;\n    }\n\n    void fillUnique(int s) {\n        int guard = 0;\n        while (sideUncovered(s) > 0 && guard++ < 1000) {\n            bool progress = false;\n\n            for (int z = 0; z < D; z++) {\n                vector<int> X, Y;\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1' && !covF[s][z * D + x]) X.push_back(x);\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) Y.push_back(y);\n                }\n\n                if (X.empty() && Y.empty()) continue;\n\n                if (!X.empty() && !Y.empty()) {\n                    int m = max((int)X.size(), (int)Y.size());\n                    for (int k = 0; k < m; k++) {\n                        int x = (k < (int)X.size() ? X[k] : X[0]);\n                        int y = (k < (int)Y.size() ? Y[k] : Y[0]);\n                        int v = chooseCell(s, z, x, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else if (!X.empty()) {\n                    for (int x : X) {\n                        int v = chooseCell(s, z, x, -1);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else {\n                    for (int y : Y) {\n                        int v = chooseCell(s, z, -1, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                }\n            }\n\n            if (!progress) {\n                int v = findBestCell(s, true);\n                if (!placeUniqueCell(s, v)) break;\n            }\n        }\n    }\n\n    void finalRepair() {\n        for (int s = 0; s < 2; s++) {\n            int guard = 0;\n            while (sideUncovered(s) > 0 && guard++ < 1000) {\n                bool progress = false;\n                for (int z = 0; z < D; z++) {\n                    for (int x = 0; x < D; x++) {\n                        if (F[s][z][x] == '1' && !covF[s][z * D + x]) {\n                            int v = chooseCell(s, z, x, -1);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                    for (int y = 0; y < D; y++) {\n                        if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) {\n                            int v = chooseCell(s, z, -1, y);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                }\n                if (!progress) break;\n            }\n        }\n    }\n\n    void buildBlockLists() {\n        for (int s = 0; s < 2; s++) {\n            blk[s].assign(label + 1, vector<int>());\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0) blk[s][a].push_back(v);\n            }\n        }\n\n        activeLab.assign(label + 1, 0);\n        for (int l = 1; l <= label; l++) {\n            if (!blk[0][l].empty() || !blk[1][l].empty()) activeLab[l] = 1;\n        }\n    }\n\n    bool isCommonLabel(int l) const {\n        return l > 0\n            && l < (int)activeLab.size()\n            && activeLab[l]\n            && !blk[0][l].empty()\n            && !blk[1][l].empty();\n    }\n\n    vector<int> canonicalShape(const vector<int>& cells) const {\n        vector<int> best;\n        bool first = true;\n        vector<array<int, 3>> tmp;\n        vector<int> enc;\n        tmp.reserve(cells.size());\n        enc.reserve(cells.size());\n\n        for (const Rot& rr : rots) {\n            tmp.clear();\n            int mn[3] = {INT_MAX, INT_MAX, INT_MAX};\n\n            for (int v : cells) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) {\n                    q[a] = rr.sign[a] * p[rr.perm[a]];\n                    mn[a] = min(mn[a], q[a]);\n                }\n                tmp.push_back({q[0], q[1], q[2]});\n            }\n\n            enc.clear();\n            for (auto t : tmp) {\n                int a = t[0] - mn[0];\n                int b = t[1] - mn[1];\n                int c = t[2] - mn[2];\n                enc.push_back((a * 64 + b) * 64 + c);\n            }\n            sort(enc.begin(), enc.end());\n\n            if (first || enc < best) {\n                first = false;\n                best = enc;\n            }\n        }\n\n        return best;\n    }\n\n    void pairUniqueUnits() {\n        vector<int> u0, u1;\n        for (int l = 1; l <= label; l++) {\n            if (!activeLab[l]) continue;\n            if (blk[0][l].size() == 1 && blk[1][l].empty()) u0.push_back(l);\n            if (blk[1][l].size() == 1 && blk[0][l].empty()) u1.push_back(l);\n        }\n\n        int m = min((int)u0.size(), (int)u1.size());\n        for (int i = 0; i < m; i++) {\n            int a = u0[i];\n            int b = u1[i];\n            if (!activeLab[a] || !activeLab[b]) continue;\n            if (blk[0][a].size() != 1 || !blk[1][a].empty()) continue;\n            if (blk[1][b].size() != 1 || !blk[0][b].empty()) continue;\n\n            int v = blk[1][b][0];\n            blk[1][a].push_back(v);\n            ans[1][v] = a;\n\n            blk[1][b].clear();\n            activeLab[b] = 0;\n        }\n    }\n\n    bool canMergeCommon(int a, int b) const {\n        if (!isCommonLabel(a) || !isCommonLabel(b)) return false;\n        if (blk[0][a].size() != blk[1][a].size()) return false;\n        if (blk[0][b].size() != blk[1][b].size()) return false;\n\n        vector<int> u0, u1;\n        u0.reserve(blk[0][a].size() + blk[0][b].size());\n        u1.reserve(blk[1][a].size() + blk[1][b].size());\n\n        u0.insert(u0.end(), blk[0][a].begin(), blk[0][a].end());\n        u0.insert(u0.end(), blk[0][b].begin(), blk[0][b].end());\n        u1.insert(u1.end(), blk[1][a].begin(), blk[1][a].end());\n        u1.insert(u1.end(), blk[1][b].begin(), blk[1][b].end());\n\n        if (u0.size() != u1.size()) return false;\n        return canonicalShape(u0) == canonicalShape(u1);\n    }\n\n    void mergeCommonLabels(int a, int b) {\n        if ((int)blk[0][a].size() < (int)blk[0][b].size()) swap(a, b);\n\n        for (int s = 0; s < 2; s++) {\n            for (int v : blk[s][b]) {\n                ans[s][v] = a;\n                blk[s][a].push_back(v);\n            }\n            blk[s][b].clear();\n        }\n        activeLab[b] = 0;\n    }\n\n    void postMergeCommon(double deadline) {\n        while (elapsed() < deadline) {\n            unordered_map<long long, int> flags;\n            flags.reserve(N * 4 + 10);\n\n            for (int s = 0; s < 2; s++) {\n                for (int v = 0; v < N; v++) {\n                    int a = ans[s][v];\n                    if (!isCommonLabel(a)) continue;\n\n                    for (int dir : {1, 3, 5}) {\n                        int nb = neigh[v][dir];\n                        if (nb < 0) continue;\n                        int b = ans[s][nb];\n                        if (a == b || !isCommonLabel(b)) continue;\n                        int x = a, y = b;\n                        if (x > y) swap(x, y);\n                        long long key = ((long long)x << 32) | (unsigned int)y;\n                        flags[key] |= (1 << s);\n                    }\n                }\n            }\n\n            int bestA = -1, bestB = -1;\n            double bestSave = 1e-12;\n            int bestVol = -1;\n\n            for (auto& kv : flags) {\n                if (elapsed() > deadline) return;\n                if (kv.second != 3) continue;\n\n                long long key = kv.first;\n                int a = (int)(key >> 32);\n                int b = (int)(key & 0xffffffffLL);\n                if (!isCommonLabel(a) || !isCommonLabel(b)) continue;\n\n                int va = (int)blk[0][a].size();\n                int vb = (int)blk[0][b].size();\n                if (va <= 0 || vb <= 0) continue;\n\n                double save = 1.0 / va + 1.0 / vb - 1.0 / (va + vb);\n                if (save + 1e-12 < bestSave) continue;\n\n                if (!canMergeCommon(a, b)) continue;\n\n                int vol = va + vb;\n                if (save > bestSave + 1e-12 || vol > bestVol) {\n                    bestSave = save;\n                    bestVol = vol;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n\n            if (bestA == -1) break;\n            mergeCommonLabels(bestA, bestB);\n        }\n    }\n\n    void postProcess(double deadline) {\n        buildBlockLists();\n        pairUniqueUnits();\n        if (elapsed() < deadline) {\n            postMergeCommon(deadline);\n        }\n    }\n\n    double computeScoreForAns(const array<vector<int>, 2>& A, int maxLab) const {\n        vector<int> c0(maxLab + 1, 0), c1(maxLab + 1, 0);\n        for (int v = 0; v < N; v++) {\n            if (A[0][v] > 0) c0[A[0][v]]++;\n            if (A[1][v] > 0) c1[A[1][v]]++;\n        }\n        double sc = 0.0;\n        for (int l = 1; l <= maxLab; l++) {\n            if (c0[l] && c1[l]) sc += 1.0 / max(1, c0[l]);\n            else if (c0[l]) sc += c0[l];\n            else if (c1[l]) sc += c1[l];\n        }\n        return sc;\n    }\n\n    void buildPrefix3Mask(const vector<char>& mask, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P * P, 0);\n        for (int x = 1; x <= D; x++) {\n            for (int y = 1; y <= D; y++) {\n                for (int z = 1; z <= D; z++) {\n                    int val = mask[id(x - 1, y - 1, z - 1)] ? 1 : 0;\n                    ps[p3id(x, y, z)] =\n                        val\n                        + ps[p3id(x - 1, y, z)]\n                        + ps[p3id(x, y - 1, z)]\n                        + ps[p3id(x, y, z - 1)]\n                        - ps[p3id(x - 1, y - 1, z)]\n                        - ps[p3id(x - 1, y, z - 1)]\n                        - ps[p3id(x, y - 1, z - 1)]\n                        + ps[p3id(x - 1, y - 1, z - 1)];\n                }\n            }\n        }\n    }\n\n    void enumeratePoolBoxesSide(const vector<char>& pool, vector<SimpleBox>& best, double deadline) {\n        vector<int> ps;\n        buildPrefix3Mask(pool, ps);\n\n        for (int x0 = 0; x0 < D; x0++) {\n            if (elapsed() > deadline) return;\n            for (int x1 = x0 + 1; x1 <= D; x1++) {\n                int lx = x1 - x0;\n                for (int y0 = 0; y0 < D; y0++) {\n                    for (int y1 = y0 + 1; y1 <= D; y1++) {\n                        int ly = y1 - y0;\n                        for (int z0 = 0; z0 < D; z0++) {\n                            for (int z1 = z0 + 1; z1 <= D; z1++) {\n                                int lz = z1 - z0;\n                                int vol = lx * ly * lz;\n                                if (vol < 2) continue;\n                                if (query3(ps, x0, x1, y0, y1, z0, z1) != vol) continue;\n\n                                int key = shapeKey(lx, ly, lz);\n                                if (!best[key].valid || vol > best[key].vol) {\n                                    SimpleBox b;\n                                    b.x = x0; b.y = y0; b.z = z0;\n                                    b.lx = lx; b.ly = ly; b.lz = lz;\n                                    b.vol = vol;\n                                    b.valid = true;\n                                    best[key] = b;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    PoolBoxCand findBestPoolCuboid(array<vector<char>, 2>& pool, double deadline) {\n        const int KEY = 15 * 15 * 15;\n        vector<SimpleBox> best0(KEY), best1(KEY);\n\n        enumeratePoolBoxesSide(pool[0], best0, deadline);\n        if (elapsed() > deadline) return PoolBoxCand();\n        enumeratePoolBoxesSide(pool[1], best1, deadline);\n\n        PoolBoxCand res;\n        for (int k = 0; k < KEY; k++) {\n            if (!best0[k].valid || !best1[k].valid) continue;\n            int vol = best0[k].vol;\n            if (!res.valid || vol > res.vol) {\n                res.valid = true;\n                res.b0 = best0[k];\n                res.b1 = best1[k];\n                res.vol = vol;\n            }\n        }\n        return res;\n    }\n\n    void postRepartitionSmall(double deadline) {\n        if (elapsed() > deadline) return;\n\n        array<vector<int>, 2> oldAns = ans;\n        int oldLabel = label;\n        double oldScore = computeScoreForAns(oldAns, oldLabel);\n\n        array<vector<vector<int>>, 2> cells;\n        cells[0].assign(label + 1, vector<int>());\n        cells[1].assign(label + 1, vector<int>());\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0) cells[s][a].push_back(v);\n            }\n        }\n\n        array<vector<int>, 2> newAns;\n        newAns[0].assign(N, 0);\n        newAns[1].assign(N, 0);\n\n        array<vector<char>, 2> pool;\n        pool[0].assign(N, 0);\n        pool[1].assign(N, 0);\n\n        int newLabel = 0;\n\n        for (int l = 1; l <= label; l++) {\n            int c0 = cells[0][l].size();\n            int c1 = cells[1][l].size();\n\n            bool freeze = (c0 > 0 && c1 > 0 && c0 == c1 && c0 >= 3);\n\n            if (freeze) {\n                int nl = ++newLabel;\n                for (int s = 0; s < 2; s++) {\n                    for (int v : cells[s][l]) newAns[s][v] = nl;\n                }\n            } else {\n                for (int s = 0; s < 2; s++) {\n                    for (int v : cells[s][l]) pool[s][v] = 1;\n                }\n            }\n        }\n\n        while (elapsed() < deadline) {\n            PoolBoxCand pc = findBestPoolCuboid(pool, deadline);\n            if (!pc.valid || pc.vol < 2) break;\n\n            int nl = ++newLabel;\n\n            auto put = [&](int s, const SimpleBox& b) {\n                for (int x = b.x; x < b.x + b.lx; x++) {\n                    for (int y = b.y; y < b.y + b.ly; y++) {\n                        for (int z = b.z; z < b.z + b.lz; z++) {\n                            int v = id(x, y, z);\n                            newAns[s][v] = nl;\n                            pool[s][v] = 0;\n                        }\n                    }\n                }\n            };\n\n            put(0, pc.b0);\n            put(1, pc.b1);\n        }\n\n        vector<int> rest0, rest1;\n        for (int v = 0; v < N; v++) {\n            if (pool[0][v]) rest0.push_back(v);\n            if (pool[1][v]) rest1.push_back(v);\n        }\n\n        int m = min((int)rest0.size(), (int)rest1.size());\n        for (int i = 0; i < m; i++) {\n            int nl = ++newLabel;\n            newAns[0][rest0[i]] = nl;\n            newAns[1][rest1[i]] = nl;\n        }\n        for (int i = m; i < (int)rest0.size(); i++) {\n            int nl = ++newLabel;\n            newAns[0][rest0[i]] = nl;\n        }\n        for (int i = m; i < (int)rest1.size(); i++) {\n            int nl = ++newLabel;\n            newAns[1][rest1[i]] = nl;\n        }\n\n        double newScore = computeScoreForAns(newAns, newLabel);\n\n        if (newScore + 1e-12 < oldScore) {\n            ans = std::move(newAns);\n            label = newLabel;\n        } else {\n            ans = std::move(oldAns);\n            label = oldLabel;\n        }\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        double compDeadline = 2.35;\n        for (int it = 0; it < 12 && totalUncov > 0 && elapsed() < compDeadline; it++) {\n            CompCand c = findBestComponent(90, compDeadline);\n            if (!c.valid || c.size < 3) break;\n            placeCommonMapped(c);\n        }\n\n        double cuboidDeadline = 4.75;\n        for (int it = 0; it < 180 && totalUncov > 0 && elapsed() < cuboidDeadline; it++) {\n            BoxCand b = findBestCuboid(cuboidDeadline);\n            if (!b.valid || b.vol < 2 || b.cov <= 0) break;\n            placeCommonBox(b.b0, b.b1);\n        }\n\n        double exhaustiveDeadline = 5.20;\n        for (int it = 0; it < 50 && totalUncov > 0 && elapsed() < exhaustiveDeadline; it++) {\n            CompCand c = findBestComponentExhaustive(exhaustiveDeadline, 2);\n            if (!c.valid || c.size < 2 || c.score <= 0.0) break;\n            placeCommonMapped(c);\n        }\n\n        double barDeadline = 5.40;\n        for (int it = 0; it < 300 && totalUncov > 0 && elapsed() < barDeadline; it++) {\n            BarCand b = findBestBar(barDeadline);\n            if (!b.valid || b.len < 2 || b.cov <= 0) break;\n            placeCommonBar(b.b0, b.b1);\n        }\n\n        placeCommonUnits();\n        fillUnique(0);\n        fillUnique(1);\n        finalRepair();\n\n        postProcess(5.55);\n        postRepartitionSmall(5.75);\n    }\n\n    void print() const {\n        vector<int> mp(label + 1, 0);\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0 && a <= label) mp[a] = 1;\n            }\n        }\n\n        int n = 0;\n        for (int l = 1; l <= label; l++) {\n            if (mp[l]) mp[l] = ++n;\n        }\n\n        cout << n << '\\n';\n        for (int s = 0; s < 2; s++) {\n            for (int i = 0; i < N; i++) {\n                if (i) cout << ' ';\n                int a = ans[s][i];\n                cout << (a == 0 ? 0 : mp[a]);\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n\n    array<vector<string>, 2> F, R;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        R[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> R[i][z];\n    }\n\n    Solver solver(D, F, R);\n    solver.run();\n    solver.print();\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 105;\nstatic const int MAXM = 305;\nstatic const long long INFLL = (1LL << 62);\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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} gtimer;\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) {\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);\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 Edge {\n    int u, v;\n    long long w;\n};\n\nstruct RK {\n    unsigned short p;\n    int k;\n};\n\nstruct TreeResult {\n    long long cost = INFLL;\n    bitset<MAXM> mask;\n};\n\nstruct Solution {\n    vector<int> P;\n    TreeResult tree;\n    long long radCost = INFLL;\n    long long total = INFLL;\n};\n\nint N, M, K;\nvector<int> X, Y, RA, RB;\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj;\n\nvector<vector<int>> distSq;\nvector<vector<unsigned short>> ceilD;\nvector<RK> coverList[MAXN];\n\nlong long spDist[MAXN][MAXN];\nbitset<MAXM> pathE[MAXN][MAXN];\nbitset<MAXN> pathV[MAXN][MAXN];\n\nvector<int> edgeOrder;\nbitset<MAXM> globalMSTMask;\nbitset<MAXM> allEdgesMask;\n\nint ceil_sqrt_ll(long long v) {\n    int r = (int) sqrt((long double) v);\n    while (1LL * r * r < v) ++r;\n    while (r > 0 && 1LL * (r - 1) * (r - 1) >= v) --r;\n    return r;\n}\n\nlong long calcRadCost(const vector<int>& P) {\n    long long s = 0;\n    for (int p : P) s += 1LL * p * p;\n    return s;\n}\n\nint computeCovered(const vector<int>& P, vector<char>& covered) {\n    covered.assign(K, 0);\n    int rem = K;\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                if (rem == 0) return K;\n            }\n        }\n    }\n    return K - rem;\n}\n\nbool isFull(const vector<int>& P) {\n    vector<char> covered;\n    return computeCovered(P, covered) == K;\n}\n\nvector<char> makeTerminal(const vector<int>& P) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terminal[i] = 1;\n    }\n    return terminal;\n}\n\nvector<int> makeOrder(const vector<int>& P, int mode, const vector<long long>* branch = nullptr) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            double p2 = 1.0 * P[i] * P[i];\n            double rd = (double) spDist[0][i];\n            if (mode == 0) sc = p2;\n            else if (mode == 1) sc = p2 + 0.7 * rd;\n            else if (mode == 2) sc = 0.2 * p2 + rd;\n            else {\n                long long b = (branch ? (*branch)[i] : 0LL);\n                sc = p2 + (double)b;\n            }\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvoid trimP(vector<int>& P, const vector<int>& order) {\n    vector<int> cnt(K, 0);\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            cnt[rk.k]++;\n        }\n    }\n\n    for (int i : order) {\n        if (P[i] <= 0) continue;\n        int old = P[i];\n        int need = 0;\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > old) break;\n            if (cnt[rk.k] == 1) need = max(need, (int)rk.p);\n        }\n        if (need < old) {\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > old) break;\n                if ((int)rk.p > need) cnt[rk.k]--;\n            }\n            P[i] = need;\n        }\n    }\n}\n\nTreeResult reduceMask(const bitset<MAXM>& mask, const vector<char>& terminal) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    DSU d(N);\n    bitset<MAXM> tree;\n    for (int eid : edgeOrder) {\n        if (mask.test(eid) && d.unite(edges[eid].u, edges[eid].v)) {\n            tree.set(eid);\n        }\n    }\n\n    vector<int> deg(N, 0);\n    vector<vector<int>> inc(N);\n    for (int e = 0; e < M; ++e) {\n        if (!tree.test(e)) continue;\n        int u = edges[e].u, v = edges[e].v;\n        deg[u]++;\n        deg[v]++;\n        inc[u].push_back(e);\n        inc[v].push_back(e);\n    }\n\n    queue<int> q;\n    for (int i = 0; i < N; ++i) {\n        if (!terminal[i] && deg[i] <= 1) q.push(i);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (terminal[v] || deg[v] != 1) continue;\n\n        int remEdge = -1;\n        for (int e : inc[v]) {\n            if (tree.test(e)) {\n                remEdge = e;\n                break;\n            }\n        }\n        if (remEdge == -1) {\n            deg[v] = 0;\n            continue;\n        }\n\n        int to = edges[remEdge].u ^ edges[remEdge].v ^ v;\n        tree.reset(remEdge);\n        deg[v]--;\n        deg[to]--;\n        if (!terminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    vector<char> vis(N, 0);\n    queue<int> qq;\n    vis[0] = 1;\n    qq.push(0);\n    while (!qq.empty()) {\n        int v = qq.front();\n        qq.pop();\n        for (auto [to, eid] : adj[v]) {\n            if (!tree.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            qq.push(to);\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (terminal[i] && !vis[i]) return res;\n    }\n\n    long long cost = 0;\n    for (int e = 0; e < M; ++e) {\n        if (tree.test(e)) cost += edges[e].w;\n    }\n    res.cost = cost;\n    res.mask = tree;\n    return res;\n}\n\nbitset<MAXM> buildMetricMSTMask(const vector<char>& terminal) {\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) terms.push_back(i);\n    }\n\n    int T = (int)terms.size();\n    bitset<MAXM> mask;\n    if (T <= 1) return mask;\n\n    vector<char> used(T, 0);\n    vector<long long> key(T, INFLL);\n    vector<int> parent(T, -1);\n    key[0] = 0;\n\n    for (int it = 0; it < T; ++it) {\n        int v = -1;\n        long long best = INFLL;\n        for (int i = 0; i < T; ++i) {\n            if (!used[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) {\n            mask |= pathE[terms[v]][terms[parent[v]]];\n        }\n\n        for (int u = 0; u < T; ++u) {\n            if (!used[u] && spDist[terms[v]][terms[u]] < key[u]) {\n                key[u] = spDist[terms[v]][terms[u]];\n                parent[u] = v;\n            }\n        }\n    }\n    return mask;\n}\n\nbitset<MAXM> buildSPTMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) mask |= pathE[0][i];\n    }\n    return mask;\n}\n\nbitset<MAXM> buildGreedyMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(0);\n\n    while (true) {\n        bool any = false;\n        for (int t = 1; t < N; ++t) {\n            if (terminal[t] && !treeV.test(t)) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n        for (int t = 1; t < N; ++t) {\n            if (!terminal[t] || treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult buildBestTree(const vector<int>& P, const bitset<MAXM>* extraMask = nullptr) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    int termCnt = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminal[i] = 1;\n            termCnt++;\n        }\n    }\n\n    TreeResult best;\n    best.cost = INFLL;\n    best.mask.reset();\n\n    if (termCnt <= 1) {\n        best.cost = 0;\n        return best;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    upd(buildMetricMSTMask(terminal));\n    upd(buildSPTMask(terminal));\n    upd(buildGreedyMask(terminal));\n    upd(globalMSTMask);\n    upd(allEdgesMask);\n\n    // Safe only when explicitly supplied: try pruning the previous/current tree.\n    if (extraMask) upd(*extraMask);\n\n    return best;\n}\n\nvector<char> getReachable(const bitset<MAXM>& mask) {\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] : adj[v]) {\n            if (!mask.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return vis;\n}\n\nvector<long long> computeBranch(const vector<int>& P, const TreeResult& tr) {\n    vector<char> terminal = makeTerminal(P);\n\n    vector<long long> branch(N, 0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        vector<char> t2 = terminal;\n        t2[i] = 0;\n        t2[0] = 1;\n        TreeResult r = reduceMask(tr.mask, t2);\n        if (r.cost < INFLL / 2) {\n            branch[i] = max(0LL, tr.cost - r.cost);\n        }\n    }\n    return branch;\n}\n\nSolution evaluateSolution(const vector<int>& P, const bitset<MAXM>* extraMask = nullptr) {\n    Solution s;\n    s.P = P;\n    if (!isFull(P)) {\n        s.total = INFLL;\n        return s;\n    }\n    s.radCost = calcRadCost(P);\n    s.tree = buildBestTree(P, extraMask);\n    if (s.tree.cost >= INFLL / 2) {\n        s.total = INFLL;\n    } else {\n        s.total = s.radCost + s.tree.cost;\n    }\n    return s;\n}\n\nbool greedyRepair(\n    vector<int>& P,\n    const vector<char>& allowed,\n    double connWeight,\n    double exponent,\n    const vector<char>* freeVertices = nullptr,\n    double stopTime = 1e100\n) {\n    for (int i = 0; i < N; ++i) {\n        if (!allowed[i]) P[i] = 0;\n        P[i] = min(5000, max(0, P[i]));\n    }\n\n    vector<char> covered;\n    int cov = computeCovered(P, covered);\n    int rem = K - cov;\n    if (rem == 0) return true;\n\n    vector<long long> minConn(N);\n    for (int i = 0; i < N; ++i) minConn[i] = spDist[0][i];\n\n    for (int t = 0; t < N; ++t) {\n        if (P[t] > 0) {\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][t]);\n            }\n        }\n    }\n\n    vector<double> denom(K + 1, 1.0);\n    if (fabs(exponent - 1.0) < 1e-9) {\n        for (int i = 1; i <= K; ++i) denom[i] = (double)i;\n    } else {\n        for (int i = 1; i <= K; ++i) denom[i] = pow((double)i, exponent);\n    }\n\n    int iter = 0;\n    while (rem > 0) {\n        if ((iter & 7) == 0 && gtimer.elapsed() > stopTime) return false;\n        if (iter > 1000) {\n            for (int k = 0; k < K && rem > 0; ++k) {\n                if (covered[k]) continue;\n                int bestI = -1, bestP = 0;\n                double bestCost = 1e100;\n\n                for (int i = 0; i < N; ++i) {\n                    if (!allowed[i]) continue;\n                    int p = (int)ceilD[i][k];\n                    if (p > 5000) continue;\n                    int old = P[i];\n                    int np = max(old, p);\n                    double act = 0.0;\n                    if (old == 0 && connWeight != 0.0) {\n                        if (freeVertices && (*freeVertices)[i]) act = 0.0;\n                        else act = connWeight * (double)minConn[i];\n                    }\n                    double cost = (double)(1LL * np * np - 1LL * old * old) + act;\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestI = i;\n                        bestP = np;\n                    }\n                }\n\n                if (bestI == -1) return false;\n\n                int old = P[bestI];\n                P[bestI] = bestP;\n                if (old == 0) {\n                    for (int j = 0; j < N; ++j) {\n                        minConn[j] = min(minConn[j], spDist[j][bestI]);\n                    }\n                }\n\n                for (const auto& rk : coverList[bestI]) {\n                    if ((int)rk.p > bestP) break;\n                    if (!covered[rk.k]) {\n                        covered[rk.k] = 1;\n                        --rem;\n                    }\n                }\n\n                if (gtimer.elapsed() > stopTime) return false;\n            }\n            return rem == 0;\n        }\n\n        ++iter;\n\n        double bestScore = 1e100;\n        double bestAbsCost = 1e100;\n        int bestI = -1, bestP = -1, bestCnt = -1;\n\n        for (int i = 0; i < N; ++i) {\n            if (!allowed[i] || P[i] >= 5000 || coverList[i].empty()) continue;\n\n            int old = P[i];\n            double activation = 0.0;\n            if (old == 0 && connWeight != 0.0) {\n                if (freeVertices && (*freeVertices)[i]) activation = 0.0;\n                else activation = connWeight * (double)minConn[i];\n            }\n\n            int cnt = 0;\n            const auto& lst = coverList[i];\n            int idx = 0, sz = (int)lst.size();\n\n            while (idx < sz && (int)lst[idx].p <= old) idx++;\n\n            while (idx < sz) {\n                int p = (int)lst[idx].p;\n                int add = 0;\n                while (idx < sz && (int)lst[idx].p == p) {\n                    if (!covered[lst[idx].k]) add++;\n                    idx++;\n                }\n                if (add == 0) continue;\n\n                cnt += add;\n                double cost = (double)(1LL * p * p - 1LL * old * old) + activation;\n                double score = cost / denom[cnt];\n\n                if (score < bestScore - 1e-12 ||\n                    (fabs(score - bestScore) <= 1e-12 &&\n                     (cost < bestAbsCost || cnt > bestCnt))) {\n                    bestScore = score;\n                    bestAbsCost = cost;\n                    bestI = i;\n                    bestP = p;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestI == -1) return false;\n\n        int old = P[bestI];\n        P[bestI] = bestP;\n\n        int gained = 0;\n        for (const auto& rk : coverList[bestI]) {\n            if ((int)rk.p > bestP) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                gained++;\n            }\n        }\n\n        if (old == 0) {\n            for (int j = 0; j < N; ++j) {\n                minConn[j] = min(minConn[j], spDist[j][bestI]);\n            }\n        }\n\n        if (gained == 0) return false;\n    }\n\n    return true;\n}\n\nvoid computeShortestPaths() {\n    for (int s = 0; s < N; ++s) {\n        vector<long long> dist(N, INFLL);\n        vector<int> parNode(N, -1), parEdge(N, -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n\n        dist[s] = 0;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n\n            for (auto [to, eid] : adj[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parNode[to] = v;\n                    parEdge[to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        for (int t = 0; t < N; ++t) {\n            spDist[s][t] = dist[t];\n            pathE[s][t].reset();\n            pathV[s][t].reset();\n\n            if (dist[t] >= INFLL / 2) continue;\n\n            int cur = t;\n            pathV[s][t].set(cur);\n            while (cur != s) {\n                int e = parEdge[cur];\n                if (e < 0) break;\n                pathE[s][t].set(e);\n                cur = parNode[cur];\n                pathV[s][t].set(cur);\n            }\n        }\n    }\n}\n\nbitset<MAXM> buildGlobalMST() {\n    DSU d(N);\n    bitset<MAXM> m;\n    for (int eid : edgeOrder) {\n        if (d.unite(edges[eid].u, edges[eid].v)) {\n            m.set(eid);\n        }\n    }\n    return m;\n}\n\nvector<int> nearestSolution(double lambda) {\n    vector<int> P(N, 0);\n    for (int k = 0; k < K; ++k) {\n        double best = 1e100;\n        int bi = -1;\n        for (int i = 0; i < N; ++i) {\n            int p = (int)ceilD[i][k];\n            if (p > 5000) continue;\n            double val = (double)distSq[i][k] + lambda * (double)spDist[0][i];\n            if (val < best) {\n                best = val;\n                bi = i;\n            }\n        }\n\n        if (bi == -1) {\n            int bp = INT_MAX;\n            for (int i = 0; i < N; ++i) {\n                if ((int)ceilD[i][k] < bp) {\n                    bp = (int)ceilD[i][k];\n                    bi = i;\n                }\n            }\n        }\n\n        P[bi] = max(P[bi], (int)ceilD[bi][k]);\n    }\n    return P;\n}\n\nvoid considerCandidate(vector<int> P, vector<Solution>& sols, double stopTime) {\n    for (int& p : P) p = min(5000, max(0, p));\n\n    vector<char> allAllowed(N, 1);\n    if (!isFull(P)) {\n        greedyRepair(P, allAllowed, 0.6, 1.0, nullptr, stopTime);\n    }\n    if (!isFull(P)) return;\n\n    auto add = [&](const vector<int>& Q) {\n        Solution s = evaluateSolution(Q);\n        if (s.total < INFLL / 2) sols.push_back(s);\n    };\n\n    add(P);\n\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<int> q = P;\n        trimP(q, makeOrder(q, mode));\n        add(q);\n    }\n\n    vector<int> q = P;\n    trimP(q, makeOrder(q, 1));\n    trimP(q, makeOrder(q, 0));\n    add(q);\n}\n\nSolution localSearch(Solution cur, double deadline) {\n    vector<char> allAllowed(N, 1);\n\n    for (int pass = 0; pass < 6 && gtimer.elapsed() < deadline; ++pass) {\n        cur = evaluateSolution(cur.P);\n        bool improved = false;\n\n        if (gtimer.elapsed() < deadline) {\n            vector<long long> br = computeBranch(cur.P, cur.tree);\n            vector<int> p2 = cur.P;\n            trimP(p2, makeOrder(p2, 3, &br));\n            Solution ns = evaluateSolution(p2);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        if (gtimer.elapsed() < deadline) {\n            vector<char> avail = getReachable(cur.tree.mask);\n            double exps[2] = {1.0, 1.15};\n            for (double ex : exps) {\n                vector<int> p0(N, 0);\n                if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n                trimP(p0, makeOrder(p0, 0));\n                Solution ns = evaluateSolution(p0);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        vector<int> order = makeOrder(cur.P, 3, &br);\n\n        int stationTried = 0;\n        int maxStations = (pass == 0 ? 50 : 30);\n\n        for (int id : order) {\n            if (cur.P[id] <= 0) continue;\n            if (gtimer.elapsed() > deadline) break;\n            if (stationTried++ >= maxStations) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            vector<int> uniqTargets;\n            for (int t : targets) {\n                if (t < 0 || t >= p) continue;\n                bool seen = false;\n                for (int u : uniqTargets) if (u == t) seen = true;\n                if (!seen) uniqTargets.push_back(t);\n            }\n\n            for (int np : uniqTargets) {\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                p2[id] = np;\n\n                double beta = (np == 0 ? 0.8 : 0.4);\n                if (!greedyRepair(p2, allAllowed, beta, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n        if (improved) continue;\n\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            struct CutCand {\n                long long score;\n                int e;\n                vector<int> terms;\n            };\n            vector<CutCand> cuts;\n\n            for (int e = 0; e < M; ++e) {\n                if (!cur.tree.mask.test(e)) continue;\n\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] : adj[v]) {\n                        if (eid == e || !cur.tree.mask.test(eid) || vis[to]) continue;\n                        vis[to] = 1;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> terms;\n                long long p2sum = 0;\n                for (int v = 0; v < N; ++v) {\n                    if (!vis[v] && cur.P[v] > 0) {\n                        terms.push_back(v);\n                        p2sum += 1LL * cur.P[v] * cur.P[v];\n                    }\n                }\n                if (terms.empty()) continue;\n\n                long long branchCost = edges[e].w;\n                for (int ee = 0; ee < M; ++ee) {\n                    if (ee == e || !cur.tree.mask.test(ee)) continue;\n                    int u = edges[ee].u, v = edges[ee].v;\n                    if (!vis[u] && !vis[v]) branchCost += edges[ee].w;\n                }\n\n                cuts.push_back({branchCost + p2sum, e, terms});\n            }\n\n            sort(cuts.begin(), cuts.end(), [](const CutCand& a, const CutCand& b) {\n                return a.score > b.score;\n            });\n\n            int tried = 0;\n            for (const auto& cc : cuts) {\n                if (tried++ >= 8) break;\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                for (int v : cc.terms) p2[v] = 0;\n\n                if (!greedyRepair(p2, allAllowed, 0.9, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            vector<int> top;\n            for (int id : order) {\n                if (cur.P[id] > 0) {\n                    top.push_back(id);\n                    if ((int)top.size() >= 8) break;\n                }\n            }\n\n            for (int a = 0; a < (int)top.size() && !improved; ++a) {\n                for (int b = a + 1; b < (int)top.size(); ++b) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> p2 = cur.P;\n                    p2[top[a]] = 0;\n                    p2[top[b]] = 0;\n\n                    if (!greedyRepair(p2, allAllowed, 0.85, 1.05, nullptr, deadline)) continue;\n\n                    trimP(p2, makeOrder(p2, 1));\n                    trimP(p2, makeOrder(p2, 0));\n\n                    Solution ns = evaluateSolution(p2);\n                    if (ns.total < cur.total) {\n                        cur = ns;\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution optimizeOnReachableFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        bool improved = false;\n        vector<double> exps = {1.0, 1.15, 0.9, 1.3, 0.75};\n\n        for (double ex : exps) {\n            if (gtimer.elapsed() > deadline) break;\n\n            vector<int> p0(N, 0);\n            if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n\n            vector<vector<int>> candP;\n\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 0));\n                candP.push_back(q);\n            }\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 1));\n                candP.push_back(q);\n            }\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 1));\n                trimP(q, makeOrder(q, 0));\n                candP.push_back(q);\n            }\n\n            for (auto& q : candP) {\n                if (gtimer.elapsed() > deadline) break;\n                Solution ns = evaluateSolution(q, &baseMask);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                }\n            }\n\n            if (improved) break;\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nTreeResult finalImproveTree(const vector<int>& P, TreeResult best, double deadline) {\n    vector<char> terminal = makeTerminal(P);\n\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terms.push_back(i);\n    }\n\n    if ((int)terms.size() <= 1) {\n        TreeResult r;\n        r.cost = 0;\n        r.mask.reset();\n        return r;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        if (gtimer.elapsed() > deadline) return;\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    // Simple cycle exchanges by adding one unused edge.\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        TreeResult rb = best;\n        for (int e = 0; e < M; ++e) {\n            if ((e & 15) == 0 && gtimer.elapsed() > deadline) break;\n            if (best.mask.test(e)) continue;\n            bitset<MAXM> nm = best.mask;\n            nm.set(e);\n            TreeResult r = reduceMask(nm, terminal);\n            if (r.cost < rb.cost) rb = r;\n        }\n        if (rb.cost < best.cost) best = rb;\n        else break;\n    }\n\n    // Union of all terminal-pair shortest paths.\n    if (gtimer.elapsed() < deadline) {\n        bitset<MAXM> m;\n        for (int i = 0; i < (int)terms.size(); ++i) {\n            for (int j = i + 1; j < (int)terms.size(); ++j) {\n                m |= pathE[terms[i]][terms[j]];\n            }\n        }\n        upd(m);\n    }\n\n    // Star-shaped shortest path candidates.\n    for (int c = 0; c < N && gtimer.elapsed() < deadline; ++c) {\n        bitset<MAXM> m;\n        for (int t : terms) {\n            if (t != c) m |= pathE[c][t];\n        }\n        upd(m);\n    }\n\n    // MST on induced subgraphs around current tree.\n    for (int depth = 0; depth < 2 && gtimer.elapsed() < deadline; ++depth) {\n        vector<char> vset(N, 0);\n        for (int t : terms) vset[t] = 1;\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                vset[edges[e].u] = 1;\n                vset[edges[e].v] = 1;\n            }\n        }\n\n        if (depth == 1) {\n            vector<char> ex = vset;\n            for (int e = 0; e < M; ++e) {\n                if (vset[edges[e].u] || vset[edges[e].v]) {\n                    ex[edges[e].u] = 1;\n                    ex[edges[e].v] = 1;\n                }\n            }\n            vset.swap(ex);\n        }\n\n        bitset<MAXM> m;\n        for (int e = 0; e < M; ++e) {\n            if (vset[edges[e].u] && vset[edges[e].v]) m.set(e);\n        }\n        upd(m);\n    }\n\n    // Add one shortest path between current tree vertices and reduce again.\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        vector<char> vset(N, 0);\n        for (int t : terms) vset[t] = 1;\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                vset[edges[e].u] = 1;\n                vset[edges[e].v] = 1;\n            }\n        }\n\n        vector<int> vs;\n        for (int i = 0; i < N; ++i) if (vset[i]) vs.push_back(i);\n\n        TreeResult rb = best;\n        for (int a = 0; a < (int)vs.size() && gtimer.elapsed() < deadline; ++a) {\n            for (int b = a + 1; b < (int)vs.size(); ++b) {\n                if ((b & 15) == 0 && gtimer.elapsed() > deadline) break;\n                bitset<MAXM> nm = best.mask | pathE[vs[a]][vs[b]];\n                TreeResult r = reduceMask(nm, terminal);\n                if (r.cost < rb.cost) rb = r;\n            }\n        }\n\n        if (rb.cost < best.cost) best = rb;\n        else break;\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gtimer.reset();\n\n    cin >> N >> M >> K;\n\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    adj.assign(N, {});\n    for (int j = 0; j < M; ++j) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n        adj[u].push_back({v, j});\n        adj[v].push_back({u, j});\n    }\n\n    RA.resize(K);\n    RB.resize(K);\n    for (int k = 0; k < K; ++k) cin >> RA[k] >> RB[k];\n\n    edgeOrder.resize(M);\n    iota(edgeOrder.begin(), edgeOrder.end(), 0);\n    sort(edgeOrder.begin(), edgeOrder.end(), [&](int a, int b) {\n        if (edges[a].w != edges[b].w) return edges[a].w < edges[b].w;\n        return a < b;\n    });\n\n    allEdgesMask.reset();\n    for (int e = 0; e < M; ++e) allEdgesMask.set(e);\n\n    computeShortestPaths();\n    globalMSTMask = buildGlobalMST();\n\n    distSq.assign(N, vector<int>(K));\n    ceilD.assign(N, vector<unsigned short>(K));\n\n    for (int i = 0; i < N; ++i) {\n        coverList[i].clear();\n        for (int k = 0; k < K; ++k) {\n            long long dx = (long long)X[i] - RA[k];\n            long long dy = (long long)Y[i] - RB[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            distSq[i][k] = (int)d2;\n            ceilD[i][k] = (unsigned short)p;\n            if (p <= 5000) coverList[i].push_back({(unsigned short)p, k});\n        }\n        sort(coverList[i].begin(), coverList[i].end(), [](const RK& a, const RK& b) {\n            if (a.p != b.p) return a.p < b.p;\n            return a.k < b.k;\n        });\n    }\n\n    vector<Solution> sols;\n    const double GEN_DEADLINE = 0.85;\n    const double LOCAL_DEADLINE = 1.90;\n\n    vector<double> lambdas = {0.0, 0.05, 0.2, 0.7, 1.5};\n    for (double l : lambdas) {\n        vector<int> P = nearestSolution(l);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    {\n        vector<int> P(N, 5000);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    vector<pair<double,double>> params = {\n        {0.0, 1.0}, {0.2, 1.0}, {0.5, 1.0}, {0.8, 1.0},\n        {1.2, 1.0}, {2.0, 1.0}, {0.3, 1.15}, {0.8, 1.15},\n        {1.5, 1.15}, {0.5, 0.9}\n    };\n\n    vector<char> allAllowed(N, 1);\n    for (auto [beta, ex] : params) {\n        if (gtimer.elapsed() > GEN_DEADLINE) break;\n        vector<int> P(N, 0);\n        if (greedyRepair(P, allAllowed, beta, ex, nullptr, GEN_DEADLINE)) {\n            considerCandidate(P, sols, GEN_DEADLINE);\n        }\n    }\n\n    if (sols.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        if (!isFull(P)) greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        sols.push_back(evaluateSolution(P));\n    }\n\n    sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b) {\n        return a.total < b.total;\n    });\n\n    vector<Solution> uniq;\n    for (const auto& s : sols) {\n        if (s.total >= INFLL / 2) continue;\n        bool dup = false;\n        for (const auto& u : uniq) {\n            if (u.P == s.P) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniq.push_back(s);\n        if ((int)uniq.size() >= 20) break;\n    }\n\n    if (uniq.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        uniq.push_back(evaluateSolution(P));\n    }\n\n    Solution best = uniq[0];\n\n    int optN = min(5, (int)uniq.size());\n    for (int i = 0; i < optN && gtimer.elapsed() < LOCAL_DEADLINE; ++i) {\n        Solution opt = localSearch(uniq[i], LOCAL_DEADLINE);\n        if (opt.total < best.total) best = opt;\n    }\n\n    best = evaluateSolution(best.P);\n\n    if (gtimer.elapsed() < 1.95) {\n        vector<long long> br = computeBranch(best.P, best.tree);\n        vector<int> p2 = best.P;\n        trimP(p2, makeOrder(p2, 3, &br));\n        Solution ns = evaluateSolution(p2);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (!isFull(best.P)) {\n        greedyRepair(best.P, allAllowed, 0.0, 1.0);\n        best = evaluateSolution(best.P);\n    } else {\n        best = evaluateSolution(best.P);\n    }\n\n    Solution safeBest = best;\n\n    // Extra monotonic post-process: use already connected Steiner vertices as free candidates.\n    if (gtimer.elapsed() < 1.965) {\n        Solution ns = optimizeOnReachableFinal(best, 1.970);\n        if (ns.total < best.total) best = ns;\n    }\n\n    // Extra safe branch-aware trimming using the current tree as an explicit candidate.\n    if (gtimer.elapsed() < 1.975) {\n        vector<long long> br = computeBranch(best.P, best.tree);\n        vector<int> p2 = best.P;\n        trimP(p2, makeOrder(p2, 3, &br));\n        bitset<MAXM> bm = best.tree.mask;\n        Solution ns = evaluateSolution(p2, &bm);\n        if (ns.total < best.total) best = ns;\n    }\n\n    // Final cable-only optimization. It never changes powers and accepts only lower tree cost.\n    if (gtimer.elapsed() < 1.980) {\n        TreeResult tr = finalImproveTree(best.P, best.tree, 1.988);\n        if (tr.cost < best.tree.cost) {\n            best.tree = tr;\n            best.total = best.radCost + best.tree.cost;\n        }\n    }\n\n    if (!isFull(best.P) || best.total >= INFLL / 2) {\n        best = safeBest;\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 e = 0; e < M; ++e) {\n        if (e) cout << ' ';\n        cout << (best.tree.mask.test(e) ? 1 : 0);\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 int M = N * (N + 1) / 2;\nstatic constexpr int INTERNAL = M - N;\n\nint ID[N][N], Xc[M], Yc[M];\nvector<int> G[M], PAR[M], CH[M];\nvector<pair<int,int>> EDGES;\nvector<pair<int,int>> ADJ;\nvector<int> INCIDENT[M];\n\nbool validXY(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y <= x;\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 FastRand {\n    uint64_t x;\n    FastRand(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nvoid precompute() {\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) ID[i][j] = -1;\n\n    int idx = 0;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            ID[x][y] = idx;\n            Xc[idx] = x;\n            Yc[idx] = y;\n            idx++;\n        }\n    }\n\n    int dx[6] = {0, 0, -1, -1, 1, 1};\n    int dy[6] = {-1, 1, -1, 0, 0, 1};\n\n    for (int p = 0; p < M; p++) {\n        int x = Xc[p], y = Yc[p];\n\n        for (int k = 0; k < 6; k++) {\n            int nx = x + dx[k], ny = y + dy[k];\n            if (validXY(nx, ny)) G[p].push_back(ID[nx][ny]);\n        }\n\n        if (x + 1 < N) {\n            CH[p].push_back(ID[x + 1][y]);\n            CH[p].push_back(ID[x + 1][y + 1]);\n        }\n        if (x > 0) {\n            if (y > 0) PAR[p].push_back(ID[x - 1][y - 1]);\n            if (y < x) PAR[p].push_back(ID[x - 1][y]);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int c : CH[p]) {\n            int ei = (int)EDGES.size();\n            EDGES.emplace_back(p, c);\n            INCIDENT[p].push_back(ei);\n            INCIDENT[c].push_back(ei);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int q : G[p]) {\n            if (p < q) ADJ.emplace_back(p, q);\n        }\n    }\n}\n\nstruct Work {\n    array<int, M> a;\n    array<int, M> pos;\n    vector<pair<int,int>> ops;\n\n    Work() {}\n\n    Work(const array<int, M>& init) {\n        a = init;\n        for (int i = 0; i < M; i++) pos[a[i]] = i;\n        ops.clear();\n    }\n};\n\ninline void doSwap(Work& w, int u, int v) {\n    int lu = w.a[u], lv = w.a[v];\n    swap(w.a[u], w.a[v]);\n    w.pos[lu] = v;\n    w.pos[lv] = u;\n    w.ops.emplace_back(u, v);\n}\n\nint countViol(const array<int, M>& a) {\n    int e = 0;\n    for (auto [p, c] : EDGES) {\n        if (a[p] > a[c]) e++;\n    }\n    return e;\n}\n\narray<int, M> simulateOps(const array<int, M>& init, const vector<pair<int,int>>& ops) {\n    array<int, M> a = init;\n    for (auto [u, v] : ops) swap(a[u], a[v]);\n    return a;\n}\n\nint centerVal(int p) {\n    return abs(2 * Yc[p] - Xc[p]);\n}\n\nint chooseCand(const vector<int>& cand, int choice, const Work& w) {\n    int best = cand[0];\n    for (int q : cand) {\n        bool take = false;\n        if (choice == 0) {\n            if (w.a[q] > w.a[best]) take = true;\n        } else if (choice == 1) {\n            if (w.a[q] < w.a[best]) take = true;\n        } else if (choice == 2) {\n            if (Yc[q] < Yc[best]) take = true;\n        } else if (choice == 3) {\n            if (Yc[q] > Yc[best]) take = true;\n        } else {\n            int cq = centerVal(q), cb = centerVal(best);\n            if (cq < cb || (cq == cb && w.a[q] > w.a[best])) take = true;\n        }\n        if (take) best = q;\n    }\n    return best;\n}\n\nint chooseCandRand(const vector<int>& cand, int mode, const Work& w, FastRand& rng, int dir) {\n    if ((int)cand.size() == 1) return cand[0];\n\n    if (mode == 0) return cand[rng.nextInt((int)cand.size())];\n\n    if (1 <= mode && mode <= 5) {\n        int base = chooseCand(cand, mode - 1, w);\n        if (rng.nextInt(100) < 75) return base;\n        vector<int> other;\n        for (int q : cand) if (q != base) other.push_back(q);\n        if (other.empty()) return base;\n        return other[rng.nextInt((int)other.size())];\n    }\n\n    int best = cand[0];\n    long long bestSc = LLONG_MIN;\n    for (int q : cand) {\n        long long sc = 0;\n        if (mode == 6) {\n            sc = 100LL * w.a[q] - 15LL * centerVal(q);\n        } else {\n            sc = -100LL * w.a[q] - 15LL * centerVal(q);\n        }\n        if (dir == 0) sc -= 3LL * Xc[q];\n        else sc += 3LL * Xc[q];\n        sc += (long long)(rng.nextInt(301) - 150);\n        if (sc > bestSc) {\n            bestSc = sc;\n            best = q;\n        }\n    }\n    return best;\n}\n\n// Guaranteed finisher.\nbool appendCone(Work& w, int yOrder, int pathMode, int limit) {\n    if (countViol(w.a) == 0) return true;\n\n    for (int x = 0; x <= N - 2; x++) {\n        for (int yi = 0; yi <= x; yi++) {\n            int y = (yOrder == 0 ? yi : x - yi);\n\n            int best = ID[x][y];\n            int bv = w.a[best];\n\n            for (int r = x; r < N; r++) {\n                int c0 = y;\n                int c1 = y + (r - x);\n                for (int c = c0; c <= c1; c++) {\n                    int p = ID[r][c];\n                    if (w.a[p] < bv) {\n                        bv = w.a[p];\n                        best = p;\n                    }\n                }\n            }\n\n            int cur = best;\n            while (Xc[cur] > x) {\n                int cx = Xc[cur], cy = Yc[cur];\n                bool goLeft = false;\n\n                if (pathMode == 0) {\n                    goLeft = (cy > y);\n                } else if (pathMode == 1) {\n                    goLeft = !(cx - cy > x - y);\n                } else {\n                    int rem = cx - x;\n                    int needLeft = cy - y;\n                    if (needLeft <= 0) goLeft = false;\n                    else if (needLeft >= rem) goLeft = true;\n                    else goLeft = (needLeft * 2 >= rem);\n                }\n\n                int np = goLeft ? ID[cx - 1][cy - 1] : ID[cx - 1][cy];\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, cur, np);\n                cur = np;\n            }\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n    return countViol(w.a) == 0;\n}\n\nbool appendSift(Work& w, int dir, int choice, int limit) {\n    if (countViol(w.a) == 0) return true;\n    if ((int)w.ops.size() > limit) return false;\n\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    } else {\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool appendSiftRandom(Work& w, int dir, int mode, uint64_t seed, int limit) {\n    if (countViol(w.a) == 0) return true;\n    if ((int)w.ops.size() > limit) return false;\n\n    FastRand rng(seed);\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    } else {\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool solveSift(const array<int, M>& init, int dir, int choice, int limit, Work& out) {\n    Work w(init);\n    if (appendSift(w, dir, choice, limit)) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool parentsFixed(int p, const vector<char>& fixed) {\n    for (int q : PAR[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nbool childrenFixed(int p, const vector<char>& fixed) {\n    for (int q : CH[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nint openInc(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (fixed[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openDec(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (fixed[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nstruct Strat {\n    int w;\n    int row;\n    int center;\n    int open;\n    int randAmp;\n    uint64_t seed;\n};\n\nbool solveBFS(const array<int, M>& init, int dir, const Strat& st, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<char> fixed(M, 0), avail(M, 0);\n\n    if (dir == 0) {\n        avail[ID[0][0]] = 1;\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openInc(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(v + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] < N - 1) internalFixed++;\n\n            for (int ch : CH[best]) {\n                if (!fixed[ch] && parentsFixed(ch, fixed)) avail[ch] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    } else {\n        for (int y = 0; y < N; y++) avail[ID[N - 1][y]] = 1;\n\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n            int step = M - 1 - v;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openDec(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] > 0) nonTopFixed++;\n\n            for (int pr : PAR[best]) {\n                if (!fixed[pr] && childrenFixed(pr, fixed)) avail[pr] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Bidirectional BFS construction.\nbool parentsTop(int p, const vector<unsigned char>& type) {\n    for (int q : PAR[p]) if (type[q] != 1) return false;\n    return true;\n}\n\nbool childrenBottom(int p, const vector<unsigned char>& type) {\n    for (int q : CH[p]) if (type[q] != 2) return false;\n    return true;\n}\n\nint openTopCnt(int p, const vector<unsigned char>& type) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (type[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && type[q] != 1) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openBottomCnt(int p, const vector<unsigned char>& type) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (type[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && type[q] != 2) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nstruct BiOpt {\n    bool ok = false;\n    int target = -1;\n    int dist = 0;\n    long long score = 0;\n};\n\nBiOpt getBiOption(\n    const Work& w,\n    const vector<unsigned char>& type,\n    const vector<char>& avail,\n    int label,\n    bool topSide,\n    const Strat& st,\n    int step,\n    array<int, M>& dist,\n    array<int, M>& prv\n) {\n    BiOpt opt;\n    int start = w.pos[label];\n    if (type[start]) return opt;\n\n    dist.fill(-1);\n    prv.fill(-1);\n\n    int que[M], head = 0, tail = 0;\n    dist[start] = 0;\n    que[tail++] = start;\n\n    while (head < tail) {\n        int u = que[head++];\n        for (int nb : G[u]) {\n            if (type[nb]) continue;\n            if (dist[nb] != -1) continue;\n            dist[nb] = dist[u] + 1;\n            prv[nb] = u;\n            que[tail++] = nb;\n        }\n    }\n\n    long long bestSc = LLONG_MAX;\n    int best = -1;\n\n    for (int p = 0; p < M; p++) {\n        if (!avail[p] || type[p] || dist[p] < 0) continue;\n\n        int opn = topSide ? openTopCnt(p, type) : openBottomCnt(p, type);\n        long long sc = 1LL * dist[p] * st.w\n                     + 1LL * st.row * Xc[p]\n                     + 1LL * st.center * centerVal(p)\n                     + 1LL * st.open * opn;\n\n        if (st.randAmp > 0) {\n            uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n            sc += (long long)(h % (uint64_t)st.randAmp);\n        }\n\n        if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n            best = p;\n            bestSc = sc;\n        }\n    }\n\n    if (best == -1) return opt;\n\n    opt.ok = true;\n    opt.target = best;\n    opt.dist = dist[best];\n    opt.score = bestSc;\n    return opt;\n}\n\nbool solveBiBFS(const array<int, M>& init, const Strat& topSt, const Strat& botSt, int sideBias, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<unsigned char> type(M, 0); // 0 free, 1 top-small fixed, 2 bottom-large fixed\n    vector<char> topAvail(M, 0), botAvail(M, 0);\n\n    topAvail[ID[0][0]] = 1;\n    for (int y = 0; y < N; y++) botAvail[ID[N - 1][y]] = 1;\n\n    int lo = 0, hi = M - 1;\n    int step = 0;\n\n    while (lo <= hi) {\n        array<int, M> distTop, prvTop, distBot, prvBot;\n\n        BiOpt ot = getBiOption(w, type, topAvail, lo, true, topSt, step, distTop, prvTop);\n        BiOpt ob = getBiOption(w, type, botAvail, hi, false, botSt, step, distBot, prvBot);\n\n        if (!ot.ok && !ob.ok) return false;\n\n        bool chooseTop;\n        if (!ob.ok) chooseTop = true;\n        else if (!ot.ok) chooseTop = false;\n        else chooseTop = (ot.score + sideBias <= ob.score);\n\n        int target;\n        array<int, M>* prv;\n\n        if (chooseTop) {\n            target = ot.target;\n            prv = &prvTop;\n            if ((int)w.ops.size() + ot.dist > limit) return false;\n        } else {\n            target = ob.target;\n            prv = &prvBot;\n            if ((int)w.ops.size() + ob.dist > limit) return false;\n        }\n\n        vector<int> path;\n        for (int cur = target; cur != -1; cur = (*prv)[cur]) path.push_back(cur);\n        reverse(path.begin(), path.end());\n\n        for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n        if (chooseTop) {\n            type[target] = 1;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            lo++;\n\n            for (int ch : CH[target]) {\n                if (!type[ch] && parentsTop(ch, type)) topAvail[ch] = 1;\n            }\n        } else {\n            type[target] = 2;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            hi--;\n\n            for (int pr : PAR[target]) {\n                if (!type[pr] && childrenBottom(pr, type)) botAvail[pr] = 1;\n            }\n        }\n\n        step++;\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint localDelta(const Work& w, int p, int c) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[c]) add(e);\n\n    int before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        if (w.a[u] > w.a[v]) before++;\n\n        int au = (u == p ? w.a[c] : (u == c ? w.a[p] : w.a[u]));\n        int av = (v == p ? w.a[c] : (v == c ? w.a[p] : w.a[v]));\n        if (au > av) after++;\n    }\n\n    return before - after;\n}\n\nint chooseViolationEdge(const Work& w, int variant) {\n    long long bestKey = LLONG_MIN;\n    int best = -1;\n\n    for (int ei = 0; ei < (int)EDGES.size(); ei++) {\n        auto [p, c] = EDGES[ei];\n        if (w.a[p] <= w.a[c]) continue;\n\n        int diff = w.a[p] - w.a[c];\n        int delta = 0;\n        if (variant >= 6) delta = localDelta(w, p, c);\n\n        long long key = 0;\n        if (variant == 0) {\n            key = diff;\n        } else if (variant == 1) {\n            key = 1LL * (M - w.a[c]) * 1000 + diff;\n        } else if (variant == 2) {\n            key = 1LL * w.a[p] * 1000 + diff;\n        } else if (variant == 3) {\n            key = 1LL * (N - Xc[p]) * 100000 + diff;\n        } else if (variant == 4) {\n            key = 1LL * Xc[p] * 100000 + diff;\n        } else if (variant == 5) {\n            key = 1LL * diff * 1000 + (N - Xc[p]) * 20 + (M - w.a[c]);\n        } else if (variant == 6) {\n            key = 1LL * delta * 1000000 + 1LL * diff * 1000 + (M - w.a[c]);\n        } else if (variant == 7) {\n            key = 1LL * delta * 1000000 + 1LL * (N - Xc[p]) * 1000 + diff;\n        } else {\n            key = 1LL * delta * 1000000 + 1LL * Xc[p] * 1000 + diff;\n        }\n\n        if (key > bestKey) {\n            bestKey = key;\n            best = ei;\n        }\n    }\n\n    return best;\n}\n\nbool runLocalSteps(Work& w, int variant, int steps, int limit) {\n    for (int s = 0; s < steps; s++) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) return true;\n\n        if ((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n    return true;\n}\n\nbool solveLocal(const array<int, M>& init, int variant, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) {\n            out = move(w);\n            return true;\n        }\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool solveSweep(const array<int, M>& init, int xdir, int ydir, int choice, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        bool changed = false;\n\n        for (int xi = 0; xi < N - 1; xi++) {\n            int x = (xdir == 0 ? N - 2 - xi : xi);\n\n            for (int yi = 0; yi <= x; yi++) {\n                int y = (ydir == 0 ? yi : x - yi);\n                int cur = ID[x][y];\n\n                while (Xc[cur] < N - 1) {\n                    vector<int> cand;\n                    for (int q : CH[cur]) {\n                        if (w.a[cur] > w.a[q]) cand.push_back(q);\n                    }\n                    if (cand.empty()) break;\n\n                    int q = chooseCand(cand, choice, w);\n                    if ((int)w.ops.size() + 1 > limit) return false;\n\n                    doSwap(w, cur, q);\n                    cur = q;\n                    changed = true;\n                }\n            }\n        }\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n        if (!changed) break;\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Greedy all-adjacent local energy prefix.\nlong long edgeCostVal(int ap, int ac, int W, bool quad) {\n    if (ap <= ac) return 0;\n    long long d = ap - ac;\n    if (quad) return (long long)W + d * d;\n    return (long long)W + d;\n}\n\nlong long swapGainCost(const array<int, M>& a, int p, int q, int W, bool quad) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[q]) add(e);\n\n    long long before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        before += edgeCostVal(a[u], a[v], W, quad);\n\n        int au = (u == p ? a[q] : (u == q ? a[p] : a[u]));\n        int av = (v == p ? a[q] : (v == q ? a[p] : a[v]));\n        after += edgeCostVal(au, av, W, quad);\n    }\n\n    return before - after;\n}\n\nbool runGreedyCost(Work& w, int W, bool quad, int maxSteps, int limit) {\n    for (int s = 0; s < maxSteps; s++) {\n        if ((int)w.ops.size() >= limit) return countViol(w.a) == 0;\n\n        long long bestGain = 0;\n        long long bestTie = LLONG_MIN;\n        int bu = -1, bv = -1;\n\n        for (auto [u, v] : ADJ) {\n            long long gain = swapGainCost(w.a, u, v, W, quad);\n            if (gain <= 0) continue;\n\n            long long deltaP = 1LL * (w.a[u] - w.a[v]) * (Xc[v] - Xc[u]);\n            long long rowGain = -deltaP;\n\n            if (gain > bestGain || (gain == bestGain && rowGain > bestTie)) {\n                bestGain = gain;\n                bestTie = rowGain;\n                bu = u;\n                bv = v;\n            }\n        }\n\n        if (bu == -1) break;\n\n        doSwap(w, bu, bv);\n        if (countViol(w.a) == 0) return true;\n    }\n\n    return countViol(w.a) == 0;\n}\n\n// Fast reverse pruning of a valid operation sequence.\nbool canSwapKeepValid(const array<int, M>& a, int p, int q) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[q]) add(e);\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n\n        int au = a[u], av = a[v];\n        if (u == p) au = a[q];\n        else if (u == q) au = a[p];\n\n        if (v == p) av = a[q];\n        else if (v == q) av = a[p];\n\n        if (au > av) return false;\n    }\n\n    return true;\n}\n\nvector<pair<int,int>> pruneOpsFast(const array<int, M>& init, const vector<pair<int,int>>& ops, int passes = 3) {\n    vector<pair<int,int>> cur = ops;\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (cur.empty()) break;\n\n        array<int, M> a = simulateOps(init, cur);\n        if (countViol(a) != 0) return cur;\n\n        array<int, M> suff;\n        for (int i = 0; i < M; i++) suff[i] = i;\n\n        vector<unsigned char> keep(cur.size(), 1);\n        int deleted = 0;\n\n        for (int ii = (int)cur.size(); ii-- > 0; ) {\n            int u = cur[ii].first;\n            int v = cur[ii].second;\n\n            int p = suff[u];\n            int q = suff[v];\n\n            if (canSwapKeepValid(a, p, q)) {\n                swap(a[p], a[q]);\n                keep[ii] = 0;\n                deleted++;\n            } else {\n                swap(suff[u], suff[v]);\n            }\n        }\n\n        if (deleted == 0) break;\n\n        vector<pair<int,int>> nxt;\n        nxt.reserve(cur.size() - deleted);\n        for (int i = 0; i < (int)cur.size(); i++) {\n            if (keep[i]) nxt.push_back(cur[i]);\n        }\n        cur.swap(nxt);\n    }\n\n    return cur;\n}\n\nbool validSkipping(const array<int, M>& init, const vector<pair<int,int>>& ops, int s1, int s2 = -1) {\n    array<int, M> a = init;\n    for (int i = 0; i < (int)ops.size(); i++) {\n        if (i == s1 || i == s2) continue;\n        swap(a[ops[i].first], a[ops[i].second]);\n    }\n    return countViol(a) == 0;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    array<int, M> init;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            cin >> init[ID[x][y]];\n        }\n    }\n\n    uint64_t inputHash = 0;\n    for (int i = 0; i < M; i++) {\n        inputHash = splitmix64(inputHash ^ (uint64_t)(init[i] + 1) * 1000003ULL ^ (uint64_t)i);\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto searchOK = [&]() {\n        return elapsed() < 1.78;\n    };\n    auto finalOK = [&]() {\n        return elapsed() < 1.93;\n    };\n\n    vector<pair<int,int>> bestOps;\n    int bestK = 10001;\n    const int PRUNE_MARGIN = 1600;\n\n    auto consider = [&](Work&& w) {\n        int raw = (int)w.ops.size();\n        if (raw > 10000) return;\n        if (countViol(w.a) != 0) return;\n\n        if (bestK <= 10000 && raw >= bestK + PRUNE_MARGIN) return;\n\n        vector<pair<int,int>> pruned = pruneOpsFast(init, w.ops, 3);\n        if ((int)pruned.size() > 10000) return;\n\n        array<int, M> aa = simulateOps(init, pruned);\n        if (countViol(aa) != 0) return;\n\n        int k = (int)pruned.size();\n        if (k < bestK) {\n            bestK = k;\n            bestOps = move(pruned);\n        }\n    };\n\n    auto limitGen = [&]() {\n        if (bestK > 10000) return 10000;\n        return min(10000, bestK + PRUNE_MARGIN);\n    };\n\n    // Guaranteed candidates first.\n    for (int yo = 0; yo < 2; yo++) {\n        for (int pm = 0; pm < 3; pm++) {\n            Work w(init);\n            if (appendCone(w, yo, pm, 10000)) consider(move(w));\n        }\n    }\n\n    // Deterministic sifts.\n    for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n        for (int ch = 0; ch < 5 && searchOK() && bestK > 0; ch++) {\n            Work w;\n            if (solveSift(init, dir, ch, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    // Randomized sifts.\n    for (int t = 0; t < 90 && searchOK() && bestK > 0; t++) {\n        int dir = t & 1;\n        int mode = (t / 2) % 8;\n        uint64_t seed = inputHash ^ (uint64_t)(t + 1) * 0x9e3779b97f4a7c15ULL;\n\n        Work w(init);\n        if (appendSiftRandom(w, dir, mode, seed, limitGen())) consider(move(w));\n    }\n\n    // Bidirectional BFS candidates.\n    vector<tuple<Strat, Strat, int>> biStrats;\n    auto addBi = [&](Strat a, Strat b, int bias) {\n        biStrats.emplace_back(a, b, bias);\n    };\n\n    addBi({1000, 5, 0, -20, 0, 0}, {1000, -5, 0, -20, 0, 0}, 0);\n    addBi({1000, 10, 0, -20, 0, 0}, {1000, -10, 0, -20, 0, 0}, 0);\n    addBi({1000, 0, 0, -20, 0, 0}, {1000, 0, 0, -20, 0, 0}, 0);\n    addBi({1000, 5, -3, -20, 0, 0}, {1000, -5, -3, -20, 0, 0}, 0);\n    addBi({1000, 5, 3, -20, 0, 0}, {1000, -5, 3, -20, 0, 0}, 0);\n    addBi({300, 20, 0, -30, 0, 0}, {300, -20, 0, -30, 0, 0}, 0);\n    addBi({500, 10, -5, -30, 80, inputHash ^ 111}, {500, -10, -5, -30, 80, inputHash ^ 222}, 0);\n    addBi({500, 10, 5, -30, 80, inputHash ^ 333}, {500, -10, 5, -30, 80, inputHash ^ 444}, 0);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 555}, {1000, -5, 0, -20, 100, inputHash ^ 666}, -200);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 777}, {1000, -5, 0, -20, 100, inputHash ^ 888}, 200);\n\n    for (auto [ts, bs, bias] : biStrats) {\n        if (!searchOK() || bestK == 0) break;\n        Work w;\n        if (solveBiBFS(init, ts, bs, bias, limitGen(), w)) consider(move(w));\n    }\n\n    // Greedy energy prefixes + sift finishers.\n    vector<tuple<int,bool,int>> gparams = {\n        {10000, false, 120},\n        {10000, false, 300},\n        {3000, false, 300},\n        {1000, false, 500},\n        {300, false, 500},\n        {20000, true, 250}\n    };\n\n    for (auto [W, quad, steps] : gparams) {\n        if (!searchOK() || bestK == 0) break;\n\n        Work pref(init);\n        runGreedyCost(pref, W, quad, steps, limitGen());\n\n        if (countViol(pref.a) == 0) consider(Work(pref));\n\n        for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n            for (int ch : {0, 1, 4}) {\n                if (!searchOK() || bestK == 0) break;\n                Work w = pref;\n                if (appendSift(w, dir, ch, limitGen())) consider(move(w));\n            }\n        }\n    }\n\n    // Local violation prefixes + sift/cone finishers.\n    vector<int> prefVars = {0, 1, 6, 7};\n    vector<int> prefSteps = {80, 180, 350, 700};\n\n    for (int var : prefVars) {\n        for (int stp : prefSteps) {\n            if (!searchOK() || bestK == 0) break;\n\n            Work pref(init);\n            if (!runLocalSteps(pref, var, stp, limitGen())) continue;\n\n            if (countViol(pref.a) == 0) {\n                consider(Work(pref));\n                continue;\n            }\n\n            for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n                for (int ch : {0, 1, 4}) {\n                    if (!searchOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendSift(w, dir, ch, limitGen())) consider(move(w));\n                }\n            }\n\n            for (int yo = 0; yo < 2 && searchOK() && bestK > 0; yo++) {\n                for (int pm = 0; pm < 3; pm++) {\n                    if (!searchOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendCone(w, yo, pm, limitGen())) consider(move(w));\n                }\n            }\n        }\n    }\n\n    // BFS topological constructions.\n    vector<Strat> strats;\n    auto addStrat = [&](int w, int r, int c, int o, int ra = 0, uint64_t seed = 0) {\n        strats.push_back({w, r, c, o, ra, seed});\n    };\n\n    addStrat(1000, 0, 0, 0);\n    addStrat(1000, 1, 0, 0);\n    addStrat(1000, -1, 0, 0);\n    addStrat(1000, 0, 1, 0);\n    addStrat(1000, 0, -1, 0);\n    addStrat(1000, 0, 0, -10);\n    addStrat(200, 10, 0, 0);\n    addStrat(200, -10, 0, 0);\n    addStrat(200, 30, 0, 0);\n    addStrat(200, -30, 0, 0);\n    addStrat(200, 0, 10, 0);\n    addStrat(200, 0, -10, 0);\n    addStrat(200, 10, -5, -20);\n    addStrat(200, -10, 5, -20);\n    addStrat(100, 10, 0, -30);\n    addStrat(100, -10, 0, -30);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 1234567);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 9876543);\n    addStrat(700, 5, -3, -15, 150, inputHash ^ 5555555);\n    addStrat(700, -5, 3, -15, 150, inputHash ^ 3141592);\n\n    for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n        for (const auto& st : strats) {\n            if (!searchOK() || bestK == 0) break;\n            Work w;\n            if (solveBFS(init, dir, st, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    // Sweep heapification variants.\n    for (int xd = 0; xd < 2 && searchOK() && bestK > 0; xd++) {\n        for (int yd = 0; yd < 2 && searchOK() && bestK > 0; yd++) {\n            for (int ch = 0; ch < 4 && searchOK() && bestK > 0; ch++) {\n                Work w;\n                if (solveSweep(init, xd, yd, ch, limitGen(), w)) consider(move(w));\n            }\n        }\n    }\n\n    // Pure local violation swapping variants.\n    for (int var = 0; var < 9 && searchOK() && bestK > 0; var++) {\n        Work w;\n        if (solveLocal(init, var, limitGen(), w)) consider(move(w));\n    }\n\n    // Safety fallback.\n    if (bestK > 10000) {\n        Work w(init);\n        appendCone(w, 0, 0, 10000);\n        bestOps = move(w.ops);\n        bestK = (int)bestOps.size();\n    }\n\n    // More exact final pruning on the best sequence.\n    bestOps = pruneOpsFast(init, bestOps, 5);\n\n    auto slowSingle = [&](bool rev) {\n        if (rev) {\n            for (int i = (int)bestOps.size() - 1; i >= 0 && finalOK(); i--) {\n                if (validSkipping(init, bestOps, i)) {\n                    bestOps.erase(bestOps.begin() + i);\n                }\n            }\n        } else {\n            for (int i = 0; i < (int)bestOps.size() && finalOK(); ) {\n                if (validSkipping(init, bestOps, i)) {\n                    bestOps.erase(bestOps.begin() + i);\n                } else {\n                    i++;\n                }\n            }\n        }\n    };\n\n    auto slowPairs = [&]() {\n        for (int i = 0; i + 1 < (int)bestOps.size() && finalOK(); ) {\n            if (validSkipping(init, bestOps, i, i + 1)) {\n                bestOps.erase(bestOps.begin() + i, bestOps.begin() + i + 2);\n            } else {\n                i++;\n            }\n        }\n    };\n\n    if (finalOK()) slowSingle(false);\n    if (finalOK()) slowSingle(true);\n    if (finalOK()) slowPairs();\n    if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n\n    // Last safety check.\n    {\n        array<int, M> aa = simulateOps(init, bestOps);\n        if (countViol(aa) != 0 || (int)bestOps.size() > 10000) {\n            Work w(init);\n            appendCone(w, 0, 0, 10000);\n            bestOps = move(w.ops);\n        }\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto [u, v] : bestOps) {\n        cout << Xc[u] << ' ' << Yc[u] << ' ' << Xc[v] << ' ' << Yc[v] << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int INF = 1e9;\n\nint D, N, M;\nint rootR, rootC;\nbool obs[9][9];\nint gid[9][9];\n\nvector<pair<int,int>> posi;\nvector<vector<int>> adjList;\nvector<int> rootAdjCells;\nvector<char> isRootAdj;\n\nvector<uint64_t> adjLo, adjHi;\nvector<int> orderP, pIndex;\n\nvector<int> assignedLabel;\nvector<char> unseenLabel;\nint emptyCnt;\n\nchrono::steady_clock::time_point globalStart;\n\nbool timeOver(double lim) {\n    return chrono::duration<double>(chrono::steady_clock::now() - globalStart).count() > lim;\n}\n\nstatic inline bool inside(int r, int c) {\n    return 0 <= r && r < D && 0 <= c && c < D;\n}\n\nstatic inline bool hasBit(uint64_t lo, uint64_t hi, int i) {\n    if (i < 64) return (lo >> i) & 1ULL;\n    return (hi >> (i - 64)) & 1ULL;\n}\n\nstatic inline void setBit(uint64_t &lo, uint64_t &hi, int i) {\n    if (i < 64) lo |= 1ULL << i;\n    else hi |= 1ULL << (i - 64);\n}\n\nstatic inline bool intersects(uint64_t aLo, uint64_t aHi, uint64_t bLo, uint64_t bHi) {\n    return ((aLo & bLo) | (aHi & bHi)) != 0;\n}\n\nstatic inline bool accessibleFrom(int cell, uint64_t lo, uint64_t hi) {\n    return isRootAdj[cell] || intersects(adjLo[cell], adjHi[cell], lo, hi);\n}\n\nstatic inline int countLessMask(uint64_t lo, uint64_t hi, int x) {\n    if (x <= 0) return 0;\n    if (x < 64) {\n        return __builtin_popcountll(lo & ((1ULL << x) - 1));\n    }\n    if (x == 64) return __builtin_popcountll(lo);\n    int h = x - 64;\n    uint64_t mask = (1ULL << h) - 1;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n}\n\n// Checks whether all current empty cells except a,b are reachable from entrance.\nbool connectedAvoid(int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (assignedLabel[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (assignedLabel[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validPlacementCandidates() {\n    vector<int> cand;\n\n    for (int c = 0; c < M; c++) {\n        if (assignedLabel[c] != -1) continue;\n        if (connectedAvoid(c, -1, emptyCnt - 1)) cand.push_back(c);\n    }\n\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (assignedLabel[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nint countNextValidAfter(int c) {\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return 0;\n    if (rem == 1) return 1;\n\n    int cnt = 0;\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (connectedAvoid(c, e, rem - 1)) cnt++;\n    }\n\n    return cnt;\n}\n\nvector<int> collectNextValidAfter(int c) {\n    vector<int> res;\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return res;\n\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (rem == 1 || connectedAvoid(c, e, rem - 1)) {\n            res.push_back(e);\n        }\n    }\n\n    return res;\n}\n\nint invOfValues(const int *seq) {\n    int inv = 0;\n\n    for (int i = 0; i < M; i++) {\n        for (int j = i + 1; j < M; j++) {\n            if (seq[i] > seq[j]) inv++;\n        }\n    }\n\n    return inv;\n}\n\nint sequenceCost(const vector<int> &seq, const vector<int> &lab) {\n    if ((int)seq.size() != M) return INF;\n\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int x = lab[seq[step]];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nbool isLegalSequence(const vector<int> &seq) {\n    if ((int)seq.size() != M) return false;\n\n    vector<char> seen(M, 0);\n    uint64_t lo = 0, hi = 0;\n\n    for (int cell : seq) {\n        if (cell < 0 || cell >= M || seen[cell]) return false;\n        if (!accessibleFrom(cell, lo, hi)) return false;\n\n        seen[cell] = 1;\n        setBit(lo, hi, cell);\n    }\n\n    return true;\n}\n\nint greedyCostLabels(const vector<int> &lab) {\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            if (accessibleFrom(i, rlo, rhi) && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) return INF;\n\n        int x = lab[best];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nint evaluateHypWithExtra(\n    int c1,\n    int t1,\n    int c2,\n    int t2,\n    const vector<int> &futureLabels,\n    vector<int> &lab,\n    int *seqVals\n) {\n    int ptr = 0;\n    int si = 0;\n\n    for (int cell : orderP) {\n        int v;\n\n        if (assignedLabel[cell] != -1) {\n            v = assignedLabel[cell];\n        } else if (cell == c1) {\n            v = t1;\n        } else if (cell == c2) {\n            v = t2;\n        } else {\n            v = futureLabels[ptr++];\n        }\n\n        lab[cell] = v;\n        seqVals[si++] = v;\n    }\n\n    int fixedInv = invOfValues(seqVals);\n    int greedyInv = greedyCostLabels(lab);\n\n    return min(fixedInv, greedyInv);\n}\n\nvector<int> greedySequenceMinLabel(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            if (accessibleFrom(i, rlo, rhi) && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) break;\n\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n    }\n\n    return seq;\n}\n\nvector<int> greedySequenceLookahead2(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestScore = INT_MAX;\n        int bestCostInc = INT_MAX;\n        int bestLab = INT_MAX;\n\n        for (int c = 0; c < M; c++) {\n            if (hasBit(rlo, rhi, c)) continue;\n            if (!accessibleFrom(c, rlo, rhi)) continue;\n\n            int x = lab[c];\n            int less = countLessMask(llo, lhi, x);\n            int inc1 = x - less;\n            int costInc = step - less;\n\n            uint64_t nrlo = rlo, nrhi = rhi;\n            uint64_t nllo = llo, nlhi = lhi;\n            setBit(nrlo, nrhi, c);\n            setBit(nllo, nlhi, x);\n\n            int inc2 = 0;\n\n            if (step + 1 < M) {\n                inc2 = INT_MAX / 4;\n\n                for (int d = 0; d < M; d++) {\n                    if (hasBit(nrlo, nrhi, d)) continue;\n                    if (!accessibleFrom(d, nrlo, nrhi)) continue;\n\n                    int y = lab[d];\n                    int less2 = countLessMask(nllo, nlhi, y);\n                    inc2 = min(inc2, y - less2);\n                }\n            }\n\n            int score = inc1 + inc2;\n\n            if (score < bestScore ||\n                (score == bestScore && costInc < bestCostInc) ||\n                (score == bestScore && costInc == bestCostInc && x < bestLab)) {\n                bestScore = score;\n                bestCostInc = costInc;\n                bestLab = x;\n                best = c;\n            }\n        }\n\n        if (best == -1) break;\n\n        int x = lab[best];\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return seq;\n}\n\n// Legal single-cell insertion improvement.\nvector<int> improveSequenceByInsertion(vector<int> seq, const vector<int> &lab, int maxIter = 1000) {\n    if (!isLegalSequence(seq)) return seq;\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (timeOver(1.86)) break;\n\n        vector<uint64_t> prefLo(M + 1, 0), prefHi(M + 1, 0);\n        vector<int> arr(M);\n\n        for (int i = 0; i < M; i++) {\n            arr[i] = lab[seq[i]];\n            prefLo[i + 1] = prefLo[i];\n            prefHi[i + 1] = prefHi[i];\n            setBit(prefLo[i + 1], prefHi[i + 1], seq[i]);\n        }\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n\n        for (int j = 1; j < M; j++) {\n            int x = arr[j];\n            int delta = 0;\n\n            for (int i = j - 1; i >= 0; i--) {\n                int y = arr[i];\n\n                if (x > y) delta++;\n                else delta--;\n\n                if (delta < bestDelta && accessibleFrom(seq[j], prefLo[i], prefHi[i])) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        int cell = seq[bestJ];\n        seq.erase(seq.begin() + bestJ);\n        seq.insert(seq.begin() + bestI, cell);\n    }\n\n    return seq;\n}\n\n// Legal block insertion improvement.\n// Move block [j,k] before i if the block itself is removable from prefix i.\nvector<int> improveSequenceByBlockInsertion(vector<int> seq, const vector<int> &lab, int maxIter = 60) {\n    if (!isLegalSequence(seq)) return seq;\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (timeOver(1.84)) break;\n\n        vector<uint64_t> prefCellLo(M + 1, 0), prefCellHi(M + 1, 0);\n        vector<uint64_t> prefLabLo(M + 1, 0), prefLabHi(M + 1, 0);\n\n        for (int i = 0; i < M; i++) {\n            prefCellLo[i + 1] = prefCellLo[i];\n            prefCellHi[i + 1] = prefCellHi[i];\n            prefLabLo[i + 1] = prefLabLo[i];\n            prefLabHi[i + 1] = prefLabHi[i];\n\n            setBit(prefCellLo[i + 1], prefCellHi[i + 1], seq[i]);\n            setBit(prefLabLo[i + 1], prefLabHi[i + 1], lab[seq[i]]);\n        }\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1, bestK = -1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = i + 1; j < M; j++) {\n                int lenA = j - i;\n                uint64_t segLo = prefLabLo[j] & ~prefLabLo[i];\n                uint64_t segHi = prefLabHi[j] & ~prefLabHi[i];\n\n                uint64_t curLo = prefCellLo[i];\n                uint64_t curHi = prefCellHi[i];\n\n                int delta = 0;\n\n                for (int k = j; k < M; k++) {\n                    int cell = seq[k];\n\n                    if (!accessibleFrom(cell, curLo, curHi)) break;\n\n                    int y = lab[cell];\n                    int less = countLessMask(segLo, segHi, y);\n                    delta += 2 * less - lenA;\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                        bestK = k;\n                    }\n\n                    setBit(curLo, curHi, cell);\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        vector<int> ns;\n        ns.reserve(M);\n\n        for (int p = 0; p < bestI; p++) ns.push_back(seq[p]);\n        for (int p = bestJ; p <= bestK; p++) ns.push_back(seq[p]);\n        for (int p = bestI; p < bestJ; p++) ns.push_back(seq[p]);\n        for (int p = bestK + 1; p < M; p++) ns.push_back(seq[p]);\n\n        seq.swap(ns);\n    }\n\n    return seq;\n}\n\nvoid addTemplateOrder(vector<vector<int>> &temps, const vector<int> &ord) {\n    if ((int)ord.size() != M) return;\n    if (!isLegalSequence(ord)) return;\n\n    for (const auto &v : temps) {\n        if (v == ord) return;\n    }\n\n    temps.push_back(ord);\n}\n\nvector<vector<int>> buildFinalTemplates() {\n    vector<vector<int>> temps;\n    addTemplateOrder(temps, orderP);\n\n    const int BIG = 1e9;\n\n    vector<vector<int>> dist(D, vector<int>(D, BIG));\n    queue<pair<int,int>> q;\n\n    dist[rootR][rootC] = 0;\n    q.push({rootR, rootC});\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != BIG) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            q.push({nr, nc});\n        }\n    }\n\n    auto makeDiscOrder = [&](const vector<pair<int,int>> &dirs) {\n        vector<vector<int>> disc(D, vector<int>(D, BIG));\n        queue<pair<int,int>> qq;\n\n        disc[rootR][rootC] = 0;\n        int cnt = 1;\n        qq.push({rootR, rootC});\n\n        while (!qq.empty()) {\n            auto [r, c] = qq.front();\n            qq.pop();\n\n            for (auto [dr, dc] : dirs) {\n                int nr = r + dr;\n                int nc = c + dc;\n\n                if (!inside(nr, nc) || obs[nr][nc]) continue;\n                if (disc[nr][nc] != BIG) continue;\n\n                disc[nr][nc] = cnt++;\n                qq.push({nr, nc});\n            }\n        }\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n\n            return a < b;\n        });\n\n        return ord;\n    };\n\n    addTemplateOrder(temps, makeDiscOrder({{1,0},{0,-1},{0,1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{1,0},{0,1},{0,-1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{0,-1},{1,0},{0,1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{0,1},{1,0},{0,-1},{-1,0}}));\n\n    auto keyOf = [&](int type, int id) -> long long {\n        auto [r, c] = posi[id];\n\n        switch (type) {\n            case 0: return c * 100LL + r;\n            case 1: return -c * 100LL + r;\n            case 2: return llabs(c - rootC) * 100LL + c;\n            case 3: return -llabs(c - rootC) * 100LL + c;\n            case 4: return r * 100LL + c;\n            case 5: return -r * 100LL + c;\n            case 6: return (r + c) * 100LL + c;\n            case 7: return (r - c) * 100LL + c;\n            default: return id;\n        }\n    };\n\n    for (int type = 0; type < 8; type++) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n\n            long long ka = keyOf(type, a);\n            long long kb = keyOf(type, b);\n\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        addTemplateOrder(temps, ord);\n    }\n\n    auto expansionOrder = [&](int type) {\n        vector<int> ord;\n        vector<char> used(M, 0);\n        uint64_t lo = 0, hi = 0;\n\n        auto score = [&](int id) -> long long {\n            auto [r, c] = posi[id];\n\n            switch (type) {\n                case 0: return c * 100LL + r;\n                case 1: return -c * 100LL + r;\n                case 2: return -r * 100LL + c;\n                case 3: return -r * 100LL - c;\n                case 4: return llabs(c - rootC) * 100LL - r;\n                case 5: return -llabs(c - rootC) * 100LL - r;\n                case 6: return (r + c) * 100LL - r;\n                default: return id;\n            }\n        };\n\n        for (int step = 0; step < M; step++) {\n            int best = -1;\n            long long bestScore = LLONG_MAX;\n\n            for (int id = 0; id < M; id++) {\n                if (used[id]) continue;\n                if (!accessibleFrom(id, lo, hi)) continue;\n\n                long long sc = score(id);\n                if (sc < bestScore || (sc == bestScore && (best == -1 || id < best))) {\n                    bestScore = sc;\n                    best = id;\n                }\n            }\n\n            if (best == -1) return vector<int>();\n\n            used[best] = 1;\n            ord.push_back(best);\n            setBit(lo, hi, best);\n        }\n\n        return ord;\n    };\n\n    for (int type = 0; type < 7; type++) {\n        addTemplateOrder(temps, expansionOrder(type));\n    }\n\n    return temps;\n}\n\nstruct Key {\n    uint64_t lo, hi;\n\n    bool operator==(const Key &o) const {\n        return lo == o.lo && hi == o.hi;\n    }\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\nstruct KeyHash {\n    size_t operator()(const Key &k) const {\n        return splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1);\n    }\n};\n\nstruct Node {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nstruct Temp {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nvector<int> beamSearchRemoval(const vector<int> &lab, int upperBound) {\n    const int BEAM = 12000;\n\n    vector<Node> nodes;\n    nodes.reserve((M + 1) * BEAM + 1);\n    nodes.push_back(Node{0, 0, 0, 0, 0, 0, -1, -1});\n\n    vector<int> cur;\n    cur.push_back(0);\n\n    auto betterTemp = [](const Temp &a, const Temp &b) {\n        if (a.forced != b.forced) return a.forced < b.forced;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.lo != b.lo) return a.lo < b.lo;\n        return a.hi < b.hi;\n    };\n\n    for (int depth = 0; depth < M; depth++) {\n        if (timeOver(1.82)) break;\n\n        vector<Temp> temps;\n        size_t reserveSize = min<size_t>((size_t)cur.size() * 40 + 100, 700000);\n        temps.reserve(reserveSize);\n\n        unordered_map<Key, int, KeyHash> mp;\n        mp.reserve(reserveSize * 2);\n\n        for (int idx : cur) {\n            const Node &s = nodes[idx];\n\n            for (int i = 0; i < M; i++) {\n                if (hasBit(s.lo, s.hi, i)) continue;\n                if (!accessibleFrom(i, s.lo, s.hi)) continue;\n\n                int x = lab[i];\n                int less = countLessMask(s.llo, s.lhi, x);\n\n                int cost2 = s.cost + (depth - less);\n                int forced2 = s.forced + (x - less);\n\n                if (forced2 > upperBound) continue;\n\n                uint64_t nlo = s.lo, nhi = s.hi;\n                uint64_t nllo = s.llo, nlhi = s.lhi;\n                setBit(nlo, nhi, i);\n                setBit(nllo, nlhi, x);\n\n                Temp t{nlo, nhi, nllo, nlhi, cost2, forced2, idx, i};\n                Key key{nlo, nhi};\n\n                auto it = mp.find(key);\n\n                if (it == mp.end()) {\n                    int id = (int)temps.size();\n                    temps.push_back(t);\n                    mp.emplace(key, id);\n                } else {\n                    int id = it->second;\n\n                    if (t.cost < temps[id].cost ||\n                        (t.cost == temps[id].cost && t.forced < temps[id].forced)) {\n                        temps[id] = t;\n                    }\n                }\n            }\n        }\n\n        if (temps.empty()) return {};\n\n        if ((int)temps.size() > BEAM) {\n            nth_element(temps.begin(), temps.begin() + BEAM, temps.end(), betterTemp);\n            temps.resize(BEAM);\n        }\n\n        vector<int> nxt;\n        nxt.reserve(temps.size());\n\n        for (const Temp &t : temps) {\n            int id = (int)nodes.size();\n            nodes.push_back(Node{t.lo, t.hi, t.llo, t.lhi, t.cost, t.forced, t.parent, t.cell});\n            nxt.push_back(id);\n        }\n\n        cur.swap(nxt);\n    }\n\n    int bestNode = -1;\n    int bestCost = INF;\n\n    for (int idx : cur) {\n        if (nodes[idx].cost < bestCost && __builtin_popcountll(nodes[idx].lo) + __builtin_popcountll(nodes[idx].hi) == M) {\n            bestCost = nodes[idx].cost;\n            bestNode = idx;\n        }\n    }\n\n    if (bestNode == -1) return {};\n\n    vector<int> seq;\n\n    while (bestNode != 0 && bestNode != -1) {\n        seq.push_back(nodes[bestNode].cell);\n        bestNode = nodes[bestNode].parent;\n    }\n\n    reverse(seq.begin(), seq.end());\n\n    if ((int)seq.size() != M) return {};\n    return seq;\n}\n\nstruct PQNode {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int forced;\n    int parent;\n    int cell;\n    int depth;\n};\n\nvector<int> bestFirstSearchRemoval(const vector<int> &lab, int upperBound, int nodeLimit = 120000) {\n    if (timeOver(1.72)) return {};\n\n    struct Item {\n        long long eval;\n        int forced;\n        int depth;\n        int id;\n    };\n\n    struct Cmp {\n        bool operator()(const Item &a, const Item &b) const {\n            if (a.eval != b.eval) return a.eval > b.eval;\n            if (a.forced != b.forced) return a.forced > b.forced;\n            return a.depth < b.depth;\n        }\n    };\n\n    vector<PQNode> nodes;\n    nodes.reserve(nodeLimit + 1);\n\n    priority_queue<Item, vector<Item>, Cmp> pq;\n    unordered_map<Key, int, KeyHash> best;\n    best.reserve(nodeLimit * 2);\n\n    nodes.push_back(PQNode{0, 0, 0, 0, 0, -1, -1, 0});\n    best[{0, 0}] = 0;\n    pq.push(Item{0, 0, 0, 0});\n\n    while (!pq.empty() && (int)nodes.size() < nodeLimit) {\n        if (timeOver(1.86)) break;\n\n        Item it = pq.top();\n        pq.pop();\n\n        const PQNode &s = nodes[it.id];\n        Key curKey{s.lo, s.hi};\n\n        auto mit = best.find(curKey);\n        if (mit == best.end() || mit->second != s.forced) continue;\n\n        if (s.depth == M) {\n            if (s.forced >= upperBound) return {};\n\n            vector<int> seq;\n            int v = it.id;\n\n            while (v != -1 && nodes[v].cell != -1) {\n                seq.push_back(nodes[v].cell);\n                v = nodes[v].parent;\n            }\n\n            reverse(seq.begin(), seq.end());\n\n            if ((int)seq.size() == M) return seq;\n            return {};\n        }\n\n        vector<int> cand;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(s.lo, s.hi, i)) continue;\n            if (accessibleFrom(i, s.lo, s.hi)) cand.push_back(i);\n        }\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            return lab[a] < lab[b];\n        });\n\n        for (int cell : cand) {\n            int x = lab[cell];\n            int less = countLessMask(s.llo, s.lhi, x);\n            int nf = s.forced + (x - less);\n\n            if (nf >= upperBound) continue;\n\n            uint64_t nlo = s.lo, nhi = s.hi;\n            uint64_t nllo = s.llo, nlhi = s.lhi;\n            setBit(nlo, nhi, cell);\n            setBit(nllo, nlhi, x);\n\n            Key nk{nlo, nhi};\n            auto bit = best.find(nk);\n\n            if (bit != best.end() && bit->second <= nf) continue;\n\n            best[nk] = nf;\n\n            if ((int)nodes.size() >= nodeLimit) break;\n\n            int nid = (int)nodes.size();\n            nodes.push_back(PQNode{nlo, nhi, nllo, nlhi, nf, it.id, cell, s.depth + 1});\n\n            long long eval = 1000LL * nf - (s.depth + 1);\n            pq.push(Item{eval, nf, s.depth + 1, nid});\n        }\n    }\n\n    return {};\n}\n\nint main() {\n    globalStart = chrono::steady_clock::now();\n\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D >> N;\n\n    rootR = 0;\n    rootC = (D - 1) / 2;\n\n    memset(obs, 0, sizeof(obs));\n    memset(gid, -1, sizeof(gid));\n\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = true;\n    }\n\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (r == rootR && c == rootC) continue;\n            if (obs[r][c]) continue;\n\n            gid[r][c] = (int)posi.size();\n            posi.push_back({r, c});\n        }\n    }\n\n    M = (int)posi.size();\n\n    adjList.assign(M, {});\n    isRootAdj.assign(M, 0);\n    adjLo.assign(M, 0);\n    adjHi.assign(M, 0);\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    for (int id = 0; id < M; id++) {\n        auto [r, c] = posi[id];\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc)) continue;\n\n            if (nr == rootR && nc == rootC) {\n                isRootAdj[id] = 1;\n            } else if (!obs[nr][nc]) {\n                int to = gid[nr][nc];\n                if (to >= 0) adjList[id].push_back(to);\n            }\n        }\n\n        if (isRootAdj[id]) rootAdjCells.push_back(id);\n    }\n\n    for (int i = 0; i < M; i++) {\n        for (int to : adjList[i]) {\n            if (to < 64) adjLo[i] |= 1ULL << to;\n            else adjHi[i] |= 1ULL << (to - 64);\n        }\n    }\n\n    // Stable BFS order from entrance.\n    int dist[9][9];\n    int disc[9][9];\n\n    for (int r = 0; r < 9; r++) {\n        for (int c = 0; c < 9; c++) {\n            dist[r][c] = INF;\n            disc[r][c] = INF;\n        }\n    }\n\n    int bfsDirs[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};\n    queue<pair<int,int>> q;\n\n    dist[rootR][rootC] = 0;\n    disc[rootR][rootC] = 0;\n\n    int dcnt = 1;\n    q.push({rootR, rootC});\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : bfsDirs) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != INF) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            disc[nr][nc] = dcnt++;\n            q.push({nr, nc});\n        }\n    }\n\n    orderP.resize(M);\n    iota(orderP.begin(), orderP.end(), 0);\n\n    sort(orderP.begin(), orderP.end(), [&](int a, int b) {\n        auto [ra, ca] = posi[a];\n        auto [rb, cb] = posi[b];\n\n        if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n        if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n\n        return a < b;\n    });\n\n    pIndex.assign(M, 0);\n    for (int i = 0; i < M; i++) pIndex[orderP[i]] = i;\n\n    assignedLabel.assign(M, -1);\n    unseenLabel.assign(M, 1);\n    emptyCnt = M;\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<int> cand = validPlacementCandidates();\n\n        vector<int> futureLabels;\n        futureLabels.reserve(emptyCnt - 1);\n\n        int rankLabel = 0;\n\n        for (int x = 0; x < M; x++) {\n            if (!unseenLabel[x]) continue;\n            if (x < t) rankLabel++;\n            if (x != t) futureLabels.push_back(x);\n        }\n\n        bool useLateLookahead = (emptyCnt <= 10 && emptyCnt >= 2 && !timeOver(1.20));\n\n        int bestCell = -1;\n        int bestHyp = INT_MAX;\n        int bestInv = INT_MAX;\n        int bestAbs = INT_MAX;\n        int bestNext = -1;\n        int bestPDiff = INT_MAX;\n        long long bestLateScore = LLONG_MAX / 4;\n\n        vector<int> lab(M);\n        int seqVals[85];\n\n        for (int c : cand) {\n            int ptr = 0;\n            int si = 0;\n\n            for (int cell : orderP) {\n                int v;\n\n                if (assignedLabel[cell] != -1) {\n                    v = assignedLabel[cell];\n                } else if (cell == c) {\n                    v = t;\n                } else {\n                    v = futureLabels[ptr++];\n                }\n\n                lab[cell] = v;\n                seqVals[si++] = v;\n            }\n\n            int fixedInv = invOfValues(seqVals);\n            int greedyInv = greedyCostLabels(lab);\n            int hyp = min(fixedInv, greedyInv);\n\n            int rankCell = 0;\n\n            for (int e = 0; e < M; e++) {\n                if (assignedLabel[e] == -1 && pIndex[e] < pIndex[c]) rankCell++;\n            }\n\n            int absDiff = abs(rankCell - rankLabel);\n\n            vector<int> nextCells;\n            int nextValid;\n\n            if (useLateLookahead) {\n                nextCells = collectNextValidAfter(c);\n                nextValid = (int)nextCells.size();\n            } else {\n                nextValid = countNextValidAfter(c);\n            }\n\n            int pDiff = abs(pIndex[c] - t);\n\n            long long lateScore = LLONG_MAX / 4;\n\n            if (useLateLookahead) {\n                long long sum = 0;\n\n                for (int u : futureLabels) {\n                    vector<int> future2;\n                    future2.reserve(futureLabels.size() - 1);\n\n                    for (int x : futureLabels) {\n                        if (x != u) future2.push_back(x);\n                    }\n\n                    int bestU = INF;\n\n                    for (int e : nextCells) {\n                        int val = evaluateHypWithExtra(c, t, e, u, future2, lab, seqVals);\n                        if (val < bestU) bestU = val;\n                    }\n\n                    sum += bestU;\n                }\n\n                lateScore = sum;\n            }\n\n            bool better = false;\n\n            if (useLateLookahead) {\n                if (lateScore != bestLateScore) better = lateScore < bestLateScore;\n                else if (hyp != bestHyp) better = hyp < bestHyp;\n                else if (fixedInv != bestInv) better = fixedInv < bestInv;\n                else if (absDiff != bestAbs) better = absDiff < bestAbs;\n                else if (nextValid != bestNext) better = nextValid > bestNext;\n                else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n            } else {\n                if (hyp != bestHyp) better = hyp < bestHyp;\n                else if (fixedInv != bestInv) better = fixedInv < bestInv;\n                else if (absDiff != bestAbs) better = absDiff < bestAbs;\n                else if (nextValid != bestNext) better = nextValid > bestNext;\n                else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n            }\n\n            if (better) {\n                bestLateScore = lateScore;\n                bestHyp = hyp;\n                bestInv = fixedInv;\n                bestAbs = absDiff;\n                bestNext = nextValid;\n                bestPDiff = pDiff;\n                bestCell = c;\n            }\n        }\n\n        if (bestCell == -1) bestCell = cand[0];\n\n        assignedLabel[bestCell] = t;\n        unseenLabel[t] = 0;\n        emptyCnt--;\n\n        cout << posi[bestCell].first << ' ' << posi[bestCell].second << endl;\n    }\n\n    vector<int> bestSeq = orderP;\n    int bestCost = sequenceCost(bestSeq, assignedLabel);\n\n    auto considerSeq = [&](vector<int> seq, int improveIter) {\n        if ((int)seq.size() != M) return;\n        if (!isLegalSequence(seq)) return;\n\n        int c0 = sequenceCost(seq, assignedLabel);\n\n        if (c0 < bestCost) {\n            bestCost = c0;\n            bestSeq = seq;\n        }\n\n        if (improveIter > 0) {\n            vector<int> imp = improveSequenceByInsertion(seq, assignedLabel, improveIter);\n\n            if (isLegalSequence(imp)) {\n                int c1 = sequenceCost(imp, assignedLabel);\n\n                if (c1 < bestCost) {\n                    bestCost = c1;\n                    bestSeq = imp;\n                }\n            }\n        }\n    };\n\n    vector<vector<int>> finalTemplates = buildFinalTemplates();\n\n    for (const auto &seq : finalTemplates) {\n        considerSeq(seq, 300);\n    }\n\n    vector<int> gseq = greedySequenceMinLabel(assignedLabel);\n    considerSeq(gseq, 1000);\n\n    vector<int> lseq = greedySequenceLookahead2(assignedLabel);\n    considerSeq(lseq, 1000);\n\n    vector<int> impBest = improveSequenceByInsertion(bestSeq, assignedLabel, 1000);\n    considerSeq(impBest, 0);\n\n    vector<int> bseq = beamSearchRemoval(assignedLabel, bestCost);\n    considerSeq(bseq, 1000);\n\n    if (!timeOver(1.74)) {\n        vector<int> blk = improveSequenceByBlockInsertion(bestSeq, assignedLabel, 60);\n        considerSeq(blk, 400);\n    }\n\n    if (!timeOver(1.76)) {\n        vector<int> aseq = bestFirstSearchRemoval(assignedLabel, bestCost, 120000);\n        considerSeq(aseq, 800);\n    }\n\n    if (!timeOver(1.84)) {\n        vector<int> blk = improveSequenceByBlockInsertion(bestSeq, assignedLabel, 40);\n        considerSeq(blk, 200);\n    }\n\n    if (!isLegalSequence(bestSeq)) {\n        bestSeq = orderP;\n    }\n\n    for (int cell : bestSeq) {\n        cout << posi[cell].first << ' ' << posi[cell].second << '\\n';\n    }\n\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 50;\nstatic const int MAXV = MAXN * MAXN;\nstatic const int MAXC = 105;\n\nint N, M, V;\nbool REQ[MAXC][MAXC];\nint GDEP[MAXC], DEGREQ[MAXC], NEED[MAXC];\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\n\nint visArr[MAXV];\nint bfsQ[MAXV];\nint visStamp = 1;\n\ninline int newStamp() {\n    ++visStamp;\n    if (visStamp == INT_MAX) {\n        memset(visArr, 0, sizeof(visArr));\n        visStamp = 1;\n    }\n    return visStamp;\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 RNG {\n    uint64_t s;\n    RNG(uint64_t seed = 1) : s(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (s += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    template<class T>\n    void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            swap(v[i], v[nextInt(i + 1)]);\n        }\n    }\n};\n\nstruct State {\n    array<unsigned char, MAXV> g;\n    int cnt[MAXC];\n    int edge[MAXC][MAXC];\n    int zeros;\n\n    void clear() {\n        g.fill(0);\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n        zeros = 0;\n    }\n\n    inline void addEdgeCnt(int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        edge[a][b] += d;\n        edge[b][a] += d;\n    }\n\n    void rebuild() {\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n\n        for (int p = 0; p < V; ++p) {\n            int a = g[p];\n            cnt[a]++;\n        }\n        zeros = cnt[0];\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int p = r * N + c;\n                int a = g[p];\n\n                if (r + 1 < N) addEdgeCnt(a, g[(r + 1) * N + c], 1);\n                if (c + 1 < N) addEdgeCnt(a, g[r * N + (c + 1)], 1);\n\n                if (r == 0) addEdgeCnt(0, a, 1);\n                if (r == N - 1) addEdgeCnt(0, a, 1);\n                if (c == 0) addEdgeCnt(0, a, 1);\n                if (c == N - 1) addEdgeCnt(0, a, 1);\n            }\n        }\n    }\n\n    inline bool hasZeroAdj(int p) const {\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return true;\n            int q = nr * N + nc;\n            if (g[q] == 0) return true;\n        }\n        return false;\n    }\n\n    bool connectedAfterRemoveColor(int p, int col) const {\n        if (cnt[col] <= 1) return false;\n\n        int r = p / N, c = p % N;\n        int nb[4], k = 0;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (g[q] == col) nb[k++] = q;\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        bool reached[4] = {};\n        reached[0] = true;\n        int found = 1;\n\n        visArr[nb[0]] = stamp;\n        bfsQ[tail++] = nb[0];\n\n        while (head < tail && found < k) {\n            int v = bfsQ[head++];\n            int vr = v / N, vc = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = vr + DR[d], nc = vc + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n\n                visArr[q] = stamp;\n\n                for (int i = 1; i < k; ++i) {\n                    if (!reached[i] && q == nb[i]) {\n                        reached[i] = true;\n                        ++found;\n                        break;\n                    }\n                }\n\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return found == k;\n    }\n\n    bool zeroConnectedAfterRemove(int p) const {\n        if (cnt[0] <= 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int q = r * N + c;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0] - 1;\n    }\n\n    bool connectedColorFull(int col) const {\n        if (col <= 0) return false;\n        if (cnt[col] <= 0) return false;\n\n        int start = -1;\n        for (int p = 0; p < V; ++p) {\n            if (g[p] == col) {\n                start = p;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        visArr[start] = stamp;\n        bfsQ[tail++] = start;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[col];\n    }\n\n    bool zeroConnectedFull() const {\n        if (cnt[0] == 0) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0];\n    }\n\n    bool tryChange(int p, int to) {\n        int from = g[p];\n        if (from == to) return false;\n        if (to < 0 || to > M) return false;\n\n        if (from > 0 && cnt[from] <= 1) return false;\n\n        if (to == 0) {\n            if (from == 0) return false;\n            if (!hasZeroAdj(p)) return false;\n        } else {\n            bool adjTarget = false;\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] == to) {\n                    adjTarget = true;\n                    break;\n                }\n            }\n            if (!adjTarget) return false;\n        }\n\n        int du[16], dv[16], dd[16], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            int nbcol = 0;\n            if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                nbcol = g[nr * N + nc];\n            }\n\n            addDelta(from, nbcol, -1);\n            addDelta(to, nbcol, +1);\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        if (from == 0) {\n            if (!zeroConnectedAfterRemove(p)) return false;\n        } else {\n            if (!connectedAfterRemoveColor(p, from)) return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        cnt[from]--;\n        cnt[to]++;\n\n        if (from == 0) zeros--;\n        if (to == 0) zeros++;\n\n        g[p] = (unsigned char)to;\n        return true;\n    }\n\n    bool tryChange2(int p, int np, int q, int nq) {\n        if (p == q) return false;\n\n        int op = g[p], oq = g[q];\n        if (op == np && oq == nq) return false;\n        if (np < 0 || np > M || nq < 0 || nq > M) return false;\n\n        int cc[8], cd[8], cn = 0;\n\n        auto addCntDelta = [&](int c, int d) {\n            if (d == 0) return;\n            for (int i = 0; i < cn; ++i) {\n                if (cc[i] == c) {\n                    cd[i] += d;\n                    return;\n                }\n            }\n            cc[cn] = c;\n            cd[cn] = d;\n            ++cn;\n        };\n\n        addCntDelta(op, -1);\n        addCntDelta(oq, -1);\n        addCntDelta(np, +1);\n        addCntDelta(nq, +1);\n\n        for (int i = 0; i < cn; ++i) {\n            if (cc[i] > 0 && cnt[cc[i]] + cd[i] <= 0) return false;\n        }\n\n        int du[40], dv[40], dd[40], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        auto oldCol = [&](int x) -> int {\n            if (x == p) return op;\n            if (x == q) return oq;\n            return g[x];\n        };\n\n        auto newCol = [&](int x) -> int {\n            if (x == p) return np;\n            if (x == q) return nq;\n            return g[x];\n        };\n\n        int cells[2] = {p, q};\n\n        for (int ii = 0; ii < 2; ++ii) {\n            int x = cells[ii];\n            int xr = x / N, xc = x % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = xr + DR[d], nc = xc + DC[d];\n\n                int a0 = oldCol(x);\n                int a1 = newCol(x);\n                int b0, b1;\n\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                    b0 = b1 = 0;\n                } else {\n                    int y = nr * N + nc;\n                    if ((y == p || y == q) && x > y) continue;\n                    b0 = oldCol(y);\n                    b1 = newCol(y);\n                }\n\n                addDelta(a0, b0, -1);\n                addDelta(a1, b1, +1);\n            }\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        g[p] = (unsigned char)np;\n        g[q] = (unsigned char)nq;\n\n        for (int i = 0; i < cn; ++i) cnt[cc[i]] += cd[i];\n        zeros = cnt[0];\n\n        int aff[4], an = 0;\n        auto addAff = [&](int c) {\n            for (int i = 0; i < an; ++i) {\n                if (aff[i] == c) return;\n            }\n            aff[an++] = c;\n        };\n\n        addAff(op);\n        addAff(oq);\n        addAff(np);\n        addAff(nq);\n\n        bool ok = true;\n        for (int i = 0; i < an && ok; ++i) {\n            int c = aff[i];\n            if (c == 0) ok = zeroConnectedFull();\n            else ok = connectedColorFull(c);\n        }\n\n        if (!ok) {\n            for (int i = 0; i < cn; ++i) cnt[cc[i]] -= cd[i];\n            zeros = cnt[0];\n            g[p] = (unsigned char)op;\n            g[q] = (unsigned char)oq;\n            return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        return true;\n    }\n};\n\nvoid computeGraphInfo() {\n    for (int i = 0; i <= M; ++i) {\n        DEGREQ[i] = 0;\n        for (int j = 0; j <= M; ++j) {\n            if (i != j && REQ[i][j]) DEGREQ[i]++;\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        NEED[i] = max(1, (DEGREQ[i] - 1) / 2);\n    }\n    NEED[0] = 0;\n\n    fill(GDEP, GDEP + MAXC, 1000000);\n    queue<int> q;\n    GDEP[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u = 0; u <= M; ++u) {\n            if (!REQ[v][u]) continue;\n            if (GDEP[u] > GDEP[v] + 1) {\n                GDEP[u] = GDEP[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        if (GDEP[i] > 100000) GDEP[i] = 50;\n    }\n}\n\nvoid computeDist(const State& st, vector<int>& dist) {\n    const int INF = 1e9;\n    dist.assign(V, INF);\n\n    int head = 0, tail = 0;\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] == 0) {\n            dist[p] = 0;\n            bfsQ[tail++] = p;\n        }\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n            int p = r * N + c;\n            if (dist[p] > 1) {\n                dist[p] = 1;\n                bfsQ[tail++] = p;\n            }\n        }\n    }\n\n    while (head < tail) {\n        int v = bfsQ[head++];\n        int r = v / N, c = v % N;\n        int nd = dist[v] + 1;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (dist[q] > nd) {\n                dist[q] = nd;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n}\n\nint greedyDelete(State& st, RNG& rng, int mode = 0) {\n    vector<int> cand;\n    cand.reserve(V * 5);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0 && st.hasZeroAdj(p)) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    if (mode == 1) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            int sa = st.cnt[ca] - NEED[ca];\n            int sb = st.cnt[cb] - NEED[cb];\n            if (sa != sb) return sa > sb;\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 2) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (st.cnt[ca] != st.cnt[cb]) return st.cnt[ca] > st.cnt[cb];\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 3) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return st.cnt[ca] > st.cnt[cb];\n        });\n    }\n\n    int deleted = 0;\n\n    for (size_t idx = 0; idx < cand.size(); ++idx) {\n        int p = cand[idx];\n        if (st.g[p] == 0) continue;\n        if (!st.hasZeroAdj(p)) continue;\n\n        if (st.tryChange(p, 0)) {\n            ++deleted;\n\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) cand.push_back(q);\n            }\n        }\n    }\n\n    return deleted;\n}\n\nint greedyDeleteMulti(State& st, RNG& rng, int repeats, int modeBase) {\n    int old = st.zeros;\n    if (repeats <= 1) {\n        greedyDelete(st, rng, modeBase & 3);\n        return st.zeros - old;\n    }\n\n    State base = st;\n    State best = st;\n\n    for (int r = 0; r < repeats; ++r) {\n        State tmp = base;\n        greedyDelete(tmp, rng, (modeBase + r) & 3);\n        if (tmp.zeros > best.zeros) best = tmp;\n    }\n\n    st = best;\n    return st.zeros - old;\n}\n\nstruct Params {\n    int strategy;\n    int orderMode;\n    int eqProb;\n    bool useLayer;\n    bool targetRandom;\n    bool preDelete;\n    int delRepeats;\n    int delMode;\n};\n\nParams getParams(int run) {\n    switch (run % 20) {\n        case 0:  return {0, 0,  0, false, false, true,  1, 0};\n        case 1:  return {0, 0, 10, true,  false, true,  1, 1};\n        case 2:  return {1, 0, 15, false, false, true,  1, 0};\n        case 3:  return {1, 3, 20, true,  false, true,  1, 1};\n        case 4:  return {3, 0, 15, false, false, true,  1, 2};\n        case 5:  return {4, 0, 10, false, false, true,  1, 1};\n        case 6:  return {2, 1,  0, false, true,  true,  1, 0};\n        case 7:  return {0, 1, 30, false, true,  true,  1, 2};\n        case 8:  return {1, 4, 25, false, false, false, 1, 3};\n        case 9:  return {3, 3, 20, true,  false, false, 1, 1};\n        case 10: return {0, 2,  0, false, true,  true,  1, 0};\n        case 11: return {4, 1, 20, false, true,  true,  1, 2};\n        case 12: return {1, 0,  0, true,  false, true,  2, 0};\n        case 13: return {3, 0, 30, false, false, true,  2, 1};\n        case 14: return {2, 1,  0, false, true,  false, 1, 0};\n        case 15: return {0, 0, 50, false, true,  false, 1, 1};\n        case 16: return {1, 3, 40, false, true,  false, 1, 2};\n        case 17: return {4, 3, 30, true,  false, true,  1, 3};\n        case 18: return {3, 1, 10, false, true,  true,  2, 0};\n        default: return {0, 0, 20, true,  false, true,  1, 0};\n    }\n}\n\nint recolorPass(State& st, const vector<int>& dist, RNG& rng, const Params& par) {\n    const int INF = 1e9;\n\n    int layer[MAXC];\n    for (int i = 0; i < MAXC; ++i) layer[i] = INF;\n    layer[0] = 0;\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a > 0) layer[a] = min(layer[a], dist[p]);\n    }\n\n    vector<int> order;\n    order.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) order.push_back(p);\n    }\n\n    rng.shuffleVec(order);\n\n    if (par.orderMode == 0) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 2) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n    } else if (par.orderMode == 3) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] > GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 4) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    }\n\n    struct Target {\n        int col;\n        int score;\n        int td;\n        int gd;\n        int rnd;\n    };\n\n    int changed = 0;\n\n    for (int p : order) {\n        int a = st.g[p];\n        if (a == 0) continue;\n        if (st.cnt[a] <= 1) continue;\n\n        int dp = dist[p];\n        int r = p / N, c = p % N;\n\n        Target ts[4];\n        int tn = 0;\n\n        auto addTarget = [&](int b, int dq, int score) {\n            int pos = -1;\n            for (int i = 0; i < tn; ++i) {\n                if (ts[i].col == b) {\n                    pos = i;\n                    break;\n                }\n            }\n\n            if (pos == -1) {\n                ts[tn++] = {b, score, dq, GDEP[b], (int)(rng.next() & 0x7fffffff)};\n            } else {\n                if (score > ts[pos].score) {\n                    ts[pos].score = score;\n                    ts[pos].td = min(ts[pos].td, dq);\n                }\n            }\n        };\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int q = nr * N + nc;\n            int b = st.g[q];\n            if (b == 0 || b == a) continue;\n\n            int dq = dist[q];\n            bool ok = false;\n            int score = 0;\n\n            if (par.strategy == 0) {\n                ok = (dq < dp) || (dq == dp && par.eqProb > 0 && rng.nextInt(100) < par.eqProb);\n                if (par.useLayer && layer[b] > layer[a]) ok = false;\n                score = (dp - dq) * 20 + (layer[a] - layer[b]) * 3 + (GDEP[a] - GDEP[b]);\n            } else if (par.strategy == 1) {\n                int da = GDEP[a], db = GDEP[b];\n                ok = (db < da) ||\n                     (db == da && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (dq < dp && db <= da + 1);\n\n                if (par.useLayer && layer[b] > layer[a] + 1) ok = false;\n                score = (da - db) * 30 + (dp - dq) * 5 + (layer[a] - layer[b]);\n            } else if (par.strategy == 2) {\n                ok = true;\n                score = (int)(rng.next() & 0xffff);\n            } else if (par.strategy == 3) {\n                int val =\n                    (GDEP[a] - GDEP[b]) * 18 +\n                    (dp - dq) * 7 +\n                    (layer[a] - layer[b]) * 4 +\n                    ((st.cnt[a] - NEED[a]) - (st.cnt[b] - NEED[b]));\n\n                ok = (val > 0) ||\n                     (val == 0 && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (rng.nextInt(100) < 4);\n\n                score = val;\n            } else {\n                int surplusA = st.cnt[a] - NEED[a];\n                int surplusB = st.cnt[b] - NEED[b];\n                int val =\n                    (surplusA - surplusB) * 5 +\n                    (GDEP[a] - GDEP[b]) * 8 +\n                    (dp - dq) * 3;\n\n                ok = (val > 0) ||\n                     (par.eqProb > 0 && rng.nextInt(100) < par.eqProb / 2);\n\n                score = val;\n            }\n\n            if (!ok) continue;\n            addTarget(b, dq, score);\n        }\n\n        if (tn == 0) continue;\n\n        if (par.targetRandom || par.strategy == 2) {\n            for (int i = tn - 1; i > 0; --i) {\n                swap(ts[i], ts[rng.nextInt(i + 1)]);\n            }\n        } else {\n            for (int i = 0; i < tn; ++i) {\n                for (int j = i + 1; j < tn; ++j) {\n                    bool better = false;\n                    if (ts[j].score != ts[i].score) {\n                        better = ts[j].score > ts[i].score;\n                    } else if (ts[j].td != ts[i].td) {\n                        better = ts[j].td < ts[i].td;\n                    } else if (ts[j].gd != ts[i].gd) {\n                        better = ts[j].gd < ts[i].gd;\n                    } else {\n                        better = ts[j].rnd < ts[i].rnd;\n                    }\n                    if (better) swap(ts[i], ts[j]);\n                }\n            }\n        }\n\n        for (int i = 0; i < tn; ++i) {\n            if (st.tryChange(p, ts[i].col)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid improve(State& st, State& best, RNG& rng, const Params& par, const Timer& timer, double limit) {\n    vector<int> dist;\n    int lastZeros = st.zeros;\n    int stagnant = 0;\n\n    for (int cycle = 0; cycle < 80; ++cycle) {\n        if (timer.elapsed() > limit) break;\n\n        int del = 0;\n\n        if (par.preDelete) {\n            del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode);\n            if (st.zeros > best.zeros) best = st;\n        }\n\n        computeDist(st, dist);\n        int rec = recolorPass(st, dist, rng, par);\n\n        del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode + cycle);\n        if (st.zeros > best.zeros) best = st;\n\n        if (st.zeros > lastZeros) {\n            lastZeros = st.zeros;\n            stagnant = 0;\n        } else {\n            ++stagnant;\n        }\n\n        if (rec + del == 0) break;\n\n        int maxStag = 4;\n        if (par.strategy == 2) maxStag = 3;\n        if (par.eqProb >= 30) maxStag++;\n        if (par.delRepeats >= 2) maxStag++;\n\n        if (stagnant >= maxStag) break;\n    }\n}\n\nint randomInterfaceRecolorPass(State& st, RNG& rng, int limitChanges) {\n    vector<int> cells;\n    cells.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b > 0 && b != a) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cells.push_back(p);\n    }\n\n    rng.shuffleVec(cells);\n\n    int changed = 0;\n\n    for (int p : cells) {\n        if (changed >= limitChanges) break;\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b == 0 || b == a) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint randomExpandPass(State& st, RNG& rng, int quota) {\n    vector<int> cand;\n    cand.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            if (st.g[nr * N + nc] > 0) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n\n    for (int p : cand) {\n        if (changed >= quota) break;\n        if (st.g[p] != 0) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b <= 0) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint swapPass(State& st, RNG& rng, int maxTries, int mode) {\n    vector<pair<int, int>> cand;\n    cand.reserve(2 * V);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n\n            if (r + 1 < N) {\n                int q = (r + 1) * N + c;\n                int a = st.g[p], b = st.g[q];\n                if (a != b) {\n                    bool z = (a == 0 || b == 0);\n                    if (mode == 2 || (mode == 0 && z) || (mode == 1 && !z)) {\n                        cand.push_back({p, q});\n                    }\n                }\n            }\n\n            if (c + 1 < N) {\n                int q = r * N + (c + 1);\n                int a = st.g[p], b = st.g[q];\n                if (a != b) {\n                    bool z = (a == 0 || b == 0);\n                    if (mode == 2 || (mode == 0 && z) || (mode == 1 && !z)) {\n                        cand.push_back({p, q});\n                    }\n                }\n            }\n        }\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n    int tried = 0;\n\n    for (auto [p, q] : cand) {\n        if (tried >= maxTries) break;\n\n        int a = st.g[p], b = st.g[q];\n        if (a == b) continue;\n\n        bool z = (a == 0 || b == 0);\n        if (!(mode == 2 || (mode == 0 && z) || (mode == 1 && !z))) continue;\n\n        ++tried;\n        if (st.tryChange2(p, b, q, a)) {\n            ++changed;\n        }\n    }\n\n    return changed;\n}\n\nint pairDeletePass(State& st, RNG& rng, int maxTries, int mode) {\n    vector<pair<int, int>> cand;\n    cand.reserve(2 * V);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n            int a = st.g[p];\n\n            if (r + 1 < N) {\n                int q = (r + 1) * N + c;\n                int b = st.g[q];\n                if (a > 0 && b > 0 && a != b && (st.hasZeroAdj(p) || st.hasZeroAdj(q))) {\n                    cand.push_back({p, q});\n                }\n            }\n\n            if (c + 1 < N) {\n                int q = r * N + (c + 1);\n                int b = st.g[q];\n                if (a > 0 && b > 0 && a != b && (st.hasZeroAdj(p) || st.hasZeroAdj(q))) {\n                    cand.push_back({p, q});\n                }\n            }\n        }\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n    int tried = 0;\n\n    struct Var {\n        int np, nq;\n        int score;\n    };\n\n    for (auto [p, q] : cand) {\n        if (tried >= maxTries) break;\n\n        int a = st.g[p], b = st.g[q];\n        if (a <= 0 || b <= 0 || a == b) continue;\n\n        bool hp = st.hasZeroAdj(p);\n        bool hq = st.hasZeroAdj(q);\n        if (!hp && !hq) continue;\n\n        ++tried;\n\n        Var vars[2];\n        int vn = 0;\n\n        if (hp) {\n            int lost = b;\n            int invader = a;\n            int score =\n                (st.cnt[lost] - NEED[lost]) * 12 +\n                (GDEP[lost] - GDEP[invader]) * 5 -\n                DEGREQ[lost];\n            vars[vn++] = {0, a, score};\n        }\n\n        if (hq) {\n            int lost = a;\n            int invader = b;\n            int score =\n                (st.cnt[lost] - NEED[lost]) * 12 +\n                (GDEP[lost] - GDEP[invader]) * 5 -\n                DEGREQ[lost];\n            vars[vn++] = {b, 0, score};\n        }\n\n        if (vn == 2) {\n            bool firstSecond = false;\n            if (mode == 0) {\n                firstSecond = rng.nextInt(2);\n            } else if (mode == 3) {\n                firstSecond = vars[1].score < vars[0].score;\n            } else {\n                firstSecond = vars[1].score > vars[0].score;\n            }\n            if (firstSecond) swap(vars[0], vars[1]);\n        }\n\n        for (int i = 0; i < vn; ++i) {\n            if (st.tryChange2(p, vars[i].np, q, vars[i].nq)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid shakeSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    while (timer.elapsed() < limit) {\n        State st = best;\n\n        int rounds = 3 + rng.nextInt(4);\n\n        for (int rd = 0; rd < rounds; ++rd) {\n            if (timer.elapsed() >= limit) break;\n\n            if (st.zeros > best.zeros - 25) {\n                randomExpandPass(st, rng, 2 + rng.nextInt(7));\n            }\n\n            randomInterfaceRecolorPass(st, rng, 80 + rng.nextInt(160));\n            pairDeletePass(st, rng, 120 + rng.nextInt(220), rng.nextInt(4));\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n\n            if (st.zeros > best.zeros) {\n                best = st;\n            }\n\n            if (st.zeros + 30 < best.zeros) break;\n        }\n    }\n}\n\nvoid neutralSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    State cur = best;\n    int stagnant = 0;\n\n    while (timer.elapsed() < limit) {\n        if (stagnant > 9) {\n            cur = best;\n            stagnant = 0;\n        }\n\n        int before = cur.zeros;\n        int total = 0;\n\n        total += pairDeletePass(cur, rng, 300 + rng.nextInt(450), rng.nextInt(4));\n\n        if (total == 0) {\n            total += swapPass(cur, rng, 180 + rng.nextInt(320), rng.nextInt(3));\n            total += randomInterfaceRecolorPass(cur, rng, 50 + rng.nextInt(130));\n            total += pairDeletePass(cur, rng, 180 + rng.nextInt(260), rng.nextInt(4));\n        }\n\n        total += greedyDeleteMulti(cur, rng, 1, rng.nextInt(4));\n\n        if (cur.zeros > best.zeros) {\n            best = cur;\n            stagnant = 0;\n        } else {\n            if (cur.zeros < best.zeros) cur = best;\n            if (cur.zeros == before && total == 0) stagnant += 2;\n            else stagnant++;\n        }\n    }\n}\n\nbool validUsingState(const State& st) {\n    for (int c = 1; c <= M; ++c) {\n        if (st.cnt[c] <= 0) return false;\n    }\n\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if ((st.edge[i][j] > 0) != REQ[i][j]) return false;\n        }\n    }\n\n    if (!st.zeroConnectedFull()) return false;\n\n    for (int c = 1; c <= M; ++c) {\n        if (!st.connectedColorFull(c)) return false;\n    }\n\n    return true;\n}\n\nstruct BandOp {\n    int type;\n    int idx;\n    int len;\n};\n\nvoid applyBandDelete(State& out, const State& st, int type, int idx, int len) {\n    out = st;\n\n    if (type == 0) {\n        // remove rows [idx, idx+len), shift lower rows upward, add zero rows at bottom\n        for (int r = idx; r + len < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = st.g[(r + len) * N + c];\n            }\n        }\n        for (int r = N - len; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else if (type == 1) {\n        // remove rows [idx, idx+len), shift upper rows downward, add zero rows at top\n        for (int r = idx + len - 1; r >= len; --r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = st.g[(r - len) * N + c];\n            }\n        }\n        for (int r = 0; r < len; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else if (type == 2) {\n        // remove columns [idx, idx+len), shift right columns left, add zero columns at right\n        for (int r = 0; r < N; ++r) {\n            for (int c = idx; c + len < N; ++c) {\n                out.g[r * N + c] = st.g[r * N + (c + len)];\n            }\n            for (int c = N - len; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else {\n        // remove columns [idx, idx+len), shift left columns right, add zero columns at left\n        for (int r = 0; r < N; ++r) {\n            for (int c = idx + len - 1; c >= len; --c) {\n                out.g[r * N + c] = st.g[r * N + (c - len)];\n            }\n            for (int c = 0; c < len; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    }\n\n    out.rebuild();\n}\n\nbool compactBandsOnce(State& st, RNG& rng, const Timer& timer, double limit, int mode, int maxLen) {\n    vector<BandOp> ops;\n    ops.reserve(4 * N * maxLen);\n\n    for (int len = 1; len <= maxLen; ++len) {\n        for (int idx = 0; idx + len <= N; ++idx) {\n            for (int type = 0; type < 4; ++type) {\n                ops.push_back({type, idx, len});\n            }\n        }\n    }\n\n    rng.shuffleVec(ops);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyBandDelete(tmp, st, op.type, op.idx, op.len);\n\n        if (tmp.zeros <= st.zeros) continue;\n\n        if (!validUsingState(tmp)) continue;\n\n        if (mode == 1) {\n            st = tmp;\n            return true;\n        }\n\n        if (!found || tmp.zeros > best.zeros) {\n            best = tmp;\n            found = true;\n        }\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nvoid compactBandSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    int fail = 0;\n\n    while (timer.elapsed() < limit && fail < 4) {\n        State st = best;\n\n        int steps = 0;\n        int mode = (fail == 0 ? 0 : 1);\n        int maxLen = (fail >= 2 ? 3 : 2);\n\n        while (timer.elapsed() < limit && steps < 5) {\n            bool ok = compactBandsOnce(st, rng, timer, limit, mode, maxLen);\n            if (!ok) break;\n\n            ++steps;\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n        }\n\n        if (st.zeros > best.zeros) {\n            best = st;\n            fail = 0;\n        } else {\n            ++fail;\n        }\n    }\n}\n\nbool validateState(const State& st) {\n    static int cnt2[MAXC];\n    static int ed2[MAXC][MAXC];\n\n    memset(cnt2, 0, sizeof(cnt2));\n    memset(ed2, 0, sizeof(ed2));\n\n    auto add = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        ed2[a][b]++;\n        ed2[b][a]++;\n    };\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a < 0 || a > M) return false;\n        cnt2[a]++;\n    }\n\n    for (int c = 1; c <= M; ++c) {\n        if (cnt2[c] == 0) return false;\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n            int a = st.g[p];\n\n            if (r + 1 < N) add(a, st.g[(r + 1) * N + c]);\n            if (c + 1 < N) add(a, st.g[r * N + (c + 1)]);\n\n            if (r == 0) add(0, a);\n            if (r == N - 1) add(0, a);\n            if (c == 0) add(0, a);\n            if (c == N - 1) add(0, a);\n        }\n    }\n\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if ((ed2[i][j] > 0) != REQ[i][j]) return false;\n        }\n    }\n\n    for (int col = 1; col <= M; ++col) {\n        int start = -1;\n\n        for (int p = 0; p < V; ++p) {\n            if (st.g[p] == col) {\n                start = p;\n                break;\n            }\n        }\n\n        if (start == -1) return false;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        visArr[start] = stamp;\n        bfsQ[tail++] = start;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != cnt2[col]) return false;\n    }\n\n    if (cnt2[0] > 0) {\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (st.g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != cnt2[0]) return false;\n    }\n\n    return true;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    V = N * N;\n\n    State init;\n    init.clear();\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int x;\n            cin >> x;\n            init.g[i * N + j] = (unsigned char)x;\n\n            seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    init.rebuild();\n\n    memset(REQ, 0, sizeof(REQ));\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if (init.edge[i][j] > 0) {\n                REQ[i][j] = REQ[j][i] = true;\n            }\n        }\n    }\n\n    computeGraphInfo();\n\n    Timer timer;\n\n    const double MAIN_LIMIT = 1.55;\n    const double SHAKE_LIMIT = 1.73;\n    const double NEUTRAL_LIMIT = 1.83;\n    const double COMPACT_LIMIT = 1.89;\n    const double POLISH_LIMIT = 1.925;\n\n    State best = init;\n\n    int run = 0;\n    while (timer.elapsed() < MAIN_LIMIT) {\n        State st;\n\n        if (run >= 4 && run % 3 == 2) {\n            st = best;\n        } else {\n            st = init;\n        }\n\n        uint64_t rseed =\n            seed\n            + 0x9e3779b97f4a7c15ULL * (uint64_t)(run + 1)\n            + 0xbf58476d1ce4e5b9ULL * (uint64_t)(best.zeros + 1);\n\n        RNG rng(rseed);\n        Params par = getParams(run);\n\n        improve(st, best, rng, par, timer, MAIN_LIMIT);\n        ++run;\n    }\n\n    RNG shakeRng(seed ^ 0xd1b54a32d192ed03ULL ^ (uint64_t)best.zeros);\n    shakeSearch(best, shakeRng, timer, SHAKE_LIMIT);\n\n    RNG neutralRng(seed ^ 0x6a09e667f3bcc909ULL ^ ((uint64_t)best.zeros << 17));\n    neutralSearch(best, neutralRng, timer, NEUTRAL_LIMIT);\n\n    RNG compactRng(seed ^ 0xbb67ae8584caa73bULL ^ ((uint64_t)best.zeros << 9));\n    compactBandSearch(best, compactRng, timer, COMPACT_LIMIT);\n\n    RNG finalRng(seed ^ 0x94d049bb133111ebULL);\n    while (timer.elapsed() < POLISH_LIMIT) {\n        int before = best.zeros;\n\n        for (int mode = 0; mode < 4; ++mode) {\n            if (timer.elapsed() >= POLISH_LIMIT) break;\n            greedyDelete(best, finalRng, mode);\n            pairDeletePass(best, finalRng, 250, mode);\n            greedyDelete(best, finalRng, mode);\n        }\n\n        if (best.zeros == before) {\n            State tmp = best;\n            swapPass(tmp, finalRng, 300, finalRng.nextInt(3));\n            randomInterfaceRecolorPass(tmp, finalRng, 90);\n            pairDeletePass(tmp, finalRng, 350, finalRng.nextInt(4));\n            greedyDelete(tmp, finalRng, finalRng.nextInt(4));\n\n            if (tmp.zeros > best.zeros) {\n                best = tmp;\n            } else {\n                break;\n            }\n        }\n    }\n\n    if (!validateState(best)) {\n        best = init;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (j) cout << ' ';\n            cout << (int)best.g[i * N + j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, D, Q;\nint qUsed = 0;\nmt19937_64 rng;\nvector<vector<char>> itemCmp;\n\nconstexpr int DP_SCALE_BASE = 500;\nconstexpr int DP_SUM_LIMIT = 80000;\n\nstruct Solution {\n    vector<int> assign;\n    vector<vector<int>> bins;\n    vector<double> load;\n    double obj = 1e100;\n};\n\nchar invCmp(char c) {\n    if (c == '>') return '<';\n    if (c == '<') return '>';\n    return c;\n}\n\nchar ask(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    if (!(cin >> s)) exit(0);\n    qUsed++;\n    return s[0];\n}\n\nchar compareItems(int a, int b) {\n    if (a == b) return '=';\n    if (itemCmp[a][b] != '?') return itemCmp[a][b];\n    if (qUsed >= Q) return '?';\n\n    vector<int> L{a}, R{b};\n    char c = ask(L, R);\n    itemCmp[a][b] = c;\n    itemCmp[b][a] = invCmp(c);\n    return c;\n}\n\ndouble norm_pdf(double x) {\n    static const double INV_SQRT_2PI = 1.0 / sqrt(2.0 * acos(-1.0));\n    if (abs(x) > 40) return 0.0;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble norm_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble truncatedNormalMean(double mu, double sd, double lo, double hi) {\n    if (sd < 1e-12) return clamp(mu, lo, hi);\n\n    double a = (lo - mu) / sd;\n    double b = (hi - mu) / sd;\n    double A = norm_cdf(a);\n    double B = norm_cdf(b);\n    double Z = B - A;\n\n    if (Z < 1e-14) {\n        if (mu < lo) return lo;\n        if (mu > hi) return hi;\n        return clamp(mu, lo, hi);\n    }\n\n    double mean = mu + sd * (norm_pdf(a) - norm_pdf(b)) / Z;\n    return clamp(mean, lo, hi);\n}\n\nvector<double> estimateWeights(const vector<double>& score, int qRand) {\n    vector<double> est(N, 1.0);\n    if (qRand <= 0) return est;\n\n    const double PI = acos(-1.0);\n    const double c = sqrt(2.0 / PI);\n\n    int K = N / 2;\n    double pNonZero = 2.0 * K / N;\n    double lambda = 2.0 * K / (N - 1.0);\n    double ce = c * sqrt(lambda);\n\n    double sigmaZ = sqrt(pNonZero * N) / (ce * sqrt((double)qRand));\n\n    // Prior: Exp(1), truncated at b=N/D, then normalized to mean 1.\n    double cap = (double)N / D;\n    double e = exp(-cap);\n    double Z = 1.0 - e;\n    double meanX = (1.0 - (cap + 1.0) * e) / Z;\n    double secondX = (2.0 - (cap * cap + 2.0 * cap + 2.0) * e) / Z;\n    double varX = max(1e-12, secondX - meanX * meanX);\n    double cv = sqrt(varX) / meanX;\n    double rMax = cap / meanX;\n\n    double tau = max(1e-6, cv * sigmaZ);\n    double rate = meanX;\n\n    for (int i = 0; i < N; i++) {\n        double zObs = score[i] * sqrt((double)N) / (ce * qRand);\n        double obsR = 1.0 + cv * zObs;\n\n        // Posterior with exponential prior:\n        // exp(-rate*r) * Normal(obsR | r, tau^2)\n        double mu = obsR - rate * tau * tau;\n        est[i] = truncatedNormalMean(mu, tau, 0.0, rMax);\n        est[i] = max(est[i], 1e-6);\n    }\n\n    return est;\n}\n\ndouble totalWeight(const vector<double>& w) {\n    return accumulate(w.begin(), w.end(), 0.0);\n}\n\ndouble sqr(double x) {\n    return x * x;\n}\n\ndouble calcObjLoad(const vector<double>& load, double target) {\n    double res = 0.0;\n    for (double x : load) {\n        double d = x - target;\n        res += d * d;\n    }\n    return res;\n}\n\nSolution buildSolution(const vector<int>& assign, const vector<double>& w) {\n    Solution sol;\n    sol.assign = assign;\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    for (int i = 0; i < N; i++) {\n        int b = sol.assign[i];\n        sol.bins[b].push_back(i);\n        sol.load[b] += w[i];\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nvoid eraseItem(vector<int>& v, int x) {\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (v[i] == x) {\n            v[i] = v.back();\n            v.pop_back();\n            return;\n        }\n    }\n}\n\nvoid moveItemSol(Solution& sol, int item, int from, int to, const vector<double>& w) {\n    eraseItem(sol.bins[from], item);\n    sol.bins[to].push_back(item);\n    sol.assign[item] = to;\n    sol.load[from] -= w[item];\n    sol.load[to] += w[item];\n}\n\nvoid swapItemsSol(Solution& sol, int x, int y, int bx, int by, const vector<double>& w) {\n    for (int& v : sol.bins[bx]) {\n        if (v == x) {\n            v = y;\n            break;\n        }\n    }\n    for (int& v : sol.bins[by]) {\n        if (v == y) {\n            v = x;\n            break;\n        }\n    }\n\n    sol.assign[x] = by;\n    sol.assign[y] = bx;\n\n    sol.load[bx] += w[y] - w[x];\n    sol.load[by] += w[x] - w[y];\n}\n\nvoid localImprove(Solution& sol, const vector<double>& w, double target) {\n    for (int iter = 0; iter < 2000; iter++) {\n        double bestDelta = -1e-12;\n        int bestType = 0;\n        int bestI = -1, bestJ = -1;\n        int bestA = -1, bestB = -1;\n\n        // Single-item move\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            if ((int)sol.bins[a].size() <= 1) continue;\n\n            for (int b = 0; b < D; b++) {\n                if (a == b) continue;\n\n                double oldVal =\n                    sqr(sol.load[a] - target) +\n                    sqr(sol.load[b] - target);\n\n                double newVal =\n                    sqr(sol.load[a] - w[i] - target) +\n                    sqr(sol.load[b] + w[i] - target);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        // Swap\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            for (int j = i + 1; j < N; j++) {\n                int b = sol.assign[j];\n                if (a == b) continue;\n\n                double oldVal =\n                    sqr(sol.load[a] - target) +\n                    sqr(sol.load[b] - target);\n\n                double newVal =\n                    sqr(sol.load[a] - w[i] + w[j] - target) +\n                    sqr(sol.load[b] - w[j] + w[i] - target);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestI = i;\n                    bestJ = j;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        if (bestType == 0) break;\n\n        if (bestType == 1) {\n            moveItemSol(sol, bestI, bestA, bestB, w);\n        } else {\n            swapItemsSol(sol, bestI, bestJ, bestA, bestB, w);\n        }\n\n        sol.obj += bestDelta;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nbool pairBalanceDP(Solution& sol, int a, int b, const vector<double>& w, double target) {\n    vector<int> items = sol.bins[a];\n    for (int x : sol.bins[b]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 1) return false;\n\n    double pairSum = sol.load[a] + sol.load[b];\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(w[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1);\n    vector<int> parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    int bestS = -1;\n    int bestDiff = INT_MAX;\n    for (int s = 0; s <= total; s++) {\n        if (!dp[s]) continue;\n        int diff = abs(total - 2 * s);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestS = s;\n        }\n    }\n\n    if (bestS < 0) return false;\n\n    vector<char> inA(M, 0);\n    int cur = bestS;\n    while (cur > 0) {\n        int idx = parItem[cur];\n        if (idx < 0) return false;\n        inA[idx] = 1;\n        cur = parPrev[cur];\n    }\n\n    int cntA = 0;\n    double loadA = 0.0;\n    for (int i = 0; i < M; i++) {\n        if (inA[i]) {\n            cntA++;\n            loadA += w[items[i]];\n        }\n    }\n\n    if (cntA == 0 || cntA == M) return false;\n\n    double loadB = pairSum - loadA;\n\n    // Keep orientation closer to the previous one.\n    double keepCost = abs(loadA - sol.load[a]) + abs(loadB - sol.load[b]);\n    double flipCost = abs(loadB - sol.load[a]) + abs(loadA - sol.load[b]);\n    if (flipCost < keepCost) {\n        for (char& x : inA) x ^= 1;\n        swap(loadA, loadB);\n        cntA = M - cntA;\n    }\n\n    double oldPair =\n        sqr(sol.load[a] - target) +\n        sqr(sol.load[b] - target);\n\n    double newPair =\n        sqr(loadA - target) +\n        sqr(loadB - target);\n\n    if (newPair >= oldPair - 1e-12) return false;\n\n    sol.bins[a].clear();\n    sol.bins[b].clear();\n    sol.load[a] = 0.0;\n    sol.load[b] = 0.0;\n\n    for (int i = 0; i < M; i++) {\n        int item = items[i];\n        if (inA[i]) {\n            sol.assign[item] = a;\n            sol.bins[a].push_back(item);\n            sol.load[a] += w[item];\n        } else {\n            sol.assign[item] = b;\n            sol.bins[b].push_back(item);\n            sol.load[b] += w[item];\n        }\n    }\n\n    sol.obj += newPair - oldPair;\n    return true;\n}\n\nvoid improveSolution(Solution& sol, const vector<double>& w, int sweeps) {\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n\n    localImprove(sol, w, target);\n\n    for (int sw = 0; sw < sweeps; sw++) {\n        double before = sol.obj;\n        vector<tuple<double, int, int>> pairs;\n\n        for (int a = 0; a < D; a++) {\n            for (int b = a + 1; b < D; b++) {\n                pairs.emplace_back(abs(sol.load[a] - sol.load[b]), a, b);\n            }\n        }\n\n        sort(pairs.rbegin(), pairs.rend());\n\n        bool changed = false;\n        for (auto [_, a, b] : pairs) {\n            changed |= pairBalanceDP(sol, a, b, w, target);\n        }\n\n        localImprove(sol, w, target);\n\n        if (!changed || sol.obj >= before - 1e-12) break;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nSolution makeGreedyOrder(const vector<int>& order, const vector<double>& w) {\n    Solution sol;\n    sol.assign.assign(N, -1);\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    vector<int> cnt(D, 0);\n\n    for (int item : order) {\n        int best = 0;\n        for (int b = 1; b < D; b++) {\n            if (sol.load[b] < sol.load[best] - 1e-12 ||\n                (abs(sol.load[b] - sol.load[best]) <= 1e-12 && cnt[b] < cnt[best])) {\n                best = b;\n            }\n        }\n\n        sol.assign[item] = best;\n        sol.bins[best].push_back(item);\n        sol.load[best] += w[item];\n        cnt[best]++;\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nSolution makeSnake(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        int block = i / D;\n        int pos = i % D;\n        int b = (block % 2 == 0) ? pos : (D - 1 - pos);\n        assign[order[i]] = b;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution makeRoundRobin(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        assign[order[i]] = i % D;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution partitionEstimated(const vector<double>& w) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return w[a] > w[b];\n    });\n\n    Solution best;\n\n    auto consider = [&](Solution sol) {\n        improveSolution(sol, w, 2);\n        if (sol.obj < best.obj) best = sol;\n    };\n\n    consider(makeGreedyOrder(order, w));\n    consider(makeSnake(order, w));\n    consider(makeRoundRobin(order, w));\n\n    normal_distribution<double> nd(0.0, 0.35);\n\n    for (int rep = 0; rep < 3; rep++) {\n        vector<pair<double, int>> keys;\n        keys.reserve(N);\n\n        for (int i = 0; i < N; i++) {\n            double key = log(max(1e-9, w[i])) + nd(rng);\n            keys.emplace_back(-key, i);\n        }\n\n        sort(keys.begin(), keys.end());\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto [_, id] : keys) ord.push_back(id);\n\n        consider(makeGreedyOrder(ord, w));\n    }\n\n    improveSolution(best, w, 2);\n    return best;\n}\n\nvector<int> withoutItem(const vector<int>& v, int x) {\n    vector<int> res;\n    res.reserve(v.size());\n    for (int y : v) {\n        if (y != x) res.push_back(y);\n    }\n    return res;\n}\n\nint minMaxCost() {\n    int pairs = D / 2;\n    int sz = pairs + (D % 2);\n    return pairs + max(0, sz - 1) + max(0, sz - 1);\n}\n\nbool findActualMinMax(const vector<vector<int>>& bins, int& mn, int& mx) {\n    vector<int> winners, losers;\n\n    for (int i = 0; i + 1 < D; i += 2) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[i], bins[i + 1]);\n        if (c == '>') {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        } else if (c == '<') {\n            winners.push_back(i + 1);\n            losers.push_back(i);\n        } else {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        }\n    }\n\n    if (D % 2 == 1) {\n        winners.push_back(D - 1);\n        losers.push_back(D - 1);\n    }\n\n    mx = winners[0];\n    for (int i = 1; i < (int)winners.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[winners[i]], bins[mx]);\n        if (c == '>') mx = winners[i];\n    }\n\n    mn = losers[0];\n    for (int i = 1; i < (int)losers.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[losers[i]], bins[mn]);\n        if (c == '<') mn = losers[i];\n    }\n\n    return true;\n}\n\n// H and L must be actual-oriented: H is heavier than L.\n// Every accepted operation is mathematically guaranteed to reduce actual pair variance.\nbool tryImproveOrientedPair(Solution& sol, int H, int L, const vector<double>& est, int moveCap, int swapCap) {\n    if (H == L) return false;\n    if (sol.bins[H].empty() || sol.bins[L].empty()) return false;\n\n    bool success = false;\n\n    // Try moving one item from H to L.\n    // If H - x > L, then x < H-L and the pair variance decreases.\n    if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n        vector<int> items = sol.bins[H];\n        sort(items.begin(), items.end(), [&](int a, int b) {\n            return est[a] < est[b];\n        });\n\n        int rem = Q - qUsed;\n        int moveLimit = min((int)items.size(), min(moveCap, max(1, rem / 3)));\n        if (rem <= 3) moveLimit = min((int)items.size(), rem);\n\n        int bestMove = -1;\n        int tried = 0;\n\n        for (int x : items) {\n            if (tried >= moveLimit || qUsed >= Q) break;\n\n            vector<int> left = withoutItem(sol.bins[H], x);\n            if (left.empty()) break;\n\n            char c = ask(left, sol.bins[L]);\n            tried++;\n\n            if (c == '>') {\n                bestMove = x;\n            } else if (bestMove != -1) {\n                break;\n            }\n        }\n\n        if (bestMove != -1) {\n            moveItemSol(sol, bestMove, H, L, est);\n            return true;\n        }\n    }\n\n    // Try swapping x in H and y in L.\n    // If x > y and H-x > L-y, then 0 < x-y < H-L, so variance decreases.\n    if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n        vector<tuple<double, int, int>> cand;\n\n        for (int x : sol.bins[H]) {\n            for (int y : sol.bins[L]) {\n                double diff = est[x] - est[y];\n                double key = (diff >= 0.0) ? diff : (2.0 + (-diff));\n                cand.emplace_back(key, x, y);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        int tried = 0;\n        for (auto [_, x, y] : cand) {\n            if (tried >= swapCap || qUsed >= Q) break;\n            tried++;\n\n            char xy = compareItems(x, y);\n            if (xy == '?') break;\n            if (xy != '>') continue;\n\n            if ((int)sol.bins[L].size() == 1) {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n\n            vector<int> left = withoutItem(sol.bins[H], x);\n            vector<int> right = withoutItem(sol.bins[L], y);\n\n            if (left.empty()) continue;\n            if (right.empty()) {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n\n            if (qUsed >= Q) break;\n\n            char c = ask(left, right);\n            if (c == '>') {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n        }\n    }\n\n    return success;\n}\n\nbool tryImproveUnknownPair(Solution& sol, int a, int b, const vector<double>& est) {\n    if (a == b) return false;\n    if (qUsed >= Q) return false;\n    if (sol.bins[a].empty() || sol.bins[b].empty()) return false;\n\n    char c = ask(sol.bins[a], sol.bins[b]);\n    if (c == '=') return false;\n\n    int H = a, L = b;\n    if (c == '<') swap(H, L);\n\n    // Lighter settings than exact min/max refinement, to test more pairs.\n    return tryImproveOrientedPair(sol, H, L, est, 4, 10);\n}\n\n// Uses leftover queries after the standard min/max refinement is stuck.\n// Accepted moves are still provably safe.\nbool tryEstimatedPairFallback(Solution& sol, const vector<double>& est, int skipA = -1, int skipB = -1) {\n    if (qUsed >= Q) return false;\n\n    vector<tuple<double, int, int>> pairs;\n\n    for (int a = 0; a < D; a++) {\n        for (int b = a + 1; b < D; b++) {\n            if ((a == skipA && b == skipB) || (a == skipB && b == skipA)) continue;\n\n            if (sol.load[a] >= sol.load[b]) {\n                pairs.emplace_back(sol.load[a] - sol.load[b], a, b);\n            } else {\n                pairs.emplace_back(sol.load[b] - sol.load[a], b, a);\n            }\n        }\n    }\n\n    sort(pairs.rbegin(), pairs.rend());\n\n    int maxPairs = min((int)pairs.size(), max(5, min(80, Q - qUsed)));\n\n    for (int i = 0; i < maxPairs && qUsed < Q; i++) {\n        auto [_, Hest, Lest] = pairs[i];\n        if (tryImproveUnknownPair(sol, Hest, Lest, est)) return true;\n    }\n\n    return false;\n}\n\nint actualRefine(Solution& sol, const vector<double>& est) {\n    int successes = 0;\n\n    while (qUsed < Q) {\n        bool success = false;\n        int failedH = -1, failedL = -1;\n\n        // Original robust strategy: find actual global heaviest/lightest bins.\n        int cost = minMaxCost();\n        if (Q - qUsed >= cost + 1) {\n            int mn = -1, mx = -1;\n            if (!findActualMinMax(sol.bins, mn, mx)) break;\n\n            failedH = mx;\n            failedL = mn;\n\n            if (mx != mn) {\n                success = tryImproveOrientedPair(sol, mx, mn, est, 6, 20);\n            }\n\n            if (success) {\n                successes++;\n                continue;\n            }\n        }\n\n        // New safe fallback: try promising estimated pairs.\n        // If it fails, the partition is unchanged; only otherwise-dummy queries are consumed.\n        if (qUsed < Q) {\n            success = tryEstimatedPairFallback(sol, est, failedH, failedL);\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        break;\n    }\n\n    return successes;\n}\n\nvoid randomBalancedQueries(int cnt, vector<double>& score) {\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n\n    int K = N / 2;\n\n    for (int q = 0; q < cnt && qUsed < Q; q++) {\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L, R;\n        L.reserve(K);\n        R.reserve(K);\n\n        for (int i = 0; i < K; i++) L.push_back(perm[i]);\n        for (int i = 0; i < K; i++) R.push_back(perm[K + i]);\n\n        char c = ask(L, R);\n        int y = 0;\n        if (c == '>') y = 1;\n        else if (c == '<') y = -1;\n\n        if (y != 0) {\n            for (int x : L) score[x] += y;\n            for (int x : R) score[x] -= y;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)N * 1000003ULL;\n    seed ^= (uint64_t)D * 10007ULL;\n    seed ^= (uint64_t)Q * 998244353ULL;\n    rng.seed(seed);\n\n    itemCmp.assign(N, vector<char>(N, '?'));\n    for (int i = 0; i < N; i++) itemCmp[i][i] = '=';\n\n    vector<double> score(N, 0.0);\n\n    int qRefine = min(Q / 5, 2 * N);\n    int qRandom = Q - qRefine;\n\n    randomBalancedQueries(qRandom, score);\n\n    vector<double> est = estimateWeights(score, qRandom);\n\n    Solution sol = partitionEstimated(est);\n\n    actualRefine(sol, est);\n\n    // Remaining queries are consumed safely.\n    while (qUsed < Q) {\n        vector<int> L{0}, R{1};\n        ask(L, R);\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << sol.assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MMAX = 10;\nstatic const int INF = 1000000000;\n\nint nG, mG;\nusing StackArray = array<vector<int>, MMAX>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (double)(next() >> 11) * (1.0 / (double)(1ULL << 53));\n    }\n};\n\nstruct Params {\n    int mode = 2;\n    int badMode = 0;\n    int goodMode = 0;\n    int thresholdMode = 0;\n    int destMode = 0;\n\n    double noise = 0.0;\n\n    double lenW = 0.06;\n    double dirtyW = 1.5;\n    double badW = 3.0;\n    double amountW = 0.05;\n    double slackW = 0.02;\n    double heightW = 0.0;\n    double gW = 0.05;\n\n    int initA = -1, initB = -1;\n};\n\nstruct Result {\n    vector<pair<int,int>> ops;\n    int cost = INF;\n    bool ok = false;\n};\n\nstruct Stats {\n    int len = 0;\n    int maxv = -1;\n    int minv = INF;\n    int internalBad = 0;\n};\n\nResult invalidResult() {\n    return Result{{}, INF, false};\n}\n\npair<int,int> findBox(const StackArray& st, int v) {\n    for (int i = 0; i < mG; 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\nint minStackValue(const StackArray& st, int s) {\n    if (st[s].empty()) return INF;\n    int mn = INF;\n    for (int x : st[s]) mn = min(mn, x);\n    return mn;\n}\n\nint thresholdValue(const StackArray& st, int s, int mode) {\n    if (st[s].empty()) return INF;\n    if (mode == 1) return st[s].back();\n    return minStackValue(st, s);\n}\n\nint aboveMinCountOne(const vector<int>& a) {\n    if (a.empty()) return 0;\n    int mn = INF, pos = -1;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i] < mn) {\n            mn = a[i];\n            pos = i;\n        }\n    }\n    return (int)a.size() - pos - 1;\n}\n\nStats blockStats(const vector<int>& a, int cut) {\n    Stats s;\n    s.len = (int)a.size() - cut;\n    for (int i = cut; i < (int)a.size(); i++) {\n        s.maxv = max(s.maxv, a[i]);\n        s.minv = min(s.minv, a[i]);\n        if (i + 1 < (int)a.size() && a[i] < a[i + 1]) s.internalBad++;\n    }\n    return s;\n}\n\nint countGreaterThan(const vector<int>& a, int cut, int g) {\n    int c = 0;\n    for (int i = cut; i < (int)a.size(); i++) {\n        if (a[i] > g) c++;\n    }\n    return c;\n}\n\nint topCleanStart(const vector<int>& a, int targetPos) {\n    int c = (int)a.size() - 1;\n    while (c - 1 > targetPos && a[c - 1] > a[c]) c--;\n    return c;\n}\n\nbool existsGoodDest(const StackArray& st, int src, const Stats& bs, const Params& p) {\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int g = thresholdValue(st, d, p.thresholdMode);\n        if (bs.maxv < g) return true;\n    }\n    return false;\n}\n\nint chooseDest(const StackArray& st, int src, int cut, const Params& p, XorShift& rng) {\n    Stats bs = blockStats(st[src], cut);\n    int bestDst = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        int g = thresholdValue(st, d, p.thresholdMode);\n        double normG = (g >= INF / 2 ? 1000.0 : (double)g);\n        bool good = (bs.maxv < g);\n        int badCnt = countGreaterThan(st[src], cut, g);\n        int h = (int)st[d].size();\n        int aboveMin = aboveMinCountOne(st[d]);\n\n        double score = 0.0;\n        if (p.destMode == 0) {\n            if (good) {\n                score = normG * 10.0 + h * 0.01;\n            } else {\n                score = 100000.0 - normG * 10.0 + badCnt * 100.0 + h * 0.01;\n            }\n        } else if (p.destMode == 1) {\n            if (good) {\n                score = normG * 10.0 - h * 0.05;\n            } else {\n                score = 100000.0 - normG * 10.0 - aboveMin * 5.0 + h * 0.01;\n            }\n        } else if (p.destMode == 2) {\n            if (good) {\n                score = (g >= INF / 2 ? 0.0 : normG * 10.0) + h * 0.02;\n            } else {\n                score = 100000.0 + badCnt * 1000.0 - normG * 20.0 - aboveMin * 5.0;\n            }\n        } else {\n            if (good) {\n                score = (normG - bs.maxv) * 10.0 + h * 0.1;\n            } else {\n                score = 100000.0 + badCnt * 500.0\n                      + max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g)) * 5.0\n                      - normG * 10.0 + h * 0.1;\n            }\n        }\n\n        if (p.noise > 0.0) {\n            score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestDst = d;\n        }\n    }\n\n    if (bestDst == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return bestDst;\n}\n\nbool applyMove(StackArray& st, vector<pair<int,int>>& ops, int& cost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    int label = st[src][cut];\n\n    ops.push_back({label, dst + 1});\n    cost += len + 1;\n\n    if (cost >= cutoff) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    if ((int)ops.size() > 5000) return false;\n    return true;\n}\n\nstruct Choice {\n    int cut = -1;\n    int dst = -1;\n};\n\nChoice chooseEnumMove(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    int blockers = h - pos - 1;\n\n    vector<int> cuts;\n    auto addCut = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    addCut(h - 1);\n    addCut(pos + 1);\n    int c0 = topCleanStart(a, pos);\n    addCut(c0);\n\n    for (int c = c0; c < h; c++) addCut(c);\n\n    int cur = h - 1;\n    int added = 0;\n    while (cur > pos && added < 12) {\n        int r = cur;\n        while (r - 1 > pos && a[r - 1] > a[r]) r--;\n        addCut(r);\n        cur = r - 1;\n        added++;\n    }\n\n    if (blockers <= 25) {\n        for (int c = pos + 1; c < h; c++) addCut(c);\n    } else {\n        for (int t = 1; t <= 10; t++) {\n            int c = pos + 1 + (int)((long long)(blockers - 1) * t / 11);\n            addCut(c);\n        }\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    Choice best;\n    double bestScore = 1e100;\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(a, cut);\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            int g = thresholdValue(st, d, p.thresholdMode);\n            int badCnt = countGreaterThan(a, cut, g);\n            double normG = (g >= INF / 2 ? 250.0 : (double)g);\n\n            double score = 1.0 - p.lenW * bs.len + p.dirtyW * bs.internalBad;\n\n            if (badCnt == 0) {\n                score += p.slackW * (normG - bs.maxv);\n                score += p.heightW * (int)st[d].size();\n            } else {\n                score += p.badW * badCnt;\n                score += p.amountW * max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g));\n                score -= p.gW * normG;\n                score += p.heightW * (int)st[d].size();\n            }\n\n            if (p.noise > 0.0) {\n                score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best.cut = cut;\n                best.dst = d;\n            }\n        }\n    }\n\n    if (best.cut == -1) {\n        best.cut = h - 1;\n        best.dst = (src == 0 ? 1 : 0);\n    }\n    return best;\n}\n\nChoice chooseActionByParams(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    int h = (int)st[src].size();\n\n    if (p.mode == 3) {\n        return chooseEnumMove(st, src, pos, p, rng);\n    }\n\n    int cut = -1;\n\n    if (p.mode == 0) {\n        cut = pos + 1;\n    } else if (p.mode == 1) {\n        cut = h - 1;\n    } else {\n        int c0 = topCleanStart(st[src], pos);\n        bool selected = false;\n\n        if (p.goodMode == 0) {\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(st[src], c);\n                if (existsGoodDest(st, src, bs, p)) {\n                    cut = c;\n                    selected = true;\n                    break;\n                }\n            }\n        } else if (p.goodMode == 1) {\n            Stats bs = blockStats(st[src], c0);\n            if (existsGoodDest(st, src, bs, p)) {\n                cut = c0;\n                selected = true;\n            }\n        } else {\n            cut = c0;\n            selected = true;\n        }\n\n        if (!selected) {\n            if (p.badMode == 3) {\n                return chooseEnumMove(st, src, pos, p, rng);\n            } else if (p.badMode == 0) {\n                cut = c0;\n            } else if (p.badMode == 1) {\n                cut = pos + 1;\n            } else {\n                cut = h - 1;\n            }\n        }\n    }\n\n    int dst = chooseDest(st, src, cut, p, rng);\n    return {cut, dst};\n}\n\nbool applyMoveCostOnly(StackArray& st, int& cost, int& opCnt,\n                       int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    cost += len + 1;\n    opCnt++;\n    if (cost >= cutoff || opCnt > 5000) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n    return true;\n}\n\nint completeCostPolicy(const StackArray& initial, int startV, Params p, int limit) {\n    if (limit <= 0) return INF;\n\n    StackArray st = initial;\n    int cost = 0;\n    int opCnt = 0;\n    XorShift rng(123456789ULL + (uint64_t)p.mode * 10007ULL\n                 + (uint64_t)p.badMode * 1009ULL\n                 + (uint64_t)p.goodMode * 9176ULL\n                 + (uint64_t)p.destMode * 13331ULL);\n\n    for (int v = startV; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return INF;\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n                return INF;\n            }\n\n            if (!applyMoveCostOnly(st, cost, opCnt, src, ch.cut, ch.dst, limit)) {\n                return INF;\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return INF;\n        st[src].pop_back();\n        opCnt++;\n        if (opCnt > 5000) return INF;\n    }\n\n    return cost;\n}\n\nResult completeOpsPolicy(const StackArray& initial, int startV, Params p, int cutoff) {\n    StackArray st = initial;\n    vector<pair<int,int>> ops;\n    ops.reserve(5000);\n    int cost = 0;\n    XorShift rng(987654321ULL + (uint64_t)p.mode * 10007ULL);\n\n    for (int v = startV; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n                return invalidResult();\n            }\n\n            if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                return invalidResult();\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint completeCostMulti(const StackArray& st, int startV, const vector<Params>& policies, int limit) {\n    if (startV > nG) return 0;\n    int best = INF;\n    for (const Params& p : policies) {\n        int c = completeCostPolicy(st, startV, p, min(limit, best));\n        if (c < best) best = c;\n    }\n    if (best >= limit) return INF;\n    return best;\n}\n\nResult simulateGreedy(const StackArray& init, Params p, uint64_t seed, int cutoff) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n    XorShift rng(seed);\n\n    if (p.initA >= 0 && p.initA < mG && p.initB >= 0 && p.initB < mG &&\n        p.initA != p.initB && !st[p.initA].empty()) {\n        if (!applyMove(st, ops, cost, p.initA, 0, p.initB, cutoff)) {\n            return invalidResult();\n        }\n    }\n\n    for (int v = 1; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                return invalidResult();\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    for (int i = 0; i < mG; i++) {\n        if (!st[i].empty()) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint stateBadCount(const StackArray& st) {\n    int cnt = 0;\n    for (int i = 0; i < mG; i++) {\n        int mn = INF;\n        for (int x : st[i]) {\n            if (x > mn) cnt++;\n            mn = min(mn, x);\n        }\n    }\n    return cnt;\n}\n\nint aboveMinTotal(const StackArray& st) {\n    int s = 0;\n    for (int i = 0; i < mG; i++) s += aboveMinCountOne(st[i]);\n    return s;\n}\n\ndouble beamEval(const StackArray& st, int cost, double alpha) {\n    return cost + alpha * stateBadCount(st) + 0.30 * alpha * aboveMinTotal(st);\n}\n\nstruct BeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateBeamWhole(const StackArray& init, int W, double alpha, int cutoff) {\n    BeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(6000);\n    first.eval = beamEval(first.st, first.cost, alpha);\n\n    vector<BeamState> beam;\n    beam.push_back(first);\n\n    for (int v = 1; v <= nG; v++) {\n        vector<BeamState> cand;\n        cand.reserve(beam.size() * mG);\n\n        for (const auto& bs : beam) {\n            if (bs.cost >= cutoff) continue;\n\n            auto [src, pos] = findBox(bs.st, v);\n            if (src < 0) continue;\n\n            int h = (int)bs.st[src].size();\n\n            if (pos == h - 1) {\n                BeamState ns = bs;\n                ns.ops.push_back({v, 0});\n                ns.st[src].pop_back();\n                if ((int)ns.ops.size() > 5000) continue;\n                ns.eval = beamEval(ns.st, ns.cost, alpha);\n                cand.push_back(std::move(ns));\n            } else {\n                int cut = pos + 1;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n\n                    BeamState ns = bs;\n                    if (!applyMove(ns.st, ns.ops, ns.cost, src, cut, d, cutoff)) continue;\n\n                    if (ns.st[src].empty() || ns.st[src].back() != v) continue;\n                    ns.ops.push_back({v, 0});\n                    ns.st[src].pop_back();\n                    if ((int)ns.ops.size() > 5000) continue;\n\n                    ns.eval = beamEval(ns.st, ns.cost, alpha);\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const BeamState& a, const BeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)cand.size() > W) cand.resize(W);\n        beam = std::move(cand);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nint validateCost(const StackArray& init, const vector<pair<int,int>>& ops) {\n    if ((int)ops.size() > 5000) return -1;\n\n    StackArray st = init;\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (auto [v, to] : ops) {\n        if (v < 1 || v > nG) return -1;\n\n        if (to == 0) {\n            if (v != nextRemove) return -1;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!st[s].empty() && st[s].back() == v) {\n                    st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return -1;\n            int dst = to - 1;\n\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)st[s].size(); j++) {\n                    if (st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n            if (src == -1) return -1;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n\n            if (src != dst) {\n                st[dst].insert(st[dst].end(), st[src].begin() + pos, st[src].end());\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return -1;\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return -1;\n    return cost;\n}\n\nParams randomParams(XorShift& rng) {\n    Params p;\n\n    int r = rng.nextInt(100);\n    if (r < 12) p.mode = 0;\n    else if (r < 30) p.mode = 1;\n    else if (r < 82) p.mode = 2;\n    else p.mode = 3;\n\n    p.badMode = rng.nextInt(4);\n    p.goodMode = rng.nextInt(3);\n    p.thresholdMode = (rng.nextInt(100) < 85 ? 0 : 1);\n    p.destMode = rng.nextInt(4);\n\n    p.noise = rng.nextDouble() * 4.0;\n\n    p.lenW = 0.02 + rng.nextDouble() * 0.18;\n    p.dirtyW = 0.5 + rng.nextDouble() * 4.0;\n    p.badW = 1.0 + rng.nextDouble() * 6.0;\n    p.amountW = rng.nextDouble() * 0.25;\n    p.slackW = rng.nextDouble() * 0.08;\n    p.heightW = (rng.nextDouble() - 0.5) * 0.06;\n    p.gW = rng.nextDouble() * 0.20;\n\n    if (mG >= 2 && rng.nextInt(100) < 12) {\n        p.initA = rng.nextInt(mG);\n        p.initB = rng.nextInt(mG - 1);\n        if (p.initB >= p.initA) p.initB++;\n    }\n\n    return p;\n}\n\n/* ---------- Feature-based macro candidates ---------- */\n\nstruct Feature {\n    int bad = 0;\n    int above = 0;\n    int runs = 0;\n    int inc = 0;\n    int empty = 0;\n};\n\nFeature& operator+=(Feature& a, const Feature& b) {\n    a.bad += b.bad;\n    a.above += b.above;\n    a.runs += b.runs;\n    a.inc += b.inc;\n    a.empty += b.empty;\n    return a;\n}\n\nFeature& operator-=(Feature& a, const Feature& b) {\n    a.bad -= b.bad;\n    a.above -= b.above;\n    a.runs -= b.runs;\n    a.inc -= b.inc;\n    a.empty -= b.empty;\n    return a;\n}\n\nFeature calcFeatureParts(const vector<int>& A, int l1, int r1,\n                         const vector<int>& B, int l2, int r2) {\n    Feature f;\n    int len = (r1 - l1) + (r2 - l2);\n    if (len == 0) {\n        f.empty = 1;\n        return f;\n    }\n\n    int idx = 0;\n    int mnBelow = INF;\n    int minVal = INF, minPos = -1;\n    int prevVal = -1;\n    bool hasPrev = false;\n    bool prevBad = false;\n\n    auto process = [&](int x) {\n        if (hasPrev && prevVal < x) f.inc++;\n\n        bool isBad = (x > mnBelow);\n        if (isBad) {\n            f.bad++;\n            if (!prevBad) f.runs++;\n        }\n        prevBad = isBad;\n\n        if (x < minVal) {\n            minVal = x;\n            minPos = idx;\n        }\n        mnBelow = min(mnBelow, x);\n\n        prevVal = x;\n        hasPrev = true;\n        idx++;\n    };\n\n    for (int i = l1; i < r1; i++) process(A[i]);\n    for (int i = l2; i < r2; i++) process(B[i]);\n\n    f.above = len - minPos - 1;\n    return f;\n}\n\nFeature totalFeatures(const StackArray& st, array<Feature, MMAX>* per = nullptr) {\n    Feature total;\n    for (int i = 0; i < mG; i++) {\n        Feature fi = calcFeatureParts(st[i], 0, (int)st[i].size(), st[i], 0, 0);\n        if (per) (*per)[i] = fi;\n        total += fi;\n    }\n    return total;\n}\n\nstruct EvalParam {\n    double A = 2.7;\n    double B = 0.9;\n    double C = 1.2;\n    double D = 0.25;\n    double E = 2.0;\n    double F = 1.5;\n    double beta = 0.75;\n};\n\ndouble heuristicFeature(const Feature& f, const EvalParam& ep) {\n    return ep.A * f.bad + ep.B * f.above + ep.C * f.runs\n         + ep.D * f.inc - ep.E * f.empty;\n}\n\nint aboveBoxCount(const StackArray& st, int v) {\n    if (v > nG) return 0;\n    auto [s, p] = findBox(st, v);\n    if (s < 0) return 0;\n    return (int)st[s].size() - p - 1;\n}\n\ndouble heuristicState(const StackArray& st, int nextv, const EvalParam& ep) {\n    Feature f = totalFeatures(st, nullptr);\n    double h = heuristicFeature(f, ep);\n    if (nextv <= nG) h += ep.F * aboveBoxCount(st, nextv);\n    return h;\n}\n\nFeature featureAfterMoveContext(const StackArray& st,\n                                const array<Feature, MMAX>& sf,\n                                const Feature& total,\n                                int src, int pos, int cut, int dst,\n                                bool popIfExpose) {\n    int h = (int)st[src].size();\n\n    int srcEnd = cut;\n    if (popIfExpose && cut == pos + 1) srcEnd = pos;\n\n    Feature fsrc = calcFeatureParts(st[src], 0, srcEnd, st[src], 0, 0);\n    Feature fdst = calcFeatureParts(st[dst], 0, (int)st[dst].size(), st[src], cut, h);\n\n    Feature nf = total;\n    nf -= sf[src];\n    nf -= sf[dst];\n    nf += fsrc;\n    nf += fdst;\n    return nf;\n}\n\nuint64_t hashState(const StackArray& st) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < mG; i++) {\n        h ^= (uint64_t)(239 + i);\n        h *= 1099511628211ULL;\n        for (int x : st[i]) {\n            h ^= (uint64_t)(x + 1009);\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nstruct Macro {\n    StackArray st;\n    int addCost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n    bool ok = false;\n};\n\nMacro invalidMacro() {\n    Macro m;\n    m.ok = false;\n    m.addCost = INF;\n    return m;\n}\n\nbool macroMove(StackArray& st, vector<pair<int,int>>& ops, int& addCost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    if (addCost + len + 1 >= cutoff) return false;\n\n    int label = st[src][cut];\n    ops.push_back({label, dst + 1});\n    addCost += len + 1;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    return (int)ops.size() <= 5000;\n}\n\nbool macroRemove(StackArray& st, vector<pair<int,int>>& ops, int v) {\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return false;\n    if (pos != (int)st[src].size() - 1) return false;\n    ops.push_back({v, 0});\n    st[src].pop_back();\n    return (int)ops.size() <= 5000;\n}\n\nint bestDestByFeature(const StackArray& st, int src, int pos, int cut, const EvalParam& ep) {\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n    Stats bs = blockStats(st[src], cut);\n\n    int best = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n        double score = heuristicFeature(nf, ep);\n\n        int thr = minStackValue(st, d);\n        double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n\n        if (bs.maxv < thr) score += 0.0005 * thrNorm;\n        else score -= 0.0005 * thrNorm;\n\n        score += 0.00001 * (int)st[d].size();\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = d;\n        }\n    }\n\n    if (best == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return best;\n}\n\nvector<int> generateCutsForAction(const StackArray& st, int src, int pos, int maxCuts = 16) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    vector<int> cuts;\n\n    auto add = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    int c0 = topCleanStart(a, pos);\n    add(pos + 1);\n    add(h - 1);\n    add(c0);\n\n    int runLen = h - c0;\n    if (runLen <= 16) {\n        for (int c = c0; c < h; c++) add(c);\n    } else {\n        for (int t = 0; t < 10; t++) {\n            int c = c0 + (int)((long long)(runLen - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    int end = h;\n    int cnt = 0;\n    while (end > pos + 1 && cnt < 12) {\n        int start = end - 1;\n        while (start - 1 > pos && a[start - 1] > a[start]) start--;\n        add(start);\n        end = start;\n        cnt++;\n    }\n\n    int r = h - pos - 1;\n    if (r <= 18) {\n        for (int c = pos + 1; c < h; c++) add(c);\n    } else {\n        for (int t = 1; t <= 8; t++) {\n            int c = pos + 1 + (int)((long long)(r - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int thr = minStackValue(st, d);\n        int mx = -1;\n        int best = -1;\n        for (int c = h - 1; c > pos; c--) {\n            mx = max(mx, a[c]);\n            if (mx < thr) best = c;\n            else break;\n        }\n        if (best != -1) add(best);\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    if ((int)cuts.size() > maxCuts) {\n        vector<int> old = cuts;\n        vector<int> nc;\n        auto add2 = [&](int c) {\n            if (c > pos && c < h) nc.push_back(c);\n        };\n        add2(pos + 1);\n        add2(h - 1);\n        add2(c0);\n\n        int samples = max(1, maxCuts - 3);\n        for (int t = 0; t < samples; t++) {\n            int idx = (int)((long long)(old.size() - 1) * t / max(1, samples - 1));\n            add2(old[idx]);\n        }\n\n        sort(nc.begin(), nc.end());\n        nc.erase(unique(nc.begin(), nc.end()), nc.end());\n        cuts = nc;\n    }\n\n    return cuts;\n}\n\nstruct Action {\n    int cut = -1;\n    int dst = -1;\n    double score = 1e100;\n};\n\nvector<Action> getTopActions(const StackArray& st, int src, int pos,\n                             const EvalParam& ep, double beta, int limit) {\n    vector<Action> actions;\n    if (limit <= 0) return actions;\n\n    auto cuts = generateCutsForAction(st, src, pos, 16);\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n\n    int h = (int)st[src].size();\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(st[src], cut);\n        int len = h - cut;\n\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n            double sc = (len + 1) + beta * heuristicFeature(nf, ep);\n\n            int thr = minStackValue(st, d);\n            double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n            int badCnt = countGreaterThan(st[src], cut, thr);\n\n            if (bs.maxv < thr) {\n                sc += 0.0002 * thrNorm;\n                if (bs.internalBad == 0) sc -= 0.05 * bs.len;\n            } else {\n                sc += 0.20 * badCnt;\n                sc -= 0.0002 * thrNorm;\n            }\n            sc += 0.10 * bs.internalBad;\n\n            actions.push_back({cut, d, sc});\n        }\n    }\n\n    sort(actions.begin(), actions.end(), [](const Action& a, const Action& b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.cut != b.cut) return a.cut < b.cut;\n        return a.dst < b.dst;\n    });\n\n    if ((int)actions.size() > limit) actions.resize(limit);\n    return actions;\n}\n\n/* Small beam search only for exposing current target. */\nvector<Macro> generateClearBeamMacros(const StackArray& st, int v, const EvalParam& ep,\n                                      int cutoff, int beamW, int outLimit, int actionLimit) {\n    vector<Macro> done;\n\n    auto [s0, p0] = findBox(st, v);\n    if (s0 < 0) return done;\n    int initialBlockers = (int)st[s0].size() - p0 - 1;\n    if (initialBlockers <= 0 || initialBlockers > 35) return done;\n\n    struct Node {\n        StackArray st;\n        int cost = 0;\n        vector<pair<int,int>> ops;\n        double eval = 0.0;\n    };\n\n    Node first;\n    first.st = st;\n    first.cost = 0;\n    first.ops.reserve(128);\n    first.eval = heuristicState(first.st, v, ep);\n\n    vector<Node> beam;\n    beam.push_back(std::move(first));\n\n    int maxSteps = min(initialBlockers, 10);\n\n    for (int step = 0; step <= maxSteps; step++) {\n        vector<Node> nxt;\n\n        for (const Node& nd : beam) {\n            auto [src, pos] = findBox(nd.st, v);\n            if (src < 0) continue;\n            int h = (int)nd.st[src].size();\n\n            if (pos == h - 1) {\n                Macro mo;\n                mo.st = nd.st;\n                mo.addCost = nd.cost;\n                mo.ops = nd.ops;\n                if (macroRemove(mo.st, mo.ops, v)) {\n                    mo.ok = true;\n                    mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n                    done.push_back(std::move(mo));\n                }\n                continue;\n            }\n\n            if (step == maxSteps) continue;\n\n            vector<Action> acts = getTopActions(nd.st, src, pos, ep, ep.beta, actionLimit);\n\n            auto addAction = [&](int cut) {\n                if (cut <= pos || cut >= h) return;\n                int dst = bestDestByFeature(nd.st, src, pos, cut, ep);\n                acts.push_back({cut, dst, 1e50});\n            };\n\n            addAction(pos + 1);\n            addAction(h - 1);\n            addAction(topCleanStart(nd.st[src], pos));\n\n            sort(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                if (a.cut != b.cut) return a.cut < b.cut;\n                return a.dst < b.dst;\n            });\n            acts.erase(unique(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                return a.cut == b.cut && a.dst == b.dst;\n            }), acts.end());\n            sort(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                return a.score < b.score;\n            });\n            if ((int)acts.size() > actionLimit + 3) acts.resize(actionLimit + 3);\n\n            for (const Action& ac : acts) {\n                if (ac.cut <= pos || ac.cut >= h || ac.dst == src || ac.dst < 0 || ac.dst >= mG) continue;\n\n                Node nn = nd;\n                if (!macroMove(nn.st, nn.ops, nn.cost, src, ac.cut, ac.dst, cutoff)) continue;\n\n                nn.eval = nn.cost + 0.65 * heuristicState(nn.st, v, ep)\n                        + 0.40 * aboveBoxCount(nn.st, v);\n                nxt.push_back(std::move(nn));\n            }\n        }\n\n        if (nxt.empty()) break;\n\n        sort(nxt.begin(), nxt.end(), [](const Node& a, const Node& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        vector<Node> nb;\n        nb.reserve(beamW);\n        unordered_set<uint64_t> seen;\n        seen.reserve(nxt.size() * 2 + 10);\n\n        for (auto& x : nxt) {\n            uint64_t hs = hashState(x.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(x));\n                if ((int)nb.size() >= beamW) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    sort(done.begin(), done.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.addCost < b.addCost;\n    });\n\n    vector<Macro> out;\n    out.reserve(outLimit);\n    unordered_set<uint64_t> seen;\n    seen.reserve(done.size() * 2 + 10);\n\n    for (auto& mo : done) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= outLimit) break;\n        }\n    }\n\n    return out;\n}\n\nMacro completePolicy(const StackArray& input, int v, int policy,\n                     const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        int cut = -1, dst = -1;\n\n        if (policy == 0) {\n            int c0 = topCleanStart(mo.st[src], pos);\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(mo.st[src], c);\n                bool good = false;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n                    if (bs.maxv < minStackValue(mo.st, d)) {\n                        good = true;\n                        break;\n                    }\n                }\n                if (good) {\n                    cut = c;\n                    break;\n                }\n            }\n            if (cut == -1) cut = c0;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 1) {\n            cut = topCleanStart(mo.st[src], pos);\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 2) {\n            cut = h - 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 3) {\n            cut = pos + 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else {\n            auto acts = getTopActions(mo.st, src, pos, ep, ep.beta, 1);\n            if (acts.empty()) return invalidMacro();\n            cut = acts[0].cut;\n            dst = acts[0].dst;\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, cut, dst, cutoff)) {\n            return invalidMacro();\n        }\n    }\n}\n\nMacro completeCurrentByParams(const StackArray& input, int v, Params p,\n                              const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    XorShift rng(5555555ULL + (uint64_t)p.mode * 10007ULL + (uint64_t)p.destMode * 101ULL);\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        Choice ch = chooseActionByParams(mo.st, src, pos, p, rng);\n        if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n            return invalidMacro();\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, ch.cut, ch.dst, cutoff)) {\n            return invalidMacro();\n        }\n    }\n}\n\nvector<Macro> generateMacros(const StackArray& st, int v,\n                             const EvalParam& ep, int cutoff, int limit) {\n    vector<Macro> res;\n\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return res;\n\n    int h = (int)st[src].size();\n\n    auto pushMacro = [&](Macro&& mo) {\n        if (!mo.ok) return;\n        if (mo.addCost >= cutoff) return;\n        if ((int)mo.ops.size() > 5000) return;\n        mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n        res.push_back(std::move(mo));\n    };\n\n    if (pos == h - 1) {\n        Macro mo;\n        mo.st = st;\n        mo.addCost = 0;\n        mo.ops.reserve(1);\n        if (macroRemove(mo.st, mo.ops, v)) {\n            mo.ok = true;\n            pushMacro(std::move(mo));\n        }\n        return res;\n    }\n\n    int r = h - pos - 1;\n\n    pushMacro(completePolicy(st, v, 0, ep, cutoff));\n    pushMacro(completePolicy(st, v, 1, ep, cutoff));\n    pushMacro(completePolicy(st, v, 2, ep, cutoff));\n    if (r <= 60) pushMacro(completePolicy(st, v, 4, ep, cutoff));\n\n    auto addFirstFinish = [&](int cut, int dst, int finishPolicy) {\n        StackArray tmp = st;\n        vector<pair<int,int>> ops;\n        ops.reserve(256);\n        int cst = 0;\n        if (!macroMove(tmp, ops, cst, src, cut, dst, cutoff)) return;\n\n        Macro rest = completePolicy(tmp, v, finishPolicy, ep, cutoff - cst);\n        if (!rest.ok) return;\n\n        Macro mo;\n        mo.st = rest.st;\n        mo.addCost = cst + rest.addCost;\n        mo.ops = std::move(ops);\n        mo.ops.insert(mo.ops.end(), rest.ops.begin(), rest.ops.end());\n        mo.ok = true;\n        pushMacro(std::move(mo));\n    };\n\n    int wholeCut = pos + 1;\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        addFirstFinish(wholeCut, d, 0);\n    }\n\n    int cleanCut = topCleanStart(st[src], pos);\n    if (cleanCut != wholeCut) {\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n            addFirstFinish(cleanCut, d, 0);\n        }\n    }\n\n    int firstLimit = (r <= 8 ? 8 : 6);\n    auto acts = getTopActions(st, src, pos, ep, ep.beta, firstLimit);\n    for (const auto& ac : acts) {\n        addFirstFinish(ac.cut, ac.dst, 0);\n    }\n\n    if (r <= 35) {\n        auto bm = generateClearBeamMacros(st, v, ep, cutoff, 6, 6, 6);\n        for (auto& mo : bm) {\n            pushMacro(std::move(mo));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        if (a.addCost != b.addCost) return a.addCost < b.addCost;\n        return a.ops.size() < b.ops.size();\n    });\n\n    vector<Macro> out;\n    out.reserve(min(limit, (int)res.size()));\n    unordered_set<uint64_t> seen;\n    seen.reserve(res.size() * 2 + 10);\n\n    for (auto& mo : res) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= limit) break;\n        }\n    }\n\n    return out;\n}\n\nstruct MacroBeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateMacroRollout(const StackArray& init,\n                            const vector<Params>& macroParams,\n                            const vector<Params>& evalParams,\n                            const EvalParam& ep,\n                            int cutoff,\n                            chrono::steady_clock::time_point deadline,\n                            int candidateLimit) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n\n    for (int v = 1; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) {\n            if (!evalParams.empty()) {\n                Result tail = completeOpsPolicy(st, v, evalParams[0], cutoff - cost);\n                if (tail.ok) {\n                    ops.insert(ops.end(), tail.ops.begin(), tail.ops.end());\n                    if ((int)ops.size() <= 5000) {\n                        return Result{ops, cost + tail.cost, true};\n                    }\n                }\n            }\n            return invalidResult();\n        }\n\n        int remainCutoff = cutoff - cost;\n        if (remainCutoff <= 0) return invalidResult();\n\n        vector<Macro> candidates;\n        candidates.reserve(candidateLimit + (int)macroParams.size() + 5);\n        unordered_set<uint64_t> seen;\n        seen.reserve(128);\n\n        auto addCandidate = [&](Macro&& mo) {\n            if (!mo.ok) return;\n            if (mo.addCost >= remainCutoff) return;\n            if ((int)ops.size() + (int)mo.ops.size() > 5000) return;\n            uint64_t hs = hashState(mo.st);\n            if (seen.insert(hs).second) {\n                candidates.push_back(std::move(mo));\n            }\n        };\n\n        for (const Params& p : macroParams) {\n            Macro mo = completeCurrentByParams(st, v, p, ep, remainCutoff);\n            addCandidate(std::move(mo));\n        }\n\n        auto base = generateMacros(st, v, ep, remainCutoff, candidateLimit);\n        for (auto& mo : base) {\n            if ((int)candidates.size() >= candidateLimit) break;\n            addCandidate(std::move(mo));\n        }\n\n        if (candidates.empty()) return invalidResult();\n\n        int bestIdx = -1;\n        int bestEval = INF;\n\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (chrono::steady_clock::now() > deadline) break;\n\n            const Macro& mo = candidates[i];\n            if (mo.addCost >= remainCutoff) continue;\n\n            int remLimit = remainCutoff - mo.addCost;\n            int cc = completeCostMulti(mo.st, v + 1, evalParams, remLimit);\n            if (cc >= INF) continue;\n\n            int val = mo.addCost + cc;\n            if (val < bestEval) {\n                bestEval = val;\n                bestIdx = i;\n            }\n        }\n\n        if (bestIdx == -1) {\n            if (!evalParams.empty()) {\n                Result tail = completeOpsPolicy(st, v, evalParams[0], cutoff - cost);\n                if (tail.ok) {\n                    ops.insert(ops.end(), tail.ops.begin(), tail.ops.end());\n                    if ((int)ops.size() <= 5000) {\n                        return Result{ops, cost + tail.cost, true};\n                    }\n                }\n            }\n            return invalidResult();\n        }\n\n        Macro& ch = candidates[bestIdx];\n        cost += ch.addCost;\n        ops.insert(ops.end(), ch.ops.begin(), ch.ops.end());\n        if (cost >= cutoff || (int)ops.size() > 5000) return invalidResult();\n        st = std::move(ch.st);\n    }\n\n    for (int i = 0; i < mG; i++) {\n        if (!st[i].empty()) return invalidResult();\n    }\n    return Result{ops, cost, true};\n}\n\nResult simulateTailMacroBeam(const StackArray& initState, int startV, int W,\n                             const EvalParam& ep, int cutoff,\n                             chrono::steady_clock::time_point deadline,\n                             int perStateLimit) {\n    if (startV > nG) return Result{{}, 0, true};\n\n    MacroBeamState first;\n    first.st = initState;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(1000);\n    first.eval = heuristicState(first.st, startV, ep);\n\n    vector<MacroBeamState> beam;\n    beam.push_back(std::move(first));\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) return invalidResult();\n\n        vector<MacroBeamState> cand;\n        cand.reserve(beam.size() * perStateLimit);\n\n        for (const auto& bs : beam) {\n            if (chrono::steady_clock::now() > deadline) return invalidResult();\n            if (bs.cost >= cutoff) continue;\n\n            auto macros = generateMacros(bs.st, v, ep, cutoff - bs.cost, perStateLimit);\n\n            for (auto& mo : macros) {\n                int nc = bs.cost + mo.addCost;\n                if (nc >= cutoff) continue;\n\n                MacroBeamState ns;\n                ns.st = std::move(mo.st);\n                ns.cost = nc;\n                ns.ops = bs.ops;\n                ns.ops.insert(ns.ops.end(), mo.ops.begin(), mo.ops.end());\n                if ((int)ns.ops.size() > 5000) continue;\n\n                ns.eval = ns.cost + heuristicState(ns.st, v + 1, ep);\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const MacroBeamState& a, const MacroBeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.ops.size() < b.ops.size();\n        });\n\n        vector<MacroBeamState> nb;\n        nb.reserve(W);\n        unordered_set<uint64_t> seen;\n        seen.reserve(cand.size() * 2 + 10);\n\n        for (auto& c : cand) {\n            uint64_t hs = hashState(c.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(c));\n                if ((int)nb.size() >= W) break;\n            }\n        }\n\n        if (nb.empty()) return invalidResult();\n        beam = std::move(nb);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nstruct PrefixResult {\n    StackArray st;\n    vector<pair<int,int>> ops;\n    int cost = 0;\n    bool ok = false;\n};\n\nPrefixResult extractPrefix(const StackArray& init, const vector<pair<int,int>>& fullOps, int stopV) {\n    PrefixResult pr;\n    pr.st = init;\n    pr.ops.reserve(fullOps.size());\n    pr.cost = 0;\n    pr.ok = false;\n\n    if (stopV == 0) {\n        pr.ok = true;\n        return pr;\n    }\n\n    int nextRemove = 1;\n\n    for (auto [v, to] : fullOps) {\n        if (to == 0) {\n            if (v != nextRemove) return pr;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!pr.st[s].empty() && pr.st[s].back() == v) {\n                    pr.st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return pr;\n\n            pr.ops.push_back({v, 0});\n            nextRemove++;\n\n            if (v == stopV) {\n                pr.ok = true;\n                return pr;\n            }\n        } else {\n            int dst = to - 1;\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)pr.st[s].size(); j++) {\n                    if (pr.st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n            if (src < 0) return pr;\n\n            int len = (int)pr.st[src].size() - pos;\n            pr.cost += len + 1;\n            pr.ops.push_back({v, to});\n\n            if (src != dst) {\n                pr.st[dst].insert(pr.st[dst].end(), pr.st[src].begin() + pos, pr.st[src].end());\n                pr.st[src].erase(pr.st[src].begin() + pos, pr.st[src].end());\n            }\n        }\n    }\n\n    return pr;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> nG >> mG;\n\n    StackArray init;\n    for (int i = 0; i < mG; i++) {\n        init[i].reserve(nG);\n        for (int j = 0; j < nG / mG; j++) {\n            int x;\n            cin >> x;\n            init[i].push_back(x);\n        }\n    }\n\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < mG; i++) {\n        for (int x : init[i]) {\n            seed = seed * 1000003ULL + (uint64_t)x + 97ULL;\n        }\n    }\n    XorShift master(seed);\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto timeUp = [&]() -> bool {\n        return elapsed() > 1.86;\n    };\n\n    Result best;\n\n    auto consider = [&](Result r) {\n        if (!r.ok) return;\n        if ((int)r.ops.size() > 5000) return;\n        if (best.ok && r.cost >= best.cost) return;\n\n        int vc = validateCost(init, r.ops);\n        if (vc < 0 || vc != r.cost) return;\n\n        best = std::move(r);\n    };\n\n    Params pClean;\n    pClean.mode = 2;\n    pClean.goodMode = 0;\n    pClean.badMode = 0;\n    pClean.thresholdMode = 0;\n    pClean.destMode = 0;\n\n    Params pCleanBad = pClean;\n    pCleanBad.badMode = 1;\n\n    Params pCleanD1 = pClean;\n    pCleanD1.destMode = 1;\n\n    Params pWhole;\n    pWhole.mode = 0;\n    pWhole.thresholdMode = 0;\n    pWhole.destMode = 0;\n\n    Params pSingle;\n    pSingle.mode = 1;\n    pSingle.thresholdMode = 0;\n    pSingle.destMode = 0;\n\n    Params pEnum;\n    pEnum.mode = 3;\n    pEnum.thresholdMode = 0;\n    pEnum.lenW = 0.07;\n    pEnum.dirtyW = 1.8;\n    pEnum.badW = 3.0;\n    pEnum.gW = 0.08;\n    pEnum.slackW = 0.02;\n\n    vector<Params> macroParams = {pClean, pCleanBad, pCleanD1, pWhole, pSingle, pEnum};\n\n    vector<pair<EvalParam, vector<Params>>> rollCfgs;\n    rollCfgs.push_back({\n        EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75},\n        vector<Params>{pClean}\n    });\n    rollCfgs.push_back({\n        EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65},\n        vector<Params>{pClean, pEnum}\n    });\n    rollCfgs.push_back({\n        EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85},\n        vector<Params>{pCleanBad}\n    });\n    rollCfgs.push_back({\n        EvalParam{3.0, 1.0, 2.0, 0.18, 2.8, 2.4, 0.70},\n        vector<Params>{pClean, pCleanD1, pEnum}\n    });\n\n    // Guaranteed valid fallback.\n    consider(simulateGreedy(init, pWhole, master.next(), INF));\n\n    auto runParam = [&](Params p) {\n        if (timeUp()) return;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    // Deterministic greedy variants.\n    for (int th = 0; th <= 1; th++) {\n        for (int dm = 0; dm < 4; dm++) {\n            Params p;\n\n            p = Params();\n            p.mode = 0;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            p = Params();\n            p.mode = 1;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            for (int bad = 0; bad <= 2; bad++) {\n                for (int good = 0; good <= 2; good++) {\n                    p = Params();\n                    p.mode = 2;\n                    p.badMode = bad;\n                    p.goodMode = good;\n                    p.thresholdMode = th;\n                    p.destMode = dm;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Scored-enumeration presets.\n    for (int th = 0; th <= 1; th++) {\n        for (double lw : {0.03, 0.07, 0.13}) {\n            for (double dw : {0.8, 1.8, 3.0}) {\n                Params p;\n                p.mode = 3;\n                p.thresholdMode = th;\n                p.lenW = lw;\n                p.dirtyW = dw;\n                p.badW = 3.0;\n                p.gW = 0.08;\n                p.slackW = 0.02;\n                runParam(p);\n            }\n        }\n    }\n\n    // Expanded deterministic initial empty-stack attempts.\n    {\n        vector<Params> initPool = {pClean, pCleanBad, pCleanD1, pWhole, pSingle, pEnum};\n        for (Params base : initPool) {\n            if (timeUp()) break;\n            for (int a = 0; a < mG && !timeUp(); a++) {\n                for (int b = 0; b < mG && !timeUp(); b++) {\n                    if (a == b) continue;\n                    Params p = base;\n                    p.initA = a;\n                    p.initB = b;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Whole-suffix beam.\n    for (double alpha : {0.0, 1.0, 2.0, 4.0, 6.0}) {\n        if (timeUp()) break;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateBeamWhole(init, 55, alpha, cutoff));\n    }\n\n    // Rollout-based macro improvement.\n    {\n        auto rollEnd = startTime + chrono::milliseconds(1580);\n\n        for (auto& cfg : rollCfgs) {\n            if (timeUp()) break;\n            if (chrono::steady_clock::now() > rollEnd) break;\n\n            int cutoff = best.ok ? best.cost + 350 : INF;\n            consider(simulateMacroRollout(init, macroParams, cfg.second, cfg.first,\n                                          cutoff, rollEnd, 20));\n        }\n    }\n\n    // Try rollout after creating one empty stack, for a few promising initial moves.\n    if (!timeUp() && best.ok) {\n        auto initRollEnd = startTime + chrono::milliseconds(1710);\n\n        vector<tuple<int,int,int>> candInit; // estimated cost, a, b\n        vector<Params> initEval = {pClean, pEnum};\n        int roughLimit = best.cost + 500;\n\n        for (int a = 0; a < mG; a++) {\n            for (int b = 0; b < mG; b++) {\n                if (a == b) continue;\n\n                StackArray st = init;\n                int c0 = (int)st[a].size() + 1;\n                st[b].insert(st[b].end(), st[a].begin(), st[a].end());\n                st[a].clear();\n\n                int tail = completeCostMulti(st, 1, initEval, roughLimit - c0);\n                if (tail < INF) candInit.push_back({c0 + tail, a, b});\n            }\n        }\n\n        sort(candInit.begin(), candInit.end());\n\n        int tried = 0;\n        for (auto [est, a, b] : candInit) {\n            if (tried >= 2) break;\n            if (timeUp() || chrono::steady_clock::now() > initRollEnd) break;\n\n            StackArray st = init;\n            int label = st[a][0];\n            int c0 = (int)st[a].size() + 1;\n            st[b].insert(st[b].end(), st[a].begin(), st[a].end());\n            st[a].clear();\n\n            int cutoffTail = (best.ok ? best.cost + 350 - c0 : INF);\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[min(1, (int)rollCfgs.size() - 1)];\n            Result tail = simulateMacroRollout(st, macroParams, cfg.second, cfg.first,\n                                               cutoffTail, initRollEnd, 15);\n            if (tail.ok) {\n                Result r;\n                r.ok = true;\n                r.cost = c0 + tail.cost;\n                r.ops.reserve(tail.ops.size() + 1);\n                r.ops.push_back({label, b + 1});\n                r.ops.insert(r.ops.end(), tail.ops.begin(), tail.ops.end());\n                consider(std::move(r));\n            }\n\n            tried++;\n        }\n    }\n\n    // Optimize the final part of the currently best solution by macro beam.\n    if (!timeUp() && best.ok) {\n        auto tailEnd = startTime + chrono::milliseconds(1830);\n\n        vector<tuple<int,int,int,EvalParam>> tailCfgs;\n        tailCfgs.push_back({151, 45, 10, EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75}});\n        tailCfgs.push_back({161, 60, 12, EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65}});\n        tailCfgs.push_back({171, 80, 14, EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85}});\n        tailCfgs.push_back({181, 100, 16, EvalParam{3.0, 1.0, 2.0, 0.18, 2.8, 2.4, 0.70}});\n\n        for (auto [startV, W, perLimit, ep] : tailCfgs) {\n            if (timeUp() || chrono::steady_clock::now() > tailEnd) break;\n            if (!best.ok) break;\n\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost;\n            if (cutoffTail <= 0) continue;\n\n            Result tail = simulateTailMacroBeam(pref.st, startV, W, ep,\n                                                cutoffTail, tailEnd, perLimit);\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n    }\n\n    // Random multi-start until time limit.\n    while (!timeUp()) {\n        Params p = randomParams(master);\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    }\n\n    // Final safety.\n    if (!best.ok || validateCost(init, best.ops) < 0) {\n        best = simulateGreedy(init, pWhole, seed, INF);\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIMIT_LEN = 100000;\nstatic const int INTERNAL_LIMIT = 150000;\nstatic const unsigned short INF_DIST = 30000;\n\nint N, V;\nvector<string> hwall, vwall;\nvector<int> dirtv;\nvector<double> rootDirt;\ndouble meanRootDirt = 1.0;\n\nstruct Edge {\n    int to;\n    char ch;\n};\n\nvector<vector<Edge>> adjg;\nvector<unsigned short> distAll;\nvector<int> dist0;\nvector<vector<int>> nearList;\n\ninline int D(int a, int b) {\n    return distAll[a * V + b];\n}\n\ninline char moveChar(int from, int to) {\n    int diff = to - from;\n    if (diff == 1) return 'R';\n    if (diff == -1) return 'L';\n    if (diff == N) return 'D';\n    return 'U';\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 RouteBuilder {\n    int cur = 0;\n    int t = 0;\n    vector<int> seq;\n    string moves;\n    vector<int> last;\n    vector<char> seen;\n    int unseen = 0;\n\n    void init() {\n        cur = 0;\n        t = 0;\n        seq.clear();\n        moves.clear();\n        last.assign(V, 0);\n        seen.assign(V, 0);\n        seen[0] = 1;\n        unseen = V - 1;\n    }\n\n    void addMove(int nb) {\n        moves.push_back(moveChar(cur, nb));\n        cur = nb;\n        ++t;\n        seq.push_back(nb);\n        last[nb] = t;\n        if (!seen[nb]) {\n            seen[nb] = 1;\n            --unseen;\n        }\n    }\n};\n\nvoid computeAllPairsDistances() {\n    distAll.assign(V * V, INF_DIST);\n    vector<int> q(V);\n\n    for (int s = 0; s < V; ++s) {\n        unsigned short* ds = &distAll[s * V];\n        int head = 0, tail = 0;\n        ds[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int x = q[head++];\n            unsigned short nd = ds[x] + 1;\n            for (const auto& e : adjg[x]) {\n                if (ds[e.to] == INF_DIST) {\n                    ds[e.to] = nd;\n                    q[tail++] = e.to;\n                }\n            }\n        }\n    }\n\n    dist0.assign(V, 0);\n    for (int i = 0; i < V; ++i) dist0[i] = D(i, 0);\n}\n\nint chooseNextOnShortestPath(const RouteBuilder& b, int target, bool preferUnseen) {\n    int cur = b.cur;\n    int cd = D(target, cur);\n    int best = -1;\n    long double bestVal = -1e100L;\n\n    for (const auto& e : adjg[cur]) {\n        int nb = e.to;\n        if (D(target, nb) + 1 != cd) continue;\n\n        long long age = (long long)b.t + 1 - b.last[nb];\n        long double val = (long double)dirtv[nb] * age * age;\n\n        if (preferUnseen && !b.seen[nb]) val += 1e30L;\n        val += (long double)(nb % 23) * 1e-9L;\n\n        if (val > bestVal) {\n            bestVal = val;\n            best = nb;\n        }\n    }\n\n    if (best == -1) {\n        for (const auto& e : adjg[cur]) {\n            if (D(target, e.to) + 1 == cd) return e.to;\n        }\n    }\n    return best;\n}\n\nvoid appendPath(RouteBuilder& b, int target, bool preferUnseen) {\n    while (b.cur != target) {\n        int nb = chooseNextOnShortestPath(b, target, preferUnseen);\n        if (nb < 0) break;\n        b.addMove(nb);\n        if (b.t > INTERNAL_LIMIT) break;\n    }\n}\n\nlong double evaluateRange(const vector<int>& seq, int l, int r) {\n    int L = r - l;\n    if (L <= 0 || L > LIMIT_LEN) return 1e100L;\n    if (l < 0 || r > (int)seq.size()) return 1e100L;\n    if (seq[r - 1] != 0) return 1e100L;\n\n    vector<int> first(V, -1), prev(V, -1);\n    vector<long long> gapSum(V, 0);\n\n    for (int idx = l; idx < r; ++idx) {\n        int tt = idx - l + 1;\n        int id = seq[idx];\n\n        if (first[id] == -1) {\n            first[id] = tt;\n        } else {\n            long long g = tt - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = tt;\n    }\n\n    long double total = 0;\n    for (int id = 0; id < V; ++id) {\n        if (first[id] == -1) return 1e100L;\n        long long g = (long long)L - prev[id] + first[id];\n        gapSum[id] += g * (g - 1) / 2;\n        total += (long double)gapSum[id] * dirtv[id];\n    }\n\n    return total / L;\n}\n\nlong double evaluateSeq(const vector<int>& seq, int L) {\n    return evaluateRange(seq, 0, L);\n}\n\nvector<int> rowOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        } else {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> rowOrderBottom() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int ii = 0; ii < N; ++ii) {\n        int i = N - 1 - ii;\n        if (ii % 2 == 0) {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        } else {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int j = 0; j < N; ++j) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        } else {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrderRight() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int jj = 0; jj < N; ++jj) {\n        int j = N - 1 - jj;\n        if (jj % 2 == 0) {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        } else {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvoid rotHilbert(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\nlong long hilbertIndex(int x, int y) {\n    int S = 1;\n    while (S < N) S <<= 1;\n\n    long long d = 0;\n    for (int s = S / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += 1LL * s * s * ((3 * rx) ^ ry);\n        rotHilbert(s, x, y, rx, ry);\n    }\n    return d;\n}\n\nvector<int> hilbertOrder() {\n    vector<pair<long long, int>> a;\n    a.reserve(V);\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            a.push_back({hilbertIndex(j, i), i * N + j});\n        }\n    }\n\n    sort(a.begin(), a.end());\n    vector<int> ord;\n    ord.reserve(V);\n    for (auto [_, id] : a) ord.push_back(id);\n    return ord;\n}\n\nvector<int> metricNearestOrder(double beta, double expv) {\n    vector<double> attr(V);\n    for (int id = 0; id < V; ++id) {\n        attr[id] = pow((double)dirtv[id], expv);\n    }\n\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    int cur = 0;\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int step = 1; step < V; ++step) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (used[id]) continue;\n            double key = (double)D(cur, id) - beta * attr[id] + 0.002 * dist0[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n\n    return ord;\n}\n\nvector<int> metricInsertionOrder(int mode) {\n    vector<int> ids;\n    ids.reserve(V - 1);\n    for (int id = 1; id < V; ++id) ids.push_back(id);\n\n    if (mode == 0) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return dist0[a] > dist0[b];\n        });\n    } else if (mode == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return dirtv[a] > dirtv[b];\n        });\n    } else if (mode == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return rootDirt[a] * (dist0[a] + 1) > rootDirt[b] * (dist0[b] + 1);\n        });\n    } else {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            unsigned ha = (unsigned)(a * 1103515245u + 12345u);\n            unsigned hb = (unsigned)(b * 1103515245u + 12345u);\n            return ha < hb;\n        });\n    }\n\n    vector<int> ord;\n    ord.push_back(0);\n\n    for (int x : ids) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = (i + 1 < m ? ord[i + 1] : 0);\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        ord.insert(ord.begin() + bestPos, x);\n    }\n\n    return ord;\n}\n\nvector<int> highBackboneOrder(double frac, double beta) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<char> high(V, 0);\n    for (int i = 0; i < K; ++i) high[ids[i]] = 1;\n    high[0] = 1;\n\n    vector<int> ord;\n    vector<char> used(V, 0);\n    ord.push_back(0);\n    used[0] = 1;\n\n    int rem = 0;\n    for (int id = 0; id < V; ++id) if (high[id] && !used[id]) ++rem;\n\n    int cur = 0;\n    while (rem > 0) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (!high[id] || used[id]) continue;\n            double key = (double)D(cur, id) - beta * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n        --rem;\n    }\n\n    vector<int> lows;\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) lows.push_back(id);\n    }\n    sort(lows.begin(), lows.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    for (int x : lows) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = ord[(i + 1) % m];\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        if (bestPos >= (int)ord.size()) ord.push_back(x);\n        else ord.insert(ord.begin() + bestPos, x);\n        used[x] = 1;\n    }\n\n    return ord;\n}\n\nRouteBuilder makeRouteByOrder(const vector<int>& ord) {\n    RouteBuilder b;\n    b.init();\n\n    for (int id : ord) {\n        if (!b.seen[id]) appendPath(b, id, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeNearestCover(int variant) {\n    RouteBuilder b;\n    b.init();\n\n    while (b.unseen > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n\n            int r = D(b.cur, id);\n            double key;\n\n            if (variant == 0) {\n                key = r * 1000000.0 + dist0[id];\n            } else if (variant == 1) {\n                key = r * 1000000.0 - dirtv[id] * 200.0;\n            } else if (variant == 2) {\n                key = (r + 0.20 * dist0[id]) * 1000000.0 - dirtv[id] * 10.0;\n            } else if (variant == 3) {\n                unsigned x = (unsigned)(id * 1103515245u + 12345u);\n                key = r * 1000000.0 + (x % 10000) * 0.01;\n            } else {\n                int degUnseen = 0;\n                for (auto& e : adjg[id]) if (!b.seen[e.to]) ++degUnseen;\n                key = r * 1000000.0 + degUnseen * 1000.0 - dirtv[id] * 0.05;\n            }\n\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best == -1) break;\n        appendPath(b, best, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeDFSRoute(const string& dirOrder, int sortMode) {\n    RouteBuilder b;\n    b.init();\n\n    vector<int> rankDir(256, 0);\n    for (int i = 0; i < 4; ++i) rankDir[(unsigned char)dirOrder[i]] = i;\n\n    vector<char> vis(V, 0);\n\n    function<void(int)> dfs = [&](int u) {\n        vis[u] = 1;\n        vector<Edge> es = adjg[u];\n\n        sort(es.begin(), es.end(), [&](const Edge& a, const Edge& c) {\n            if (sortMode == 1 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] > dirtv[c.to];\n            }\n            if (sortMode == 2 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] < dirtv[c.to];\n            }\n            return rankDir[(unsigned char)a.ch] < rankDir[(unsigned char)c.ch];\n        });\n\n        for (auto& e : es) {\n            if (!vis[e.to]) {\n                b.addMove(e.to);\n                dfs(e.to);\n                b.addMove(u);\n            }\n        }\n    };\n\n    dfs(0);\n    return b;\n}\n\nvector<int> firstVisitOrder(const RouteBuilder& b) {\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int id : b.seq) {\n        if (!used[id]) {\n            used[id] = 1;\n            ord.push_back(id);\n        }\n    }\n\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) ord.push_back(id);\n    }\n\n    return ord;\n}\n\nvoid buildNearLists(int K) {\n    K = min(K, V - 1);\n    nearList.assign(V, {});\n\n    for (int a = 0; a < V; ++a) {\n        vector<pair<unsigned short, int>> tmp;\n        tmp.reserve(V - 1);\n\n        for (int b = 0; b < V; ++b) {\n            if (a != b) tmp.push_back({(unsigned short)D(a, b), b});\n        }\n\n        if (K < (int)tmp.size()) {\n            nth_element(tmp.begin(), tmp.begin() + K, tmp.end());\n            tmp.resize(K);\n        }\n\n        sort(tmp.begin(), tmp.end());\n        nearList[a].reserve(K);\n        for (auto [_, id] : tmp) nearList[a].push_back(id);\n    }\n}\n\nvoid rotateZeroFront(vector<int>& ord) {\n    auto it = find(ord.begin(), ord.end(), 0);\n    if (it != ord.end()) rotate(ord.begin(), it, ord.end());\n}\n\nvector<int> improveOrder2Opt(vector<int> ord, double lambda, const Timer& timer,\n                             double deadline, int maxImp) {\n    if (nearList.empty() || (int)ord.size() != V) return ord;\n    rotateZeroFront(ord);\n\n    int n = (int)ord.size();\n    vector<int> pos(V);\n    for (int i = 0; i < n; ++i) pos[ord[i]] = i;\n\n    auto edgeCost = [&](int a, int b) -> double {\n        double base = (double)D(a, b);\n        if (lambda <= 0.0) return base;\n        double w = min(rootDirt[a], rootDirt[b]) / meanRootDirt;\n        return base * (1.0 + lambda * w);\n    };\n\n    int imp = 0;\n\n    while (imp < maxImp && timer.elapsed() < deadline) {\n        bool changed = false;\n\n        for (int i = 0; i < n - 1 && !changed && timer.elapsed() < deadline; ++i) {\n            int a = ord[i];\n            int b = ord[i + 1];\n            double oldAB = edgeCost(a, b);\n\n            auto tryK = [&](int k) -> bool {\n                if (k <= i + 1 || k >= n) return false;\n                if (i == 0 && k == n - 1) return false;\n\n                int c = ord[k];\n                int d = ord[(k + 1) % n];\n\n                double delta = edgeCost(a, c) + edgeCost(b, d) - oldAB - edgeCost(c, d);\n                if (delta < -1e-9) {\n                    reverse(ord.begin() + i + 1, ord.begin() + k + 1);\n                    for (int p = i + 1; p <= k; ++p) pos[ord[p]] = p;\n                    ++imp;\n                    return true;\n                }\n                return false;\n            };\n\n            for (int cnode : nearList[a]) {\n                int k = pos[cnode];\n                if (tryK(k)) {\n                    changed = true;\n                    break;\n                }\n            }\n            if (changed) break;\n\n            for (int dnode : nearList[b]) {\n                int k = pos[dnode] - 1;\n                if (k < 0) k = n - 1;\n                if (tryK(k)) {\n                    changed = true;\n                    break;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n\n    return ord;\n}\n\nvector<int> makeCounts(const vector<double>& weight, double scale, int& M) {\n    vector<int> cnt(V);\n    M = 1;\n\n    for (int id = 0; id < V; ++id) {\n        int c = max(1, (int)(scale * weight[id] + 0.5));\n        cnt[id] = c;\n        M = max(M, c);\n    }\n\n    return cnt;\n}\n\nint initialAccumulator(int pos, int id, int M, int mode) {\n    if (M <= 1) return 0;\n    if (mode == 0) return 0;\n\n    int desired = 0;\n\n    if (mode == 1) {\n        desired = (int)((long long)pos * M / V);\n    } else if (mode == 2) {\n        desired = (int)((long long)(V - 1 - pos) * M / V);\n    } else if (mode == 3) {\n        unsigned x = (unsigned)(pos * 2654435761u + 1013904223u);\n        desired = x % M;\n    } else {\n        unsigned x = (unsigned)(id * 1103515245u + pos * 12345u + 24691u);\n        desired = x % M;\n    }\n\n    int a = M - 1 - desired;\n    a %= M;\n    if (a < 0) a += M;\n    return a;\n}\n\nvector<vector<int>> buildEvents(const vector<int>& ord, const vector<int>& cnt, int M, int mode) {\n    vector<vector<int>> events(M);\n\n    for (int k = 0; k < V; ++k) {\n        int id = ord[k];\n        int c = cnt[id];\n        int a = initialAccumulator(k, id, M, mode);\n\n        for (int m = 1; m <= c; ++m) {\n            long long num = 1LL * m * M - a;\n            int p = (int)((num + c - 1) / c - 1);\n            if (p < 0) p = 0;\n            if (p >= M) p = M - 1;\n            events[p].push_back(id);\n        }\n    }\n\n    return events;\n}\n\nlong long phaseLength(const vector<int>& ord, const vector<double>& weight,\n                      double scale, int mode, long long cap) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    long long len = 0;\n    int cur = 0;\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) {\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                int id = ev[idx];\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        }\n    }\n\n    len += D(cur, 0);\n    return len;\n}\n\nRouteBuilder buildPhaseRoute(const vector<int>& ord, const vector<double>& weight,\n                             double scale, int mode) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    RouteBuilder b;\n    b.init();\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) appendPath(b, id, true);\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                appendPath(b, ev[idx], true);\n            }\n        }\n\n        if (b.t > LIMIT_LEN + 2000) break;\n    }\n\n    appendPath(b, 0, true);\n    return b;\n}\n\ndouble findPhaseScale(const vector<int>& ord, const vector<double>& weight, int mode) {\n    double lo = 0.0, hi = 1.0;\n\n    while (hi < 2048.0 && phaseLength(ord, weight, hi, mode, LIMIT_LEN + 1) <= LIMIT_LEN) {\n        lo = hi;\n        hi *= 2.0;\n    }\n\n    for (int it = 0; it < 13; ++it) {\n        double mid = (lo + hi) * 0.5;\n        if (phaseLength(ord, weight, mid, mode, LIMIT_LEN + 1) <= LIMIT_LEN) lo = mid;\n        else hi = mid;\n    }\n\n    return lo;\n}\n\nRouteBuilder buildChunkGreedy(RouteBuilder prefix, double offset, int minTargetDist,\n                              int chunk, int maxLen, const Timer& timer, double timeLimit) {\n    RouteBuilder b = std::move(prefix);\n\n    auto selectTarget = [&](int md) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (b.t + r + dist0[id] > maxLen) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n\n    while (b.t + D(b.cur, 0) < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        int target = selectTarget(minTargetDist);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n            if (b.t > INTERNAL_LIMIT) break;\n        }\n\n        if (b.t > INTERNAL_LIMIT) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n    return b;\n}\n\nvoid finishCoverAndReturn(RouteBuilder& b, int maxLen) {\n    while (b.unseen > 0 && b.t < maxLen) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n            int r = D(b.cur, id);\n            if (b.t + r + dist0[id] > maxLen) continue;\n            double key = r + 0.15 * dist0[id] - 0.02 * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        appendPath(b, best, true);\n        if (b.t > maxLen) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n}\n\nRouteBuilder buildIntegratedGreedy(double offset, int minTargetDist, int chunk,\n                                   int maxLen, double unseenBonus, double unseenMult,\n                                   const Timer& timer, double timeLimit) {\n    RouteBuilder b;\n    b.init();\n\n    auto selectTarget = [&](int md, bool forceUnseen) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (forceUnseen && b.seen[id]) continue;\n            if (b.t + r + dist0[id] + 2 * b.unseen > maxLen + 1000) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (!b.seen[id]) {\n                score = score * unseenMult + unseenBonus / (r + 1.0);\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n    while (b.t + D(b.cur, 0) + 2 * V + 30 < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        bool force = (b.unseen > 0 && b.t + D(b.cur, 0) + 2 * V + 1500 > maxLen);\n        int target = selectTarget(minTargetDist, force);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1, force);\n        if (target == -1 && force) target = selectTarget(1, false);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n        }\n    }\n\n    finishCoverAndReturn(b, maxLen);\n    return b;\n}\n\nRouteBuilder buildHighSubsetLoop(double frac) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<char> need(V, 0);\n    for (int i = 0; i < K; ++i) need[ids[i]] = 1;\n\n    RouteBuilder b;\n    b.init();\n\n    auto remaining = [&]() {\n        int r = 0;\n        for (int id = 0; id < V; ++id) {\n            if (need[id] && !b.seen[id]) ++r;\n        }\n        return r;\n    };\n\n    while (remaining() > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (!need[id] || b.seen[id]) continue;\n            double key = (double)D(b.cur, id) - 0.35 * rootDirt[id] + 0.01 * dist0[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        appendPath(b, best, true);\n        if (b.t + D(b.cur, 0) > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder composeLoops(const RouteBuilder& cover, const RouteBuilder& loop, int reps) {\n    RouteBuilder b;\n    b.init();\n\n    for (int nb : cover.seq) b.addMove(nb);\n\n    for (int r = 0; r < reps; ++r) {\n        for (int nb : loop.seq) b.addMove(nb);\n    }\n\n    return b;\n}\n\nvector<int> topCellsByDirt(double frac) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    ids.resize(K);\n    return ids;\n}\n\nint chooseMedoid(const vector<int>& cells) {\n    if (cells.empty()) return 0;\n\n    vector<int> cand = cells;\n    sort(cand.begin(), cand.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n    if ((int)cand.size() > 40) cand.resize(40);\n\n    int best = cand[0];\n    long double bestCost = 1e100L;\n\n    for (int a : cand) {\n        long double cost = 0;\n        for (int x : cells) {\n            cost += (long double)D(a, x) * rootDirt[x];\n        }\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = a;\n        }\n    }\n\n    return best;\n}\n\nRouteBuilder makeLocalLoop(int anchor, const vector<int>& cells, double beta) {\n    RouteBuilder b;\n    b.init();\n    b.cur = anchor;\n    b.seen.assign(V, 1);\n    b.unseen = 0;\n    b.last.assign(V, 0);\n\n    vector<char> need(V, 0), done(V, 0);\n    int rem = 0;\n\n    for (int id : cells) {\n        if (!need[id]) {\n            need[id] = 1;\n            ++rem;\n        }\n    }\n\n    if (need[anchor]) {\n        done[anchor] = 1;\n        --rem;\n    }\n\n    auto markNew = [&](int fromIdx) {\n        for (int i = fromIdx; i < b.t; ++i) {\n            int id = b.seq[i];\n            if (need[id] && !done[id]) {\n                done[id] = 1;\n                --rem;\n            }\n        }\n    };\n\n    while (rem > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id : cells) {\n            if (!need[id] || done[id]) continue;\n            double key = D(b.cur, id) + 0.08 * D(id, anchor) - beta * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n\n        int oldT = b.t;\n        appendPath(b, best, false);\n        markNew(oldT);\n\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    appendPath(b, anchor, false);\n    return b;\n}\n\nvector<int> selectAnchors(const vector<int>& cells, int C) {\n    vector<int> sorted = cells;\n    sort(sorted.begin(), sorted.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    vector<int> anchors;\n    if (sorted.empty()) return anchors;\n\n    anchors.push_back(sorted[0]);\n\n    while ((int)anchors.size() < C && (int)anchors.size() < (int)sorted.size()) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int id : sorted) {\n            bool used = false;\n            for (int a : anchors) if (a == id) used = true;\n            if (used) continue;\n\n            int md = 1000000;\n            for (int a : anchors) md = min(md, D(id, a));\n\n            double score = rootDirt[id] * (md + 1);\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        anchors.push_back(best);\n    }\n\n    return anchors;\n}\n\nRouteBuilder composeLocalInsertion(const RouteBuilder& cover, int anchor,\n                                   const RouteBuilder& loop, int reps) {\n    RouteBuilder invalid;\n    if (loop.t <= 0 || reps <= 0) return invalid;\n    if (cover.t + 1LL * reps * loop.t > LIMIT_LEN) return invalid;\n\n    int p = -2;\n    if (anchor == 0) {\n        p = -1;\n    } else {\n        for (int i = 0; i < cover.t; ++i) {\n            if (cover.seq[i] == anchor) {\n                p = i;\n                break;\n            }\n        }\n    }\n\n    if (p == -2) return invalid;\n\n    RouteBuilder b;\n    b.init();\n\n    for (int i = 0; i <= p; ++i) b.addMove(cover.seq[i]);\n\n    for (int r = 0; r < reps; ++r) {\n        for (int nb : loop.seq) b.addMove(nb);\n    }\n\n    for (int i = p + 1; i < cover.t; ++i) b.addMove(cover.seq[i]);\n\n    return b;\n}\n\nRouteBuilder composeMultiLocal(const RouteBuilder& cover,\n                               const vector<int>& anchors,\n                               const vector<RouteBuilder>& loops,\n                               const vector<int>& reps) {\n    RouteBuilder invalid;\n\n    int m = loops.size();\n    long long len = cover.t;\n    for (int i = 0; i < m; ++i) len += 1LL * reps[i] * loops[i].t;\n    if (len <= 0 || len > LIMIT_LEN) return invalid;\n\n    vector<int> pos(m, -2);\n    for (int k = 0; k < m; ++k) {\n        if (anchors[k] == 0) {\n            pos[k] = -1;\n        } else {\n            for (int i = 0; i < cover.t; ++i) {\n                if (cover.seq[i] == anchors[k]) {\n                    pos[k] = i;\n                    break;\n                }\n            }\n        }\n        if (pos[k] == -2) return invalid;\n    }\n\n    RouteBuilder b;\n    b.init();\n\n    for (int k = 0; k < m; ++k) {\n        if (pos[k] == -1) {\n            for (int r = 0; r < reps[k]; ++r) {\n                for (int nb : loops[k].seq) b.addMove(nb);\n            }\n        }\n    }\n\n    for (int i = 0; i < cover.t; ++i) {\n        b.addMove(cover.seq[i]);\n\n        for (int k = 0; k < m; ++k) {\n            if (pos[k] == i) {\n                for (int r = 0; r < reps[k]; ++r) {\n                    for (int nb : loops[k].seq) b.addMove(nb);\n                }\n            }\n        }\n    }\n\n    return b;\n}\n\nuint64_t hashOrder(const vector<int>& ord) {\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\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n\n    cin >> N;\n    V = N * N;\n\n    hwall.resize(N - 1);\n    for (int i = 0; i < N - 1; ++i) cin >> hwall[i];\n\n    vwall.resize(N);\n    for (int i = 0; i < N; ++i) cin >> vwall[i];\n\n    dirtv.assign(V, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> dirtv[i * N + j];\n        }\n    }\n\n    adjg.assign(V, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = i * N + j;\n\n            if (i + 1 < N && hwall[i][j] == '0') {\n                int to = (i + 1) * N + j;\n                adjg[id].push_back({to, 'D'});\n                adjg[to].push_back({id, 'U'});\n            }\n\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int to = i * N + (j + 1);\n                adjg[id].push_back({to, 'R'});\n                adjg[to].push_back({id, 'L'});\n            }\n        }\n    }\n\n    computeAllPairsDistances();\n\n    rootDirt.assign(V, 1.0);\n    meanRootDirt = 0.0;\n    for (int id = 0; id < V; ++id) {\n        rootDirt[id] = sqrt((double)dirtv[id]);\n        meanRootDirt += rootDirt[id];\n    }\n    meanRootDirt /= V;\n    if (meanRootDirt <= 0) meanRootDirt = 1.0;\n\n    long double bestScore = 1e100L;\n    string bestMoves;\n\n    RouteBuilder bestShort;\n    long double bestShortScore = 1e100L;\n\n    RouteBuilder shortestShort;\n    int shortestLen = INT_MAX;\n\n    auto considerSegment = [&](const RouteBuilder& b, int l, int r) {\n        if (l < 0 || r > b.t || l >= r) return;\n        if (r - l > LIMIT_LEN) return;\n        if (l > 0 && b.seq[l - 1] != 0) return;\n        if (b.seq[r - 1] != 0) return;\n\n        long double sc = evaluateRange(b.seq, l, r);\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestMoves = b.moves.substr(l, r - l);\n        }\n    };\n\n    auto considerFull = [&](const RouteBuilder& b) {\n        considerSegment(b, 0, b.t);\n    };\n\n    auto considerShort = [&](const RouteBuilder& b) {\n        if (b.t <= LIMIT_LEN && b.cur == 0 && b.unseen == 0) {\n            long double sc = evaluateSeq(b.seq, b.t);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = b.moves;\n            }\n\n            if (sc < bestShortScore) {\n                bestShortScore = sc;\n                bestShort = b;\n            }\n\n            if (b.t < shortestLen) {\n                shortestLen = b.t;\n                shortestShort = b;\n            }\n        }\n    };\n\n    vector<int> ordRow = rowOrder();\n    vector<int> ordCol = colOrder();\n    vector<int> ordRowB = rowOrderBottom();\n    vector<int> ordColR = colOrderRight();\n    vector<int> ordHilbert = hilbertOrder();\n\n    vector<int> ordMet0 = metricNearestOrder(0.0, 0.5);\n    vector<int> ordMet1 = metricNearestOrder(0.25, 0.5);\n    vector<int> ordMet2 = metricNearestOrder(0.55, 0.5);\n    vector<int> ordHigh25 = highBackboneOrder(0.25, 0.20);\n    vector<int> ordHigh50 = highBackboneOrder(0.50, 0.10);\n    vector<int> ordIns0 = metricInsertionOrder(0);\n    vector<int> ordIns1 = metricInsertionOrder(1);\n    vector<int> ordIns2 = metricInsertionOrder(2);\n\n    vector<RouteBuilder> shortCandidates;\n\n    vector<string> dirs = {\"RDLU\", \"DRUL\", \"LURD\", \"ULDR\", \"RULD\", \"DLUR\"};\n    for (int i = 0; i < (int)dirs.size(); ++i) {\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 0));\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 1));\n        if (i < 2) shortCandidates.push_back(makeDFSRoute(dirs[i], 2));\n    }\n\n    shortCandidates.push_back(makeRouteByOrder(ordRow));\n    shortCandidates.push_back(makeRouteByOrder(ordCol));\n    shortCandidates.push_back(makeRouteByOrder(ordRowB));\n    shortCandidates.push_back(makeRouteByOrder(ordColR));\n    shortCandidates.push_back(makeRouteByOrder(ordMet0));\n    shortCandidates.push_back(makeRouteByOrder(ordMet1));\n    shortCandidates.push_back(makeRouteByOrder(ordHigh25));\n    shortCandidates.push_back(makeRouteByOrder(ordHigh50));\n    shortCandidates.push_back(makeRouteByOrder(ordIns0));\n    shortCandidates.push_back(makeRouteByOrder(ordIns1));\n    shortCandidates.push_back(makeRouteByOrder(ordIns2));\n\n    for (int v = 0; v < 5; ++v) {\n        shortCandidates.push_back(makeNearestCover(v));\n    }\n\n    for (auto& b : shortCandidates) considerShort(b);\n\n    if (bestShort.t == 0) {\n        bestShort = shortCandidates[0];\n        shortestShort = shortCandidates[0];\n        shortestLen = shortestShort.t;\n        considerFull(bestShort);\n    }\n\n    vector<vector<int>> optOrders;\n\n    if (timer.elapsed() < 0.34) {\n        buildNearLists(34);\n\n        vector<vector<int>> bases;\n        bases.push_back(firstVisitOrder(bestShort));\n        bases.push_back(ordMet0);\n        bases.push_back(ordMet1);\n        bases.push_back(ordMet2);\n        bases.push_back(ordHigh25);\n        bases.push_back(ordHigh50);\n        bases.push_back(ordIns0);\n        bases.push_back(ordIns1);\n        bases.push_back(ordIns2);\n        bases.push_back(ordRow);\n        bases.push_back(ordCol);\n\n        for (int i = 0; i < (int)bases.size() && timer.elapsed() < 0.66; ++i) {\n            vector<int> op = improveOrder2Opt(bases[i], 0.0, timer, 0.66, 260);\n            optOrders.push_back(op);\n\n            RouteBuilder rb = makeRouteByOrder(op);\n            shortCandidates.push_back(rb);\n            considerShort(rb);\n\n            if (i < 6 && timer.elapsed() < 0.72) {\n                vector<int> opw = improveOrder2Opt(bases[i], 0.85, timer, 0.72, 180);\n                optOrders.push_back(opw);\n\n                RouteBuilder rbw = makeRouteByOrder(opw);\n                shortCandidates.push_back(rbw);\n                considerShort(rbw);\n            }\n        }\n    }\n\n    if (shortestShort.t == 0) shortestShort = bestShort;\n\n    if (timer.elapsed() < 0.78) {\n        vector<double> fracs = {0.03, 0.06, 0.10, 0.18, 0.30};\n\n        auto tryLocalCover = [&](const RouteBuilder& cover) {\n            for (double f : fracs) {\n                if (timer.elapsed() > 0.92) break;\n\n                vector<int> cells = topCellsByDirt(f);\n                int anchor = chooseMedoid(cells);\n                RouteBuilder loop = makeLocalLoop(anchor, cells, 0.35);\n\n                if (loop.t <= 0 || loop.cur != anchor) continue;\n                int maxR = (LIMIT_LEN - cover.t) / loop.t;\n                if (maxR <= 0) continue;\n\n                vector<int> rs = {1, 2, 3, 5, 8, 13, 21, maxR / 6, maxR / 4, maxR / 2, maxR};\n                sort(rs.begin(), rs.end());\n                rs.erase(unique(rs.begin(), rs.end()), rs.end());\n\n                for (int r : rs) {\n                    if (r <= 0 || r > maxR) continue;\n                    RouteBuilder c = composeLocalInsertion(cover, anchor, loop, r);\n                    if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n                    if (timer.elapsed() > 0.94) break;\n                }\n            }\n        };\n\n        tryLocalCover(shortestShort);\n        if (bestShort.moves != shortestShort.moves && timer.elapsed() < 0.94) tryLocalCover(bestShort);\n    }\n\n    if (timer.elapsed() < 0.95) {\n        vector<double> fracs = {0.10, 0.20, 0.35};\n\n        for (double f : fracs) {\n            if (timer.elapsed() > 1.02) break;\n\n            vector<int> cells = topCellsByDirt(f);\n            vector<int> anchors = selectAnchors(cells, 3);\n            if (anchors.empty()) continue;\n\n            vector<vector<int>> groups(anchors.size());\n            for (int x : cells) {\n                int bi = 0;\n                int bd = D(x, anchors[0]);\n                for (int i = 1; i < (int)anchors.size(); ++i) {\n                    int dd = D(x, anchors[i]);\n                    if (dd < bd) {\n                        bd = dd;\n                        bi = i;\n                    }\n                }\n                groups[bi].push_back(x);\n            }\n\n            vector<int> useAnchors;\n            vector<RouteBuilder> loops;\n            vector<double> vals;\n\n            for (int i = 0; i < (int)anchors.size(); ++i) {\n                if ((int)groups[i].size() <= 1) continue;\n                RouteBuilder lp = makeLocalLoop(anchors[i], groups[i], 0.25);\n                if (lp.t <= 0 || lp.cur != anchors[i]) continue;\n\n                double val = 0;\n                for (int x : groups[i]) val += rootDirt[x];\n\n                useAnchors.push_back(anchors[i]);\n                loops.push_back(lp);\n                vals.push_back(val);\n            }\n\n            int m = loops.size();\n            if (m == 0) continue;\n\n            vector<double> ratios = {0.12, 0.25, 0.40, 0.65};\n            for (double ratio : ratios) {\n                int budget = max(0, (int)((LIMIT_LEN - shortestShort.t) * ratio));\n                vector<int> reps(m, 0);\n                int used = 0;\n\n                while (true) {\n                    int bj = -1;\n                    double bs = -1;\n\n                    for (int j = 0; j < m; ++j) {\n                        if (used + loops[j].t > budget) continue;\n                        double s = vals[j] / ((reps[j] + 1.0) * (reps[j] + 1.0) * loops[j].t);\n                        if (s > bs) {\n                            bs = s;\n                            bj = j;\n                        }\n                    }\n\n                    if (bj < 0) break;\n                    ++reps[bj];\n                    used += loops[bj].t;\n                }\n\n                bool any = false;\n                for (int r : reps) if (r > 0) any = true;\n                if (!any) continue;\n\n                RouteBuilder c = composeMultiLocal(shortestShort, useAnchors, loops, reps);\n                if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n            }\n        }\n    }\n\n    if (timer.elapsed() < 1.03) {\n        vector<double> fracs = {0.05, 0.10, 0.20, 0.35, 0.50};\n\n        for (double f : fracs) {\n            if (timer.elapsed() > 1.08) break;\n\n            RouteBuilder loop = buildHighSubsetLoop(f);\n            if (loop.t <= 0 || loop.cur != 0) continue;\n\n            auto tryCover = [&](const RouteBuilder& cover) {\n                if (cover.t <= 0 || loop.t <= 0) return;\n                int maxR = (LIMIT_LEN - cover.t) / loop.t;\n                if (maxR <= 0) return;\n\n                vector<int> rs = {1, 2, 3, 5, 8, 13, 21, maxR / 4, maxR / 2, maxR};\n                sort(rs.begin(), rs.end());\n                rs.erase(unique(rs.begin(), rs.end()), rs.end());\n\n                for (int r : rs) {\n                    if (r <= 0 || r > maxR) continue;\n                    if (cover.t + 1LL * r * loop.t > LIMIT_LEN) continue;\n\n                    RouteBuilder c = composeLoops(cover, loop, r);\n                    if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n                }\n            };\n\n            tryCover(shortestShort);\n            if (bestShort.moves != shortestShort.moves) tryCover(bestShort);\n        }\n    }\n\n    vector<vector<int>> orders;\n    unordered_set<uint64_t> orderHashes;\n\n    auto addOrder = [&](vector<int> ord) {\n        if ((int)ord.size() != V) return;\n\n        vector<char> seen(V, 0);\n        for (int x : ord) {\n            if (x < 0 || x >= V || seen[x]) return;\n            seen[x] = 1;\n        }\n\n        uint64_t h = hashOrder(ord);\n        if (orderHashes.insert(h).second) orders.push_back(ord);\n    };\n\n    addOrder(firstVisitOrder(bestShort));\n    for (auto& o : optOrders) addOrder(o);\n\n    addOrder(ordMet0);\n    addOrder(ordMet1);\n    addOrder(ordMet2);\n    addOrder(ordHigh25);\n    addOrder(ordHigh50);\n    addOrder(ordIns0);\n    addOrder(ordIns1);\n    addOrder(ordIns2);\n    addOrder(ordRow);\n    addOrder(ordCol);\n    addOrder(ordRowB);\n    addOrder(ordColR);\n    addOrder(ordHilbert);\n\n    for (auto& b : shortCandidates) {\n        addOrder(firstVisitOrder(b));\n    }\n\n    int initialOrderCount = orders.size();\n    for (int i = 0; i < initialOrderCount; ++i) {\n        vector<int> rev = orders[i];\n        reverse(rev.begin(), rev.end());\n        addOrder(rev);\n    }\n\n    vector<double> baseExps = {0.36, 0.44, 0.52, 0.62};\n    vector<double> richExps = {0.28, 0.36, 0.44, 0.52, 0.60, 0.70};\n    vector<double> muls = {1.00, 0.96, 0.90, 0.82, 0.72, 0.60, 0.48, 0.38, 0.30, 1.05};\n\n    double phaseEnd = 1.50;\n\n    for (int oi = 0; oi < (int)orders.size(); ++oi) {\n        if (timer.elapsed() > phaseEnd) break;\n\n        const vector<int>& ord = orders[oi];\n        const vector<double>& exps = (oi < 11 ? richExps : baseExps);\n\n        vector<int> modes;\n        if (oi < 6) modes = {0, 1, 2, 3, 4};\n        else if (oi < 14) modes = {0, 1, 2, 3};\n        else modes = {0, 1};\n\n        for (double ep : exps) {\n            if (timer.elapsed() > phaseEnd) break;\n\n            vector<double> weight(V);\n            for (int id = 0; id < V; ++id) {\n                weight[id] = pow((double)dirtv[id], ep);\n            }\n\n            for (int mode : modes) {\n                if (timer.elapsed() > phaseEnd + 0.02) break;\n\n                double scale = findPhaseScale(ord, weight, mode);\n\n                for (double m : muls) {\n                    double sca = scale * m;\n                    if (sca < 0.0) continue;\n\n                    long long len = phaseLength(ord, weight, sca, mode, LIMIT_LEN + 1);\n                    if (len <= LIMIT_LEN) {\n                        RouteBuilder b = buildPhaseRoute(ord, weight, sca, mode);\n                        if (b.t <= LIMIT_LEN && b.cur == 0) {\n                            considerFull(b);\n                        }\n                    }\n\n                    if (timer.elapsed() > phaseEnd + 0.03) break;\n                }\n            }\n        }\n    }\n\n    auto considerSegments = [&](const RouteBuilder& b, int minGap) {\n        vector<int> zeros;\n        zeros.push_back(0);\n        for (int t = 1; t <= b.t; ++t) {\n            if (b.seq[t - 1] == 0) zeros.push_back(t);\n        }\n\n        int lastPrefix = 0;\n        for (int z : zeros) {\n            if (z > 0 && z - lastPrefix >= minGap) {\n                considerSegment(b, 0, z);\n                lastPrefix = z;\n                if (timer.elapsed() > 1.93) return;\n            }\n        }\n\n        int lastS = -1000000000;\n        int cnt = 0;\n        for (int z : zeros) {\n            int L = b.t - z;\n            if (L <= 0 || L > LIMIT_LEN) continue;\n            if (z - lastS >= max(2000, minGap / 2)) {\n                considerSegment(b, z, b.t);\n                lastS = z;\n                ++cnt;\n                if (cnt >= 30 || timer.elapsed() > 1.93) return;\n            }\n        }\n\n        vector<int> targets = {minGap, 20000, 35000, 50000, 70000, 90000, 100000};\n        unordered_set<unsigned long long> usedPairs;\n        int evals = 0;\n\n        for (int ei = 1; ei < (int)zeros.size() && evals < 45; ++ei) {\n            int e = zeros[ei];\n\n            for (int TL : targets) {\n                int want = e - TL;\n                auto it = lower_bound(zeros.begin(), zeros.begin() + ei, want);\n\n                for (int rep = 0; rep < 2; ++rep) {\n                    if (it == zeros.begin() + ei) {\n                        if (it == zeros.begin()) break;\n                        --it;\n                    }\n\n                    int s = *it;\n                    int L = e - s;\n                    if (L >= max(1000, minGap / 2) && L <= LIMIT_LEN) {\n                        unsigned long long key = ((unsigned long long)(unsigned int)s << 32) ^ (unsigned int)e;\n                        if (usedPairs.insert(key).second) {\n                            considerSegment(b, s, e);\n                            ++evals;\n                            if (timer.elapsed() > 1.93) return;\n                        }\n                    }\n\n                    if (it == zeros.begin()) break;\n                    --it;\n                }\n            }\n        }\n    };\n\n    if (timer.elapsed() < 1.54) {\n        RouteBuilder ig = buildIntegratedGreedy(28.0, 1, 8, 70000, 8e9, 5.0, timer, 1.61);\n        if (ig.cur == 0) {\n            considerFull(ig);\n            considerSegments(ig, 10000);\n        }\n    }\n\n    if (timer.elapsed() < 1.62) {\n        RouteBuilder ig = buildIntegratedGreedy(45.0, 1, 10, LIMIT_LEN, 1.2e10, 7.0, timer, 1.70);\n        if (ig.cur == 0) {\n            considerFull(ig);\n            considerSegments(ig, 12000);\n        }\n    }\n\n    if (timer.elapsed() < 1.70) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 20.0, 1, 4, LIMIT_LEN, timer, 1.78);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 12000);\n            if (bestShort.t < g.t) considerSegment(g, bestShort.t, g.t);\n        }\n    }\n\n    if (timer.elapsed() < 1.78) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 25.0, 1, 1,\n                                          bestShort.t + LIMIT_LEN, timer, 1.86);\n        if (g.cur == 0) {\n            if (bestShort.t < g.t) considerSegment(g, bestShort.t, g.t);\n            considerSegments(g, 14000);\n        }\n    }\n\n    if (timer.elapsed() < 1.86) {\n        RouteBuilder g = buildChunkGreedy(shortestShort, 36.0, 1, 2,\n                                          LIMIT_LEN, timer, 1.92);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 12000);\n            if (shortestShort.t < g.t) considerSegment(g, shortestShort.t, g.t);\n        }\n    }\n\n    if (timer.elapsed() < 1.92) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 70.0, 3, 5,\n                                          76000, timer, 1.96);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 9000);\n        }\n    }\n\n    if (bestMoves.empty()) {\n        bestMoves = shortCandidates[0].moves;\n    }\n\n    cout << bestMoves << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x = 88172645463325252ull;\n    uint32_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n    double nextDouble() { return (next() >> 8) * (1.0 / 16777216.0); }\n};\n\nstruct Solver {\n    static constexpr unsigned short USINF = 30000;\n\n    int N, M;\n    int si, sj, startId;\n    vector<string> grid;\n    vector<string> words;\n    vector<array<int, 5>> wch;\n\n    vector<int> letterPos[26];\n    unsigned char distCell[225][225];\n\n    vector<int> lastChar;\n    vector<unsigned char> overlap;\n\n    vector<int> initOff;\n    vector<unsigned short> initData;\n    vector<int> startMinCost, startMin10, startAvg10;\n\n    vector<int> edgeOff;\n    vector<unsigned short> edgeData;\n    vector<int> edgeMin10, edgeAvg10;\n\n    int maxOcc = 0;\n\n    struct Mode {\n        vector<int> edge;\n        vector<int> start;\n    };\n    vector<Mode> modes;\n\n    struct Move {\n        int type; // 0 relocate, 1 swap, 2 reverse, 3 block relocate, 4 block swap, 5 reversed block relocate\n        int a, b;\n        long long delta;\n        int c;\n    };\n\n    struct Candidate {\n        int cost;\n        vector<int> order;\n    };\n\n    struct ExactCtx {\n        int n;\n        vector<int> cnt;\n        vector<int> foff, roff;\n        vector<unsigned short> fdata, rdata;\n        vector<int> prefOff, suffOff;\n        vector<unsigned short> prefData, suffData;\n        int current = 0;\n    };\n\n    Timer timer;\n    XorShift rng;\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    unordered_map<int, int> targetMap;\n    int pow4 = 456976;\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        startId = si * N + sj;\n\n        grid.resize(N);\n        for (int c = 0; c < 26; c++) letterPos[c].clear();\n\n        for (int i = 0; i < N; i++) {\n            cin >> grid[i];\n            for (int j = 0; j < N; j++) {\n                int c = grid[i][j] - 'A';\n                letterPos[c].push_back(i * N + j);\n            }\n        }\n\n        words.resize(M);\n        wch.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) wch[i][k] = words[i][k] - 'A';\n        }\n    }\n\n    int encodeWord(const string& s) const {\n        int code = 0;\n        for (char ch : s) code = code * 26 + (ch - 'A');\n        return code;\n    }\n\n    int calcOverlap(int a, int b) const {\n        for (int k = 4; k >= 1; k--) {\n            bool ok = true;\n            for (int p = 0; p < k; p++) {\n                if (words[a][5 - k + p] != words[b][p]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    inline int wordCnt(int w) const {\n        return (int)letterPos[lastChar[w]].size();\n    }\n\n    void precompute() {\n        int V = N * N;\n        for (int a = 0; a < V; a++) {\n            int ai = a / N, aj = a % N;\n            for (int b = 0; b < V; b++) {\n                int bi = b / N, bj = b % N;\n                distCell[a][b] = (unsigned char)(abs(ai - bi) + abs(aj - bj));\n            }\n        }\n\n        maxOcc = 0;\n        for (int c = 0; c < 26; c++) {\n            maxOcc = max(maxOcc, (int)letterPos[c].size());\n        }\n\n        lastChar.assign(M, 0);\n        for (int i = 0; i < M; i++) lastChar[i] = wch[i][4];\n\n        overlap.assign(M * M, 0);\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                overlap[i * M + j] = (unsigned char)calcOverlap(i, j);\n            }\n        }\n\n        targetMap.clear();\n        targetMap.reserve(512);\n        for (int i = 0; i < M; i++) targetMap[encodeWord(words[i])] = i;\n\n        long long sumOccLast = 0;\n        for (int i = 0; i < M; i++) {\n            sumOccLast += (int)letterPos[lastChar[i]].size();\n        }\n\n        initOff.assign(M, 0);\n        startMinCost.assign(M, 0);\n        startMin10.assign(M, 0);\n        startAvg10.assign(M, 0);\n        initData.clear();\n        initData.reserve((size_t)sumOccLast);\n\n        vector<int> cur(maxOcc), nxt(maxOcc);\n        const int INF = 1e9;\n\n        for (int i = 0; i < M; i++) {\n            int c0 = wch[i][0];\n            int cnt = (int)letterPos[c0].size();\n\n            for (int p = 0; p < cnt; p++) {\n                cur[p] = (int)distCell[startId][letterPos[c0][p]] + 1;\n            }\n\n            int prevC = c0;\n            int prevCnt = cnt;\n            for (int h = 1; h < 5; h++) {\n                int nc = wch[i][h];\n                int nextCnt = (int)letterPos[nc].size();\n\n                for (int q = 0; q < nextCnt; q++) {\n                    int best = INF;\n                    int qid = letterPos[nc][q];\n                    for (int p = 0; p < prevCnt; p++) {\n                        int v = cur[p] + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                        if (v < best) best = v;\n                    }\n                    nxt[q] = best;\n                }\n\n                for (int q = 0; q < nextCnt; q++) cur[q] = nxt[q];\n                prevC = nc;\n                prevCnt = nextCnt;\n            }\n\n            initOff[i] = (int)initData.size();\n            int mn = INF;\n            long long sum = 0;\n            for (int p = 0; p < prevCnt; p++) {\n                mn = min(mn, cur[p]);\n                sum += cur[p];\n                initData.push_back((unsigned short)cur[p]);\n            }\n            startMinCost[i] = mn;\n            startMin10[i] = 10 * mn;\n            startAvg10[i] = (int)((10 * sum + prevCnt / 2) / prevCnt);\n        }\n\n        edgeOff.assign(M * M, 0);\n        edgeAvg10.assign(M * M, 0);\n        edgeMin10.assign(M * M, 0);\n        edgeData.clear();\n\n        long long totalMat = sumOccLast * sumOccLast;\n        if (totalMat < 100000000LL) edgeData.reserve((size_t)totalMat);\n\n        vector<int> mat(maxOcc * maxOcc), mat2(maxOcc * maxOcc);\n\n        for (int i = 0; i < M; i++) {\n            int cStart = lastChar[i];\n            int rows = (int)letterPos[cStart].size();\n\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int k = overlap[idx];\n\n                int prevC = cStart;\n                int prevCnt = rows;\n\n                fill(mat.begin(), mat.begin() + rows * prevCnt, INF);\n                for (int r = 0; r < rows; r++) mat[r * prevCnt + r] = 0;\n\n                for (int h = k; h < 5; h++) {\n                    int nc = wch[j][h];\n                    int nextCnt = (int)letterPos[nc].size();\n\n                    for (int r = 0; r < rows; r++) {\n                        int baseIdx = r * prevCnt;\n                        int outIdx = r * nextCnt;\n                        for (int q = 0; q < nextCnt; q++) {\n                            int best = INF;\n                            int qid = letterPos[nc][q];\n                            for (int p = 0; p < prevCnt; p++) {\n                                int v = mat[baseIdx + p]\n                                      + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                                if (v < best) best = v;\n                            }\n                            mat2[outIdx + q] = best;\n                        }\n                    }\n\n                    mat.swap(mat2);\n                    prevC = nc;\n                    prevCnt = nextCnt;\n                }\n\n                int cols = (int)letterPos[lastChar[j]].size();\n                edgeOff[idx] = (int)edgeData.size();\n                edgeData.resize(edgeData.size() + rows * cols);\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                int off = edgeOff[idx];\n\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    for (int q = 0; q < cols; q++) {\n                        int v = mat[r * cols + q];\n                        edgeData[off + r * cols + q] = (unsigned short)v;\n                        rowMin = min(rowMin, v);\n                        globalMin = min(globalMin, v);\n                    }\n                    sumRowMin += rowMin;\n                }\n\n                edgeMin10[idx] = 10 * globalMin;\n                edgeAvg10[idx] = (int)((10 * sumRowMin + rows / 2) / rows);\n            }\n        }\n    }\n\n    void buildModes() {\n        modes.clear();\n        modes.resize(4);\n\n        for (auto& mo : modes) {\n            mo.edge.assign(M * M, 0);\n            mo.start.assign(M, 0);\n        }\n\n        for (int i = 0; i < M; i++) {\n            modes[0].start[i] = startAvg10[i];\n            modes[1].start[i] = startMin10[i];\n            modes[2].start[i] = startAvg10[i];\n            modes[3].start[i] = startAvg10[i];\n        }\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int len = 5 - (int)overlap[idx];\n\n                modes[0].edge[idx] = edgeAvg10[idx];\n                modes[1].edge[idx] = edgeMin10[idx];\n                modes[2].edge[idx] = len * 1000 + edgeAvg10[idx];\n                modes[3].edge[idx] = len * 10000 + edgeAvg10[idx];\n            }\n        }\n    }\n\n    inline long long arc(const Mode& mode, int u, int v) const {\n        if (u < 0 && v < 0) return 0;\n        if (u < 0) return mode.start[v];\n        if (v < 0) return 0;\n        return mode.edge[u * M + v];\n    }\n\n    int exactCost(const vector<int>& ord) const {\n        if (ord.empty()) return 0;\n\n        const int INF = 1e9;\n        int dp[225], ndp[225];\n\n        int first = ord[0];\n        int cnt = (int)letterPos[lastChar[first]].size();\n        int off0 = initOff[first];\n\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off0 + i];\n\n        for (int idx = 1; idx < (int)ord.size(); idx++) {\n            int a = ord[idx - 1];\n            int b = ord[idx];\n\n            int rows = (int)letterPos[lastChar[a]].size();\n            int cols = (int)letterPos[lastChar[b]].size();\n\n            fill(ndp, ndp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[a * M + b]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)mr[c];\n                    if (v < ndp[c]) ndp[c] = v;\n                }\n            }\n\n            for (int c = 0; c < cols; c++) dp[c] = ndp[c];\n        }\n\n        int last = ord.back();\n        int lastCnt = (int)letterPos[lastChar[last]].size();\n        int ans = INF;\n        for (int i = 0; i < lastCnt; i++) ans = min(ans, dp[i]);\n        return ans;\n    }\n\n    vector<int> hungarian(const vector<vector<int>>& a) const {\n        int n = (int)a.size();\n        const long long INF = (1LL << 60);\n\n        vector<long long> u(n + 1), v(n + 1);\n        vector<int> p(n + 1), way(n + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<long long> minv(n + 1, INF);\n            vector<char> used(n + 1, false);\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0];\n                int j1 = 0;\n                long long delta = INF;\n\n                for (int j = 1; j <= n; j++) {\n                    if (used[j]) continue;\n                    long long cur = (long long)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\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\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);\n        for (int j = 1; j <= n; j++) ans[p[j] - 1] = j - 1;\n        return ans;\n    }\n\n    vector<int> patchAssignment(const vector<int>& succ, const Mode& mode) const {\n        int D = M;\n        int n = M + 1;\n\n        vector<char> visited(n, false);\n        vector<int> path;\n\n        int cur = succ[D];\n        visited[D] = true;\n        while (cur != D && !visited[cur]) {\n            visited[cur] = true;\n            path.push_back(cur);\n            cur = succ[cur];\n        }\n\n        vector<vector<int>> cycles;\n        for (int i = 0; i < M; i++) {\n            if (visited[i]) continue;\n\n            vector<int> cyc;\n            cur = i;\n            while (!visited[cur]) {\n                visited[cur] = true;\n                cyc.push_back(cur);\n                cur = succ[cur];\n            }\n            if (!cyc.empty()) cycles.push_back(cyc);\n        }\n\n        auto costArc = [&](int u, int v) -> long long {\n            if (u == D && v == D) return 0;\n            if (u == D) return mode.start[v];\n            if (v == D) return 0;\n            return mode.edge[u * M + v];\n        };\n\n        while (!cycles.empty()) {\n            long long bestDelta = (1LL << 60);\n            int bestC = -1, bestE = -1, bestBreak = -1;\n\n            for (int ci = 0; ci < (int)cycles.size(); ci++) {\n                const auto& C = cycles[ci];\n                int k = (int)C.size();\n\n                for (int e = 0; e <= (int)path.size(); e++) {\n                    int u = (e == 0 ? D : path[e - 1]);\n                    int v = (e == (int)path.size() ? D : path[e]);\n                    long long oldCost = costArc(u, v);\n\n                    for (int bidx = 0; bidx < k; bidx++) {\n                        int a = C[bidx];\n                        int b = C[(bidx + 1) % k];\n\n                        long long delta = costArc(u, b) + costArc(a, v)\n                                        - oldCost - costArc(a, b);\n\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestC = ci;\n                            bestE = e;\n                            bestBreak = bidx;\n                        }\n                    }\n                }\n            }\n\n            const auto& C = cycles[bestC];\n            int k = (int)C.size();\n            vector<int> seg;\n            seg.reserve(k);\n            for (int t = 0; t < k; t++) {\n                seg.push_back(C[(bestBreak + 1 + t) % k]);\n            }\n\n            path.insert(path.begin() + bestE, seg.begin(), seg.end());\n            cycles.erase(cycles.begin() + bestC);\n        }\n\n        return path;\n    }\n\n    vector<int> hungarianPatch(const Mode& mode) const {\n        int n = M + 1;\n        int D = M;\n        const int INF = 100000000;\n\n        vector<vector<int>> cost(n, vector<int>(n, INF));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                cost[i][j] = (i == j ? INF : mode.edge[i * M + j]);\n            }\n            cost[i][D] = 0;\n        }\n\n        for (int j = 0; j < M; j++) cost[D][j] = mode.start[j];\n        cost[D][D] = INF;\n\n        vector<int> assign = hungarian(cost);\n        return patchAssignment(assign, mode);\n    }\n\n    vector<int> cheapestInsertion(const Mode& mode) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestDelta = (1LL << 60);\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> regretInsertion(const Mode& mode, int regretW) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestScore = (1LL << 60);\n            int chosen = -1, chosenPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                long long b1 = (1LL << 60), b2 = (1LL << 60);\n                int pos1 = 0;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n\n                    if (delta < b1) {\n                        b2 = b1;\n                        b1 = delta;\n                        pos1 = pos;\n                    } else if (delta < b2) {\n                        b2 = delta;\n                    }\n                }\n\n                if (b2 >= (1LL << 50)) b2 = b1 + 1000000;\n                long long regret = b2 - b1;\n                long long score = b1 * 10 - (long long)regretW * regret;\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    chosen = x;\n                    chosenPos = pos1;\n                }\n            }\n\n            path.insert(path.begin() + chosenPos, chosen);\n            used[chosen] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> nearestNeighborBest(const Mode& mode) const {\n        vector<int> bestPath;\n        long long bestScore = (1LL << 60);\n\n        for (int s = 0; s < M; s++) {\n            vector<char> used(M, false);\n            vector<int> path;\n            path.reserve(M);\n\n            path.push_back(s);\n            used[s] = true;\n\n            long long score = mode.start[s];\n            int last = s;\n\n            for (int step = 1; step < M; step++) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (used[j]) continue;\n                    int c = mode.edge[last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                path.push_back(bestJ);\n                used[bestJ] = true;\n                score += bestC;\n                last = bestJ;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestPath = path;\n            }\n        }\n\n        return bestPath;\n    }\n\n    struct DSU {\n        vector<int> p;\n        DSU(int n = 0) { init(n); }\n        void init(int n) {\n            p.resize(n);\n            iota(p.begin(), p.end(), 0);\n        }\n        int find(int x) {\n            return p[x] == x ? x : p[x] = find(p[x]);\n        }\n        bool unite(int a, int b) {\n            a = find(a);\n            b = find(b);\n            if (a == b) return false;\n            p[b] = a;\n            return true;\n        }\n    };\n\n    vector<int> greedyPathCover(const Mode& mode, bool overlapKey) const {\n        struct E {\n            int u, v, ov, cost;\n        };\n\n        vector<E> es;\n        es.reserve(M * (M - 1));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                es.push_back({i, j, (int)overlap[i * M + j], mode.edge[i * M + j]});\n            }\n        }\n\n        if (overlapKey) {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                if (a.ov != b.ov) return a.ov > b.ov;\n                return a.cost < b.cost;\n            });\n        } else {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                return a.cost < b.cost;\n            });\n        }\n\n        vector<int> out(M, -1), in(M, -1);\n        DSU dsu(M);\n        int added = 0;\n\n        for (const auto& e : es) {\n            if (out[e.u] != -1 || in[e.v] != -1) continue;\n            if (dsu.find(e.u) == dsu.find(e.v)) continue;\n\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n\n            added++;\n            if (added == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) {\n            if (in[i] == -1) {\n                head = i;\n                break;\n            }\n        }\n\n        vector<int> path;\n        while (head != -1) {\n            path.push_back(head);\n            head = out[head];\n        }\n\n        if ((int)path.size() != M) {\n            path.resize(M);\n            iota(path.begin(), path.end(), 0);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedy(int startWord) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = (int)letterPos[lastChar[curWord]].size();\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            int bestScore = INF;\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = (int)letterPos[lastChar[j]].size();\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                if (minv < bestScore) {\n                    bestScore = minv;\n                    bestJ = j;\n                }\n            }\n\n            int cols = (int)letterPos[lastChar[bestJ]].size();\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedyLookahead(int startWord, int futureWeight) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = (int)letterPos[lastChar[curWord]].size();\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            long long bestScore = (1LL << 60);\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = (int)letterPos[lastChar[j]].size();\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                int fut = 0;\n                if (step + 1 < M && futureWeight != 0) {\n                    fut = INF;\n                    for (int k = 0; k < M; k++) {\n                        if (!used[k] && k != j) {\n                            fut = min(fut, modes[0].edge[j * M + k]);\n                        }\n                    }\n                    if (fut == INF) fut = 0;\n                }\n\n                long long score = (long long)minv * 10 + (long long)futureWeight * fut;\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestJ = j;\n                }\n            }\n\n            int cols = (int)letterPos[lastChar[bestJ]].size();\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    long long relocateDelta(const vector<int>& ord, int i, int p, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (p == i) return 0;\n\n        int x = ord[i];\n\n        int L = (i > 0 ? ord[i - 1] : -1);\n        int R = (i + 1 < n ? ord[i + 1] : -1);\n\n        long long rem = arc(mode, L, R) - arc(mode, L, x) - arc(mode, x, R);\n\n        auto getRemoved = [&](int idx) -> int {\n            return ord[idx < i ? idx : idx + 1];\n        };\n\n        int left = (p > 0 ? getRemoved(p - 1) : -1);\n        int right = (p < n - 1 ? getRemoved(p) : -1);\n\n        long long ins = arc(mode, left, x) + arc(mode, x, right) - arc(mode, left, right);\n        return rem + ins;\n    }\n\n    long long blockRelocateDelta(const vector<int>& ord, int l, int r, int q, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (q >= l && q <= r + 1) return 0;\n\n        int A = ord[l];\n        int B = ord[r];\n\n        int L = (l > 0 ? ord[l - 1] : -1);\n        int R = (r + 1 < n ? ord[r + 1] : -1);\n\n        int P = (q > 0 ? ord[q - 1] : -1);\n        int Q = (q < n ? ord[q] : -1);\n\n        long long oldCost = arc(mode, L, A) + arc(mode, B, R) + arc(mode, P, Q);\n        long long newCost = arc(mode, L, R) + arc(mode, P, A) + arc(mode, B, Q);\n        return newCost - oldCost;\n    }\n\n    long long blockSwapDelta(const vector<int>& ord, int l1, int r1, int l2, int r2, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (l1 > r1 || l2 > r2 || r1 >= l2) return 0;\n\n        int A = ord[l1], B = ord[r1];\n        int C = ord[l2], D = ord[r2];\n\n        int L = (l1 > 0 ? ord[l1 - 1] : -1);\n        int R = (r2 + 1 < n ? ord[r2 + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (r1 + 1 == l2) {\n            oldCost = arc(mode, L, A) + arc(mode, B, C) + arc(mode, D, R);\n            newCost = arc(mode, L, C) + arc(mode, D, A) + arc(mode, B, R);\n        } else {\n            int E = ord[r1 + 1];\n            int F = ord[l2 - 1];\n\n            oldCost = arc(mode, L, A) + arc(mode, B, E) + arc(mode, F, C) + arc(mode, D, R);\n            newCost = arc(mode, L, C) + arc(mode, D, E) + arc(mode, F, A) + arc(mode, B, R);\n        }\n\n        return newCost - oldCost;\n    }\n\n    long long swapDelta(const vector<int>& ord, int i, int j, const Mode& mode) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int n = (int)ord.size();\n        vector<int> ks;\n        int arr[4] = {i - 1, i, j - 1, j};\n\n        for (int t = 0; t < 4; t++) {\n            int k = arr[t];\n            if (k < -1 || k > n - 1) continue;\n            if (find(ks.begin(), ks.end(), k) == ks.end()) ks.push_back(k);\n        }\n\n        auto nodeNew = [&](int idx) -> int {\n            if (idx == i) return ord[j];\n            if (idx == j) return ord[i];\n            return ord[idx];\n        };\n\n        auto edgeOld = [&](int k) -> long long {\n            if (k == -1) return modes[0].start[ord[0]];\n            if (k >= n - 1) return 0;\n            return mode.edge[ord[k] * M + ord[k + 1]];\n        };\n\n        auto edgeNew = [&](int k) -> long long {\n            if (k == -1) return modes[0].start[nodeNew(0)];\n            if (k >= n - 1) return 0;\n            return mode.edge[nodeNew(k) * M + nodeNew(k + 1)];\n        };\n\n        long long oldSum = 0, newSum = 0;\n        for (int k : ks) {\n            oldSum += edgeOld(k);\n            newSum += edgeNew(k);\n        }\n        return newSum - oldSum;\n    }\n\n    long long reverseDeltaSlow(const vector<int>& ord, int l, int r, const Mode& mode) const {\n        int n = (int)ord.size();\n        long long oldCost = 0, newCost = 0;\n\n        if (l == 0) {\n            oldCost += mode.start[ord[l]];\n            newCost += mode.start[ord[r]];\n        } else {\n            oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n            newCost += mode.edge[ord[l - 1] * M + ord[r]];\n        }\n\n        if (r + 1 < n) {\n            oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n            newCost += mode.edge[ord[l] * M + ord[r + 1]];\n        }\n\n        for (int k = l; k < r; k++) {\n            oldCost += mode.edge[ord[k] * M + ord[k + 1]];\n            newCost += mode.edge[ord[k + 1] * M + ord[k]];\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyMove(vector<int>& ord, const Move& mv) const {\n        if (mv.type == 0) {\n            int x = ord[mv.a];\n            ord.erase(ord.begin() + mv.a);\n            ord.insert(ord.begin() + mv.b, x);\n        } else if (mv.type == 1) {\n            swap(ord[mv.a], ord[mv.b]);\n        } else if (mv.type == 2) {\n            reverse(ord.begin() + mv.a, ord.begin() + mv.b + 1);\n        } else if (mv.type == 3) {\n            int l = mv.a;\n            int r = mv.b;\n            int q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos;\n            if (q < l) pos = q;\n            else pos = q - len;\n\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        } else if (mv.type == 4) {\n            int l1 = mv.a;\n            int r1 = mv.b;\n            int l2 = mv.c / 256;\n            int r2 = mv.c % 256;\n\n            vector<int> res;\n            res.reserve(ord.size());\n\n            res.insert(res.end(), ord.begin(), ord.begin() + l1);\n            res.insert(res.end(), ord.begin() + l2, ord.begin() + r2 + 1);\n            res.insert(res.end(), ord.begin() + r1 + 1, ord.begin() + l2);\n            res.insert(res.end(), ord.begin() + l1, ord.begin() + r1 + 1);\n            res.insert(res.end(), ord.begin() + r2 + 1, ord.end());\n\n            ord.swap(res);\n        } else if (mv.type == 5) {\n            int l = mv.a;\n            int r = mv.b;\n            int q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            reverse(block.begin(), block.end());\n\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos;\n            if (q < l) pos = q;\n            else pos = q - len;\n\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        }\n    }\n\n    void improveAdditive(vector<int>& ord, const Mode& mode, int maxIter = 40, int maxBlockLen = 3) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if ((iter & 1) == 0 && timer.elapsed() > 1.48) break;\n\n            long long bestDelta = 0;\n            Move bestMove{-1, 0, 0, 0};\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {0, i, p, d};\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {1, i, j, d};\n                    }\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    long long d = newCost - oldCost;\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {2, l, r, d};\n                    }\n                }\n            }\n\n            bool stopBlock = false;\n            int limLen = min(maxBlockLen, n - 1);\n            for (int len = 2; len <= limLen && !stopBlock; len++) {\n                for (int l = 0; l + len <= n && !stopBlock; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        if (d < bestDelta) {\n                            bestDelta = d;\n                            bestMove = {3, l, r, d, q};\n                        }\n                    }\n                    if ((l & 15) == 0 && timer.elapsed() > 1.48) stopBlock = true;\n                }\n            }\n\n            if (bestDelta < 0) {\n                applyMove(ord, bestMove);\n            } else {\n                break;\n            }\n        }\n    }\n\n    Candidate exactRefine(vector<int> ord, double deadline, int rounds, int K) {\n        int cur = exactCost(ord);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestOrder = ord;\n        }\n\n        const Mode& mode = modes[0];\n        int n = (int)ord.size();\n\n        for (int round = 0; round < rounds; round++) {\n            if (timer.elapsed() > deadline) break;\n\n            vector<Move> moves;\n            moves.reserve(n * n * 3);\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    moves.push_back({0, i, p, d});\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    moves.push_back({1, i, j, d});\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    moves.push_back({2, l, r, newCost - oldCost});\n                }\n            }\n\n            int limLen = min(4, n - 1);\n            for (int len = 2; len <= limLen; len++) {\n                for (int l = 0; l + len <= n; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        moves.push_back({3, l, r, d, q});\n                    }\n                }\n            }\n\n            if (timer.elapsed() < deadline - 0.04) {\n                int maxSwapLen = min(3, n);\n                bool stop = false;\n                for (int len1 = 1; len1 <= maxSwapLen && !stop; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n && !stop; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxSwapLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n                                long long d = blockSwapDelta(ord, l1, r1, l2, r2, mode);\n                                if (d < 0) {\n                                    moves.push_back({4, l1, r1, d, l2 * 256 + r2});\n                                }\n                            }\n                        }\n                        if ((l1 & 15) == 0 && timer.elapsed() > deadline - 0.03) stop = true;\n                    }\n                }\n            }\n\n            sort(moves.begin(), moves.end(), [](const Move& a, const Move& b) {\n                return a.delta < b.delta;\n            });\n\n            int bestLocal = cur;\n            Move bestMv{-1, 0, 0, 0};\n            int lim = min(K, (int)moves.size());\n\n            for (int i = 0; i < lim; i++) {\n                if ((i & 31) == 0 && timer.elapsed() > deadline) break;\n\n                vector<int> cand = ord;\n                applyMove(cand, moves[i]);\n                int nc = exactCost(cand);\n\n                if (nc < bestLocal) {\n                    bestLocal = nc;\n                    bestMv = moves[i];\n                }\n            }\n\n            if (bestMv.type != -1) {\n                applyMove(ord, bestMv);\n                cur = bestLocal;\n\n                if (cur < bestCost) {\n                    bestCost = cur;\n                    bestOrder = ord;\n                }\n            } else {\n                break;\n            }\n        }\n\n        return {cur, ord};\n    }\n\n    void buildExactCtx(const vector<int>& ord, ExactCtx& ctx, bool needRev) const {\n        int n = (int)ord.size();\n        ctx.n = n;\n        ctx.cnt.assign(n, 0);\n        for (int i = 0; i < n; i++) ctx.cnt[i] = wordCnt(ord[i]);\n\n        ctx.foff.assign(n * n, -1);\n        ctx.fdata.clear();\n        ctx.fdata.reserve((size_t)n * n * 90);\n\n        vector<unsigned short> prev, cur;\n\n        for (int l = 0; l < n; l++) {\n            int rows = ctx.cnt[l];\n            prev.assign(rows * rows, USINF);\n            for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n            ctx.foff[l * n + l] = (int)ctx.fdata.size();\n            ctx.fdata.insert(ctx.fdata.end(), prev.begin(), prev.end());\n\n            for (int r = l + 1; r < n; r++) {\n                int mid = ctx.cnt[r - 1];\n                int cols = ctx.cnt[r];\n                cur.assign(rows * cols, USINF);\n\n                const unsigned short* e = &edgeData[edgeOff[ord[r - 1] * M + ord[r]]];\n\n                for (int i = 0; i < rows; i++) {\n                    for (int k = 0; k < mid; k++) {\n                        int base = prev[i * mid + k];\n                        if (base >= USINF) continue;\n                        const unsigned short* er = e + k * cols;\n                        int outBase = i * cols;\n                        for (int j = 0; j < cols; j++) {\n                            int v = base + (int)er[j];\n                            if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                        }\n                    }\n                }\n\n                ctx.foff[l * n + r] = (int)ctx.fdata.size();\n                ctx.fdata.insert(ctx.fdata.end(), cur.begin(), cur.end());\n                prev.swap(cur);\n            }\n        }\n\n        ctx.roff.assign(n * n, -1);\n        ctx.rdata.clear();\n        if (needRev) {\n            ctx.rdata.reserve((size_t)n * n * 90);\n\n            for (int r = 0; r < n; r++) {\n                int rows = ctx.cnt[r];\n                prev.assign(rows * rows, USINF);\n                for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n                ctx.roff[r * n + r] = (int)ctx.rdata.size();\n                ctx.rdata.insert(ctx.rdata.end(), prev.begin(), prev.end());\n\n                for (int l = r - 1; l >= 0; l--) {\n                    int mid = ctx.cnt[l + 1];\n                    int cols = ctx.cnt[l];\n                    cur.assign(rows * cols, USINF);\n\n                    const unsigned short* e = &edgeData[edgeOff[ord[l + 1] * M + ord[l]]];\n\n                    for (int i = 0; i < rows; i++) {\n                        for (int k = 0; k < mid; k++) {\n                            int base = prev[i * mid + k];\n                            if (base >= USINF) continue;\n                            const unsigned short* er = e + k * cols;\n                            int outBase = i * cols;\n                            for (int j = 0; j < cols; j++) {\n                                int v = base + (int)er[j];\n                                if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                            }\n                        }\n                    }\n\n                    ctx.roff[l * n + r] = (int)ctx.rdata.size();\n                    ctx.rdata.insert(ctx.rdata.end(), cur.begin(), cur.end());\n                    prev.swap(cur);\n                }\n            }\n        }\n\n        ctx.prefOff.assign(n, 0);\n        ctx.prefData.clear();\n        ctx.prefData.reserve(n * maxOcc);\n\n        vector<unsigned short> dp, ndp;\n\n        {\n            int w = ord[0];\n            int cnt = ctx.cnt[0];\n            dp.resize(cnt);\n            int off = initOff[w];\n            for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n            ctx.prefOff[0] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        for (int pos = 1; pos < n; pos++) {\n            int rows = ctx.cnt[pos - 1];\n            int cols = ctx.cnt[pos];\n            ndp.assign(cols, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos - 1] * M + ord[pos]]];\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)er[c];\n                    if (v < ndp[c]) ndp[c] = (unsigned short)v;\n                }\n            }\n\n            dp.swap(ndp);\n            ctx.prefOff[pos] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        ctx.current = USINF;\n        for (unsigned short v : dp) ctx.current = min(ctx.current, (int)v);\n\n        vector<vector<unsigned short>> sv(n);\n        sv[n - 1].assign(ctx.cnt[n - 1], 0);\n\n        for (int pos = n - 2; pos >= 0; pos--) {\n            int rows = ctx.cnt[pos];\n            int cols = ctx.cnt[pos + 1];\n            sv[pos].assign(rows, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos] * M + ord[pos + 1]]];\n\n            for (int r = 0; r < rows; r++) {\n                int best = USINF;\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = (int)er[c] + (int)sv[pos + 1][c];\n                    if (v < best) best = v;\n                }\n                sv[pos][r] = (unsigned short)best;\n            }\n        }\n\n        ctx.suffOff.assign(n, 0);\n        ctx.suffData.clear();\n        ctx.suffData.reserve(n * maxOcc);\n        for (int pos = 0; pos < n; pos++) {\n            ctx.suffOff[pos] = (int)ctx.suffData.size();\n            ctx.suffData.insert(ctx.suffData.end(), sv[pos].begin(), sv[pos].end());\n        }\n    }\n\n    inline void loadInitWord(int w, int* a, int& cnt) const {\n        cnt = wordCnt(w);\n        const unsigned short* p = &initData[initOff[w]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void loadPrefPos(const ExactCtx& ctx, int pos, int* a, int& cnt) const {\n        cnt = ctx.cnt[pos];\n        const unsigned short* p = &ctx.prefData[ctx.prefOff[pos]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void applyEdgeArr(int* a, int& cnt, int u, int v, int* tmp) const {\n        const int INF = 1e9;\n        int rows = cnt;\n        int cols = wordCnt(v);\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n        for (int r = 0; r < rows; r++) {\n            int base = a[r];\n            const unsigned short* mr = mat + r * cols;\n            for (int c = 0; c < cols; c++) {\n                int val = base + (int)mr[c];\n                if (val < tmp[c]) tmp[c] = val;\n            }\n        }\n\n        for (int c = 0; c < cols; c++) a[c] = tmp[c];\n        cnt = cols;\n    }\n\n    inline void applyFInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[r];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[l];\n        int cols = ctx.cnt[r];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.fdata[ctx.foff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline void applyRInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[l];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[r];\n        int cols = ctx.cnt[l];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.rdata[ctx.roff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline int finishAt(const ExactCtx& ctx, int pos, int* a, int cnt) const {\n        const unsigned short* s = &ctx.suffData[ctx.suffOff[pos]];\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) {\n            int v = a[i] + (int)s[i];\n            if (v < ans) ans = v;\n        }\n        return ans;\n    }\n\n    inline int minArr(int* a, int cnt) const {\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) ans = min(ans, a[i]);\n        return ans;\n    }\n\n    int evalBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[l], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            }\n\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n\n            applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n\n            applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    int evalRelocateExact(const vector<int>& ord, const ExactCtx& ctx, int i, int p) const {\n        if (i == p) return ctx.current;\n        int q = (p < i ? p : p + 1);\n        return evalBlockExact(ord, ctx, i, i, q);\n    }\n\n    int evalSwapExact(const vector<int>& ord, const ExactCtx& ctx, int i, int j) const {\n        if (i > j) swap(i, j);\n        int n = ctx.n;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (i == 0) {\n            loadInitWord(ord[j], a, cnt);\n        } else {\n            loadPrefPos(ctx, i - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[i - 1], ord[j], tmp);\n        }\n\n        if (j == i + 1) {\n            applyEdgeArr(a, cnt, ord[j], ord[i], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[j], ord[i + 1], tmp);\n            applyFInterval(ctx, i + 1, j - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[j - 1], ord[i], tmp);\n        }\n\n        if (j + 1 < n) {\n            applyEdgeArr(a, cnt, ord[i], ord[j + 1], tmp);\n            return finishAt(ctx, j + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalReverseExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r) const {\n        int n = ctx.n;\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l == 0) {\n            loadInitWord(ord[r], a, cnt);\n        } else {\n            loadPrefPos(ctx, l - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l - 1], ord[r], tmp);\n        }\n\n        applyRInterval(ctx, l, r, a, cnt, tmp);\n\n        if (r + 1 < n) {\n            applyEdgeArr(a, cnt, ord[l], ord[r + 1], tmp);\n            return finishAt(ctx, r + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalBlockSwapExact(const vector<int>& ord, const ExactCtx& ctx, int l1, int r1, int l2, int r2) const {\n        int n = ctx.n;\n        if (r1 >= l2) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l1 == 0) {\n            loadInitWord(ord[l2], a, cnt);\n        } else {\n            loadPrefPos(ctx, l1 - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l1 - 1], ord[l2], tmp);\n        }\n\n        applyFInterval(ctx, l2, r2, a, cnt, tmp);\n\n        if (r1 + 1 < l2) {\n            applyEdgeArr(a, cnt, ord[r2], ord[r1 + 1], tmp);\n            applyFInterval(ctx, r1 + 1, l2 - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l2 - 1], ord[l1], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[r2], ord[l1], tmp);\n        }\n\n        applyFInterval(ctx, l1, r1, a, cnt, tmp);\n\n        if (r2 + 1 < n) {\n            applyEdgeArr(a, cnt, ord[r1], ord[r2 + 1], tmp);\n            return finishAt(ctx, r2 + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalRevBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[r], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[r], tmp);\n            }\n\n            applyRInterval(ctx, l, r, a, cnt, tmp);\n\n            applyEdgeArr(a, cnt, ord[l], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n\n            applyEdgeArr(a, cnt, ord[q - 1], ord[r], tmp);\n            applyRInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[l], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    void improveExactInterval(vector<int>& ord, double deadline, int maxIter) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if (timer.elapsed() > deadline - 0.07) break;\n\n            ExactCtx ctx;\n            buildExactCtx(ord, ctx, true);\n\n            int cur = ctx.current;\n            if (cur < bestCost) {\n                bestCost = cur;\n                bestOrder = ord;\n            }\n\n            int bestVal = cur;\n            Move bestMv{-1, 0, 0, 0};\n\n            int checks = 0;\n            bool timeout = false;\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    int val = evalRelocateExact(ord, ctx, i, p);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {0, i, p, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    int val = evalSwapExact(ord, ctx, i, j);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {1, i, j, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    int val = evalReverseExact(ord, ctx, l, r);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {2, l, r, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(10, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {3, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(9, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalRevBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {5, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(4, n);\n                for (int len1 = 1; len1 <= maxLen; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n\n                                int val = evalBlockSwapExact(ord, ctx, l1, r1, l2, r2);\n                                if (val < bestVal) {\n                                    bestVal = val;\n                                    bestMv = {4, l1, r1, val - cur, l2 * 256 + r2};\n                                }\n\n                                if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                    timeout = true;\n                                    goto ENUM_DONE;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n        ENUM_DONE:\n            if (bestMv.type != -1 && bestVal < cur) {\n                applyMove(ord, bestMv);\n                int real = exactCost(ord);\n                if (real < bestCost) {\n                    bestCost = real;\n                    bestOrder = ord;\n                }\n                if (real >= cur) break;\n            } else {\n                break;\n            }\n\n            if (timeout || timer.elapsed() > deadline) break;\n        }\n    }\n\n    void simulatedAnnealing(double deadline) {\n        if (timer.elapsed() > deadline) return;\n\n        vector<int> curOrd = bestOrder;\n        int curCost = bestCost;\n        const Mode& mode = modes[0];\n\n        double st = timer.elapsed();\n        int n = (int)curOrd.size();\n        if (n <= 1) return;\n\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            Move mv{-1, 0, 0, 0};\n\n            int typ = rng.nextInt(100);\n            if (typ < 28) {\n                int i = rng.nextInt(n);\n                int p = rng.nextInt(n);\n                if (p == i) continue;\n                long long d = relocateDelta(curOrd, i, p, mode);\n                mv = {0, i, p, d};\n            } else if (typ < 50) {\n                int i = rng.nextInt(n);\n                int j = rng.nextInt(n);\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                long long d = swapDelta(curOrd, i, j, mode);\n                mv = {1, i, j, d};\n            } else if (typ < 69) {\n                int l = rng.nextInt(n);\n                int r = rng.nextInt(n);\n                if (l == r) continue;\n                if (l > r) swap(l, r);\n                long long d = reverseDeltaSlow(curOrd, l, r, mode);\n                mv = {2, l, r, d};\n            } else if (typ < 84) {\n                if (n <= 3) continue;\n                int maxL = min(7, n - 1);\n                int len = 2 + rng.nextInt(maxL - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                long long d = blockRelocateDelta(curOrd, l, r, q, mode);\n                mv = {3, l, r, d, q};\n            } else if (typ < 91) {\n                if (n <= 3) continue;\n                int maxL = min(7, n - 1);\n                int len = 2 + rng.nextInt(maxL - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                mv = {5, l, r, 0, q};\n            } else {\n                if (n <= 3) continue;\n                int maxL = min(5, n - 1);\n                int len1 = 1 + rng.nextInt(maxL);\n                int len2 = 1 + rng.nextInt(maxL);\n                int l1 = rng.nextInt(n - len1 + 1);\n                int r1 = l1 + len1 - 1;\n                int l2 = rng.nextInt(n - len2 + 1);\n                int r2 = l2 + len2 - 1;\n\n                if (l2 < l1) {\n                    swap(l1, l2);\n                    swap(r1, r2);\n                }\n                if (r1 >= l2) continue;\n                if (len1 == 1 && len2 == 1) continue;\n\n                long long d = blockSwapDelta(curOrd, l1, r1, l2, r2, mode);\n                mv = {4, l1, r1, d, l2 * 256 + r2};\n            }\n\n            if (mv.delta > 3000) continue;\n            if (mv.delta > 800 && rng.nextInt(100) < 95) continue;\n\n            vector<int> cand = curOrd;\n            applyMove(cand, mv);\n            int nc = exactCost(cand);\n\n            int diff = nc - curCost;\n            double progress = (timer.elapsed() - st) / max(1e-9, deadline - st);\n            double temp = 18.0 * pow(0.05, progress) + 0.4;\n\n            if (diff <= 0 || rng.nextDouble() < exp(-diff / temp)) {\n                curOrd.swap(cand);\n                curCost = nc;\n\n                if (curCost < bestCost) {\n                    bestCost = curCost;\n                    bestOrder = curOrd;\n                }\n            }\n\n            iter++;\n            if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    string buildString(const vector<int>& ord) const {\n        if (ord.empty()) return \"\";\n\n        string s = words[ord[0]];\n        for (int i = 1; i < (int)ord.size(); i++) {\n            int a = ord[i - 1];\n            int b = ord[i];\n            int k = overlap[a * M + b];\n            s += words[b].substr(k);\n        }\n        return s;\n    }\n\n    bool containsAll(const string& s) const {\n        if ((int)s.size() < 5) return false;\n\n        vector<char> seen(M, false);\n        int got = 0;\n\n        int code = 0;\n        for (int i = 0; i < 5; i++) code = code * 26 + (s[i] - 'A');\n\n        auto mark = [&](int cd) {\n            auto it = targetMap.find(cd);\n            if (it != targetMap.end()) {\n                int id = it->second;\n                if (!seen[id]) {\n                    seen[id] = true;\n                    got++;\n                }\n            }\n        };\n\n        mark(code);\n\n        for (int i = 5; i < (int)s.size(); i++) {\n            code = (code % pow4) * 26 + (s[i] - 'A');\n            mark(code);\n        }\n\n        return got == M;\n    }\n\n    void tryRemoveRedundant(double deadline) {\n        bool improved = true;\n\n        while (improved && timer.elapsed() < deadline) {\n            improved = false;\n\n            for (int p = 0; p < (int)bestOrder.size(); p++) {\n                if (timer.elapsed() > deadline) break;\n                if ((int)bestOrder.size() <= 1) break;\n\n                vector<int> cand = bestOrder;\n                cand.erase(cand.begin() + p);\n\n                string s = buildString(cand);\n                if (!containsAll(s)) continue;\n\n                int c = exactCost(cand);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestOrder = cand;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    void outputStringPath(const string& s) const {\n        int L = (int)s.size();\n        const int INF = 1e9;\n\n        vector<vector<int>> pred(L);\n        vector<int> dpPrev, dpCur;\n\n        for (int idx = 0; idx < L; idx++) {\n            int c = s[idx] - 'A';\n            int cnt = (int)letterPos[c].size();\n\n            dpCur.assign(cnt, INF);\n            pred[idx].assign(cnt, -1);\n\n            if (idx == 0) {\n                for (int q = 0; q < cnt; q++) {\n                    int id = letterPos[c][q];\n                    dpCur[q] = (int)distCell[startId][id] + 1;\n                }\n            } else {\n                int pc = s[idx - 1] - 'A';\n                int pcnt = (int)letterPos[pc].size();\n\n                for (int q = 0; q < cnt; q++) {\n                    int qid = letterPos[c][q];\n                    int best = INF;\n                    int bestP = -1;\n\n                    for (int p = 0; p < pcnt; p++) {\n                        int pid = letterPos[pc][p];\n                        int v = dpPrev[p] + (int)distCell[pid][qid] + 1;\n                        if (v < best) {\n                            best = v;\n                            bestP = p;\n                        }\n                    }\n\n                    dpCur[q] = best;\n                    pred[idx][q] = bestP;\n                }\n            }\n\n            dpPrev.swap(dpCur);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < dpPrev[bestIdx]) bestIdx = i;\n        }\n\n        vector<int> outIds(L);\n        for (int idx = L - 1; idx >= 0; idx--) {\n            int c = s[idx] - 'A';\n            outIds[idx] = letterPos[c][bestIdx];\n            bestIdx = pred[idx][bestIdx];\n        }\n\n        for (int id : outIds) {\n            cout << id / N << ' ' << id % N << '\\n';\n        }\n    }\n\n    void solve() {\n        timer.reset();\n\n        precompute();\n        buildModes();\n\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = exactCost(bestOrder);\n\n        vector<Candidate> candidates;\n\n        auto consider = [&](const vector<int>& ord) {\n            int c = exactCost(ord);\n            candidates.push_back({c, ord});\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = ord;\n            }\n        };\n\n        consider(bestOrder);\n\n        for (int mi = 0; mi < (int)modes.size(); mi++) {\n            if (timer.elapsed() > 1.25) break;\n\n            {\n                vector<int> ord = hungarianPatch(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = cheapestInsertion(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = nearestNeighborBest(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes[0], false);\n            improveAdditive(ord, modes[0], 35, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes.back(), true);\n            improveAdditive(ord, modes.back(), 35, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.39) {\n            vector<int> ord = regretInsertion(modes[0], 10);\n            improveAdditive(ord, modes[0], 24, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.42) {\n            vector<int> ord = regretInsertion(modes[3], 12);\n            improveAdditive(ord, modes[3], 22, 3);\n            consider(ord);\n        }\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return startMinCost[a] < startMinCost[b];\n        });\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<int> starts;\n        for (int i = 0; i < min(M, 10); i++) starts.push_back(ids[i]);\n        for (int i = 0; i < min((int)candidates.size(), 8); i++) {\n            if (!candidates[i].order.empty()) starts.push_back(candidates[i].order[0]);\n        }\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        int greedyRuns = 0;\n        int lookRuns = 0;\n        for (int stWord : starts) {\n            if (greedyRuns >= 12 || timer.elapsed() > 1.45) break;\n\n            vector<int> ord = coordinateGreedy(stWord);\n            consider(ord);\n\n            improveAdditive(ord, modes[0], 25, 3);\n            consider(ord);\n\n            if (lookRuns < 4 && timer.elapsed() < 1.445) {\n                vector<int> ord2 = coordinateGreedyLookahead(stWord, 1);\n                consider(ord2);\n                improveAdditive(ord2, modes[0], 18, 3);\n                consider(ord2);\n                lookRuns++;\n            }\n\n            greedyRuns++;\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<vector<int>> refineList;\n        for (const auto& cand : candidates) {\n            bool dup = false;\n            for (const auto& v : refineList) {\n                if (v == cand.order) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) refineList.push_back(cand.order);\n            if ((int)refineList.size() >= 3) break;\n        }\n\n        for (auto& ord : refineList) {\n            if (timer.elapsed() > 1.60) break;\n            Candidate r = exactRefine(ord, 1.60, 3, 350);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.64) {\n            Candidate r = exactRefine(bestOrder, 1.64, 3, 500);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.865) {\n            improveExactInterval(bestOrder, 1.865, 3);\n        }\n\n        simulatedAnnealing(1.885);\n        tryRemoveRedundant(1.895);\n\n        string finalS = buildString(bestOrder);\n        if (!containsAll(finalS) || (int)finalS.size() > 5000) {\n            bestOrder.resize(M);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n            finalS = buildString(bestOrder);\n        }\n\n        outputStringPath(finalS);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXC = 400;\nstatic constexpr double EXACT_W = 1e7;\nstatic constexpr double BAN_W = 1e8;\n\nstruct Placement {\n    int di, dj;\n    vector<int> cells;\n    bitset<MAXC> bits;\n};\n\nstruct Field {\n    int area = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> placements;\n    vector<uint16_t> contrib;\n};\n\nstruct Observation {\n    vector<int> cells;\n    int k;\n    int y;\n};\n\nstruct State {\n    bool valid = false;\n    vector<int> pos;\n    vector<int> pred;\n    vector<int> cnt;\n    double score = -1e300;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n    int totalArea = 0;\n    int Q = 0;\n    int stride = 0;\n\n    vector<Field> fields;\n    vector<Observation> obs;\n\n    vector<double> scoreFlat;\n    vector<double> tHat, invVarT;\n\n    vector<unsigned char> drilled;\n    vector<int> drillVal;\n    vector<int> drilledCells;\n    int drilledCount = 0;\n    int knownReserveSum = 0;\n\n    vector<vector<unsigned char>> bannedEqMasks;\n    vector<vector<unsigned char>> subsetMasks;\n\n    vector<int> fallbackRank;\n\n    int opCount = 0;\n    int maxInitialQueries = 0;\n\n    mt19937 rng{123456789};\n\n    chrono::steady_clock::time_point startTime;\n\n    double elapsedMs() const {\n        return chrono::duration<double, milli>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    }\n\n    double normalCDF(double x) {\n        return 0.5 * erfc(-x / sqrt(2.0));\n    }\n\n    void readInput() {\n        cin >> N >> M >> eps;\n        C = N * N;\n        alpha = 1.0 - 2.0 * eps;\n        fields.resize(M);\n\n        for (int m = 0; m < M; m++) {\n            int d;\n            cin >> d;\n            fields[m].area = d;\n            fields[m].rel.resize(d);\n            int mx_i = 0, mx_j = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[m].rel[t] = {i, j};\n                mx_i = max(mx_i, i);\n                mx_j = max(mx_j, j);\n            }\n            fields[m].h = mx_i + 1;\n            fields[m].w = mx_j + 1;\n            totalArea += d;\n        }\n\n        generatePlacements();\n\n        drilled.assign(C, 0);\n        drillVal.assign(C, 0);\n        fallbackRank.assign(C, 0);\n    }\n\n    void generatePlacements() {\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            for (int di = 0; di + f.h <= N; di++) {\n                for (int dj = 0; dj + f.w <= N; dj++) {\n                    Placement p;\n                    p.di = di;\n                    p.dj = dj;\n                    p.bits.reset();\n                    for (auto [ri, rj] : f.rel) {\n                        int c = (di + ri) * N + (dj + rj);\n                        p.cells.push_back(c);\n                        p.bits.set(c);\n                    }\n                    f.placements.push_back(std::move(p));\n                }\n            }\n        }\n    }\n\n    void maybeAskDiv(vector<int> cells) {\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        if ((int)cells.size() < 2) return;\n        if ((int)obs.size() >= maxInitialQueries) return;\n\n        cout << \"q \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int y;\n        if (!(cin >> y)) exit(0);\n        if (y < 0) exit(0);\n\n        opCount++;\n        obs.push_back({cells, (int)cells.size(), y});\n    }\n\n    void askInitialQueries() {\n        maxInitialQueries = max(0, C - 10);\n\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            maybeAskDiv(cells);\n        }\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            maybeAskDiv(cells);\n        }\n\n        int B = max(3, (N + 4) / 5);\n        for (int r = 0; r < N; r += B) {\n            for (int c = 0; c < N; c += B) {\n                vector<int> cells;\n                for (int i = r; i < min(N, r + B); i++) {\n                    for (int j = c; j < min(N, c + B); j++) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                maybeAskDiv(cells);\n            }\n        }\n\n        int off = B / 2;\n        if (off > 0) {\n            for (int r = off; r + B <= N; r += B) {\n                for (int c = off; c + B <= N; c += B) {\n                    vector<int> cells;\n                    for (int i = r; i < r + B; i++) {\n                        for (int j = c; j < c + B; j++) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        }\n\n        auto addModQueries = [&](int mod) {\n            for (int a = 0; a < mod; a++) {\n                for (int b = 0; b < mod; b++) {\n                    vector<int> cells;\n                    for (int i = 0; i < N; i++) {\n                        for (int j = 0; j < N; j++) {\n                            if (i % mod == a && j % mod == b) {\n                                cells.push_back(i * N + j);\n                            }\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        };\n        addModQueries(2);\n        if (N >= 13) addModQueries(3);\n\n        int R = (N <= 12 ? N : 2 * N);\n        for (int r = 0; r < R; r++) {\n            vector<int> cells;\n            for (int attempt = 0; attempt < 100; attempt++) {\n                cells.clear();\n                for (int c = 0; c < C; c++) {\n                    if ((int)(rng() % 10000) < 2500) cells.push_back(c);\n                }\n                if ((int)cells.size() >= 2) break;\n            }\n            if ((int)cells.size() < 2) cells = {0, C - 1};\n            maybeAskDiv(cells);\n        }\n    }\n\n    bool submitAnswer(vector<unsigned char> mask) {\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        vector<int> cells;\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) cells.push_back(c);\n        }\n\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int res;\n        if (!(cin >> res)) exit(0);\n        opCount++;\n\n        if (res == 1) exit(0);\n        if (res < 0) exit(0);\n        return false;\n    }\n\n    int drillCell(int c) {\n        if (drilled[c]) return drillVal[c];\n\n        cout << \"q 1 \" << c / N << ' ' << c % N << '\\n';\n        cout.flush();\n\n        int v;\n        if (!(cin >> v)) exit(0);\n        if (v < 0) exit(0);\n\n        opCount++;\n        drilled[c] = 1;\n        drillVal[c] = v;\n        drilledCount++;\n        drilledCells.push_back(c);\n        knownReserveSum += v;\n\n        // Exact certificate: all reserves have been accounted for.\n        if (knownReserveSum == totalArea) {\n            vector<unsigned char> mask(C, 0);\n            for (int x : drilledCells) {\n                if (drillVal[x] > 0) mask[x] = 1;\n            }\n            submitAnswer(mask);\n        }\n\n        return v;\n    }\n\n    bool canFallback() const {\n        return opCount + (C - drilledCount) + 1 <= 2 * C;\n    }\n\n    bool canWrongGuessAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    void fallback() {\n        vector<int> order;\n        order.reserve(C);\n        for (int c = 0; c < C; c++) {\n            if (!drilled[c]) order.push_back(c);\n        }\n\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            if (fallbackRank[a] != fallbackRank[b]) return fallbackRank[a] > fallbackRank[b];\n            return a < b;\n        });\n\n        for (int c : order) {\n            if (!drilled[c]) drillCell(c);\n        }\n\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (drillVal[c] > 0) mask[c] = 1;\n        }\n\n        submitAnswer(mask);\n        exit(0);\n    }\n\n    void buildContrib() {\n        Q = (int)obs.size();\n        vector<vector<int>> obsOfCell(C);\n\n        for (int q = 0; q < Q; q++) {\n            for (int c : obs[q].cells) obsOfCell[c].push_back(q);\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            int P = (int)f.placements.size();\n            f.contrib.assign(P * Q, 0);\n\n            for (int p = 0; p < P; p++) {\n                uint16_t *arr = Q ? &f.contrib[p * Q] : nullptr;\n                for (int c : f.placements[p].cells) {\n                    for (int q : obsOfCell[c]) {\n                        arr[q]++;\n                    }\n                }\n            }\n        }\n    }\n\n    void buildScoreTables() {\n        stride = totalArea + 1;\n        scoreFlat.assign(Q * stride, 0.0);\n        tHat.assign(Q, 0.0);\n        invVarT.assign(Q, 1.0);\n\n        for (int q = 0; q < Q; q++) {\n            int k = obs[q].k;\n            int y = obs[q].y;\n\n            double sigma = sqrt(k * eps * (1.0 - eps));\n            double varT = k * eps * (1.0 - eps) / (alpha * alpha)\n                        + 0.25 / (alpha * alpha);\n            invVarT[q] = 1.0 / max(1e-9, varT);\n\n            double th = (y - eps * k) / alpha;\n            th = min<double>(totalArea, max<double>(0.0, th));\n            tHat[q] = th;\n\n            for (int t = 0; t <= totalArea; t++) {\n                double mu = eps * k + alpha * t;\n                double prob;\n\n                if (y == 0) {\n                    prob = normalCDF((0.5 - mu) / sigma);\n                } else {\n                    double lo = (y - 0.5 - mu) / sigma;\n                    double hi = (y + 0.5 - mu) / sigma;\n                    prob = normalCDF(hi) - normalCDF(lo);\n                }\n\n                if (!(prob > 1e-300)) prob = 1e-300;\n                scoreFlat[q * stride + t] = log(prob);\n            }\n        }\n    }\n\n    void addToState(State &s, int m, int p, int sign) {\n        if (Q) {\n            const uint16_t *arr = &fields[m].contrib[p * Q];\n            for (int q = 0; q < Q; q++) s.pred[q] += sign * (int)arr[q];\n        }\n\n        for (int c : fields[m].placements[p].cells) {\n            s.cnt[c] += sign;\n        }\n    }\n\n    double computeExactScore(const vector<int> &cnt) const {\n        long long sq = 0;\n        for (int c : drilledCells) {\n            int diff = cnt[c] - drillVal[c];\n            sq += 1LL * diff * diff;\n        }\n        return -EXACT_W * (double)sq;\n    }\n\n    double computeBanPenalty(const vector<int> &cnt) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = cnt[c] > 0;\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (cnt[c] > 0 && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeBanPenaltyBits(const bitset<MAXC> &uni) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = uni.test(c);\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (uni.test(c) && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeScore(const State &s) const {\n        double sc = 0.0;\n\n        for (int q = 0; q < Q; q++) {\n            sc += scoreFlat[q * stride + s.pred[q]];\n        }\n\n        sc += computeExactScore(s.cnt);\n        sc += computeBanPenalty(s.cnt);\n        return sc;\n    }\n\n    State buildState(const vector<int> &pos) {\n        State s;\n        s.valid = true;\n        s.pos = pos;\n        s.pred.assign(Q, 0);\n        s.cnt.assign(C, 0);\n\n        for (int m = 0; m < M; m++) {\n            addToState(s, m, s.pos[m], +1);\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    bool placementCoversKnownZero(int m, int p) const {\n        for (int c : fields[m].placements[p].cells) {\n            if (drilled[c] && drillVal[c] == 0) return true;\n        }\n        return false;\n    }\n\n    int randomPlacement(int m) {\n        int P = (int)fields[m].placements.size();\n\n        for (int t = 0; t < 50; t++) {\n            int p = (int)(rng() % P);\n            if (!placementCoversKnownZero(m, p)) return p;\n        }\n\n        vector<int> valid;\n        for (int p = 0; p < P; p++) {\n            if (!placementCoversKnownZero(m, p)) valid.push_back(p);\n        }\n\n        if (!valid.empty()) {\n            return valid[(int)(rng() % valid.size())];\n        }\n        return (int)(rng() % P);\n    }\n\n    State makeRandomState() {\n        vector<int> pos(M);\n        for (int m = 0; m < M; m++) {\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makePerturbedState(const State &base, int changes) {\n        vector<int> pos = base.pos;\n        for (int t = 0; t < changes; t++) {\n            int m = (int)(rng() % M);\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makeGreedyState() {\n        vector<int> pos(M, -1);\n        vector<int> pred(Q, 0);\n        vector<int> cnt(C, 0);\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].area > fields[b].area;\n        });\n\n        int placedArea = 0;\n\n        for (int m : order) {\n            int P = (int)fields[m].placements.size();\n            int newArea = placedArea + fields[m].area;\n\n            double bestVal = 1e300;\n            int bestP = 0;\n\n            for (int p = 0; p < P; p++) {\n                double val = 0.0;\n                const uint16_t *arr = Q ? &fields[m].contrib[p * Q] : nullptr;\n\n                for (int q = 0; q < Q; q++) {\n                    double target = tHat[q] * (double)newArea / (double)totalArea;\n                    double diff = (double)(pred[q] + arr[q]) - target;\n                    val += diff * diff * invVarT[q];\n                }\n\n                for (int c : fields[m].placements[p].cells) {\n                    if (drilled[c]) {\n                        if (drillVal[c] == 0) val += 1e9;\n                        if (cnt[c] + 1 > drillVal[c]) val += 1e9;\n                    }\n                }\n\n                if (val < bestVal - 1e-9 ||\n                    (fabs(val - bestVal) <= 1e-9 && (rng() & 1))) {\n                    bestVal = val;\n                    bestP = p;\n                }\n            }\n\n            pos[m] = bestP;\n            if (Q) {\n                const uint16_t *arr = &fields[m].contrib[bestP * Q];\n                for (int q = 0; q < Q; q++) pred[q] += arr[q];\n            }\n            for (int c : fields[m].placements[bestP].cells) cnt[c]++;\n            placedArea = newArea;\n        }\n\n        return buildState(pos);\n    }\n\n    State optimizeExactSmall() {\n        State invalid;\n\n        if (M == 2) {\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n\n            double bestSc = -1e300;\n            vector<int> bestPos(2, 0);\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    double sc = 0.0;\n                    for (int q = 0; q < Q; q++) {\n                        int t = a0[q] + a1[q];\n                        sc += scoreFlat[q * stride + t];\n                    }\n\n                    if (drilledCount > 0) {\n                        long long sq = 0;\n                        for (int c : drilledCells) {\n                            int cnt = (b0.test(c) ? 1 : 0) + (b1.test(c) ? 1 : 0);\n                            int diff = cnt - drillVal[c];\n                            sq += 1LL * diff * diff;\n                        }\n                        sc -= EXACT_W * (double)sq;\n                    }\n\n                    if (hasBan) {\n                        bitset<MAXC> uni = b0 | b1;\n                        sc += computeBanPenaltyBits(uni);\n                    }\n\n                    if (sc > bestSc) {\n                        bestSc = sc;\n                        bestPos[0] = p0;\n                        bestPos[1] = p1;\n                    }\n                }\n            }\n\n            return buildState(bestPos);\n        }\n\n        if (M == 3) {\n            long long prod = 1;\n            for (int m = 0; m < 3; m++) {\n                prod *= (long long)fields[m].placements.size();\n            }\n            if (prod > 250000) return invalid;\n\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n            int P2 = (int)fields[2].placements.size();\n\n            double bestSc = -1e300;\n            vector<int> bestPos(3, 0);\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            vector<int> pred01(Q);\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    for (int q = 0; q < Q; q++) pred01[q] = a0[q] + a1[q];\n\n                    bitset<MAXC> bits01;\n                    if (hasBan) bits01 = b0 | b1;\n\n                    for (int p2 = 0; p2 < P2; p2++) {\n                        const uint16_t *a2 = Q ? &fields[2].contrib[p2 * Q] : nullptr;\n                        const auto &b2 = fields[2].placements[p2].bits;\n\n                        double sc = 0.0;\n                        for (int q = 0; q < Q; q++) {\n                            int t = pred01[q] + a2[q];\n                            sc += scoreFlat[q * stride + t];\n                        }\n\n                        if (drilledCount > 0) {\n                            long long sq = 0;\n                            for (int c : drilledCells) {\n                                int cnt = (b0.test(c) ? 1 : 0)\n                                        + (b1.test(c) ? 1 : 0)\n                                        + (b2.test(c) ? 1 : 0);\n                                int diff = cnt - drillVal[c];\n                                sq += 1LL * diff * diff;\n                            }\n                            sc -= EXACT_W * (double)sq;\n                        }\n\n                        if (hasBan) {\n                            bitset<MAXC> uni = bits01 | b2;\n                            sc += computeBanPenaltyBits(uni);\n                        }\n\n                        if (sc > bestSc) {\n                            bestSc = sc;\n                            bestPos[0] = p0;\n                            bestPos[1] = p1;\n                            bestPos[2] = p2;\n                        }\n                    }\n                }\n            }\n\n            return buildState(bestPos);\n        }\n\n        return invalid;\n    }\n\n    State coordinateDescent(State s, int sweeps, double deadlineMs) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            shuffle(order.begin(), order.end(), rng);\n            bool changed = false;\n\n            for (int m : order) {\n                if (elapsedMs() > deadlineMs) {\n                    s.score = computeScore(s);\n                    return s;\n                }\n\n                int oldP = s.pos[m];\n                addToState(s, m, oldP, -1);\n\n                double baseExact = computeExactScore(s.cnt);\n\n                vector<int> baseDiff(bannedEqMasks.size(), 0);\n                vector<int> baseOut(subsetMasks.size(), 0);\n\n                for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                    const auto &mask = bannedEqMasks[f];\n                    int diff = 0;\n                    for (int c = 0; c < C; c++) {\n                        bool cov = s.cnt[c] > 0;\n                        if (cov != (bool)mask[c]) diff++;\n                    }\n                    baseDiff[f] = diff;\n                }\n\n                for (size_t f = 0; f < subsetMasks.size(); f++) {\n                    const auto &mask = subsetMasks[f];\n                    int out = 0;\n                    for (int c = 0; c < C; c++) {\n                        if (s.cnt[c] > 0 && !mask[c]) out++;\n                    }\n                    baseOut[f] = out;\n                }\n\n                int P = (int)fields[m].placements.size();\n                int bestP = oldP;\n                double bestSc = -1e300;\n\n                for (int p = 0; p < P; p++) {\n                    const auto &pl = fields[m].placements[p];\n                    double total = baseExact;\n\n                    if (Q) {\n                        const uint16_t *arr = &fields[m].contrib[p * Q];\n                        for (int q = 0; q < Q; q++) {\n                            int t = s.pred[q] + arr[q];\n                            total += scoreFlat[q * stride + t];\n                        }\n                    }\n\n                    if (drilledCount > 0) {\n                        for (int c : pl.cells) {\n                            if (drilled[c]) {\n                                int diff = s.cnt[c] - drillVal[c];\n                                total += -EXACT_W *\n                                    (double)((diff + 1) * (diff + 1) - diff * diff);\n                            }\n                        }\n                    }\n\n                    for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                        int diff = baseDiff[f];\n                        const auto &mask = bannedEqMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0) {\n                                if (mask[c]) diff--;\n                                else diff++;\n                            }\n                        }\n\n                        if (diff == 0) total -= BAN_W;\n                    }\n\n                    for (size_t f = 0; f < subsetMasks.size(); f++) {\n                        int out = baseOut[f];\n                        const auto &mask = subsetMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0 && !mask[c]) out++;\n                        }\n\n                        if (out == 0) total -= BAN_W;\n                    }\n\n                    if (total > bestSc + 1e-9 ||\n                        (fabs(total - bestSc) <= 1e-9 && (rng() & 1))) {\n                        bestSc = total;\n                        bestP = p;\n                    }\n                }\n\n                addToState(s, m, bestP, +1);\n                s.pos[m] = bestP;\n                s.score = bestSc;\n                if (bestP != oldP) changed = true;\n            }\n\n            if (!changed) break;\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    State optimize(const State *prev, bool first) {\n        State exact = optimizeExactSmall();\n        if (exact.valid) return exact;\n\n        double now = elapsedMs();\n        double req = first ? 1200.0 : 450.0;\n        double deadline = min(2450.0, now + req);\n        if (deadline < now + 30.0) deadline = now + 30.0;\n\n        int maxRestarts;\n        if (first) {\n            if (M <= 4) maxRestarts = 80;\n            else if (M <= 10) maxRestarts = 50;\n            else maxRestarts = 35;\n        } else {\n            if (M <= 4) maxRestarts = 40;\n            else if (M <= 10) maxRestarts = 25;\n            else maxRestarts = 18;\n        }\n\n        int sweeps = first ? 7 : 5;\n\n        State best;\n\n        for (int r = 0; r < maxRestarts && elapsedMs() < deadline; r++) {\n            State s;\n\n            if (r == 0 && prev && prev->valid) {\n                s = buildState(prev->pos);\n            } else if ((r == 0 && (!prev || !prev->valid)) ||\n                       (r == 1 && prev && prev->valid)) {\n                s = makeGreedyState();\n            } else if (prev && prev->valid && r < 6) {\n                int changes = 1 + (r % max(1, M / 2));\n                s = makePerturbedState(*prev, changes);\n            } else {\n                s = makeRandomState();\n            }\n\n            s = coordinateDescent(s, sweeps, deadline);\n\n            if (!best.valid || s.score > best.score) {\n                best = std::move(s);\n            }\n        }\n\n        if (!best.valid) {\n            if (prev && prev->valid) best = buildState(prev->pos);\n            else best = makeGreedyState();\n        }\n\n        return best;\n    }\n\n    int countExactMismatch(const State &s) const {\n        int mism = 0;\n        for (int c : drilledCells) {\n            if (s.cnt[c] != drillVal[c]) mism++;\n        }\n        return mism;\n    }\n\n    vector<unsigned char> unionMask(const State &s) const {\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) mask[c] = 1;\n        }\n        return mask;\n    }\n\n    bool allVerifiedPositive(const vector<unsigned char> &mask) const {\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) {\n                if (!drilled[c]) return false;\n                if (drillVal[c] <= 0) return false;\n            }\n        }\n        return true;\n    }\n\n    bool sameMask(const vector<unsigned char> &a,\n                  const vector<unsigned char> &b) const {\n        return a == b;\n    }\n\n    bool isBannedEq(const vector<unsigned char> &mask) const {\n        for (const auto &x : bannedEqMasks) {\n            if (sameMask(x, mask)) return true;\n        }\n        return false;\n    }\n\n    void addBannedEq(const vector<unsigned char> &mask) {\n        if (!isBannedEq(mask)) bannedEqMasks.push_back(mask);\n    }\n\n    void addSubsetMask(const vector<unsigned char> &mask) {\n        for (const auto &x : subsetMasks) {\n            if (sameMask(x, mask)) return;\n        }\n        subsetMasks.push_back(mask);\n    }\n\n    int boundaryScore(int c, const vector<unsigned char> &mask) const {\n        int i = c / N;\n        int j = c % N;\n        int score = 0;\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                score++;\n            } else {\n                int nc = ni * N + nj;\n                if (!mask[nc]) score++;\n            }\n        }\n\n        return score;\n    }\n\n    vector<int> cellsToDrillInUnion(const vector<unsigned char> &U) {\n        vector<pair<int,int>> order;\n\n        for (int c = 0; c < C; c++) {\n            if (U[c] && !drilled[c]) {\n                int key = boundaryScore(c, U) * 1000000 + (int)(rng() % 1000000);\n                order.push_back({-key, c});\n            }\n        }\n\n        sort(order.begin(), order.end());\n\n        vector<int> res;\n        for (auto [_, c] : order) res.push_back(c);\n        return res;\n    }\n\n    void updateFallbackRank(const State &s) {\n        fallbackRank.assign(C, 0);\n        vector<unsigned char> U(C, 0);\n\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) {\n                U[c] = 1;\n                fallbackRank[c] += 100000 + 1000 * s.cnt[c];\n            }\n        }\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int c = 0; c < C; c++) {\n            if (!U[c]) continue;\n            int i = c / N;\n            int j = c % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!U[nc]) fallbackRank[nc] += 10000;\n            }\n        }\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        askInitialQueries();\n        buildContrib();\n        buildScoreTables();\n\n        State best = optimize(nullptr, true);\n\n        int maxUnverifiedGuesses = (N >= 15 ? 3 : 2);\n        int unverifiedUsed = 0;\n        int mismatchRetries = 0;\n\n        int probeGuessUsed = 0;\n        int maxProbeGuesses = (N >= 15 ? 2 : 1);\n\n        while (true) {\n            updateFallbackRank(best);\n\n            if (!canFallback()) {\n                fallback();\n            }\n\n            if (elapsedMs() > 2600.0) {\n                fallback();\n            }\n\n            if (drilledCount == C) {\n                fallback();\n            }\n\n            int mism = countExactMismatch(best);\n            if (mism > 0) {\n                if (mismatchRetries < 3 && elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    mismatchRetries++;\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n            mismatchRetries = 0;\n\n            vector<unsigned char> U = unionMask(best);\n            vector<unsigned char> A = U;\n            for (int c = 0; c < C; c++) {\n                if (drilled[c] && drillVal[c] > 0) A[c] = 1;\n            }\n\n            bool verified = allVerifiedPositive(A);\n\n            // If every predicted-positive cell has been drilled and matches the model,\n            // the total reserve count proves this answer. No fallback reserve is needed.\n            if (verified) {\n                submitAnswer(A);\n\n                // Should be unreachable, but keep the search legal if the impossible happens.\n                addSubsetMask(A);\n                addBannedEq(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            // Conservative speculative guesses: keep the original small limit.\n            if (unverifiedUsed < maxUnverifiedGuesses &&\n                canWrongGuessAndFallback() &&\n                !isBannedEq(A)) {\n                submitAnswer(A);\n                addBannedEq(A);\n                unverifiedUsed++;\n                best = optimize(&best, false);\n                continue;\n            }\n\n            vector<int> todo = cellsToDrillInUnion(U);\n\n            if (todo.empty()) {\n                if (elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n\n            bool contradiction = false;\n            int startIdx = 0;\n\n            // Cautious extra guess:\n            // drill a few boundary cells first. If they all agree, the candidate is\n            // much more trustworthy, and one extra answer can save drilling the whole union.\n            if (probeGuessUsed < maxProbeGuesses &&\n                (int)todo.size() >= 10 &&\n                elapsedMs() < 2450.0 &&\n                !isBannedEq(A)) {\n                int probeK = min((int)todo.size(), (N >= 15 ? 5 : 4));\n\n                for (; startIdx < probeK; startIdx++) {\n                    int c = todo[startIdx];\n                    if (drilled[c]) continue;\n                    if (!canFallback()) fallback();\n\n                    int v = drillCell(c);\n                    if (v != best.cnt[c]) {\n                        contradiction = true;\n                        break;\n                    }\n                }\n\n                if (contradiction) {\n                    best = optimize(&best, false);\n                    continue;\n                }\n\n                vector<unsigned char> PA = U;\n                for (int c = 0; c < C; c++) {\n                    if (drilled[c] && drillVal[c] > 0) PA[c] = 1;\n                }\n\n                if (allVerifiedPositive(PA)) {\n                    submitAnswer(PA);\n                    addSubsetMask(PA);\n                    addBannedEq(PA);\n                    best = optimize(&best, false);\n                    continue;\n                }\n\n                if (canWrongGuessAndFallback() && !isBannedEq(PA)) {\n                    submitAnswer(PA);\n                    addBannedEq(PA);\n                    probeGuessUsed++;\n                    best = optimize(&best, false);\n                    continue;\n                }\n            }\n\n            for (int idx = startIdx; idx < (int)todo.size(); idx++) {\n                int c = todo[idx];\n                if (drilled[c]) continue;\n                if (!canFallback()) fallback();\n\n                int v = drillCell(c);\n                if (v != best.cnt[c]) {\n                    contradiction = true;\n                    break;\n                }\n            }\n\n            if (contradiction) {\n                best = optimize(&best, false);\n                continue;\n            } else {\n                continue;\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int W = 1000;\nstatic const int AREA = W * W;\nstatic const unsigned short INF = 30000;\nenum { VERT = 0, HOR = 1 };\nenum { POLICY_STATIC_ABS = 0, POLICY_STATIC_RATIO = 1, POLICY_PREV = 2 };\n\nstruct Rect {\n    int y0, x0, y1, x1;\n};\n\nint D, N;\nvector<vector<int>> A;\nvector<int> globalMaxDemand, meanDemand, medDemand, p75Demand, p90Demand;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nint clamp_int(int v, int lo, int hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\n/* ---------- exact evaluator ---------- */\n\nstruct Bound {\n    array<vector<pair<int,int>>, W + 1> H, V;\n    void clear() {\n        for (int i = 0; i <= W; i++) {\n            H[i].clear();\n            V[i].clear();\n        }\n    }\n};\n\nvoid merge_intervals(vector<pair<int,int>>& v) {\n    if (v.empty()) return;\n    sort(v.begin(), v.end());\n    int m = 0;\n    for (auto p : v) {\n        if (m == 0 || p.first > v[m-1].second) {\n            v[m++] = p;\n        } else {\n            v[m-1].second = max(v[m-1].second, p.second);\n        }\n    }\n    v.resize(m);\n}\n\nvoid build_bound(const vector<Rect>& rs, Bound& b) {\n    b.clear();\n    for (const auto& r : rs) {\n        if (r.y0 > 0 && r.y0 < W) b.H[r.y0].push_back({r.x0, r.x1});\n        if (r.y1 > 0 && r.y1 < W) b.H[r.y1].push_back({r.x0, r.x1});\n        if (r.x0 > 0 && r.x0 < W) b.V[r.x0].push_back({r.y0, r.y1});\n        if (r.x1 > 0 && r.x1 < W) b.V[r.x1].push_back({r.y0, r.y1});\n    }\n    for (int i = 1; i < W; i++) {\n        merge_intervals(b.H[i]);\n        merge_intervals(b.V[i]);\n    }\n}\n\nlong long symdiff_line(const vector<pair<int,int>>& a, const vector<pair<int,int>>& b) {\n    long long la = 0, lb = 0, inter = 0;\n    for (auto [l, r] : a) la += r - l;\n    for (auto [l, r] : b) lb += r - l;\n\n    int i = 0, j = 0;\n    while (i < (int)a.size() && j < (int)b.size()) {\n        int l = max(a[i].first, b[j].first);\n        int r = min(a[i].second, b[j].second);\n        if (l < r) inter += r - l;\n        if (a[i].second < b[j].second) i++;\n        else j++;\n    }\n    return la + lb - 2 * inter;\n}\n\nlong long diff_bound(const Bound& a, const Bound& b) {\n    long long res = 0;\n    for (int i = 1; i < W; i++) {\n        res += symdiff_line(a.H[i], b.H[i]);\n        res += symdiff_line(a.V[i], b.V[i]);\n    }\n    return res;\n}\n\nlong long transition_cost(const vector<Rect>& x, const vector<Rect>& y) {\n    Bound bx, by;\n    build_bound(x, bx);\n    build_bound(y, by);\n    return diff_bound(bx, by);\n}\n\nlong long shortage_day(const vector<Rect>& rs, int d) {\n    long long res = 0;\n    for (int k = 0; k < N; k++) {\n        long long area = 1LL * (rs[k].y1 - rs[k].y0) * (rs[k].x1 - rs[k].x0);\n        if (area < A[d][k]) res += 100LL * (A[d][k] - area);\n    }\n    return res;\n}\n\nlong long evaluate_solution(const vector<vector<Rect>>& sol, long long limit = LLONG_MAX) {\n    long long total = 0;\n    Bound prev, cur;\n    for (int d = 0; d < D; d++) {\n        total += shortage_day(sol[d], d);\n        if (total > limit) return total;\n        build_bound(sol[d], cur);\n        if (d > 0) {\n            total += diff_bound(prev, cur);\n            if (total > limit) return total;\n        }\n        swap(prev, cur);\n    }\n    return total;\n}\n\n/* ---------- slicing tree ---------- */\n\nstruct Node {\n    int l = 0, r = 0;\n    int left = -1, right = -1;\n    int orient = VERT;\n    double ratio = 0.5;\n    int target = 1;\n    int targetCoord = -1;\n\n    bool leaf() const { return left == -1; }\n};\n\nstruct Tree {\n    vector<Node> nodes;\n    int root = 0;\n    vector<int> order;\n};\n\nvoid build_order(Tree& t) {\n    t.order.clear();\n    function<void(int)> dfs = [&](int v) {\n        if (!t.nodes[v].leaf()) {\n            dfs(t.nodes[v].left);\n            dfs(t.nodes[v].right);\n        }\n        t.order.push_back(v);\n    };\n    dfs(t.root);\n}\n\nint choose_split(int l, int r, int mode, const vector<double>& pref) {\n    if (r - l <= 1) return l + 1;\n    if (mode == 1) return (l + r) / 2;\n\n    double total = pref[r] - pref[l];\n    int best = l + 1;\n    double bestScore = 1e100;\n\n    for (int m = l + 1; m <= r - 1; m++) {\n        double af = (pref[m] - pref[l]) / total;\n        double cf = double(m - l) / double(r - l);\n        double score;\n        if (mode == 0) {\n            score = fabs(af - 0.5);\n        } else {\n            score = fabs(af - 0.5) + 0.35 * fabs(cf - 0.5);\n        }\n        if (score < bestScore) {\n            bestScore = score;\n            best = m;\n        }\n    }\n    return best;\n}\n\nTree build_aspect_tree(const vector<int>& base, int splitMode, int orientMode) {\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    Tree t;\n    function<int(int,int,int,int,int)> rec = [&](int l, int r, int h, int w, int depth) -> int {\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].l = l;\n        t.nodes[idx].r = r;\n\n        if (r - l == 1) return idx;\n\n        int orient;\n        if (orientMode == 0) orient = (w >= h ? VERT : HOR);\n        else if (orientMode == 1) orient = (depth % 2 == 0 ? VERT : HOR);\n        else orient = (depth % 2 == 0 ? HOR : VERT);\n\n        int m = choose_split(l, r, splitMode, pref);\n        double sL = pref[m] - pref[l];\n        double sT = pref[r] - pref[l];\n        double ratio = sL / sT;\n\n        t.nodes[idx].orient = orient;\n        t.nodes[idx].ratio = ratio;\n\n        int hL = h, hR = h, wL = w, wR = w;\n        if (orient == VERT) {\n            int c = (w >= 2 ? clamp_int((int)llround(w * ratio), 1, w - 1) : 1);\n            wL = max(1, c);\n            wR = max(1, w - c);\n        } else {\n            int c = (h >= 2 ? clamp_int((int)llround(h * ratio), 1, h - 1) : 1);\n            hL = max(1, c);\n            hR = max(1, h - c);\n        }\n\n        int li = rec(l, m, hL, wL, depth + 1);\n        int ri = rec(m, r, hR, wR, depth + 1);\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        return idx;\n    };\n\n    t.root = rec(0, N, W, W, 0);\n    build_order(t);\n    return t;\n}\n\nint build_fixed_rec(Tree& t, int l, int r, int orient, int splitMode, const vector<double>& pref) {\n    int idx = (int)t.nodes.size();\n    t.nodes.push_back(Node());\n    t.nodes[idx].l = l;\n    t.nodes[idx].r = r;\n    t.nodes[idx].orient = orient;\n\n    if (r - l == 1) return idx;\n\n    int m = choose_split(l, r, splitMode, pref);\n    double sL = pref[m] - pref[l];\n    double sT = pref[r] - pref[l];\n    t.nodes[idx].ratio = sL / sT;\n\n    int li = build_fixed_rec(t, l, m, orient, splitMode, pref);\n    int ri = build_fixed_rec(t, m, r, orient, splitMode, pref);\n    t.nodes[idx].left = li;\n    t.nodes[idx].right = ri;\n    return idx;\n}\n\nTree build_shelf_tree(const vector<int>& base, int R, int groupMode, int itemSplitMode) {\n    R = clamp_int(R, 1, N);\n\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> groups;\n    int prev = 0;\n    for (int g = 0; g < R; g++) {\n        int en;\n        if (g == R - 1) {\n            en = N;\n        } else {\n            int minEnd = prev + 1;\n            int maxEnd = N - (R - g - 1);\n            if (groupMode == 0) {\n                double target = pref[N] * double(g + 1) / double(R);\n                en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            } else {\n                en = (int)llround(double(N) * double(g + 1) / double(R));\n            }\n            en = clamp_int(en, minEnd, maxEnd);\n        }\n        groups.push_back({prev, en});\n        prev = en;\n    }\n\n    Tree t;\n    vector<int> rowRoot;\n    vector<double> rowPref(R + 1, 0);\n\n    for (int i = 0; i < R; i++) {\n        auto [l, r] = groups[i];\n        rowRoot.push_back(build_fixed_rec(t, l, r, VERT, itemSplitMode, pref));\n        rowPref[i+1] = rowPref[i] + (pref[r] - pref[l]);\n    }\n\n    function<int(int,int)> combine = [&](int lo, int hi) -> int {\n        if (hi - lo == 1) return rowRoot[lo];\n\n        int mid = lo + 1;\n        double total = rowPref[hi] - rowPref[lo];\n        double best = 1e100;\n        for (int m = lo + 1; m <= hi - 1; m++) {\n            double d = fabs((rowPref[m] - rowPref[lo]) - total * 0.5);\n            if (d < best) {\n                best = d;\n                mid = m;\n            }\n        }\n\n        int li = combine(lo, mid);\n        int ri = combine(mid, hi);\n\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        t.nodes[idx].l = t.nodes[li].l;\n        t.nodes[idx].r = t.nodes[ri].r;\n        t.nodes[idx].orient = HOR;\n        t.nodes[idx].ratio = (rowPref[mid] - rowPref[lo]) / (rowPref[hi] - rowPref[lo]);\n        return idx;\n    };\n\n    t.root = combine(0, R);\n    build_order(t);\n    return t;\n}\n\n/* ---------- DP for slicing tree ---------- */\n\nstruct DPComputer {\n    const Tree* tr;\n    bool freeOrient;\n    vector<array<unsigned short, W + 1>> dp;\n    vector<array<unsigned short, W + 1>> mh;\n\n    DPComputer(const Tree& t, bool f) : tr(&t), freeOrient(f) {\n        dp.resize(t.nodes.size());\n        mh.resize(t.nodes.size());\n    }\n\n    void compute_mh_from_dp(int idx) {\n        auto& P = dp[idx];\n        auto& M = mh[idx];\n        for (int i = 0; i <= W; i++) M[i] = INF;\n\n        int prev = W + 1;\n        for (int h = 1; h <= W; h++) {\n            int v = P[h];\n            if (v <= W && v < prev) {\n                for (int w = v; w < prev; w++) M[w] = h;\n                prev = v;\n            }\n        }\n    }\n\n    void horizontal_merge(int L, int R, array<unsigned short, W + 1>& out) {\n        for (int i = 0; i <= W; i++) out[i] = INF;\n        int prev = W + 1;\n        for (int w = 1; w <= W; w++) {\n            int hL = mh[L][w], hR = mh[R][w];\n            int req = (hL >= INF || hR >= INF ? INF : hL + hR);\n            if (req <= W && req < prev) {\n                for (int h = req; h < prev; h++) out[h] = w;\n                prev = req;\n            }\n        }\n    }\n\n    void compute(const vector<int>& demand) {\n        for (int idx : tr->order) {\n            const Node& nd = tr->nodes[idx];\n            auto& P = dp[idx];\n            auto& M = mh[idx];\n\n            if (nd.leaf()) {\n                long long a = demand[nd.l];\n                P[0] = M[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    long long v = (a + h - 1) / h;\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                for (int w = 1; w <= W; w++) {\n                    long long v = (a + w - 1) / w;\n                    M[w] = (v <= W ? (unsigned short)v : INF);\n                }\n                continue;\n            }\n\n            int L = nd.left, R = nd.right;\n\n            if (!freeOrient && nd.orient == VERT) {\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                compute_mh_from_dp(idx);\n            } else if (!freeOrient && nd.orient == HOR) {\n                horizontal_merge(L, R, P);\n                compute_mh_from_dp(idx);\n            } else {\n                array<unsigned short, W + 1> HP;\n                horizontal_merge(L, R, HP);\n\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    if (v > W) v = INF;\n                    P[h] = (unsigned short)min(v, (int)HP[h]);\n                }\n                compute_mh_from_dp(idx);\n            }\n        }\n    }\n};\n\n/* ---------- target assignment and reconstruction ---------- */\n\nbool assign_targets_dp_rec(Tree& t, int idx, int y, int x, int h, int w, const DPComputer& comp) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return true;\n\n    int L = nd.left, R = nd.right;\n\n    if (nd.orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(w * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        nd.target = c;\n        nd.targetCoord = x + c;\n        return assign_targets_dp_rec(t, L, y, x, h, c, comp) &&\n               assign_targets_dp_rec(t, R, y, x + c, h, w - c, comp);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(h * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        nd.target = c;\n        nd.targetCoord = y + c;\n        return assign_targets_dp_rec(t, L, y, x, c, w, comp) &&\n               assign_targets_dp_rec(t, R, y + c, x, h - c, w, comp);\n    }\n}\n\nvoid assign_targets_ratio_rec(Tree& t, int idx, int y, int x, int h, int w) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return;\n\n    if (nd.orient == VERT) {\n        int c = (w >= 2 ? clamp_int((int)llround(w * nd.ratio), 1, w - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = x + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, h, max(1, c));\n        assign_targets_ratio_rec(t, nd.right, y, x + c, h, max(1, w - c));\n    } else {\n        int c = (h >= 2 ? clamp_int((int)llround(h * nd.ratio), 1, h - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = y + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, max(1, c), w);\n        assign_targets_ratio_rec(t, nd.right, y + c, x, max(1, h - c), w);\n    }\n}\n\nvoid assign_targets(Tree& t, const vector<int>& demand) {\n    for (auto& nd : t.nodes) {\n        nd.target = 1;\n        nd.targetCoord = -1;\n    }\n\n    DPComputer comp(t, false);\n    comp.compute(demand);\n\n    bool ok = (comp.dp[t.root][W] <= W);\n    if (ok) ok = assign_targets_dp_rec(t, t.root, 0, 0, W, W, comp);\n\n    if (!ok) assign_targets_ratio_rec(t, t.root, 0, 0, W, W);\n}\n\nbool feasible_vert(const DPComputer& comp, int L, int R, int h, int w) {\n    if (w < 2) return false;\n    int a = comp.dp[L][h], b = comp.dp[R][h];\n    return a < INF && b < INF && a + b <= w;\n}\n\nbool feasible_hor(const DPComputer& comp, int L, int R, int h, int w) {\n    if (h < 2) return false;\n    int a = comp.mh[L][w], b = comp.mh[R][w];\n    return a < INF && b < INF && a + b <= h;\n}\n\nint target_size_for(\n    const Tree& t,\n    int idx,\n    int orient,\n    int dim,\n    int originCoord,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (policy == POLICY_PREV && prevOrient[idx] == orient && prevCoord[idx] >= 0) {\n        return prevCoord[idx] - originCoord;\n    }\n\n    if (policy == POLICY_STATIC_RATIO || orient != nd.orient || nd.targetCoord < 0) {\n        return (int)llround(dim * nd.ratio);\n    }\n\n    return nd.targetCoord - originCoord;\n}\n\nbool reconstruct_rec(\n    const Tree& t,\n    int idx,\n    int y,\n    int x,\n    int h,\n    int w,\n    const DPComputer& comp,\n    vector<Rect>& rects,\n    bool freeOrient,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord,\n    vector<int>& curOrient,\n    vector<int>& curCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (nd.leaf()) {\n        if (h <= 0 || w <= 0) return false;\n        rects[nd.l] = {y, x, y + h, x + w};\n        return true;\n    }\n\n    int L = nd.left, R = nd.right;\n    bool canV = feasible_vert(comp, L, R, h, w);\n    bool canH = feasible_hor(comp, L, R, h, w);\n\n    int orient = nd.orient;\n    if (freeOrient) {\n        int po = (policy == POLICY_PREV ? prevOrient[idx] : -1);\n        if (po == VERT && canV) orient = VERT;\n        else if (po == HOR && canH) orient = HOR;\n        else if (nd.orient == VERT && canV) orient = VERT;\n        else if (nd.orient == HOR && canH) orient = HOR;\n        else if (canV) orient = VERT;\n        else if (canH) orient = HOR;\n        else return false;\n    } else {\n        if (orient == VERT && !canV) return false;\n        if (orient == HOR && !canH) return false;\n    }\n\n    if (orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, VERT, w, x, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        curOrient[idx] = VERT;\n        curCoord[idx] = x + c;\n\n        return reconstruct_rec(t, L, y, x, h, c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y, x + c, h, w - c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, HOR, h, y, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        curOrient[idx] = HOR;\n        curCoord[idx] = y + c;\n\n        return reconstruct_rec(t, L, y, x, c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y + c, x, h - c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    }\n}\n\nbool make_solution(const Tree& t, bool freeOrient, int policy, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n\n    DPComputer comp(t, freeOrient);\n    int M = (int)t.nodes.size();\n\n    vector<int> prevOrient(M, -1), prevCoord(M, -1);\n    for (int i = 0; i < M; i++) {\n        if (!t.nodes[i].leaf()) {\n            prevOrient[i] = t.nodes[i].orient;\n            prevCoord[i] = t.nodes[i].targetCoord;\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        comp.compute(A[d]);\n        if (comp.dp[t.root][W] > W) return false;\n\n        vector<int> curOrient(M, -1), curCoord(M, -1);\n        bool ok = reconstruct_rec(\n            t, t.root, 0, 0, W, W, comp, sol[d],\n            freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord\n        );\n        if (!ok) return false;\n\n        if (policy == POLICY_PREV) {\n            prevOrient.swap(curOrient);\n            prevCoord.swap(curCoord);\n        }\n    }\n    return true;\n}\n\nbool make_static_solution(const Tree& t, const vector<int>& demand, bool freeOrient, vector<vector<Rect>>& sol) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][W] > W) return false;\n\n    vector<Rect> one(N);\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    bool ok = reconstruct_rec(\n        t, t.root, 0, 0, W, W, comp, one,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n    if (!ok) return false;\n\n    sol.assign(D, one);\n    return true;\n}\n\n/* ---------- candidates and postprocessing ---------- */\n\nvector<int> scale_to_limit(const vector<int>& v) {\n    long long s = 0;\n    for (int x : v) s += x;\n    if (s <= AREA) return v;\n\n    vector<int> r(N);\n    double f = double(AREA) / double(s);\n    long long sr = 0;\n    for (int i = 0; i < N; i++) {\n        r[i] = max(1, (int)floor(v[i] * f));\n        sr += r[i];\n    }\n\n    while (sr > AREA) {\n        int id = -1;\n        for (int i = 0; i < N; i++) {\n            if (r[i] > 1 && (id == -1 || r[i] > r[id])) id = i;\n        }\n        if (id == -1) break;\n        r[id]--;\n        sr--;\n    }\n    return r;\n}\n\nvector<vector<Rect>> make_fallback() {\n    vector<vector<Rect>> sol(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; d++) {\n        vector<int> h(N, 1);\n        int rem = W - N;\n\n        auto gain = [&](int k) -> int {\n            long long covered = 1LL * h[k] * W;\n            if (covered >= A[d][k]) return 0;\n            return (int)min<long long>(W, A[d][k] - covered);\n        };\n\n        priority_queue<pair<int,int>> pq;\n        for (int k = 0; k < N; k++) pq.push({gain(k), k});\n\n        while (rem > 0 && !pq.empty()) {\n            auto [g, k] = pq.top();\n            pq.pop();\n            int cg = gain(k);\n            if (cg != g) {\n                pq.push({cg, k});\n                continue;\n            }\n            if (cg <= 0) break;\n            h[k]++;\n            rem--;\n            pq.push({gain(k), k});\n        }\n\n        h[N-1] += rem;\n\n        int y = 0;\n        for (int k = 0; k < N; k++) {\n            sol[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    return sol;\n}\n\nvector<vector<Rect>> bestSol;\nlong long bestScore = LLONG_MAX;\n\nvoid consider_solution(const vector<vector<Rect>>& sol) {\n    long long sc = evaluate_solution(sol, bestScore);\n    if (sc < bestScore) {\n        bestScore = sc;\n        bestSol = sol;\n    }\n}\n\n/* ---------- new day-specific relaxed slicing DP ---------- */\n\nbool same_layout(const vector<Rect>& a, const vector<Rect>& b) {\n    if ((int)a.size() != (int)b.size()) return false;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i].y0 != b[i].y0 || a[i].x0 != b[i].x0 ||\n            a[i].y1 != b[i].y1 || a[i].x1 != b[i].x1) return false;\n    }\n    return true;\n}\n\nvoid add_unique_layout(vector<vector<Rect>>& cand, const vector<Rect>& layout) {\n    for (const auto& x : cand) {\n        if (same_layout(x, layout)) return;\n    }\n    cand.push_back(layout);\n}\n\nbool try_single_tree_layout(Tree t, const vector<int>& demand, bool freeOrient, vector<Rect>& layout) {\n    assign_targets(t, demand);\n\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][W] > W) return false;\n\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    layout.assign(N, Rect());\n    bool ok = reconstruct_rec(\n        t, t.root, 0, 0, W, W, comp, layout,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n    return ok;\n}\n\nbool make_single_tree_layout_relaxed(const Tree& baseTree, const vector<int>& trueDemand, bool freeOrient, vector<Rect>& layout) {\n    if (try_single_tree_layout(baseTree, trueDemand, freeOrient, layout)) return true;\n\n    static const double factors[] = {0.999, 0.997, 0.995, 0.990, 0.980, 0.960, 0.930, 0.900, 0.850};\n\n    vector<int> dem(N);\n    for (double f : factors) {\n        for (int k = 0; k < N; k++) {\n            dem[k] = max(1, (int)floor(trueDemand[k] * f));\n        }\n        if (try_single_tree_layout(baseTree, dem, freeOrient, layout)) return true;\n    }\n\n    return false;\n}\n\nvoid run_day_specific_slicing_dp() {\n    if (bestScore == 0) return;\n\n    const double TL_DAY = 1.35;\n    vector<vector<vector<Rect>>> cand(D);\n\n    for (int d = 0; d < D; d++) {\n        cand[d].push_back(bestSol[d]);\n    }\n\n    vector<pair<int,int>> combos = {\n        {0, 0},\n        {2, 0},\n        {1, 0},\n        {0, 1},\n        {0, 2}\n    };\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL_DAY) break;\n\n        for (int ci = 0; ci < (int)combos.size(); ci++) {\n            if (elapsed_sec() > TL_DAY) break;\n\n            Tree t = build_aspect_tree(A[d], combos[ci].first, combos[ci].second);\n\n            vector<Rect> layout;\n            if (make_single_tree_layout_relaxed(t, A[d], false, layout)) {\n                add_unique_layout(cand[d], layout);\n            }\n\n            if (ci <= 1 && elapsed_sec() < TL_DAY) {\n                if (make_single_tree_layout_relaxed(t, A[d], true, layout)) {\n                    add_unique_layout(cand[d], layout);\n                }\n            }\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n\n    vector<vector<long long>> dp(D);\n    vector<vector<int>> par(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = cand[d].size();\n        dp[d].assign(C, BIG);\n        par[d].assign(C, -1);\n    }\n\n    for (int c = 0; c < (int)cand[0].size(); c++) {\n        dp[0][c] = shortage_day(cand[0][c], 0);\n    }\n\n    for (int d = 1; d < D; d++) {\n        for (int c = 0; c < (int)cand[d].size(); c++) {\n            long long sh = shortage_day(cand[d][c], d);\n            for (int pc = 0; pc < (int)cand[d-1].size(); pc++) {\n                if (dp[d-1][pc] >= BIG / 2) continue;\n                long long tr = transition_cost(cand[d-1][pc], cand[d][c]);\n                long long nv = dp[d-1][pc] + sh + tr;\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = -1;\n    long long best = BIG;\n    for (int c = 0; c < (int)cand[D-1].size(); c++) {\n        if (dp[D-1][c] < best) {\n            best = dp[D-1][c];\n            bestC = c;\n        }\n    }\n    if (bestC < 0) return;\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = cand[d][cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- shelf utilities ---------- */\n\nstatic const int SEG_INF = 1'000'000'000;\nstatic const int MAX_SEG_OPT = 4;\n\nint hMinSeg[55][55], hStaticSeg[55][55];\nint dayHSeg[55][55][55];\n\nint segOptCnt[55][55];\nint segOptH[55][55][MAX_SEG_OPT];\nlong long segOptCost[55][55][MAX_SEG_OPT];\nint segOptTarget[55][55][MAX_SEG_OPT];\nbool segOptSoft[55][55][MAX_SEG_OPT];\n\nint ceil_div_int(int a, int b) {\n    return (a + b - 1) / b;\n}\n\nbool check_day_segment_h(int d, int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(A[d][k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_day_hmin_segment(int d, int l, int r) {\n    if (!check_day_segment_h(d, l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_day_segment_h(d, l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nvoid precompute_day_segments() {\n    for (int d = 0; d < D; d++) {\n        for (int l = 0; l < N; l++) {\n            for (int r = l + 1; r <= N; r++) {\n                dayHSeg[d][l][r] = compute_day_hmin_segment(d, l, r);\n            }\n        }\n    }\n}\n\nbool check_segment_h(int l, int r, int h) {\n    for (int d = 0; d < D; d++) {\n        int s = 0;\n        for (int k = l; k < r; k++) {\n            s += ceil_div_int(A[d][k], h);\n            if (s > W) return false;\n        }\n    }\n    return true;\n}\n\nint compute_hmin_segment(int l, int r) {\n    if (!check_segment_h(l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_segment_h(l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nbool check_static_h(int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(globalMaxDemand[k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_hstatic_segment(int l, int r) {\n    if (!check_static_h(l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_static_h(l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nint base_value_for_target(int type, int k) {\n    if (type == 0) return globalMaxDemand[k];\n    if (type == 1) return p90Demand[k];\n    if (type == 2) return p75Demand[k];\n    if (type == 3) return meanDemand[k];\n    return medDemand[k];\n}\n\nvector<int> normalize_widths(vector<int> w) {\n    int m = (int)w.size();\n    int s = accumulate(w.begin(), w.end(), 0);\n    while (s < W) {\n        w[m - 1]++;\n        s++;\n    }\n    while (s > W) {\n        bool done = false;\n        for (int i = m - 1; i >= 0 && s > W; i--) {\n            if (w[i] > 1) {\n                w[i]--;\n                s--;\n                done = true;\n            }\n        }\n        if (!done) break;\n    }\n    return w;\n}\n\nvector<int> allocate_by_weights(const vector<int>& lower, const vector<double>& weights) {\n    int m = (int)lower.size();\n    int sumL = accumulate(lower.begin(), lower.end(), 0);\n    if (sumL > W) {\n        vector<int> w(m, 1);\n        int rem = W - m;\n        for (int i = 0; i < m && rem > 0; i++, rem--) w[i]++;\n        if (rem > 0) w[m-1] += rem;\n        return w;\n    }\n\n    vector<int> w = lower;\n    int rem = W - sumL;\n    if (rem == 0) return w;\n\n    double sw = 0;\n    for (double x : weights) sw += max(1e-9, x);\n    if (sw <= 0) sw = m;\n\n    vector<pair<double,int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; i++) {\n        double ideal = rem * max(1e-9, weights[i]) / sw;\n        int add = (int)floor(ideal);\n        w[i] += add;\n        used += add;\n        frac.push_back({ideal - add, i});\n    }\n    int left = rem - used;\n    sort(frac.rbegin(), frac.rend());\n    for (int i = 0; i < left; i++) w[frac[i % m].second]++;\n    return normalize_widths(w);\n}\n\nvector<int> make_target_widths(int l, int r, int h, int targetType) {\n    int m = r - l;\n    vector<int> lower(m, 1);\n    long long sumL = 0;\n    for (int i = 0; i < m; i++) {\n        int b = base_value_for_target(targetType, l + i);\n        lower[i] = max(1, ceil_div_int(b, h));\n        sumL += lower[i];\n    }\n    if (sumL > W) {\n        fill(lower.begin(), lower.end(), 1);\n    }\n\n    vector<double> weights(m);\n    for (int i = 0; i < m; i++) {\n        weights[i] = max(1, base_value_for_target(targetType, l + i));\n    }\n    return allocate_by_weights(lower, weights);\n}\n\nvector<int> project_near(vector<int> ref, const vector<int>& lb) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    vector<int> w = ref;\n    for (int i = 0; i < m; i++) {\n        if (w[i] >= lb[i]) continue;\n        int need = lb[i] - w[i];\n        w[i] = lb[i];\n\n        while (need > 0) {\n            int best = -1;\n            for (int j = 0; j < m; j++) {\n                if (w[j] <= lb[j]) continue;\n                if (best == -1 ||\n                    abs(j - i) < abs(best - i) ||\n                    (abs(j - i) == abs(best - i) && w[j] - lb[j] > w[best] - lb[best])) {\n                    best = j;\n                }\n            }\n            if (best == -1) break;\n            int x = min(need, w[best] - lb[best]);\n            w[best] -= x;\n            need -= x;\n        }\n    }\n    return normalize_widths(w);\n}\n\nvoid make_day_lb(int l, int r, int h, int d, const vector<int>& ref, bool soft, vector<int>& lb) {\n    int m = r - l;\n    lb.assign(m, 1);\n    for (int i = 0; i < m; i++) {\n        int a = A[d][l + i];\n        int q = ceil_div_int(a, h);\n        if (soft && (int)ref.size() == m && ref[i] < q && q > 1) {\n            int rem = a - h * (q - 1);\n            if (100LL * rem < 2LL * h) q--;\n        }\n        lb[i] = max(1, q);\n    }\n}\n\nvector<int> shortage_widths(const vector<int>& refIn, int l, int r, int h, int d) {\n    int m = r - l;\n    vector<int> ref = normalize_widths(refIn);\n    vector<int> w(m);\n    long long sum = 0;\n    for (int i = 0; i < m; i++) {\n        w[i] = max(1, ceil_div_int(A[d][l + i], h));\n        sum += w[i];\n    }\n    if (sum <= W) return project_near(ref, w);\n\n    vector<int> cur(m, 1);\n    int rem = W - m;\n    if (rem < 0) rem = 0;\n\n    auto gain = [&](int i) -> int {\n        long long covered = 1LL * cur[i] * h;\n        if (covered >= A[d][l + i]) return 0;\n        return (int)min<long long>(h, A[d][l + i] - covered);\n    };\n\n    using Tup = tuple<int,int,int,int>;\n    priority_queue<Tup> pq;\n    for (int i = 0; i < m; i++) {\n        int pref = (i < (int)ref.size() ? ref[i] - cur[i] : 0);\n        pq.push({gain(i), pref, -i, cur[i]});\n    }\n\n    while (rem > 0 && !pq.empty()) {\n        auto [g, pref, ni, old] = pq.top();\n        pq.pop();\n        int i = -ni;\n        if (old != cur[i]) continue;\n        int cg = gain(i);\n        if (cg <= 0) break;\n        cur[i]++;\n        rem--;\n        int np = (i < (int)ref.size() ? ref[i] - cur[i] : 0);\n        pq.push({gain(i), np, -i, cur[i]});\n    }\n    if (rem > 0) cur[m-1] += rem;\n    return normalize_widths(cur);\n}\n\nint symdiff_cut_count(const vector<int>& a, const vector<int>& b) {\n    int m = (int)a.size();\n    vector<int> ca, cb;\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += a[i];\n        ca.push_back(s);\n    }\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += b[i];\n        cb.push_back(s);\n    }\n    int i = 0, j = 0, common = 0;\n    while (i < (int)ca.size() && j < (int)cb.size()) {\n        if (ca[i] == cb[j]) {\n            common++;\n            i++;\n            j++;\n        } else if (ca[i] < cb[j]) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n    return (int)ca.size() + (int)cb.size() - 2 * common;\n}\n\nlong long row_shortage_cost(int l, int r, int h, int d, const vector<int>& w) {\n    long long res = 0;\n    for (int i = 0; i < r - l; i++) {\n        long long area = 1LL * h * w[i];\n        if (area < A[d][l + i]) res += 100LL * (A[d][l + i] - area);\n    }\n    return res;\n}\n\nlong long simulate_row_fast(int l, int r, int h, int targetType, bool soft) {\n    vector<int> target = make_target_widths(l, r, h, targetType);\n    vector<int> prev;\n    long long cost = 0;\n\n    for (int d = 0; d < D; d++) {\n        vector<int> ref = (d == 0 ? target : prev);\n        vector<int> lb;\n        make_day_lb(l, r, h, d, ref, soft, lb);\n        int sumLB = accumulate(lb.begin(), lb.end(), 0);\n\n        vector<int> w;\n        if (sumLB <= W) w = project_near(ref, lb);\n        else w = shortage_widths(ref, l, r, h, d);\n\n        cost += row_shortage_cost(l, r, h, d, w);\n        if (d > 0) cost += 1LL * h * symdiff_cut_count(prev, w);\n        prev = w;\n    }\n    return cost;\n}\n\nvoid best_row_option(int l, int r, int h, long long& best, int& bestT, bool& bestS) {\n    if (hStaticSeg[l][r] < SEG_INF && h >= hStaticSeg[l][r]) {\n        best = 0;\n        bestT = 0;\n        bestS = false;\n        return;\n    }\n\n    best = (1LL << 62);\n    bestT = 0;\n    bestS = false;\n\n    for (int t = 0; t < 4; t++) {\n        for (int s = 0; s <= 1; s++) {\n            long long c = simulate_row_fast(l, r, h, t, s);\n            if (c < best) {\n                best = c;\n                bestT = t;\n                bestS = (bool)s;\n            }\n        }\n    }\n}\n\nvector<int> choose_widths_overlap(vector<int> ref, const vector<int>& lb, vector<int> target) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n    target = normalize_widths(target);\n\n    if (m == 1) return vector<int>{W};\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    vector<int> oldSet(W + 1, 0);\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += ref[i];\n        if (0 <= s && s <= W) oldSet[s] = 1;\n    }\n\n    vector<int> targetCut(m - 1);\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += target[i];\n        targetCut[i] = s;\n    }\n\n    const int NEG = -1'000'000'000;\n    const int MATCH = 1'000'000;\n\n    vector<int> prev(W + 1, NEG), cur(W + 1, NEG);\n    vector<int> prefVal(W + 1), prefPos(W + 1);\n    vector<vector<short>> par(m, vector<short>(W + 1, -1));\n\n    prev[0] = 0;\n\n    vector<int> prefLB(m + 1, 0), suffLB(m + 1, 0);\n    for (int i = 0; i < m; i++) prefLB[i+1] = prefLB[i] + lb[i];\n    for (int i = m - 1; i >= 0; i--) suffLB[i] = suffLB[i+1] + lb[i];\n\n    for (int i = 1; i <= m - 1; i++) {\n        prefVal[0] = prev[0];\n        prefPos[0] = 0;\n        for (int x = 1; x <= W; x++) {\n            if (prev[x] > prefVal[x-1]) {\n                prefVal[x] = prev[x];\n                prefPos[x] = x;\n            } else {\n                prefVal[x] = prefVal[x-1];\n                prefPos[x] = prefPos[x-1];\n            }\n        }\n\n        fill(cur.begin(), cur.end(), NEG);\n\n        int minX = prefLB[i];\n        int maxX = W - suffLB[i];\n        for (int x = minX; x <= maxX; x++) {\n            int lim = x - lb[i-1];\n            if (lim < 0) continue;\n            int val = prefVal[lim];\n            if (val <= NEG / 2) continue;\n            int p = prefPos[lim];\n\n            int bonus = (oldSet[x] ? MATCH : 0) - abs(x - targetCut[i-1]);\n            int nv = val + bonus;\n            if (nv > cur[x]) {\n                cur[x] = nv;\n                par[i][x] = (short)p;\n            }\n        }\n        prev.swap(cur);\n    }\n\n    int bestP = -1, bestVal = NEG;\n    int maxP = W - lb[m-1];\n    for (int p = 0; p <= maxP; p++) {\n        if (prev[p] > bestVal) {\n            bestVal = prev[p];\n            bestP = p;\n        }\n    }\n\n    if (bestP < 0) return project_near(ref, lb);\n\n    vector<int> cuts(m + 1);\n    cuts[0] = 0;\n    cuts[m] = W;\n    cuts[m-1] = bestP;\n\n    for (int i = m - 1; i >= 1; i--) {\n        int p = par[i][cuts[i]];\n        if (p < 0) return project_near(ref, lb);\n        cuts[i-1] = p;\n    }\n\n    vector<int> w(m);\n    for (int i = 0; i < m; i++) {\n        w[i] = cuts[i+1] - cuts[i];\n        if (w[i] < lb[i] || w[i] <= 0) return project_near(ref, lb);\n    }\n    return normalize_widths(w);\n}\n\n/* ---------- per-day / variable-height shelf candidates ---------- */\n\nstruct TmpRow {\n    int l, r, h;\n};\n\nbool get_daily_rows(int d, int mode, vector<TmpRow>& rows) {\n    rows.clear();\n\n    if (mode == 0) {\n        vector<int> dp(N + 1, SEG_INF), cnt(N + 1, SEG_INF), par(N + 1, -1);\n        dp[0] = 0;\n        cnt[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            for (int i = 0; i < j; i++) {\n                int h = dayHSeg[d][i][j];\n                if (h >= SEG_INF || dp[i] >= SEG_INF) continue;\n                int nv = dp[i] + h;\n                int nc = cnt[i] + 1;\n                if (nv < dp[j] || (nv == dp[j] && nc < cnt[j])) {\n                    dp[j] = nv;\n                    cnt[j] = nc;\n                    par[j] = i;\n                }\n            }\n        }\n\n        if (dp[N] > W) return false;\n\n        int cur = N;\n        while (cur > 0) {\n            int p = par[cur];\n            if (p < 0) return false;\n            rows.push_back({p, cur, dayHSeg[d][p][cur]});\n            cur = p;\n        }\n        reverse(rows.begin(), rows.end());\n        return true;\n    } else {\n        const int BIG = 1'000'000'000;\n        vector<vector<int>> dp(N + 1, vector<int>(W + 1, BIG));\n        vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n        vector<vector<short>> parU(N + 1, vector<short>(W + 1, -1));\n\n        dp[0][0] = 0;\n\n        for (int i = 0; i < N; i++) {\n            for (int used = 0; used <= W; used++) {\n                if (dp[i][used] >= BIG) continue;\n\n                for (int j = i + 1; j <= N; j++) {\n                    int h = dayHSeg[d][i][j];\n                    if (h >= SEG_INF) continue;\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    int len = j - i;\n                    int add = 1000 + h * max(0, len - 1);\n                    int nv = dp[i][used] + add;\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parU[j][nu] = (short)used;\n                    }\n                }\n            }\n        }\n\n        int bestU = -1, best = BIG;\n        for (int u = 0; u <= W; u++) {\n            if (dp[N][u] < best) {\n                best = dp[N][u];\n                bestU = u;\n            }\n        }\n        if (bestU < 0) return false;\n\n        int cur = N, used = bestU;\n        while (cur > 0) {\n            int p = parI[cur][used];\n            int pu = parU[cur][used];\n            if (p < 0 || pu < 0) return false;\n            rows.push_back({p, cur, dayHSeg[d][p][cur]});\n            cur = p;\n            used = pu;\n        }\n        reverse(rows.begin(), rows.end());\n        return true;\n    }\n}\n\nbool make_daily_shelf_solution(int mode, int slackMode, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; d++) {\n        vector<TmpRow> rows;\n        if (!get_daily_rows(d, mode, rows)) return false;\n\n        int sumH = 0;\n        for (auto& row : rows) sumH += row.h;\n        if (sumH > W) return false;\n\n        int slack = W - sumH;\n        if (slack > 0) {\n            int idx = (int)rows.size() - 1;\n            if (slackMode == 1) {\n                int bestCnt = 1e9;\n                for (int i = 0; i < (int)rows.size(); i++) {\n                    int cnt = rows[i].r - rows[i].l - 1;\n                    if (cnt <= bestCnt) {\n                        bestCnt = cnt;\n                        idx = i;\n                    }\n                }\n            }\n            rows[idx].h += slack;\n        }\n\n        int y = 0;\n        for (auto& row : rows) {\n            int m = row.r - row.l;\n            vector<int> lb(m);\n            vector<double> weights(m);\n\n            for (int i = 0; i < m; i++) {\n                int k = row.l + i;\n                lb[i] = max(1, ceil_div_int(A[d][k], row.h));\n                weights[i] = max(1, A[d][k]);\n            }\n\n            vector<int> w = allocate_by_weights(lb, weights);\n            int x = 0;\n            for (int i = 0; i < m; i++) {\n                int k = row.l + i;\n                sol[d][k] = {y, x, y + row.h, x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            y += row.h;\n        }\n        if (y != W) return false;\n    }\n\n    return true;\n}\n\nvector<pair<int,int>> make_global_dp_partition(int type, int lambda) {\n    const long long BIG = (1LL << 60);\n    vector<long long> dp(N + 1, BIG);\n    vector<int> par(N + 1, -1);\n    dp[0] = 0;\n\n    for (int j = 1; j <= N; j++) {\n        for (int i = 0; i < j; i++) {\n            bool ok = true;\n            long long sumH = 0;\n            int maxH = 0;\n            for (int d = 0; d < D; d++) {\n                int h = dayHSeg[d][i][j];\n                if (h >= SEG_INF) {\n                    ok = false;\n                    break;\n                }\n                sumH += h;\n                maxH = max(maxH, h);\n            }\n            if (!ok || dp[i] >= BIG) continue;\n\n            long long segCost;\n            if (type == 0) segCost = sumH;\n            else if (type == 1) segCost = 1LL * maxH * D;\n            else segCost = sumH + 1LL * maxH * D / 2;\n\n            segCost += lambda;\n            long long nv = dp[i] + segCost;\n            if (nv < dp[j]) {\n                dp[j] = nv;\n                par[j] = i;\n            }\n        }\n    }\n\n    if (par[N] < 0) return {};\n\n    vector<pair<int,int>> g;\n    int cur = N;\n    while (cur > 0) {\n        int p = par[cur];\n        if (p < 0) return {};\n        g.push_back({p, cur});\n        cur = p;\n    }\n    reverse(g.begin(), g.end());\n    return g;\n}\n\nvector<pair<int,int>> make_equal_partition_groups(int R) {\n    R = clamp_int(R, 1, N);\n    vector<pair<int,int>> g;\n    int prev = 0;\n    for (int i = 0; i < R; i++) {\n        int en = (i == R - 1 ? N : (int)llround(1.0 * N * (i + 1) / R));\n        en = clamp_int(en, prev + 1, N - (R - i - 1));\n        g.push_back({prev, en});\n        prev = en;\n    }\n    return g;\n}\n\nvector<pair<int,int>> make_area_partition_groups(const vector<int>& base, int R) {\n    R = clamp_int(R, 1, N);\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> g;\n    int prev = 0;\n    for (int i = 0; i < R; i++) {\n        int en;\n        if (i == R - 1) {\n            en = N;\n        } else {\n            double target = pref[N] * (i + 1) / R;\n            en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            en = clamp_int(en, prev + 1, N - (R - i - 1));\n        }\n        g.push_back({prev, en});\n        prev = en;\n    }\n    return g;\n}\n\nvector<pair<int,int>> make_daily_partition_groups(int d, int mode) {\n    vector<TmpRow> rows;\n    if (!get_daily_rows(d, mode, rows)) return {};\n    vector<pair<int,int>> g;\n    for (auto& row : rows) g.push_back({row.l, row.r});\n    return g;\n}\n\nbool valid_partition_groups(const vector<pair<int,int>>& g) {\n    if (g.empty()) return false;\n    int cur = 0;\n    for (auto [l, r] : g) {\n        if (l != cur || l >= r || r > N) return false;\n        cur = r;\n    }\n    return cur == N;\n}\n\nstring partition_key(const vector<pair<int,int>>& g) {\n    string s;\n    for (auto [l, r] : g) {\n        s += to_string(l);\n        s += '-';\n        s += to_string(r);\n        s += ',';\n    }\n    return s;\n}\n\nbool build_fixed_variable_shelf_solution(\n    const vector<pair<int,int>>& groups,\n    vector<vector<Rect>>& sol,\n    bool overlap,\n    int targetType\n) {\n    if (!valid_partition_groups(groups)) return false;\n\n    int R = (int)groups.size();\n    vector<int> maxH(R, 0);\n    vector<double> avgH(R, 1.0), weightH(R, 1.0);\n\n    for (int ri = 0; ri < R; ri++) {\n        auto [l, r] = groups[ri];\n        long long sum = 0;\n        for (int d = 0; d < D; d++) {\n            int h = dayHSeg[d][l][r];\n            if (h >= SEG_INF) return false;\n            maxH[ri] = max(maxH[ri], h);\n            sum += h;\n        }\n        avgH[ri] = max(1.0, (double)sum / D);\n        weightH[ri] = max(1.0, avgH[ri] * max(1, r - l - 1));\n    }\n\n    for (int d = 0; d < D; d++) {\n        int sumL = 0;\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            sumL += dayHSeg[d][l][r];\n        }\n        if (sumL > W) return false;\n    }\n\n    int sumMax = accumulate(maxH.begin(), maxH.end(), 0);\n    vector<int> staticTarget;\n    if (sumMax <= W) {\n        staticTarget = allocate_by_weights(maxH, weightH);\n    } else {\n        vector<int> ones(R, 1);\n        staticTarget = allocate_by_weights(ones, avgH);\n    }\n\n    sol.assign(D, vector<Rect>(N));\n    vector<int> prevH;\n    vector<vector<int>> prevWidths(R);\n\n    for (int d = 0; d < D; d++) {\n        vector<int> lowerH(R);\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            lowerH[ri] = dayHSeg[d][l][r];\n        }\n\n        vector<int> h;\n        if (d == 0) {\n            h = project_near(staticTarget, lowerH);\n        } else {\n            if (overlap) h = choose_widths_overlap(prevH, lowerH, staticTarget);\n            else h = project_near(prevH, lowerH);\n        }\n\n        int y = 0;\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            int m = r - l;\n            vector<int> lb(m);\n            int sumLB = 0;\n            for (int i = 0; i < m; i++) {\n                int k = l + i;\n                lb[i] = max(1, ceil_div_int(A[d][k], h[ri]));\n                sumLB += lb[i];\n            }\n            if (sumLB > W) return false;\n\n            vector<int> targetW = make_target_widths(l, r, h[ri], targetType);\n            vector<int> ref = (d == 0 || prevWidths[ri].empty() ? targetW : prevWidths[ri]);\n            vector<int> w;\n            if (overlap) w = choose_widths_overlap(ref, lb, targetW);\n            else w = project_near(ref, lb);\n\n            int x = 0;\n            for (int i = 0; i < m; i++) {\n                int k = l + i;\n                sol[d][k] = {y, x, y + h[ri], x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            y += h[ri];\n            prevWidths[ri] = w;\n        }\n        if (y != W) return false;\n        prevH = h;\n    }\n\n    return true;\n}\n\nvoid run_daily_variable_shelf_candidates() {\n    vector<vector<Rect>> sol;\n\n    for (int mode = 0; mode <= 1; mode++) {\n        for (int slack = 0; slack <= 1; slack++) {\n            if (bestScore == 0) return;\n            if (make_daily_shelf_solution(mode, slack, sol)) consider_solution(sol);\n        }\n    }\n\n    if (bestScore == 0) return;\n\n    vector<vector<pair<int,int>>> parts;\n    set<string> seen;\n\n    auto addPart = [&](const vector<pair<int,int>>& g) {\n        if (!valid_partition_groups(g)) return;\n        string key = partition_key(g);\n        if (seen.insert(key).second) parts.push_back(g);\n    };\n\n    vector<int> lambdas = {0, 300, 1000, 3000, 10000};\n    for (int lam : lambdas) {\n        addPart(make_global_dp_partition(0, lam));\n        addPart(make_global_dp_partition(1, lam));\n    }\n\n    vector<int> Rs;\n    auto addR = [&](int r) {\n        r = clamp_int(r, 1, N);\n        if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n    };\n\n    int sq = max(1, (int)llround(sqrt((double)N)));\n    addR(sq);\n    addR(sq + 1);\n    addR(N / 4);\n    addR(N / 3);\n    addR(N / 2);\n    addR(2 * sq);\n\n    for (int r : Rs) {\n        addPart(make_equal_partition_groups(r));\n        addPart(make_area_partition_groups(meanDemand, r));\n        addPart(make_area_partition_groups(p90Demand, r));\n    }\n\n    addPart(make_daily_partition_groups(0, 1));\n    addPart(make_daily_partition_groups(D / 2, 1));\n    addPart(make_daily_partition_groups(D - 1, 1));\n\n    const double TL_NEW = 1.60;\n    int idx = 0;\n    for (auto& g : parts) {\n        if (bestScore == 0 || elapsed_sec() > TL_NEW) break;\n\n        if (build_fixed_variable_shelf_solution(g, sol, false, 1)) consider_solution(sol);\n        if (bestScore == 0) break;\n\n        if (idx < 7 && elapsed_sec() < TL_NEW) {\n            if (build_fixed_variable_shelf_solution(g, sol, true, 1)) consider_solution(sol);\n        }\n        idx++;\n    }\n}\n\n/* ---------- fixed-shelf DP ---------- */\n\nstruct ShelfRowChoice {\n    int l, r, h;\n    int targetType;\n    bool soft;\n};\n\nbool build_fixed_shelf_solution(const vector<ShelfRowChoice>& rows, vector<vector<Rect>>& sol, bool overlap) {\n    sol.assign(D, vector<Rect>(N));\n    int y = 0;\n\n    for (const auto& row : rows) {\n        if (y + row.h > W) return false;\n\n        vector<int> target = make_target_widths(row.l, row.r, row.h, row.targetType);\n        vector<int> prev;\n\n        for (int d = 0; d < D; d++) {\n            vector<int> ref = (d == 0 ? target : prev);\n            vector<int> lb;\n            make_day_lb(row.l, row.r, row.h, d, ref, row.soft, lb);\n\n            int sumLB = accumulate(lb.begin(), lb.end(), 0);\n            vector<int> w;\n            if (sumLB <= W) {\n                if (overlap) w = choose_widths_overlap(ref, lb, target);\n                else w = project_near(ref, lb);\n            } else {\n                w = shortage_widths(ref, row.l, row.r, row.h, d);\n            }\n\n            int x = 0;\n            for (int i = 0; i < row.r - row.l; i++) {\n                int k = row.l + i;\n                if (w[i] <= 0) return false;\n                sol[d][k] = {y, x, y + row.h, x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            prev = w;\n        }\n        y += row.h;\n    }\n\n    return y <= W;\n}\n\nvoid consider_static_horizontal_knapsack() {\n    const long long BIG = (1LL << 62);\n\n    vector<vector<long long>> cost(N, vector<long long>(W + 1, 0));\n    for (int k = 0; k < N; k++) {\n        for (int h = 1; h <= W; h++) {\n            long long c = 0;\n            for (int d = 0; d < D; d++) {\n                long long area = 1LL * h * W;\n                if (area < A[d][k]) c += 100LL * (A[d][k] - area);\n            }\n            cost[k][h] = c;\n        }\n    }\n\n    vector<long long> dp(W + 1, BIG), ndp(W + 1, BIG);\n    vector<vector<short>> par(N + 1, vector<short>(W + 1, -1));\n    dp[0] = 0;\n\n    for (int k = 0; k < N; k++) {\n        fill(ndp.begin(), ndp.end(), BIG);\n        int remainItems = N - k - 1;\n        for (int used = 0; used <= W; used++) {\n            if (dp[used] >= BIG / 2) continue;\n            int maxh = W - used - remainItems;\n            for (int h = 1; h <= maxh; h++) {\n                long long nv = dp[used] + cost[k][h];\n                int nu = used + h;\n                if (nv < ndp[nu]) {\n                    ndp[nu] = nv;\n                    par[k+1][nu] = (short)h;\n                }\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    long long best = BIG;\n    int bestUsed = -1;\n    for (int used = 0; used <= W; used++) {\n        if (dp[used] < best) {\n            best = dp[used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0) return;\n\n    vector<int> h(N);\n    int used = bestUsed;\n    for (int k = N; k >= 1; k--) {\n        int x = par[k][used];\n        if (x <= 0) return;\n        h[k-1] = x;\n        used -= x;\n    }\n\n    vector<Rect> one(N);\n    int y = 0;\n    for (int k = 0; k < N; k++) {\n        one[k] = {y, 0, y + h[k], W};\n        y += h[k];\n    }\n\n    vector<vector<Rect>> sol(D, one);\n    consider_solution(sol);\n}\n\nvoid run_fixed_shelf_dp() {\n    for (int l = 0; l <= N; l++) {\n        for (int r = 0; r <= N; r++) {\n            hMinSeg[l][r] = hStaticSeg[l][r] = SEG_INF;\n            segOptCnt[l][r] = 0;\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            bool ok = true;\n            int mx = 0;\n            for (int d = 0; d < D; d++) {\n                if (dayHSeg[d][l][r] >= SEG_INF) {\n                    ok = false;\n                    break;\n                }\n                mx = max(mx, dayHSeg[d][l][r]);\n            }\n            hMinSeg[l][r] = ok ? mx : SEG_INF;\n            hStaticSeg[l][r] = compute_hstatic_segment(l, r);\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            int hm = hMinSeg[l][r];\n            if (hm >= SEG_INF) continue;\n\n            vector<int> hs;\n            auto addH = [&](int h) {\n                if (h < 1 || h > W) return;\n                if (find(hs.begin(), hs.end(), h) == hs.end()) hs.push_back(h);\n            };\n\n            addH(hm);\n\n            int hsStatic = hStaticSeg[l][r];\n            if (hsStatic < SEG_INF) {\n                addH(hsStatic);\n                if (hsStatic - hm >= 2) addH((hm + hsStatic) / 2);\n            } else {\n                if (hm < W) addH((hm + W) / 2);\n            }\n\n            sort(hs.begin(), hs.end());\n            if ((int)hs.size() > MAX_SEG_OPT) hs.resize(MAX_SEG_OPT);\n\n            for (int h : hs) {\n                int idx = segOptCnt[l][r]++;\n                segOptH[l][r][idx] = h;\n\n                long long c;\n                int t;\n                bool s;\n                best_row_option(l, r, h, c, t, s);\n\n                segOptCost[l][r][idx] = c;\n                segOptTarget[l][r][idx] = t;\n                segOptSoft[l][r][idx] = s;\n            }\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, BIG));\n    vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> parUsed(N + 1, vector<short>(W + 1, -1));\n    vector<vector<signed char>> parOpt(N + 1, vector<signed char>(W + 1, -1));\n\n    dp[0][0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        for (int used = 0; used <= W; used++) {\n            if (dp[i][used] >= BIG / 2) continue;\n\n            for (int j = i + 1; j <= N; j++) {\n                for (int oi = 0; oi < segOptCnt[i][j]; oi++) {\n                    int h = segOptH[i][j][oi];\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    long long nv = dp[i][used] + segOptCost[i][j][oi];\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parUsed[j][nu] = (short)used;\n                        parOpt[j][nu] = (signed char)oi;\n                    }\n                }\n            }\n        }\n    }\n\n    long long best = BIG;\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 < 0) return;\n\n    vector<ShelfRowChoice> rows;\n    int curI = N, curH = bestH;\n    while (curI > 0) {\n        int pi = parI[curI][curH];\n        int pu = parUsed[curI][curH];\n        int oi = parOpt[curI][curH];\n        if (pi < 0 || pu < 0 || oi < 0) return;\n\n        rows.push_back({\n            pi,\n            curI,\n            segOptH[pi][curI][oi],\n            segOptTarget[pi][curI][oi],\n            segOptSoft[pi][curI][oi]\n        });\n\n        curI = pi;\n        curH = pu;\n    }\n    reverse(rows.begin(), rows.end());\n\n    vector<vector<Rect>> sol;\n    if (build_fixed_shelf_solution(rows, sol, false)) consider_solution(sol);\n    if (bestScore == 0) return;\n    if (build_fixed_shelf_solution(rows, sol, true)) consider_solution(sol);\n}\n\n/* ---------- old slicing candidate handling ---------- */\n\nconst double TL_CAND = 2.65;\nconst double TL_POST = 2.85;\n\nvoid process_tree(Tree t, const vector<int>& base, int level) {\n    if (elapsed_sec() > TL_CAND || bestScore == 0) return;\n\n    vector<int> target = scale_to_limit(base);\n    assign_targets(t, target);\n\n    vector<vector<Rect>> sol;\n\n    if (elapsed_sec() < TL_CAND && make_static_solution(t, target, false, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, globalMaxDemand, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_PREV, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 1 && elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_STATIC_ABS, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, target, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_solution(t, true, POLICY_PREV, sol)) {\n        consider_solution(sol);\n    }\n}\n\nvoid try_all_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto orig = bestSol;\n    for (int t = 0; t < D && elapsed_sec() < TL_POST; t++) {\n        vector<vector<Rect>> sol(D, orig[t]);\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n}\n\nvoid smooth_by_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto sol = bestSol;\n    long long curScore = evaluate_solution(sol);\n\n    auto local_cost = [&](int d, const vector<Rect>& cand) -> long long {\n        long long c = shortage_day(cand, d);\n        if (d > 0) c += transition_cost(sol[d-1], cand);\n        if (d + 1 < D) c += transition_cost(cand, sol[d+1]);\n        return c;\n    };\n\n    for (int pass = 0; pass < 5 && elapsed_sec() < TL_POST; pass++) {\n        bool improved = false;\n\n        for (int d = 0; d < D && elapsed_sec() < TL_POST; d++) {\n            long long old = local_cost(d, sol[d]);\n\n            if (d > 0) {\n                long long nw = local_cost(d, sol[d-1]);\n                if (nw < old) {\n                    sol[d] = sol[d-1];\n                    curScore += nw - old;\n                    old = nw;\n                    improved = true;\n                }\n            }\n\n            if (d + 1 < D) {\n                long long nw = local_cost(d, sol[d+1]);\n                if (nw < old) {\n                    sol[d] = sol[d+1];\n                    curScore += nw - old;\n                    old = nw;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    curScore = evaluate_solution(sol);\n    if (curScore < bestScore) {\n        bestScore = curScore;\n        bestSol = sol;\n    }\n}\n\n/* ---------- main ---------- */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int inputW;\n    cin >> inputW >> 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    globalMaxDemand.assign(N, 1);\n    meanDemand.assign(N, 1);\n    medDemand.assign(N, 1);\n    p75Demand.assign(N, 1);\n    p90Demand.assign(N, 1);\n\n    for (int k = 0; k < N; k++) {\n        long long s = 0;\n        vector<int> vals;\n        for (int d = 0; d < D; d++) {\n            s += A[d][k];\n            vals.push_back(A[d][k]);\n            globalMaxDemand[k] = max(globalMaxDemand[k], A[d][k]);\n        }\n        sort(vals.begin(), vals.end());\n        meanDemand[k] = max(1, (int)(s / D));\n        medDemand[k] = vals[D / 2];\n        p75Demand[k] = vals[min(D - 1, (int)llround(0.75 * (D - 1)))];\n        p90Demand[k] = vals[min(D - 1, (int)llround(0.90 * (D - 1)))];\n    }\n\n    bestSol = make_fallback();\n    bestScore = evaluate_solution(bestSol);\n\n    consider_static_horizontal_knapsack();\n\n    run_day_specific_slicing_dp();\n\n    if (bestScore != 0) {\n        precompute_day_segments();\n        run_daily_variable_shelf_candidates();\n    }\n\n    if (bestScore != 0) {\n        run_fixed_shelf_dp();\n    }\n\n    if (bestScore != 0) {\n        vector<vector<int>> bases;\n        bases.push_back(globalMaxDemand);\n        bases.push_back(p90Demand);\n        bases.push_back(p75Demand);\n        bases.push_back(meanDemand);\n        bases.push_back(medDemand);\n\n        vector<pair<int,int>> combos = {\n            {0, 0},\n            {2, 0},\n            {1, 0},\n            {0, 1},\n            {0, 2}\n        };\n\n        for (int bi = 0; bi < (int)bases.size(); bi++) {\n            for (int ci = 0; ci < (int)combos.size(); ci++) {\n                if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n\n                int splitMode = combos[ci].first;\n                int orientMode = combos[ci].second;\n                Tree t = build_aspect_tree(bases[bi], splitMode, orientMode);\n\n                int level = 1;\n                if (ci == 0 && bi <= 3) level = 2;\n                process_tree(t, bases[bi], level);\n            }\n            if (bestScore == 0) break;\n        }\n\n        vector<int> Rs;\n        auto addR = [&](int r) {\n            r = clamp_int(r, 1, N);\n            if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n        };\n\n        int sq = max(1, (int)llround(sqrt((double)N)));\n        addR(sq);\n        addR(sq + 1);\n        addR(sq - 1);\n        addR(N / 4);\n        addR(N / 3);\n        addR(N / 2);\n        addR(2 * sq);\n        addR(5);\n        addR(8);\n        addR(10);\n        addR(15);\n        addR(20);\n        addR(N);\n        addR(1);\n\n        vector<int> shelfBaseIds = {0, 1, 3, 2};\n        for (int bi : shelfBaseIds) {\n            for (int groupMode = 0; groupMode <= 1; groupMode++) {\n                for (int r : Rs) {\n                    if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n                    Tree t = build_shelf_tree(bases[bi], r, groupMode, 0);\n                    int level = (groupMode == 0 ? 1 : 0);\n                    process_tree(t, bases[bi], level);\n                }\n                if (bestScore == 0) break;\n            }\n            if (bestScore == 0) break;\n        }\n    }\n\n    try_all_copy();\n    smooth_by_copy();\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            const Rect& r = bestSol[d][k];\n            cout << r.y0 << ' ' << r.x0 << ' ' << r.y1 << ' ' << r.x1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int BN = 9;\nstatic const int AP = 7;\nstatic const int KMAX = 81;\nstatic const int MOD = 998244353;\nstatic const int MAX_MULTI = 5;\nstatic const int MAX_RUIN = 8;\n\nint N, M, K;\narray<int, KMAX> initBoard;\nlong long initScore = 0;\nint stampVal[20][9];\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\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} timer;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n} rng(123456789);\n\nstruct Action {\n    int m, p, q;\n    int anchor;\n    int idx[9];\n    int val[9];\n    uint64_t maskLo, maskHi;\n};\n\nstruct Option {\n    unsigned char cnt;\n    unsigned char s1, s2;\n    int val[9];\n};\n\nstruct MultiOption {\n    unsigned char cnt;\n    unsigned char st[MAX_MULTI];\n    int val[9];\n};\n\nstruct PairInfo {\n    unsigned short a, b;\n    unsigned char len;\n    unsigned char idx[18];\n    int val[18];\n};\n\nvector<Action> actions;\narray<array<int, 9>, 49> anchorCells;\nvector<int> cellCovers[81];\nvector<Option> options;\nvector<MultiOption> multiOpts[MAX_MULTI + 1];\nbool anchorOverlap[49][49];\nvector<PairInfo> overlapPairs;\n\ninline bool actionCoversCell(int aid, int cell) {\n    const Action& a = actions[aid];\n    if (cell < 64) return (a.maskLo >> cell) & 1ULL;\n    return (a.maskHi >> (cell - 64)) & 1ULL;\n}\n\ninline long long evalAdd(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalSub(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applyAdd(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applySub(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalPairInfo(const array<int, KMAX>& b, const PairInfo& pi) {\n    long long delta = 0;\n    for (int t = 0; t < pi.len; t++) {\n        int idx = pi.idx[t];\n        int old = b[idx];\n        int nv = old + pi.val[t];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalMultiAtAnchor(const array<int, KMAX>& b, int anc, const MultiOption& op) {\n    long long delta = 0;\n    const auto& cells = anchorCells[anc];\n    for (int k = 0; k < 9; k++) {\n        int old = b[cells[k]];\n        int nv = old + op.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\nvoid genMultiRec(int target, int start, vector<int>& chosen, array<int, 9>& vals) {\n    if ((int)chosen.size() == target) {\n        MultiOption op{};\n        op.cnt = (unsigned char)target;\n        for (int i = 0; i < MAX_MULTI; i++) op.st[i] = 0;\n        for (int i = 0; i < target; i++) op.st[i] = (unsigned char)chosen[i];\n        for (int k = 0; k < 9; k++) op.val[k] = vals[k];\n        multiOpts[target].push_back(op);\n        return;\n    }\n\n    for (int m = start; m < M; m++) {\n        auto oldVals = vals;\n        chosen.push_back(m);\n        for (int k = 0; k < 9; k++) {\n            int v = vals[k] + stampVal[m][k];\n            if (v >= MOD) v -= MOD;\n            vals[k] = v;\n        }\n        genMultiRec(target, m, chosen, vals);\n        chosen.pop_back();\n        vals = oldVals;\n    }\n}\n\nvoid precomputeMultiOptions() {\n    MultiOption zero{};\n    zero.cnt = 0;\n    for (int i = 0; i < MAX_MULTI; i++) zero.st[i] = 0;\n    for (int k = 0; k < 9; k++) zero.val[k] = 0;\n    multiOpts[0].push_back(zero);\n\n    for (int target = 1; target <= MAX_MULTI; target++) {\n        vector<int> chosen;\n        array<int, 9> vals{};\n        genMultiRec(target, 0, chosen, vals);\n    }\n}\n\nvoid precomputeOverlapPairs() {\n    overlapPairs.clear();\n    overlapPairs.reserve(170000);\n\n    int A = (int)actions.size();\n\n    for (int a = 0; a < A; a++) {\n        for (int b = a; b < A; b++) {\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) continue;\n\n            PairInfo pi{};\n            pi.a = (unsigned short)a;\n            pi.b = (unsigned short)b;\n            pi.len = 0;\n\n            auto addCell = [&](int idx, int val) {\n                for (int t = 0; t < pi.len; t++) {\n                    if (pi.idx[t] == idx) {\n                        int nv = pi.val[t] + val;\n                        if (nv >= MOD) nv -= MOD;\n                        pi.val[t] = nv;\n                        return;\n                    }\n                }\n                pi.idx[pi.len] = (unsigned char)idx;\n                pi.val[pi.len] = val;\n                pi.len++;\n            };\n\n            for (int k = 0; k < 9; k++) addCell(actions[a].idx[k], actions[a].val[k]);\n            for (int k = 0; k < 9; k++) addCell(actions[b].idx[k], actions[b].val[k]);\n\n            overlapPairs.push_back(pi);\n        }\n    }\n}\n\nvoid precompute() {\n    actions.reserve(49 * M);\n\n    for (int p = 0; p < AP; p++) {\n        for (int q = 0; q < AP; q++) {\n            int aid = p * AP + q;\n            int t = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    anchorCells[aid][t++] = (p + di) * BN + (q + dj);\n                }\n            }\n        }\n    }\n\n    for (int a = 0; a < 49; a++) {\n        int p1 = a / AP, q1 = a % AP;\n        for (int b = 0; b < 49; b++) {\n            int p2 = b / AP, q2 = b % AP;\n            anchorOverlap[a][b] = (abs(p1 - p2) <= 2 && abs(q1 - q2) <= 2);\n        }\n    }\n\n    for (int anc = 0; anc < 49; anc++) {\n        int p = anc / AP;\n        int q = anc % AP;\n        for (int m = 0; m < M; m++) {\n            Action a;\n            a.m = m;\n            a.p = p;\n            a.q = q;\n            a.anchor = anc;\n            a.maskLo = a.maskHi = 0;\n\n            for (int k = 0; k < 9; k++) {\n                int idx = anchorCells[anc][k];\n                a.idx[k] = idx;\n                a.val[k] = stampVal[m][k];\n                if (idx < 64) a.maskLo |= 1ULL << idx;\n                else a.maskHi |= 1ULL << (idx - 64);\n            }\n\n            actions.push_back(a);\n        }\n    }\n\n    for (int r = 0; r < BN; r++) {\n        for (int c = 0; c < BN; c++) {\n            int cell = r * BN + c;\n            for (int p = max(0, r - 2); p <= min(AP - 1, r); p++) {\n                for (int q = max(0, c - 2); q <= min(AP - 1, c); q++) {\n                    cellCovers[cell].push_back(p * AP + q);\n                }\n            }\n        }\n    }\n\n    Option none{};\n    none.cnt = 0;\n    none.s1 = none.s2 = 0;\n    for (int k = 0; k < 9; k++) none.val[k] = 0;\n    options.push_back(none);\n\n    for (int m = 0; m < M; m++) {\n        Option op{};\n        op.cnt = 1;\n        op.s1 = m;\n        op.s2 = 0;\n        for (int k = 0; k < 9; k++) op.val[k] = stampVal[m][k];\n        options.push_back(op);\n    }\n\n    for (int a = 0; a < M; a++) {\n        for (int b = a; b < M; b++) {\n            Option op{};\n            op.cnt = 2;\n            op.s1 = a;\n            op.s2 = b;\n            for (int k = 0; k < 9; k++) {\n                int v = stampVal[a][k] + stampVal[b][k];\n                if (v >= MOD) v -= MOD;\n                op.val[k] = v;\n            }\n            options.push_back(op);\n        }\n    }\n\n    precomputeMultiOptions();\n    precomputeOverlapPairs();\n}\n\nstruct Solution {\n    array<int, KMAX> board;\n    array<int, KMAX> slot;\n    long long score;\n};\n\nvoid rebuild(Solution& sol) {\n    sol.board = initBoard;\n    sol.score = initScore;\n    for (int i = 0; i < K; i++) {\n        if (sol.slot[i] >= 0) {\n            sol.score += applyAdd(sol.board, sol.slot[i]);\n        }\n    }\n}\n\nSolution makeSolutionFromOps(const vector<int>& ops) {\n    Solution sol;\n    sol.slot.fill(-1);\n    int L = min((int)ops.size(), K);\n    for (int i = 0; i < L; i++) sol.slot[i] = ops[i];\n    rebuild(sol);\n    return sol;\n}\n\nSolution greedySolution() {\n    Solution sol;\n    sol.board = initBoard;\n    sol.slot.fill(-1);\n    sol.score = initScore;\n\n    for (int step = 0; step < K; step++) {\n        long long bestDelta = 0;\n        int best = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long d = evalAdd(sol.board, aid);\n            if (d > bestDelta) {\n                bestDelta = d;\n                best = aid;\n            }\n        }\n\n        if (best == -1) break;\n\n        sol.slot[step] = best;\n        sol.score += applyAdd(sol.board, best);\n    }\n\n    return sol;\n}\n\nvoid coordinateDescent(Solution& sol, int maxSweeps, double timeLimit) {\n    array<int, KMAX> ord;\n    for (int i = 0; i < K; i++) ord[i] = i;\n\n    for (int sweep = 0; sweep < maxSweeps; sweep++) {\n        if (timer.elapsed() > timeLimit) break;\n\n        for (int i = K - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int oi = 0; oi < K; oi++) {\n            if ((oi & 15) == 0 && timer.elapsed() > timeLimit) return;\n\n            int pos = ord[oi];\n            int old = sol.slot[pos];\n            long long oldScore = sol.score;\n\n            if (old >= 0) {\n                sol.score += applySub(sol.board, old);\n            }\n\n            long long base = sol.score;\n            int best = old;\n            long long bestScore = oldScore;\n\n            if (base > bestScore) {\n                bestScore = base;\n                best = -1;\n            }\n\n            for (int aid = 0; aid < (int)actions.size(); aid++) {\n                long long cand = base + evalAdd(sol.board, aid);\n                if (cand > bestScore) {\n                    bestScore = cand;\n                    best = aid;\n                }\n            }\n\n            sol.score = base;\n\n            if (best >= 0) {\n                sol.score += applyAdd(sol.board, best);\n            }\n\n            sol.slot[pos] = best;\n\n            if (sol.score > oldScore) improved = true;\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid anchorGroupOptimize(Solution& sol, int maxPasses, double timeLimit) {\n    for (int pass = 0; pass < maxPasses; pass++) {\n        bool improved = false;\n\n        for (int ii = 0; ii < 49; ii++) {\n            if (timer.elapsed() > timeLimit) return;\n\n            int anc = (pass & 1) ? (48 - ii) : ii;\n\n            vector<int> slots;\n            for (int i = 0; i < K; i++) {\n                int a = sol.slot[i];\n                if (a >= 0 && actions[a].anchor == anc) slots.push_back(i);\n            }\n\n            int c = (int)slots.size();\n            if (c <= 1 || c > MAX_MULTI) continue;\n\n            vector<int> oldActs(c);\n            long long oldScore = sol.score;\n\n            for (int t = 0; t < c; t++) {\n                oldActs[t] = sol.slot[slots[t]];\n                sol.score += applySub(sol.board, oldActs[t]);\n                sol.slot[slots[t]] = -1;\n            }\n\n            long long base = sol.score;\n            long long bestScore = oldScore;\n            int bestCnt = -1;\n            int bestIdx = -1;\n\n            for (int cnt = 0; cnt <= c; cnt++) {\n                const auto& vec = multiOpts[cnt];\n                for (int oi = 0; oi < (int)vec.size(); oi++) {\n                    long long cand = base + evalMultiAtAnchor(sol.board, anc, vec[oi]);\n                    if (cand > bestScore) {\n                        bestScore = cand;\n                        bestCnt = cnt;\n                        bestIdx = oi;\n                    }\n                }\n            }\n\n            sol.score = base;\n\n            if (bestCnt >= 0) {\n                const MultiOption& op = multiOpts[bestCnt][bestIdx];\n                for (int t = 0; t < bestCnt; t++) {\n                    int aid = anc * M + (int)op.st[t];\n                    sol.slot[slots[t]] = aid;\n                    sol.score += applyAdd(sol.board, aid);\n                }\n                improved = true;\n            } else {\n                for (int t = 0; t < c; t++) {\n                    sol.slot[slots[t]] = oldActs[t];\n                    sol.score += applyAdd(sol.board, oldActs[t]);\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nlong long orderCost(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    int cnt[49] = {};\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        cnt[br]++;\n    }\n\n    int maxc = 0;\n    int sumsq = 0;\n    int zero = 0;\n\n    for (int i = 0; i < 49; i++) {\n        maxc = max(maxc, cnt[i]);\n        sumsq += cnt[i] * cnt[i];\n        if (cnt[i] == 0) zero++;\n    }\n\n    return (long long)maxc * 1000000LL + (long long)sumsq * 1000LL + zero;\n}\n\nvector<int> findBalancedOrder() {\n    vector<int> base(49);\n    iota(base.begin(), base.end(), 0);\n\n    vector<int> best = base;\n    long long bestCost = orderCost(best);\n\n    const int REPS = 10;\n    const int ITERS = 1300;\n\n    for (int rep = 0; rep < REPS; rep++) {\n        vector<int> perm = base;\n\n        for (int i = 48; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(perm[i], perm[j]);\n        }\n\n        long long cur = orderCost(perm);\n\n        for (int it = 0; it < ITERS; it++) {\n            int a = rng.nextInt(49);\n            int b = rng.nextInt(49);\n            if (a == b) continue;\n\n            swap(perm[a], perm[b]);\n            long long nc = orderCost(perm);\n\n            if (nc <= cur) {\n                cur = nc;\n            } else {\n                swap(perm[a], perm[b]);\n            }\n        }\n\n        if (cur < bestCost) {\n            bestCost = cur;\n            best = perm;\n        }\n    }\n\n    return best;\n}\n\nvector<vector<int>> computeFinalCells(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    vector<vector<int>> finalCells(49);\n\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        finalCells[br].push_back(cell);\n    }\n\n    return finalCells;\n}\n\nstruct BeamState {\n    array<int, KMAX> cell;\n    long long fin;\n    long long total;\n    long long key;\n    int parent;\n    short opt;\n    unsigned char used;\n};\n\nvector<int> beamSearch(const vector<int>& order, int perWidth, long long finalWeight) {\n    vector<vector<int>> finalCells = computeFinalCells(order);\n\n    vector<vector<BeamState>> layers;\n    layers.reserve(50);\n\n    BeamState init{};\n    init.cell = initBoard;\n    init.fin = 0;\n    init.total = initScore;\n    init.key = initScore;\n    init.parent = -1;\n    init.opt = -1;\n    init.used = 0;\n\n    layers.push_back(vector<BeamState>{init});\n\n    vector<vector<BeamState>> buckets(K + 1);\n    int reserveEach = perWidth * (int)options.size() + 8;\n    for (auto& b : buckets) b.reserve(reserveEach);\n\n    auto cmpState = [](const BeamState& a, const BeamState& b) {\n        if (a.key != b.key) return a.key > b.key;\n        if (a.fin != b.fin) return a.fin > b.fin;\n        return a.total > b.total;\n    };\n\n    for (int step = 0; step < 49; step++) {\n        for (auto& b : buckets) b.clear();\n\n        const vector<BeamState>& cur = layers.back();\n        int anc = order[step];\n        const auto& cells = anchorCells[anc];\n        const vector<int>& fins = finalCells[step];\n\n        for (int si = 0; si < (int)cur.size(); si++) {\n            const BeamState& st = cur[si];\n\n            for (int oid = 0; oid < (int)options.size(); oid++) {\n                const Option& op = options[oid];\n                int nu = (int)st.used + (int)op.cnt;\n                if (nu > K) continue;\n\n                BeamState ns;\n                ns.cell = st.cell;\n                ns.fin = st.fin;\n                ns.total = st.total;\n                ns.parent = si;\n                ns.opt = (short)oid;\n                ns.used = (unsigned char)nu;\n\n                if (op.cnt) {\n                    for (int k = 0; k < 9; k++) {\n                        int idx = cells[k];\n                        int old = ns.cell[idx];\n                        int nv = old + op.val[k];\n                        if (nv >= MOD) nv -= MOD;\n                        ns.cell[idx] = nv;\n                        ns.total += (long long)nv - old;\n                    }\n                }\n\n                for (int idx : fins) {\n                    ns.fin += ns.cell[idx];\n                }\n\n                ns.key = ns.fin * finalWeight + (ns.total - ns.fin);\n                buckets[nu].push_back(std::move(ns));\n            }\n        }\n\n        vector<BeamState> next;\n        next.reserve((K + 1) * perWidth);\n\n        for (int u = 0; u <= K; u++) {\n            auto& v = buckets[u];\n            if ((int)v.size() > perWidth) {\n                nth_element(v.begin(), v.begin() + perWidth, v.end(), cmpState);\n                v.resize(perWidth);\n            }\n            for (auto& s : v) next.push_back(std::move(s));\n        }\n\n        layers.push_back(std::move(next));\n    }\n\n    const vector<BeamState>& last = layers.back();\n    int bestIdx = 0;\n    for (int i = 1; i < (int)last.size(); i++) {\n        if (last[i].fin > last[bestIdx].fin) bestIdx = i;\n    }\n\n    vector<int> optAt(49);\n    int idx = bestIdx;\n\n    for (int step = 48; step >= 0; step--) {\n        const BeamState& st = layers[step + 1][idx];\n        optAt[step] = st.opt;\n        idx = st.parent;\n    }\n\n    vector<int> ops;\n    ops.reserve(K);\n\n    for (int step = 0; step < 49; step++) {\n        int anc = order[step];\n        const Option& op = options[optAt[step]];\n\n        if (op.cnt >= 1) ops.push_back(anc * M + (int)op.s1);\n        if (op.cnt >= 2) ops.push_back(anc * M + (int)op.s2);\n    }\n\n    if ((int)ops.size() > K) ops.resize(K);\n    return ops;\n}\n\nbool optimizePairApprox(Solution& sol, int i, int j, int topC) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    long long base = sol.score;\n\n    vector<pair<long long, int>> all;\n    all.reserve(actions.size());\n\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        all.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    auto cmpPair = [](const pair<long long, int>& a, const pair<long long, int>& b) {\n        return a.first > b.first;\n    };\n\n    if ((int)all.size() > topC) {\n        nth_element(all.begin(), all.begin() + topC, all.end(), cmpPair);\n        all.resize(topC);\n    }\n\n    vector<pair<long long, int>> firsts = all;\n    firsts.push_back({base, -1});\n\n    for (int t = 0; t < 5; t++) {\n        int aid = rng.nextInt((int)actions.size());\n        firsts.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    long long bestScore = oldScore;\n    int best1 = old1;\n    int best2 = old2;\n\n    for (auto [dummyScore, f] : firsts) {\n        long long d1 = 0;\n        if (f >= 0) d1 = applyAdd(sol.board, f);\n        long long sc1 = base + d1;\n\n        long long localBest = sc1;\n        int gbest = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long cand = sc1 + evalAdd(sol.board, aid);\n            if (cand > localBest) {\n                localBest = cand;\n                gbest = aid;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best1 = f;\n            best2 = gbest;\n        }\n\n        if (f >= 0) applySub(sol.board, f);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        sol.slot[i] = best1;\n        sol.slot[j] = best2;\n\n        if (best1 >= 0) sol.score += applyAdd(sol.board, best1);\n        if (best2 >= 0) sol.score += applyAdd(sol.board, best2);\n\n        return true;\n    } else {\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n\n        return false;\n    }\n}\n\nvoid pairSearchApproxAdaptive(Solution& sol, double timeLimit) {\n    int attempts = 0;\n    int fail = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        int i, j;\n\n        if ((attempts & 7) == 0) {\n            vector<int> none;\n            for (int t = 0; t < K; t++) {\n                if (sol.slot[t] == -1) none.push_back(t);\n            }\n\n            if ((int)none.size() >= 2) {\n                int a = rng.nextInt((int)none.size());\n                int b = rng.nextInt((int)none.size() - 1);\n                if (b >= a) b++;\n                i = none[a];\n                j = none[b];\n            } else {\n                i = rng.nextInt(K);\n                do {\n                    j = rng.nextInt(K);\n                } while (j == i);\n            }\n        } else {\n            i = rng.nextInt(K);\n            do {\n                j = rng.nextInt(K);\n            } while (j == i);\n        }\n\n        attempts++;\n\n        if (optimizePairApprox(sol, i, j, 22)) {\n            coordinateDescent(sol, 4, timeLimit);\n            fail = 0;\n        } else {\n            fail++;\n        }\n\n        if (timer.elapsed() > 1.82 && fail > 70) break;\n    }\n}\n\nbool optimizePairExact(Solution& sol, int i, int j) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    sol.slot[i] = sol.slot[j] = -1;\n\n    long long base = sol.score;\n    long long oldDelta = oldScore - base;\n    long long bestDelta = oldDelta;\n    int bestA = old1;\n    int bestB = old2;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n\n        if (d[a] > bestDelta) {\n            bestDelta = d[a];\n            bestA = a;\n            bestB = -1;\n        }\n    }\n\n    if (0 > bestDelta) {\n        bestDelta = 0;\n        bestA = bestB = -1;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    for (int ia = 0; ia < A; ia++) {\n        int a = ord[ia];\n        if (d[a] + d[ord[0]] <= bestDelta) break;\n\n        for (int ib = 0; ib < A; ib++) {\n            int b = ord[ib];\n            long long ub = d[a] + d[b];\n            if (ub <= bestDelta) break;\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                bestDelta = ub;\n                bestA = a;\n                bestB = b;\n                break;\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        if (delta > bestDelta) {\n            bestDelta = delta;\n            bestA = pi.a;\n            bestB = pi.b;\n        }\n    }\n\n    sol.score = base;\n\n    if (bestDelta > oldDelta) {\n        sol.slot[i] = bestA;\n        sol.slot[j] = bestB;\n\n        if (bestA >= 0) sol.score += applyAdd(sol.board, bestA);\n        if (bestB >= 0) sol.score += applyAdd(sol.board, bestB);\n\n        return true;\n    } else {\n        sol.slot[i] = old1;\n        sol.slot[j] = old2;\n\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n\n        return false;\n    }\n}\n\nvoid exactPairSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 18);\n        vector<pair<int, int>> pairs;\n        pairs.reserve(R * R);\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                pairs.push_back({loss[a].second, loss[b].second});\n            }\n        }\n\n        for (int i = (int)pairs.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n        int maxTries = stagnant == 0 ? 38 : 26;\n\n        for (auto [a, b] : pairs) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizePairExact(sol, a, b)) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= maxTries) break;\n        }\n\n        if (!improved) {\n            int randomTries = 14;\n\n            for (int t = 0; t < randomTries && timer.elapsed() < timeLimit; t++) {\n                int a, b;\n\n                if (rng.nextInt(100) < 75) {\n                    a = loss[rng.nextInt(R)].second;\n                } else {\n                    a = rng.nextInt(K);\n                }\n\n                do {\n                    if (rng.nextInt(100) < 75) {\n                        b = loss[rng.nextInt(R)].second;\n                    } else {\n                        b = rng.nextInt(K);\n                    }\n                } while (a == b);\n\n                if (optimizePairExact(sol, a, b)) {\n                    coordinateDescent(sol, 3, timeLimit);\n                    anchorGroupOptimize(sol, 1, timeLimit);\n                    improved = true;\n                    break;\n                }\n            }\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 3) break;\n        }\n    }\n}\n\nstruct PairCand {\n    long long delta;\n    int a, b;\n};\n\nstruct PairCandMinCmp {\n    bool operator()(const PairCand& x, const PairCand& y) const {\n        return x.delta > y.delta;\n    }\n};\n\nbool optimizeTripleApprox(Solution& sol, int i, int j, int k) {\n    if (i == j || i == k || j == k) return false;\n\n    int old[3] = {sol.slot[i], sol.slot[j], sol.slot[k]};\n    int pos[3] = {i, j, k};\n    long long oldScore = sol.score;\n\n    for (int t = 0; t < 3; t++) {\n        if (old[t] >= 0) sol.score += applySub(sol.board, old[t]);\n        sol.slot[pos[t]] = -1;\n    }\n\n    long long base = sol.score;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    const int CAND = 80;\n    priority_queue<PairCand, vector<PairCand>, PairCandMinCmp> pq;\n\n    auto pushCand = [&](long long delta, int a, int b) {\n        PairCand pc{delta, a, b};\n\n        if ((int)pq.size() < CAND) {\n            pq.push(pc);\n        } else if (delta > pq.top().delta) {\n            pq.pop();\n            pq.push(pc);\n        }\n    };\n\n    pushCand(0, -1, -1);\n\n    int singleT = min(A, 120);\n    for (int t = 0; t < singleT; t++) {\n        int a = ord[t];\n        pushCand(d[a], a, -1);\n    }\n\n    int topT = min(A, 80);\n    for (int x = 0; x < topT; x++) {\n        int a = ord[x];\n        for (int y = x + 1; y < topT; y++) {\n            int b = ord[y];\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                pushCand(d[a] + d[b], a, b);\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        pushCand(delta, pi.a, pi.b);\n    }\n\n    vector<PairCand> cands;\n    while (!pq.empty()) {\n        cands.push_back(pq.top());\n        pq.pop();\n    }\n\n    long long bestScore = oldScore;\n    int best[3] = {old[0], old[1], old[2]};\n\n    for (const PairCand& pc : cands) {\n        long long curScore = base;\n\n        if (pc.a >= 0) curScore += applyAdd(sol.board, pc.a);\n        if (pc.b >= 0) curScore += applyAdd(sol.board, pc.b);\n\n        int third = -1;\n        long long localBest = curScore;\n\n        for (int a = 0; a < A; a++) {\n            long long cand = curScore + evalAdd(sol.board, a);\n            if (cand > localBest) {\n                localBest = cand;\n                third = a;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best[0] = pc.a;\n            best[1] = pc.b;\n            best[2] = third;\n        }\n\n        if (pc.b >= 0) applySub(sol.board, pc.b);\n        if (pc.a >= 0) applySub(sol.board, pc.a);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = best[t];\n            if (best[t] >= 0) sol.score += applyAdd(sol.board, best[t]);\n        }\n        return true;\n    } else {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = old[t];\n            if (old[t] >= 0) sol.score += applyAdd(sol.board, old[t]);\n        }\n        return false;\n    }\n}\n\nvoid tripleSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 12);\n        vector<array<int, 3>> triples;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                for (int c = b + 1; c < R; c++) {\n                    triples.push_back({loss[a].second, loss[b].second, loss[c].second});\n                }\n            }\n        }\n\n        for (int i = (int)triples.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(triples[i], triples[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n\n        for (auto tr : triples) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizeTripleApprox(sol, tr[0], tr[1], tr[2])) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= 7) break;\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 2) break;\n        }\n    }\n}\n\nvector<int> selectRemovalSlots(const Solution& sol, int r, int mode) {\n    vector<pair<long long, int>> loss;\n    loss.reserve(K);\n\n    for (int i = 0; i < K; i++) {\n        long long ls = 0;\n        if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n        loss.push_back({ls, i});\n    }\n\n    sort(loss.begin(), loss.end());\n\n    array<char, KMAX> used{};\n    vector<int> slots;\n    slots.reserve(r);\n\n    auto addSlot = [&](int s) {\n        if ((int)slots.size() >= r) return;\n        if (!used[s]) {\n            used[s] = 1;\n            slots.push_back(s);\n        }\n    };\n\n    if (mode == 1) {\n        vector<int> cells(81);\n        iota(cells.begin(), cells.end(), 0);\n        sort(cells.begin(), cells.end(), [&](int x, int y) {\n            return sol.board[x] < sol.board[y];\n        });\n\n        int target = cells[rng.nextInt(20)];\n\n        vector<pair<long long, int>> pool;\n        for (int i = 0; i < K; i++) {\n            int a = sol.slot[i];\n            if (a >= 0 && actionCoversCell(a, target)) {\n                long long ls = -evalSub(sol.board, a);\n                pool.push_back({ls, i});\n            }\n        }\n\n        sort(pool.begin(), pool.end());\n\n        int lim = min((int)pool.size(), max(6, r * 3));\n        int guard = 0;\n\n        while ((int)slots.size() < r && lim > 0 && guard < 100) {\n            int id = rng.nextInt(lim);\n            addSlot(pool[id].second);\n            guard++;\n        }\n    }\n\n    int lim = min(K, max(10, r * 4));\n    int guard = 0;\n\n    while ((int)slots.size() < r && guard < 200) {\n        int id = rng.nextInt(lim);\n        addSlot(loss[id].second);\n        guard++;\n    }\n\n    for (auto [ls, s] : loss) {\n        if ((int)slots.size() >= r) break;\n        addSlot(s);\n    }\n\n    return slots;\n}\n\nvoid selectTopActionsForBoard(const array<int, KMAX>& board, int topC, vector<int>& cand) {\n    static long long bd[40];\n    static int bid[40];\n\n    int sz = 0;\n\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        long long d = evalAdd(board, aid);\n\n        if (sz < topC) {\n            int pos = sz++;\n            while (pos > 0 && d > bd[pos - 1]) {\n                bd[pos] = bd[pos - 1];\n                bid[pos] = bid[pos - 1];\n                pos--;\n            }\n            bd[pos] = d;\n            bid[pos] = aid;\n        } else if (d > bd[topC - 1]) {\n            int pos = topC - 1;\n            while (pos > 0 && d > bd[pos - 1]) {\n                bd[pos] = bd[pos - 1];\n                bid[pos] = bid[pos - 1];\n                pos--;\n            }\n            bd[pos] = d;\n            bid[pos] = aid;\n        }\n    }\n\n    cand.clear();\n    cand.reserve(sz + 1);\n\n    for (int i = 0; i < sz; i++) cand.push_back(bid[i]);\n}\n\nstruct RefillState {\n    array<int, KMAX> board;\n    long long score;\n    array<int, MAX_RUIN> ops;\n};\n\nvoid beamRefill(Solution& sol, const vector<int>& slots, int width, int topC, double timeLimit) {\n    int r = (int)slots.size();\n    if (r <= 0) return;\n    if (r > MAX_RUIN) return;\n\n    vector<RefillState> cur, nxt;\n    cur.reserve(width + 2);\n    nxt.reserve(width * (topC + 1) + 4);\n\n    RefillState init{};\n    init.board = sol.board;\n    init.score = sol.score;\n    init.ops.fill(-1);\n    cur.push_back(init);\n\n    auto cmp = [](const RefillState& a, const RefillState& b) {\n        return a.score > b.score;\n    };\n\n    vector<int> cand;\n\n    for (int depth = 0; depth < r; depth++) {\n        if (timer.elapsed() > timeLimit) return;\n\n        nxt.clear();\n\n        for (const auto& st : cur) {\n            selectTopActionsForBoard(st.board, topC, cand);\n            cand.push_back(-1);\n\n            for (int aid : cand) {\n                RefillState ns = st;\n                ns.ops[depth] = aid;\n\n                if (aid >= 0) {\n                    ns.score += applyAdd(ns.board, aid);\n                }\n\n                nxt.push_back(std::move(ns));\n            }\n        }\n\n        if ((int)nxt.size() > width) {\n            nth_element(nxt.begin(), nxt.begin() + width, nxt.end(), cmp);\n            nxt.resize(width);\n        }\n\n        cur.swap(nxt);\n    }\n\n    int bi = 0;\n    for (int i = 1; i < (int)cur.size(); i++) {\n        if (cur[i].score > cur[bi].score) bi = i;\n    }\n\n    sol.board = cur[bi].board;\n    sol.score = cur[bi].score;\n\n    for (int i = 0; i < r; i++) {\n        sol.slot[slots[i]] = cur[bi].ops[i];\n    }\n}\n\nvoid lnsSearch(Solution& sol, double timeLimit) {\n    int iter = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        int r;\n        if ((iter % 7) == 0) r = 6 + rng.nextInt(2);\n        else r = 3 + rng.nextInt(4);\n\n        r = min(r, MAX_RUIN);\n\n        int mode = ((iter % 3) == 0) ? 1 : 0;\n        vector<int> slots = selectRemovalSlots(sol, r, mode);\n\n        Solution cand = sol;\n\n        for (int s : slots) {\n            int a = cand.slot[s];\n            if (a >= 0) {\n                cand.score += applySub(cand.board, a);\n            }\n            cand.slot[s] = -1;\n        }\n\n        int width = (r <= 4 ? 7 : 5);\n        int topC = (r <= 4 ? 24 : 18);\n\n        beamRefill(cand, slots, width, topC, timeLimit);\n\n        coordinateDescent(cand, 2, timeLimit);\n\n        if ((iter & 3) == 0) {\n            anchorGroupOptimize(cand, 1, timeLimit);\n        }\n\n        if (cand.score > sol.score) {\n            sol = cand;\n            coordinateDescent(sol, 4, timeLimit);\n            anchorGroupOptimize(sol, 1, timeLimit);\n        }\n\n        iter++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> K;\n\n    for (int i = 0; i < BN; i++) {\n        for (int j = 0; j < BN; j++) {\n            int x;\n            cin >> x;\n            initBoard[i * BN + j] = x;\n            initScore += x;\n        }\n    }\n\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                cin >> stampVal[m][i * 3 + j];\n            }\n        }\n    }\n\n    timer.reset();\n\n    precompute();\n\n    Solution best = greedySolution();\n\n    // Keep the strong original construction schedule.\n    coordinateDescent(best, 25, 1.86);\n\n    vector<int> order = findBalancedOrder();\n\n    if (timer.elapsed() < 1.20) {\n        vector<int> ops = beamSearch(order, 6, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 18, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    vector<int> revOrder = order;\n    reverse(revOrder.begin(), revOrder.end());\n\n    if (timer.elapsed() < 1.45) {\n        vector<int> ops = beamSearch(revOrder, 4, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 14, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    // Original-style pair search, but with an adaptive early stop to leave time.\n    pairSearchApproxAdaptive(best, 1.86);\n\n    // Additional post-improvement phases.\n    anchorGroupOptimize(best, 2, 1.875);\n    coordinateDescent(best, 5, 1.885);\n\n    exactPairSearch(best, 1.910);\n    tripleSearch(best, 1.925);\n    lnsSearch(best, 1.940);\n\n    anchorGroupOptimize(best, 1, 1.945);\n    coordinateDescent(best, 2, 1.950);\n\n    vector<int> out;\n    for (int i = 0; i < K; i++) {\n        if (best.slot[i] >= 0) out.push_back(best.slot[i]);\n    }\n\n    cout << out.size() << '\\n';\n\n    for (int id : out) {\n        const Action& a = actions[id];\n        cout << a.m << ' ' << a.p << ' ' << a.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 TOT = 25;\nstatic constexpr int BASE = 6;\nstatic constexpr int PBASE = 7776;\nstatic constexpr int TOTAL_STATES = PBASE * PBASE;\nstatic constexpr int INF = 1e9;\n\nint A[N][N];\nint srcOf[TOT], idxOf[TOT];\nint pow6_[N + 1];\n\nuint8_t dig[PBASE][N];\nuint8_t sumCode[PBASE];\nuint8_t exhCode[PBASE];\n\nvector<signed char> memoBlock;\n\ninline int manhattan(int r1, int c1, int r2, int c2) {\n    return abs(r1 - r2) + abs(c1 - c2);\n}\n\nstruct TransCode {\n    int npcode, nqcode, code, k;\n};\n\nbool makeTransCodes(int pcode, int qcode, int d, TransCode &tr) {\n    int qd = dig[qcode][d];\n    if (qd >= N) return false;\n\n    int x = N * d + qd;\n    int s = srcOf[x];\n    int idx = idxOf[x];\n    int ps = dig[pcode][s];\n\n    int nq = qcode + pow6_[d];\n    int np = pcode;\n    int k = 0;\n\n    if (idx < ps) {\n        k = 0;\n    } else {\n        k = idx - ps;\n        int buffer = (int)sumCode[pcode] - (int)sumCode[qcode];\n        int capacity = 15 + (int)exhCode[pcode];\n        if (buffer + k > capacity) return false;\n        np = pcode + (idx + 1 - ps) * pow6_[s];\n    }\n\n    tr = {np, nq, np * PBASE + nq, k};\n    return true;\n}\n\nint dfsBlock(int code) {\n    signed char m = memoBlock[code];\n    if (m != -1) {\n        if (m >= 100) return INF;\n        return (int)m;\n    }\n\n    int pcode = code / PBASE;\n    int qcode = code % PBASE;\n\n    if (sumCode[qcode] == TOT) {\n        memoBlock[code] = 0;\n        return 0;\n    }\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(pcode, qcode, d, tr)) continue;\n        int sub = dfsBlock(tr.code);\n        if (sub >= INF) continue;\n        best = min(best, tr.k + sub);\n    }\n\n    memoBlock[code] = (best >= INF ? 100 : (signed char)best);\n    return best;\n}\n\nstruct RowOption {\n    vector<int> cols;\n    string act;\n    int len = 0;\n    int finalCol = 0;\n};\n\nvector<RowOption> smallOpts, bigOpts;\n\nRowOption makeRowOption(const vector<int> &cols) {\n    RowOption ro;\n    ro.cols = cols;\n\n    int pos = 0;\n    for (int t = 0; t < (int)cols.size(); t++) {\n        if (t > 0) {\n            while (pos > 0) {\n                ro.act.push_back('L');\n                pos--;\n            }\n        }\n\n        ro.act.push_back('P');\n\n        while (pos < cols[t]) {\n            ro.act.push_back('R');\n            pos++;\n        }\n\n        ro.act.push_back('Q');\n    }\n\n    ro.len = (int)ro.act.size();\n    ro.finalCol = cols.empty() ? 0 : cols.back();\n    return ro;\n}\n\nvoid initRowOptions() {\n    vector<vector<int>> smallDefs = {\n        {},\n        {1},\n        {2},\n        {3},\n        {2, 1},\n        {3, 1},\n        {3, 2},\n        {3, 2, 1},\n    };\n    for (auto &v : smallDefs) smallOpts.push_back(makeRowOption(v));\n\n    bigOpts.push_back(makeRowOption({}));\n    vector<int> cur;\n    bool used[4] = {};\n    function<void(int, int)> dfs = [&](int dep, int len) {\n        if (dep == len) {\n            bigOpts.push_back(makeRowOption(cur));\n            return;\n        }\n        for (int c = 1; c <= 3; c++) {\n            if (used[c]) continue;\n            used[c] = true;\n            cur.push_back(c);\n            dfs(dep + 1, len);\n            cur.pop_back();\n            used[c] = false;\n        }\n    };\n\n    for (int len = 1; len <= 3; len++) {\n        memset(used, 0, sizeof(used));\n        cur.clear();\n        dfs(0, len);\n    }\n}\n\nstring directScript(int row, int d) {\n    string s;\n    s.push_back('P');\n    s.append(4, 'R');\n    if (row < d) s.append(d - row, 'D');\n    else s.append(row - d, 'U');\n    s.push_back('Q');\n    return s;\n}\n\nstring returnScript(int d, int row) {\n    string s;\n    if (d < row) s.append(row - d, 'D');\n    else s.append(d - row, 'U');\n    s.append(4, 'L');\n    return s;\n}\n\nstruct Pattern {\n    array<int, N> opt{};\n    int directRow = -1;\n    int directD = -1;\n    int directAfter = -1;\n    int T = 0;\n    int repR = -1, repC = -1;\n};\n\nint initialLenRow(const Pattern &p, int row) {\n    if (p.directRow == row) {\n        int len = 6 + abs(row - p.directD);\n        if (p.directAfter >= 0) {\n            len += abs(row - p.directD) + 4;\n            len += (row == 0 ? bigOpts[p.directAfter].len : smallOpts[p.directAfter].len);\n        }\n        return len;\n    }\n    return row == 0 ? bigOpts[p.opt[0]].len : smallOpts[p.opt[row]].len;\n}\n\nvoid computeT(Pattern &p) {\n    p.T = 0;\n    for (int i = 0; i < N; i++) {\n        p.T = max(p.T, initialLenRow(p, i));\n    }\n}\n\npair<int, int> baseBigFinal(const Pattern &p) {\n    if (p.directRow == 0) {\n        if (p.directAfter >= 0) return {0, bigOpts[p.directAfter].finalCol};\n        return {p.directD, 4};\n    }\n    return {0, bigOpts[p.opt[0]].finalCol};\n}\n\npair<int, int> finalBigPos(const Pattern &p) {\n    if (p.repR >= 0) return {p.repR, p.repC};\n    return baseBigFinal(p);\n}\n\nstring baseBigScript(const Pattern &p) {\n    if (p.directRow == 0) {\n        string s = directScript(0, p.directD);\n        if (p.directAfter >= 0) {\n            s += returnScript(p.directD, 0);\n            s += bigOpts[p.directAfter].act;\n        }\n        return s;\n    }\n    return bigOpts[p.opt[0]].act;\n}\n\nint safeDist(pair<int, int> a, pair<int, int> b) {\n    auto [r, c] = a;\n    auto [tr, tc] = b;\n\n    if (c == 4) {\n        if (tc == 4) return abs(r - tr);\n        if (tr == 0) return r + abs(4 - tc);\n        return INF;\n    } else {\n        if (r != 0) return INF;\n        if (tr == 0) return abs(c - tc);\n        if (tc == 4) return abs(4 - c) + tr;\n        return INF;\n    }\n}\n\nstring repositionScript(pair<int, int> a, pair<int, int> b) {\n    auto [r, c] = a;\n    auto [tr, tc] = b;\n    string s;\n\n    auto moveV = [&](int from, int to) {\n        if (from < to) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    };\n    auto moveH = [&](int from, int to) {\n        if (from < to) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    };\n\n    if (c == 4) {\n        if (tc == 4) {\n            moveV(r, tr);\n        } else {\n            moveV(r, 0);\n            moveH(4, tc);\n        }\n    } else {\n        if (tr == 0) {\n            moveH(c, tc);\n        } else {\n            moveH(c, 4);\n            moveV(0, tr);\n        }\n    }\n\n    return s;\n}\n\nstring bigInitScript(const Pattern &p) {\n    string s = baseBigScript(p);\n    if (p.repR >= 0) {\n        s += repositionScript(baseBigFinal(p), {p.repR, p.repC});\n    }\n    return s;\n}\n\nstring smallInitScript(const Pattern &p, int row) {\n    string s;\n    if (p.directRow == row) {\n        s = directScript(row, p.directD);\n        if (p.directAfter >= 0) {\n            s += returnScript(p.directD, row);\n            s += smallOpts[p.directAfter].act;\n        }\n        s.push_back('B');\n    } else {\n        s = smallOpts[p.opt[row]].act;\n        s.push_back('B');\n    }\n    return s;\n}\n\nbool samePattern(const Pattern &a, const Pattern &b) {\n    return a.opt == b.opt\n        && a.directRow == b.directRow\n        && a.directD == b.directD\n        && a.directAfter == b.directAfter\n        && a.T == b.T\n        && a.repR == b.repR\n        && a.repC == b.repC;\n}\n\nvector<Pattern> reachableVariants(const Pattern &p) {\n    vector<Pattern> res;\n    res.push_back(p);\n\n    // If a small crane directly uses column 4, avoid simultaneous large-crane\n    // repositioning through column 4 for safety.\n    if (p.directRow > 0) return res;\n\n    int bigLen = initialLenRow(p, 0);\n    int slack = p.T - bigLen;\n    if (slack <= 0) return res;\n\n    pair<int, int> base = baseBigFinal(p);\n    vector<pair<int, int>> targets;\n    for (int c = 0; c < N; c++) targets.push_back({0, c});\n    for (int r = 1; r < N; r++) targets.push_back({r, 4});\n\n    for (auto tg : targets) {\n        if (tg == base) continue;\n        int d = safeDist(base, tg);\n        if (d <= slack) {\n            Pattern q = p;\n            q.repR = tg.first;\n            q.repC = tg.second;\n            res.push_back(q);\n        }\n    }\n\n    return res;\n}\n\nstruct State {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) occ[i][j] = -1;\n        }\n        r = c = 0;\n        act.clear();\n        eval = 0;\n    }\n\n    int code() const {\n        return pcode * PBASE + qcode;\n    }\n\n    int delivered() const {\n        return sumCode[qcode];\n    }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveTo(int tr, int tc) {\n        while (r < tr) add('D');\n        while (r > tr) add('U');\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    vector<pair<int, int>> storageOptions(int b, int srcRow, double storageW, int maxOpt) const {\n        vector<tuple<double, int, int, int>> cand;\n        int bd = b / N;\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n                cand.emplace_back(sc, tie, rr, cc);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        vector<pair<int, int>> res;\n        for (int i = 0; i < (int)cand.size() && i < maxOpt; i++) {\n            res.push_back({get<2>(cand[i]), get<3>(cand[i])});\n        }\n        return res;\n    }\n};\n\ntemplate<class S>\nvoid setupInitial(S &st, const Pattern &pat) {\n    st.clear();\n\n    if (pat.directRow >= 0) {\n        st.q[pat.directD] = 1;\n        st.qcode += pow6_[pat.directD];\n    }\n\n    for (int i = 0; i < N; i++) {\n        const vector<int> *cols = nullptr;\n        int offset = 0;\n        int cnt = 0;\n\n        if (pat.directRow == i) {\n            offset = 1;\n            cnt = 1;\n            if (pat.directAfter >= 0) {\n                const RowOption &ro = (i == 0 ? bigOpts[pat.directAfter] : smallOpts[pat.directAfter]);\n                cols = &ro.cols;\n                cnt += (int)ro.cols.size();\n            }\n        } else {\n            const RowOption &ro = (i == 0 ? bigOpts[pat.opt[0]] : smallOpts[pat.opt[i]]);\n            cols = &ro.cols;\n            offset = 0;\n            cnt = (int)ro.cols.size();\n        }\n\n        st.p[i] = cnt;\n        st.pcode += cnt * pow6_[i];\n\n        if (cols != nullptr) {\n            for (int t = 0; t < (int)cols->size(); t++) {\n                int b = A[i][offset + t];\n                int cc = (*cols)[t];\n                st.occ[i][cc] = b;\n                st.lr[b] = i;\n                st.lc[b] = cc;\n            }\n        }\n\n        if (cnt < N) {\n            st.occ[i][0] = A[i][cnt];\n        }\n    }\n\n    auto pos = finalBigPos(pat);\n    st.r = pos.first;\n    st.c = pos.second;\n}\n\nState makeInitialState(const Pattern &pat) {\n    State st;\n    setupInitial(st, pat);\n    st.act.reserve(512);\n    return st;\n}\n\nbool doDispatchBuffered(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int rr = ns.lr[x], cc = ns.lc[x];\n    if (rr < 0 || ns.occ[rr][cc] != x) return false;\n\n    ns.moveTo(rr, cc);\n    ns.add('P');\n    ns.occ[rr][cc] = -1;\n    ns.lr[x] = ns.lc[x] = -1;\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nbool doDispatchSource(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int s = srcOf[x];\n\n    if (ns.p[s] >= N) return false;\n    if (A[s][ns.p[s]] != x) return false;\n    if (ns.occ[s][0] != x) return false;\n\n    ns.moveTo(s, 0);\n    ns.add('P');\n    ns.occ[s][0] = -1;\n    ns.incP(s);\n    if (ns.p[s] < N) ns.occ[s][0] = A[s][ns.p[s]];\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nvoid expandBlockers(\n    const State &cur,\n    int s,\n    int idx,\n    int d,\n    double storageW,\n    int optLimit,\n    vector<State> &out\n) {\n    if (cur.p[s] == idx) {\n        State ns = cur;\n        if (doDispatchSource(ns, d)) out.push_back(std::move(ns));\n        return;\n    }\n\n    if (cur.p[s] > idx) return;\n\n    int b = A[s][cur.p[s]];\n    if (cur.occ[s][0] != b) return;\n\n    State base = cur;\n    base.moveTo(s, 0);\n    base.add('P');\n    base.occ[s][0] = -1;\n    base.incP(s);\n    if (base.p[s] < N) base.occ[s][0] = A[s][base.p[s]];\n\n    auto opts = base.storageOptions(b, s, storageW, optLimit);\n    for (auto [rr, cc] : opts) {\n        if (base.occ[rr][cc] != -1) continue;\n\n        State ns = base;\n        ns.moveTo(rr, cc);\n        ns.add('Q');\n        ns.occ[rr][cc] = b;\n        ns.lr[b] = rr;\n        ns.lc[b] = cc;\n\n        expandBlockers(ns, s, idx, d, storageW, optLimit, out);\n    }\n}\n\nvector<State> expandExecuteTarget(\n    const State &st,\n    int d,\n    double storageW,\n    int optLimit,\n    int perTransLimit\n) {\n    vector<State> res;\n\n    int x = N * d + st.q[d];\n    int s = srcOf[x];\n    int idx = idxOf[x];\n\n    if (idx < st.p[s]) {\n        State ns = st;\n        if (doDispatchBuffered(ns, d)) res.push_back(std::move(ns));\n    } else {\n        expandBlockers(st, s, idx, d, storageW, optLimit, res);\n    }\n\n    if ((int)res.size() > perTransLimit) {\n        sort(res.begin(), res.end(), [](const State &a, const State &b) {\n            return a.act.size() < b.act.size();\n        });\n        res.resize(perTransLimit);\n    }\n\n    return res;\n}\n\nint nearestHeuristic(const State &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct PlanResult {\n    bool ok = false;\n    string act;\n};\n\nPlanResult buildBeam(const State &init, double storageW, int width, int hcoef, int optLimit) {\n    if (dfsBlock(init.code()) >= INF) return {false, \"\"};\n\n    vector<State> beam;\n    beam.push_back(init);\n\n    auto comp = [](const State &a, const State &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.act.size() < b.act.size();\n    };\n\n    int perTransLimit = (optLimit <= 1 ? 1 : (optLimit == 2 ? 8 : 12));\n\n    for (int step = init.delivered(); step < TOT; step++) {\n        vector<State> cand;\n        cand.reserve((size_t)width * N * perTransLimit);\n\n        for (const State &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                vector<State> nsList = expandExecuteTarget(st, d, storageW, optLimit, perTransLimit);\n                for (State &ns : nsList) {\n                    if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n                    int near = nearestHeuristic(ns);\n                    ns.eval = (int)ns.act.size() + hcoef * remAfter + near;\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return {false, \"\"};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    string best;\n    int bestLen = INF;\n    for (const State &st : beam) {\n        if (st.delivered() == TOT && (int)st.act.size() < bestLen) {\n            bestLen = (int)st.act.size();\n            best = st.act;\n        }\n    }\n\n    if (best.empty()) return {false, \"\"};\n    return {true, best};\n}\n\nstruct LiteState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n    int r = 0, c = 0, len = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = len = 0;\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void moveTo(int tr, int tc) {\n        len += abs(r - tr) + abs(c - tc);\n        r = tr;\n        c = tc;\n    }\n\n    pair<int, int> chooseStorage(int b, int srcRow, double storageW) const {\n        int bd = b / N;\n        double best = 1e100;\n        int bestTie = INF;\n        pair<int, int> res = {-1, -1};\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n\n                if (sc + 1e-9 < best || (fabs(sc - best) <= 1e-9 && tie < bestTie)) {\n                    best = sc;\n                    bestTie = tie;\n                    res = {rr, cc};\n                }\n            }\n        }\n\n        return res;\n    }\n\n    bool dispatchBuffered(int d) {\n        int x = N * d + q[d];\n        int rr = lr[x], cc = lc[x];\n        if (rr < 0 || occ[rr][cc] != x) return false;\n\n        moveTo(rr, cc);\n        len++;\n        occ[rr][cc] = -1;\n        lr[x] = lc[x] = -1;\n\n        moveTo(d, N - 1);\n        len++;\n        incQ(d);\n        return true;\n    }\n\n    bool dispatchSource(int d) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n\n        if (p[s] >= N) return false;\n        if (A[s][p[s]] != x) return false;\n        if (occ[s][0] != x) return false;\n\n        moveTo(s, 0);\n        len++;\n        occ[s][0] = -1;\n        incP(s);\n        if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n        moveTo(d, N - 1);\n        len++;\n        incQ(d);\n        return true;\n    }\n\n    bool executeTarget(int d, double storageW) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        if (idx < p[s]) {\n            return dispatchBuffered(d);\n        }\n\n        while (p[s] < idx) {\n            int b = A[s][p[s]];\n            if (occ[s][0] != b) return false;\n\n            moveTo(s, 0);\n            len++;\n            occ[s][0] = -1;\n            incP(s);\n            if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n            auto cell = chooseStorage(b, s, storageW);\n            if (cell.first < 0) return false;\n\n            moveTo(cell.first, cell.second);\n            len++;\n            occ[cell.first][cell.second] = b;\n            lr[b] = cell.first;\n            lc[b] = cell.second;\n        }\n\n        return dispatchSource(d);\n    }\n};\n\nLiteState makeLiteInitialState(const Pattern &pat) {\n    LiteState st;\n    setupInitial(st, pat);\n    return st;\n}\n\nint nearestLite(const LiteState &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nint greedyLength(const Pattern &pat, double storageW, int hcoef) {\n    string bs = bigInitScript(pat);\n    if ((int)bs.size() > pat.T) return INF;\n\n    LiteState st = makeLiteInitialState(pat);\n    if (dfsBlock(st.code()) >= INF) return INF;\n\n    for (int step = st.delivered(); step < TOT; step++) {\n        int bestEval = INF;\n        int bestLen = INF;\n        bool found = false;\n        LiteState bestSt;\n\n        for (int d = 0; d < N; d++) {\n            TransCode tr;\n            if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n            int remAfter = dfsBlock(tr.code);\n            if (remAfter >= INF) continue;\n\n            LiteState ns = st;\n            if (!ns.executeTarget(d, storageW)) continue;\n            if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n\n            int eval = ns.len + hcoef * remAfter + nearestLite(ns);\n            if (eval < bestEval || (eval == bestEval && ns.len < bestLen)) {\n                bestEval = eval;\n                bestLen = ns.len;\n                bestSt = ns;\n                found = true;\n            }\n        }\n\n        if (!found) return INF;\n        st = bestSt;\n    }\n\n    return pat.T + st.len;\n}\n\nvector<Pattern> generateCandidates() {\n    vector<Pattern> res;\n    int B = (int)bigOpts.size();\n    int S = (int)smallOpts.size();\n    int smallCodeMax = 1;\n    for (int i = 1; i < N; i++) smallCodeMax *= S;\n\n    for (int b = 0; b < B; b++) {\n        for (int code = 0; code < smallCodeMax; code++) {\n            Pattern p;\n            p.opt.fill(0);\n            p.opt[0] = b;\n            int tmp = code;\n            for (int i = 1; i < N; i++) {\n                p.opt[i] = tmp % S;\n                tmp /= S;\n            }\n            computeT(p);\n            res.push_back(p);\n        }\n    }\n\n    vector<int> oneSmall;\n    for (int i = 0; i < S; i++) {\n        if (smallOpts[i].cols.size() == 1) oneSmall.push_back(i);\n    }\n\n    for (int dr = 0; dr < N; dr++) {\n        if (A[dr][0] % N != 0) continue;\n        int d = A[dr][0] / N;\n\n        if (dr == 0) {\n            for (int after = -1; after < B; after++) {\n                for (int code = 0; code < smallCodeMax; code++) {\n                    Pattern p;\n                    p.opt.fill(0);\n                    p.opt[0] = -1;\n                    int tmp = code;\n                    for (int i = 1; i < N; i++) {\n                        p.opt[i] = tmp % S;\n                        tmp /= S;\n                    }\n                    p.directRow = 0;\n                    p.directD = d;\n                    p.directAfter = after;\n                    computeT(p);\n                    res.push_back(p);\n                }\n            }\n        } else {\n            vector<int> afters;\n            afters.push_back(-1);\n            for (int x : oneSmall) afters.push_back(x);\n\n            int codeMax = 1;\n            for (int i = 1; i < N; i++) if (i != dr) codeMax *= S;\n\n            for (int after : afters) {\n                for (int b = 0; b < B; b++) {\n                    for (int code = 0; code < codeMax; code++) {\n                        Pattern p;\n                        p.opt.fill(0);\n                        p.opt[0] = b;\n                        int tmp = code;\n                        for (int i = 1; i < N; i++) {\n                            if (i == dr) {\n                                p.opt[i] = -1;\n                            } else {\n                                p.opt[i] = tmp % S;\n                                tmp /= S;\n                            }\n                        }\n                        p.directRow = dr;\n                        p.directD = d;\n                        p.directAfter = after;\n                        computeT(p);\n                        res.push_back(p);\n                    }\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\narray<string, N> makeSortedOutput(const Pattern &pat, const string &cont) {\n    array<string, N> out;\n\n    string big = bigInitScript(pat);\n    if ((int)big.size() < pat.T) big += string(pat.T - (int)big.size(), '.');\n    big += cont;\n    out[0] = big;\n\n    for (int i = 1; i < N; i++) {\n        out[i] = smallInitScript(pat, i);\n    }\n\n    return out;\n}\n\nstring buildDirectPlan() {\n    State st;\n    st.clear();\n    for (int i = 0; i < N; i++) st.occ[i][0] = A[i][0];\n\n    for (int s = 0; s < N; s++) {\n        while (st.p[s] < N) {\n            int x = A[s][st.p[s]];\n            int d = x / N;\n\n            st.moveTo(s, 0);\n            st.add('P');\n            st.occ[s][0] = -1;\n            st.incP(s);\n            if (st.p[s] < N) st.occ[s][0] = A[s][st.p[s]];\n\n            st.moveTo(d, N - 1);\n            st.add('Q');\n        }\n    }\n\n    return st.act;\n}\n\nint directInversions() {\n    vector<int> seq[N];\n    int inv = 0;\n\n    for (int s = 0; s < N; s++) {\n        for (int k = 0; k < N; k++) {\n            int x = A[s][k];\n            int d = x / N;\n            for (int y : seq[d]) {\n                if (y > x) inv++;\n            }\n            seq[d].push_back(x);\n        }\n    }\n\n    return inv;\n}\n\nvoid initTables() {\n    pow6_[0] = 1;\n    for (int i = 0; i < N; i++) pow6_[i + 1] = pow6_[i] * BASE;\n\n    for (int code = 0; code < PBASE; code++) {\n        int tmp = code;\n        int sm = 0, ex = 0;\n        for (int i = 0; i < N; i++) {\n            int v = tmp % BASE;\n            tmp /= BASE;\n            dig[code][i] = (uint8_t)v;\n            sm += v;\n            if (v == N) ex++;\n        }\n        sumCode[code] = (uint8_t)sm;\n        exhCode[code] = (uint8_t)ex;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initTables();\n    initRowOptions();\n\n    int Nin;\n    cin >> Nin;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> A[i][j];\n            srcOf[A[i][j]] = i;\n            idxOf[A[i][j]] = j;\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsedMs = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    };\n\n    memoBlock.assign(TOTAL_STATES, -1);\n\n    array<string, N> bestOut;\n    long long bestScore = (long long)4e18;\n\n    {\n        string directAct = buildDirectPlan();\n        int inv = directInversions();\n        long long directScore = (long long)directAct.size() + 100LL * inv;\n\n        bestOut[0] = directAct.empty() ? \".\" : directAct;\n        for (int i = 1; i < N; i++) bestOut[i] = \"B\";\n        bestScore = directScore;\n    }\n\n    auto tryUpdateSorted = [&](const Pattern &pat, const string &cont) {\n        if (cont.empty()) return;\n\n        string bs = bigInitScript(pat);\n        if ((int)bs.size() > pat.T) return;\n\n        auto out = makeSortedOutput(pat, cont);\n        int m0 = 0;\n        for (int i = 0; i < N; i++) m0 = max(m0, (int)out[i].size());\n        if (m0 <= 0 || m0 > 10000) return;\n\n        if ((long long)m0 < bestScore) {\n            bestScore = m0;\n            bestOut = out;\n        }\n    };\n\n    vector<Pattern> candidates = generateCandidates();\n\n    vector<pair<int, int>> estimates;\n    estimates.reserve(candidates.size());\n\n    for (int idx = 0; idx < (int)candidates.size(); idx++) {\n        if ((idx & 255) == 0 && elapsedMs() > 1500 && (int)estimates.size() > 80) break;\n\n        int gl = greedyLength(candidates[idx], 1.0, 8);\n        if (gl < INF) estimates.push_back({gl, idx});\n    }\n\n    sort(estimates.begin(), estimates.end());\n\n    vector<Pattern> baseSelected;\n\n    auto addUnique = [&](vector<Pattern> &v, const Pattern &p) {\n        for (const Pattern &q : v) {\n            if (samePattern(p, q)) return;\n        }\n        v.push_back(p);\n    };\n\n    for (int i = 0; i < (int)estimates.size() && i < 60; i++) {\n        addUnique(baseSelected, candidates[estimates[i].second]);\n    }\n\n    // Manual safe patterns: uniform options.\n    for (int so = 0; so < (int)smallOpts.size(); so++) {\n        int bo = -1;\n        for (int b = 0; b < (int)bigOpts.size(); b++) {\n            if (bigOpts[b].cols == smallOpts[so].cols) {\n                bo = b;\n                break;\n            }\n        }\n        if (bo < 0) continue;\n\n        Pattern p;\n        p.opt.fill(so);\n        p.opt[0] = bo;\n        computeT(p);\n        addUnique(baseSelected, p);\n    }\n\n    vector<Pattern> variants;\n    for (const Pattern &p : baseSelected) {\n        for (const Pattern &v : reachableVariants(p)) {\n            addUnique(variants, v);\n        }\n    }\n\n    vector<pair<int, int>> variantEst;\n    for (int i = 0; i < (int)variants.size(); i++) {\n        if ((i & 63) == 0 && elapsedMs() > 1900 && (int)variantEst.size() > 30) break;\n        int gl = greedyLength(variants[i], 1.0, 8);\n        if (gl < INF) variantEst.push_back({gl, i});\n    }\n\n    sort(variantEst.begin(), variantEst.end());\n\n    vector<Pattern> finalPatterns;\n    for (int i = 0; i < (int)variantEst.size() && i < 45; i++) {\n        addUnique(finalPatterns, variants[variantEst[i].second]);\n    }\n    for (int i = 0; i < (int)baseSelected.size() && i < 10; i++) {\n        addUnique(finalPatterns, baseSelected[i]);\n    }\n\n    if (finalPatterns.empty()) {\n        Pattern p;\n        p.opt.fill(0);\n        p.opt[0] = 0;\n        computeT(p);\n        finalPatterns.push_back(p);\n    }\n\n    for (int rank = 0; rank < (int)finalPatterns.size(); rank++) {\n        if (elapsedMs() > 2750) break;\n\n        const Pattern &pat = finalPatterns[rank];\n        State init = makeInitialState(pat);\n\n        if (dfsBlock(init.code()) >= INF) continue;\n\n        {\n            PlanResult pr = buildBeam(init, 1.0, 1, 8, 1);\n            if (pr.ok) tryUpdateSorted(pat, pr.act);\n        }\n\n        vector<double> weights;\n        vector<int> hs;\n        int width;\n\n        if (rank < 6) {\n            weights = {0.0, 0.4, 0.9, 1.8, 4.0};\n            hs = {0, 8};\n            width = 260;\n        } else if (rank < 20) {\n            weights = {0.4, 0.9, 1.8, 3.5};\n            hs = {8};\n            width = 160;\n        } else {\n            weights = {0.9, 2.5};\n            hs = {8};\n            width = 90;\n        }\n\n        for (int h : hs) {\n            for (double w : weights) {\n                if (elapsedMs() > 2780) break;\n\n                PlanResult pr = buildBeam(init, w, width, h, 1);\n                if (pr.ok) tryUpdateSorted(pat, pr.act);\n            }\n        }\n    }\n\n    // Additional branching over storage-cell choices for the best starts.\n    for (int rank = 0; rank < (int)finalPatterns.size() && rank < 5; rank++) {\n        if (elapsedMs() > 2550) break;\n\n        const Pattern &pat = finalPatterns[rank];\n        State init = makeInitialState(pat);\n\n        for (double w : {0.7, 1.5, 3.0}) {\n            if (elapsedMs() > 2820) break;\n            PlanResult pr = buildBeam(init, w, 80, 8, 2);\n            if (pr.ok) tryUpdateSorted(pat, pr.act);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (bestOut[i].empty()) bestOut[i] = \".\";\n        cout << bestOut[i] << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 20;\nstatic const int V = N * N;\nstatic const long long INFLL = (1LL << 60);\nstatic const int INF = 1e9;\n\nint H[V];\nint DIST[V][V];\nlong long BASE_COST = 0;\n\nint cell_id(int r, int c) {\n    return r * N + c;\n}\n\nstruct Solution {\n    vector<string> ops;\n    long long cost = 0;\n    long long load = 0;\n    int pos = 0;\n    bool valid = true;\n\n    void moveOne(char ch) {\n        ops.emplace_back(1, ch);\n        cost += 100 + load;\n\n        int r = pos / N;\n        int c = pos % N;\n        if (ch == 'U') --r;\n        if (ch == 'D') ++r;\n        if (ch == 'L') --c;\n        if (ch == 'R') ++c;\n        if (r < 0 || r >= N || c < 0 || c >= N) valid = false;\n        pos = cell_id(r, c);\n    }\n\n    void moveTo(int target) {\n        int tr = target / N;\n        int tc = target % N;\n        while (pos / N < tr) moveOne('D');\n        while (pos / N > tr) moveOne('U');\n        while (pos % N < tc) moveOne('R');\n        while (pos % N > tc) moveOne('L');\n    }\n\n    void addLoad(long long d) {\n        if (d <= 0) return;\n        ops.push_back(string(\"+\") + to_string(d));\n        cost += d;\n        load += d;\n    }\n\n    void addUnload(long long d) {\n        if (d <= 0) return;\n        if (load < d) valid = false;\n        ops.push_back(string(\"-\") + to_string(d));\n        cost += d;\n        load -= d;\n    }\n};\n\narray<int, V> nearestDist(const vector<int>& rem, bool positive, bool& has) {\n    array<int, V> dist;\n    dist.fill(INF);\n    queue<int> q;\n    has = false;\n\n    for (int i = 0; i < V; ++i) {\n        if ((positive && rem[i] > 0) || (!positive && rem[i] < 0)) {\n            dist[i] = 0;\n            q.push(i);\n            has = true;\n        }\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        int r = v / N;\n        int c = v % N;\n        const int dr[4] = {-1, 1, 0, 0};\n        const int dc[4] = {0, 0, -1, 1};\n\n        for (int k = 0; k < 4; ++k) {\n            int nr = r + dr[k];\n            int nc = c + dc[k];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int to = cell_id(nr, nc);\n            if (dist[to] > dist[v] + 1) {\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n    }\n\n    return dist;\n}\n\nint selectSource(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearNeg,\n    int mode,\n    int maxAmount\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] <= 0) continue;\n        if (maxAmount >= 0 && rem[i] > maxAmount) continue;\n\n        int d = DIST[cur][i];\n        int nd = nearNeg[i] >= INF ? 0 : nearNeg[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * rem[i];\n        } else if (mode == 1) {\n            score = 10000LL * d - 200LL * rem[i];\n        } else {\n            score = 8000LL * d + 3000LL * nd - 50LL * rem[i];\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nint selectDemand(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearPos,\n    bool hasPos,\n    long long load,\n    int mode\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] >= 0) continue;\n\n        int demand = -rem[i];\n        int del = (int)min<long long>(load, demand);\n        if (del <= 0) continue;\n\n        int d = DIST[cur][i];\n        int future = 0;\n        if (load == del && hasPos && nearPos[i] < INF) future = nearPos[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * del + 1000LL * future;\n        } else if (mode == 1) {\n            score = 1000LL * d * (100 + load) / (del + 10) + 500LL * future;\n        } else {\n            score = 10000LL * d - 200LL * del + 1000LL * future;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nSolution makeGreedySolution(int maxLoad, int ratioNum, int ratioDen, int sourceMode, int demandMode) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 10000; ++iter) {\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            sol.moveTo(p);\n            int a = rem[p];\n            sol.addLoad(a);\n            rem[p] = 0;\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (maxLoad > 0 && hasPos) {\n                int maxAmount = maxLoad - (int)sol.load;\n                if (maxAmount > 0) {\n                    p = selectSource(sol.pos, rem, nearNeg, sourceMode, maxAmount);\n                    if (p >= 0) {\n                        int nearestDemand = nearNeg[sol.pos];\n                        int dp = DIST[sol.pos][p];\n\n                        if (nearestDemand > 0 &&\n                            1LL * dp * ratioDen <= 1LL * nearestDemand * ratioNum) {\n                            takePos = true;\n                        }\n                    }\n                }\n            }\n\n            if (takePos) {\n                sol.moveTo(p);\n                int a = rem[p];\n                sol.addLoad(a);\n                rem[p] = 0;\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                sol.moveTo(q);\n                int x = (int)min<long long>(sol.load, -rem[q]);\n                sol.addUnload(x);\n                rem[q] += x;\n            }\n        }\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\n// Opportunistic path-servicing greedy.\nvoid serviceCell(Solution& sol, vector<int>& rem, int cap) {\n    int v = sol.pos;\n\n    if (rem[v] < 0 && sol.load > 0) {\n        long long x = min<long long>(sol.load, -rem[v]);\n        sol.addUnload(x);\n        rem[v] += (int)x;\n    }\n\n    if (rem[v] > 0 && sol.load < cap) {\n        long long x = min<long long>(rem[v], (long long)cap - sol.load);\n        sol.addLoad(x);\n        rem[v] -= (int)x;\n    }\n}\n\nlong long stepScoreForService(int nxt, int target, const vector<int>& rem, long long load, int cap) {\n    long long score = 0;\n\n    if (rem[nxt] < 0 && load > 0) {\n        long long x = min<long long>(load, -rem[nxt]);\n        score -= 100000LL * x;\n        score -= 3000LL * x * DIST[nxt][target];\n    }\n\n    if (rem[nxt] > 0 && load < cap) {\n        long long x = min<long long>(rem[nxt], (long long)cap - load);\n        score -= 20000LL * x;\n        score += 700LL * x * DIST[nxt][target];\n    }\n\n    return score;\n}\n\nvoid moveToService(Solution& sol, int target, vector<int>& rem, int cap, int pathMode) {\n    serviceCell(sol, rem, cap);\n\n    while (sol.pos != target) {\n        int r = sol.pos / N;\n        int c = sol.pos % N;\n        int tr = target / N;\n        int tc = target % N;\n\n        char chosen = 0;\n\n        if (pathMode == 0) {\n            if (r < tr) chosen = 'D';\n            else if (r > tr) chosen = 'U';\n            else if (c < tc) chosen = 'R';\n            else chosen = 'L';\n        } else if (pathMode == 1) {\n            if (c < tc) chosen = 'R';\n            else if (c > tc) chosen = 'L';\n            else if (r < tr) chosen = 'D';\n            else chosen = 'U';\n        } else {\n            vector<pair<char, int>> cand;\n            if (r < tr) cand.push_back({'D', cell_id(r + 1, c)});\n            if (r > tr) cand.push_back({'U', cell_id(r - 1, c)});\n            if (c < tc) cand.push_back({'R', cell_id(r, c + 1)});\n            if (c > tc) cand.push_back({'L', cell_id(r, c - 1)});\n\n            long long best = INFLL;\n            for (auto [ch, id] : cand) {\n                long long sc = stepScoreForService(id, target, rem, sol.load, cap);\n                if (sc < best) {\n                    best = sc;\n                    chosen = ch;\n                }\n            }\n        }\n\n        sol.moveOne(chosen);\n        serviceCell(sol, rem, cap);\n    }\n}\n\nSolution makeGreedyServiceSolution(\n    int cap,\n    int ratioNum,\n    int ratioDen,\n    int sourceMode,\n    int demandMode,\n    int pathMode\n) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 20000; ++iter) {\n        serviceCell(sol, rem, cap);\n\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            moveToService(sol, p, rem, cap, pathMode);\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (sol.load < cap && hasPos) {\n                p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n                if (p >= 0) {\n                    int direct = nearNeg[sol.pos];\n                    int via = DIST[sol.pos][p] + nearNeg[p];\n\n                    if (direct >= INF) direct = 1000;\n                    if (via * ratioDen <= direct * ratioNum + 2 * ratioDen) {\n                        takePos = true;\n                    }\n\n                    if (DIST[sol.pos][p] <= 2 && sol.load < cap * 3LL / 4) {\n                        takePos = true;\n                    }\n                }\n            }\n\n            if (takePos) {\n                moveToService(sol, p, rem, cap, pathMode);\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                moveToService(sol, q, rem, cap, pathMode);\n            }\n        }\n    }\n\n    serviceCell(sol, rem, cap);\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev;\n        long long cap, cost;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow(int n_) : n(n_), g(n_) {}\n\n    int addEdge(int fr, int to, long long cap, long long cost) {\n        Edge f{to, (int)g[to].size(), cap, cost};\n        Edge r{fr, (int)g[fr].size(), 0, -cost};\n        g[fr].push_back(f);\n        g[to].push_back(r);\n        return (int)g[fr].size() - 1;\n    }\n\n    pair<long long, long long> minCostFlow(int s, int t, long long maxf) {\n        long long flow = 0;\n        long long cost = 0;\n\n        vector<long long> pot(n, 0), dist(n);\n        vector<int> pv(n), pe(n);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INFLL);\n            dist[s] = 0;\n\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != d) continue;\n\n                for (int i = 0; i < (int)g[v].size(); ++i) {\n                    Edge& e = g[v][i];\n                    if (e.cap <= 0) continue;\n\n                    long long nd = d + e.cost + pot[v] - pot[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INFLL) break;\n\n            for (int v = 0; v < n; ++v) {\n                if (dist[v] < INFLL) pot[v] += dist[v];\n            }\n\n            long long add = maxf - flow;\n            for (int v = t; v != s; v = pv[v]) {\n                add = min(add, g[pv[v]][pe[v]].cap);\n            }\n\n            for (int v = t; v != s; v = pv[v]) {\n                Edge& e = g[pv[v]][pe[v]];\n                e.cap -= add;\n                g[v][e.rev].cap += add;\n                cost += add * e.cost;\n            }\n\n            flow += add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nstruct Flow {\n    int s, t, amount;\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\nvector<Flow> computeMinCostFlows(int variant) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n            total += H[i];\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n    if (total == 0) return {};\n\n    int SRC = 0;\n    int posBase = 1;\n    int negBase = 1 + P;\n    int SNK = 1 + P + Q;\n    int nodes = SNK + 1;\n\n    MinCostFlow mf(nodes);\n\n    for (int i = 0; i < P; ++i) {\n        mf.addEdge(SRC, posBase + i, posAmt[i], 0);\n    }\n\n    for (int j = 0; j < Q; ++j) {\n        mf.addEdge(negBase + j, SNK, negAmt[j], 0);\n    }\n\n    struct Ref {\n        int node, edgeIndex, pi, qi;\n    };\n    vector<Ref> refs;\n\n    const long long CAP = 1e9;\n    const long long W = 100000000LL;\n\n    for (int i = 0; i < P; ++i) {\n        for (int j = 0; j < Q; ++j) {\n            long long tie = 0;\n\n            if (variant != 0) {\n                uint64_t seed = ((uint64_t)variant << 48) ^ ((uint64_t)posCells[i] << 24) ^ (uint64_t)negCells[j];\n                tie = splitmix64(seed) % 1000;\n            }\n\n            long long c = 1LL * DIST[posCells[i]][negCells[j]] * W + tie;\n            int idx = mf.addEdge(posBase + i, negBase + j, CAP, c);\n            refs.push_back({posBase + i, idx, i, j});\n        }\n    }\n\n    mf.minCostFlow(SRC, SNK, total);\n\n    vector<Flow> flows;\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            flows.push_back({posCells[ref.pi], negCells[ref.qi], (int)used});\n        }\n    }\n\n    return flows;\n}\n\nvector<Flow> computeGreedyFlows(int mode) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n\n    vector<Flow> flows;\n\n    for (int step = 0; step < P + Q + 5; ++step) {\n        long long bestScore = INFLL;\n        int bi = -1, bj = -1;\n\n        for (int i = 0; i < P; ++i) {\n            if (posAmt[i] <= 0) continue;\n\n            for (int j = 0; j < Q; ++j) {\n                if (negAmt[j] <= 0) continue;\n\n                int a = min(posAmt[i], negAmt[j]);\n                int d = DIST[posCells[i]][negCells[j]];\n\n                long long score;\n                if (mode == 0) {\n                    score = 100000LL * d - 700LL * a;\n                } else if (mode == 1) {\n                    score = 100000LL * d\n                          + 150LL * (DIST[0][posCells[i]] + DIST[0][negCells[j]])\n                          - 500LL * a;\n                } else {\n                    score = 100000LL * d\n                          - 1200LL * a\n                          + 20LL * abs(posAmt[i] - negAmt[j]);\n                }\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi < 0) break;\n\n        int a = min(posAmt[bi], negAmt[bj]);\n        flows.push_back({posCells[bi], negCells[bj], a});\n        posAmt[bi] -= a;\n        negAmt[bj] -= a;\n    }\n\n    return flows;\n}\n\nvector<int> optimizeOrder(const vector<int>& starts, const vector<int>& ends) {\n    int m = (int)starts.size();\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    vector<int> startLink(m);\n    vector<vector<int>> link(m, vector<int>(m));\n\n    for (int i = 0; i < m; ++i) {\n        startLink[i] = DIST[0][starts[i]];\n    }\n\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < m; ++j) {\n            link[i][j] = DIST[ends[i]][starts[j]];\n        }\n    }\n\n    auto L = [&](int prev, int cur) -> int {\n        if (prev < 0) return startLink[cur];\n        return link[prev][cur];\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n\n    for (int cnt = 0; cnt < m; ++cnt) {\n        int bestG = -1, bestPos = 0;\n        int bestInc = INF;\n\n        for (int g = 0; g < m; ++g) {\n            if (used[g]) continue;\n\n            for (int p = 0; p <= (int)order.size(); ++p) {\n                int prev = (p == 0 ? -1 : order[p - 1]);\n                int nxt = (p == (int)order.size() ? -2 : order[p]);\n\n                int inc = L(prev, g);\n                if (nxt != -2) inc += L(g, nxt) - L(prev, nxt);\n\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestG = g;\n                    bestPos = p;\n                }\n            }\n        }\n\n        order.insert(order.begin() + bestPos, bestG);\n        used[bestG] = true;\n    }\n\n    for (int pass = 0; pass < 30; ++pass) {\n        int bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prev = (i == 0 ? -1 : order[i - 1]);\n            int nxt = (i + 1 == m ? -2 : order[i + 1]);\n\n            int oldRemove = L(prev, x);\n            if (nxt != -2) oldRemove += L(x, nxt);\n\n            int newRemove = 0;\n            if (nxt != -2) newRemove += L(prev, nxt);\n\n            int removeDelta = newRemove - oldRemove;\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int oldInsert = 0;\n                if (after != -2) oldInsert += L(before, after);\n\n                int newInsert = L(before, x);\n                if (after != -2) newInsert += L(x, after);\n\n                int delta = removeDelta + newInsert - oldInsert;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            int oldInternal = 0;\n            int newInternal = 0;\n            int prev = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += L(order[r - 1], order[r]);\n                newInternal += L(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                int oldCost = L(prev, order[l]) + oldInternal;\n                if (after != -2) oldCost += L(order[r], after);\n\n                int newCost = L(prev, order[r]) + newInternal;\n                if (after != -2) newCost += L(order[l], after);\n\n                int delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else if (bestType == 2) {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nstruct SourceGroup {\n    int source = -1;\n    int total = 0;\n    int end = -1;\n    vector<int> dest, amt, order;\n    long long internalCost = 0;\n};\n\nvoid computeSourceOrder(SourceGroup& g, int target) {\n    int k = (int)g.dest.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            dp[idx(mask, j)] = 1LL * DIST[g.source][g.dest[j]] * (100 + total);\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = total - sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.dest[last]][g.dest[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)];\n            if (target >= 0) c += 100LL * DIST[g.dest[last]][target];\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = g.source;\n        int load = total;\n\n        for (int left = k; left > 0; --left) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score = 1LL * DIST[cur][g.dest[j]] * (100 + load);\n                if (left == 1 && target >= 0) {\n                    score += 100LL * DIST[g.dest[j]][target];\n                }\n\n                score -= 5LL * g.amt[j];\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.dest[bj];\n            load -= g.amt[bj];\n        }\n    }\n\n    g.end = g.dest[g.order.back()];\n\n    long long c = 0;\n    int cur = g.source;\n    int load = total;\n\n    for (int idx2 : g.order) {\n        c += 1LL * DIST[cur][g.dest[idx2]] * (100 + load);\n        load -= g.amt[idx2];\n        cur = g.dest[idx2];\n    }\n\n    g.internalCost = c;\n}\n\nvector<SourceGroup> buildSourceGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.s].push_back({f.t, f.amount});\n    }\n\n    vector<SourceGroup> groups;\n\n    for (int s = 0; s < V; ++s) {\n        if (mp[s].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [t, a] : mp[s]) comb[t] += a;\n\n        SourceGroup g;\n        g.source = s;\n\n        for (auto [t, a] : comb) {\n            g.dest.push_back(t);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeSourceOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeSourceGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildSourceGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].source;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n            computeSourceOrder(groups[gi], target);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].source;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n        computeSourceOrder(groups[gi], target);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        sol.moveTo(g.source);\n        sol.addLoad(g.total);\n\n        for (int idx : g.order) {\n            sol.moveTo(g.dest[idx]);\n            sol.addUnload(g.amt[idx]);\n        }\n    }\n\n    return sol;\n}\n\nSolution makePairSolution(const vector<Flow>& flows) {\n    Solution sol;\n    int m = (int)flows.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = flows[i].s;\n        ends[i] = flows[i].t;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int idx : order) {\n        const auto& f = flows[idx];\n\n        sol.moveTo(f.s);\n        sol.addLoad(f.amount);\n        sol.moveTo(f.t);\n        sol.addUnload(f.amount);\n    }\n\n    return sol;\n}\n\nstruct DemandGroup {\n    int demand = -1;\n    int total = 0;\n    int start = -1;\n    int end = -1;\n    vector<int> src, amt, order;\n};\n\nvoid computeDemandOrder(DemandGroup& g, int prevCell) {\n    int k = (int)g.src.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            long long entry = 0;\n            if (prevCell >= 0) entry = 100LL * DIST[prevCell][g.src[j]];\n\n            dp[idx(mask, j)] = entry;\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.src[last]][g.src[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)] + 1LL * DIST[g.src[last]][g.demand] * (100 + total);\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = -1;\n        int load = 0;\n\n        for (int step = 0; step < k; ++step) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score;\n\n                if (step == 0) {\n                    score = 0;\n                    if (prevCell >= 0) score += 100LL * DIST[prevCell][g.src[j]];\n                    score -= 50LL * DIST[g.src[j]][g.demand];\n                } else {\n                    score = 1LL * DIST[cur][g.src[j]] * (100 + load)\n                          + 10LL * DIST[g.src[j]][g.demand];\n                }\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.src[bj];\n            load += g.amt[bj];\n        }\n    }\n\n    g.start = g.src[g.order.front()];\n    g.end = g.demand;\n}\n\nvector<DemandGroup> buildDemandGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.t].push_back({f.s, f.amount});\n    }\n\n    vector<DemandGroup> groups;\n\n    for (int t = 0; t < V; ++t) {\n        if (mp[t].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [s, a] : mp[t]) comb[s] += a;\n\n        DemandGroup g;\n        g.demand = t;\n\n        for (auto [s, a] : comb) {\n            g.src.push_back(s);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeDemandOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeDemandGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildDemandGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].start;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n            computeDemandOrder(groups[gi], prev);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].start;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n        computeDemandOrder(groups[gi], prev);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        for (int idx : g.order) {\n            sol.moveTo(g.src[idx]);\n            sol.addLoad(g.amt[idx]);\n        }\n\n        sol.moveTo(g.demand);\n        sol.addUnload(g.total);\n    }\n\n    return sol;\n}\n\n// Aggregated adjacent-edge flow route.\nstruct EdgeJob {\n    int s, t, amount;\n};\n\nlong long edgeTieCost(int variant, int u, int v) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    int ar2 = r1 + r2;\n    int ac2 = c1 + c2;\n\n    if (variant == 0) return 0;\n\n    if (variant == 1) {\n        return ar2 + ac2;\n    }\n\n    if (variant == 2) {\n        return (2 * (N - 1) - ar2) + (2 * (N - 1) - ac2);\n    }\n\n    if (variant == 3) {\n        return abs(ar2 - (N - 1)) + abs(ac2 - (N - 1));\n    }\n\n    uint64_t seed = ((uint64_t)variant << 40) ^ ((uint64_t)u << 20) ^ (uint64_t)v;\n    return splitmix64(seed) % 50;\n}\n\nvoid addSignedEdgeFlow(vector<long long>& right, vector<long long>& down, int u, int v, long long a) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    if (r1 == r2) {\n        if (c2 == c1 + 1) {\n            right[r1 * (N - 1) + c1] += a;\n        } else if (c2 == c1 - 1) {\n            right[r1 * (N - 1) + c2] -= a;\n        }\n    } else if (c1 == c2) {\n        if (r2 == r1 + 1) {\n            down[r1 * N + c1] += a;\n        } else if (r2 == r1 - 1) {\n            down[r2 * N + c1] -= a;\n        }\n    }\n}\n\nvector<EdgeJob> computeGridEdgeJobs(int variant) {\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) total += H[i];\n    }\n\n    if (total == 0) return {};\n\n    int SRC = V;\n    int SNK = V + 1;\n    MinCostFlow mf(V + 2);\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) mf.addEdge(SRC, i, H[i], 0);\n        if (H[i] < 0) mf.addEdge(i, SNK, -H[i], 0);\n    }\n\n    struct Ref {\n        int u, v, node, edgeIndex;\n    };\n\n    vector<Ref> refs;\n\n    const long long CAP = 1000000000LL;\n    const long long W = 100000LL;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int u = cell_id(r, c);\n\n            if (r + 1 < N) {\n                int v = cell_id(r + 1, c);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n\n            if (c + 1 < N) {\n                int v = cell_id(r, c + 1);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n        }\n    }\n\n    auto [flow, cost] = mf.minCostFlow(SRC, SNK, total);\n    if (flow != total) return {};\n\n    vector<long long> right(N * (N - 1), 0), down((N - 1) * N, 0);\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            addSignedEdgeFlow(right, down, ref.u, ref.v, used);\n        }\n    }\n\n    vector<EdgeJob> jobs;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c + 1 < N; ++c) {\n            long long f = right[r * (N - 1) + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r, c + 1), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r, c + 1), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    for (int r = 0; r + 1 < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            long long f = down[r * N + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r + 1, c), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r + 1, c), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    return jobs;\n}\n\nvector<int> optimizeEdgeOrder(const vector<EdgeJob>& jobs) {\n    int m = (int)jobs.size();\n\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    auto link = [&](int a, int b) -> long long {\n        if (b == -2) {\n            if (a == -1) return 0;\n            return jobs[a].amount;\n        }\n\n        if (a == -1) {\n            return 100LL * DIST[0][jobs[b].s] + jobs[b].amount;\n        }\n\n        if (jobs[a].t == jobs[b].s) {\n            return llabs((long long)jobs[a].amount - jobs[b].amount);\n        }\n\n        return jobs[a].amount\n             + 100LL * DIST[jobs[a].t][jobs[b].s]\n             + jobs[b].amount;\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n    int prev = -1;\n\n    for (int k = 0; k < m; ++k) {\n        long long best = INFLL;\n        int bj = -1;\n\n        for (int j = 0; j < m; ++j) {\n            if (used[j]) continue;\n\n            long long sc = link(prev, j);\n            if (sc < best) {\n                best = sc;\n                bj = j;\n            }\n        }\n\n        used[bj] = true;\n        order.push_back(bj);\n        prev = bj;\n    }\n\n    int maxPass = (m > 500 ? 5 : 10);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        long long bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prevNode = (i == 0 ? -1 : order[i - 1]);\n            int nextNode = (i + 1 == m ? -2 : order[i + 1]);\n\n            long long removeDelta = link(prevNode, nextNode) - link(prevNode, x) - link(x, nextNode);\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                long long delta = removeDelta\n                                + link(before, x)\n                                + link(x, after)\n                                - link(before, after);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            long long oldInternal = 0;\n            long long newInternal = 0;\n            int before = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += link(order[r - 1], order[r]);\n                newInternal += link(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                long long oldCost = link(before, order[l]) + oldInternal + link(order[r], after);\n                long long newCost = link(before, order[r]) + newInternal + link(order[l], after);\n\n                long long delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nSolution makeEdgeRelaySolution(const vector<EdgeJob>& jobs) {\n    Solution sol;\n\n    vector<long long> delta(V, 0);\n\n    for (auto& e : jobs) {\n        if (DIST[e.s][e.t] != 1 || e.amount <= 0) {\n            sol.valid = false;\n            return sol;\n        }\n\n        delta[e.s] -= e.amount;\n        delta[e.t] += e.amount;\n    }\n\n    for (int i = 0; i < V; ++i) {\n        if (delta[i] != -H[i]) {\n            sol.valid = false;\n            return sol;\n        }\n    }\n\n    if (jobs.empty()) return sol;\n\n    vector<int> order = optimizeEdgeOrder(jobs);\n\n    for (int idx : order) {\n        const auto& e = jobs[idx];\n\n        if (sol.pos != e.s) {\n            if (sol.load > 0) sol.addUnload(sol.load);\n            sol.moveTo(e.s);\n        }\n\n        if (sol.load < e.amount) {\n            sol.addLoad(e.amount - sol.load);\n        } else if (sol.load > e.amount) {\n            sol.addUnload(sol.load - e.amount);\n        }\n\n        sol.moveTo(e.t);\n    }\n\n    if (sol.load > 0) sol.addUnload(sol.load);\n\n    return sol;\n}\n\nSolution makeGridRelaySolution(int variant) {\n    vector<EdgeJob> jobs = computeGridEdgeJobs(variant);\n    return makeEdgeRelaySolution(jobs);\n}\n\npair<int, int> transformCoord(int r, int c, int type) {\n    if (type == 0) return {r, c};\n    if (type == 1) return {c, N - 1 - r};\n    if (type == 2) return {N - 1 - r, N - 1 - c};\n    if (type == 3) return {N - 1 - c, r};\n    if (type == 4) return {r, N - 1 - c};\n    if (type == 5) return {N - 1 - r, c};\n    if (type == 6) return {c, r};\n    return {N - 1 - c, N - 1 - r};\n}\n\nSolution makeCycleSolution() {\n    vector<pair<int, int>> base;\n\n    for (int i = 0; i < N; ++i) base.push_back({i, 0});\n\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) base.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) base.push_back({i, j});\n        }\n    }\n\n    for (int j = N - 1; j >= 1; --j) base.push_back({0, j});\n\n    long long bestCost = INFLL;\n    vector<int> bestCycle;\n    int bestStart = -1;\n\n    for (int type = 0; type < 8; ++type) {\n        vector<int> cyc;\n        cyc.reserve(V);\n\n        for (auto [r, c] : base) {\n            auto [nr, nc] = transformCoord(r, c, type);\n            cyc.push_back(cell_id(nr, nc));\n        }\n\n        for (int rev = 0; rev < 2; ++rev) {\n            if (rev) reverse(cyc.begin(), cyc.end());\n\n            for (int s = 0; s < V; ++s) {\n                long long load = 0;\n                long long cost = BASE_COST + 100LL * DIST[0][cyc[s]];\n                bool ok = true;\n\n                for (int k = 0; k < V; ++k) {\n                    int id = cyc[(s + k) % V];\n                    load += H[id];\n\n                    if (load < 0) {\n                        ok = false;\n                        break;\n                    }\n\n                    if (k + 1 < V) {\n                        int nxt = cyc[(s + k + 1) % V];\n                        cost += 1LL * DIST[id][nxt] * (100 + load);\n                    }\n                }\n\n                if (ok && cost < bestCost) {\n                    bestCost = cost;\n                    bestCycle = cyc;\n                    bestStart = s;\n                }\n            }\n\n            if (rev) reverse(cyc.begin(), cyc.end());\n        }\n    }\n\n    Solution sol;\n\n    if (bestStart < 0) {\n        sol.valid = false;\n        return sol;\n    }\n\n    sol.moveTo(bestCycle[bestStart]);\n\n    for (int k = 0; k < V; ++k) {\n        int id = bestCycle[(bestStart + k) % V];\n\n        if (H[id] > 0) sol.addLoad(H[id]);\n        else if (H[id] < 0) sol.addUnload(-H[id]);\n\n        if (k + 1 < V) {\n            int nxt = bestCycle[(bestStart + k + 1) % V];\n            sol.moveTo(nxt);\n        }\n    }\n\n    return sol;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int inputN;\n    cin >> inputN;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> H[cell_id(i, j)];\n        }\n    }\n\n    for (int a = 0; a < V; ++a) {\n        int ar = a / N;\n        int ac = a % N;\n\n        for (int b = 0; b < V; ++b) {\n            int br = b / N;\n            int bc = b % N;\n            DIST[a][b] = abs(ar - br) + abs(ac - bc);\n        }\n    }\n\n    for (int i = 0; i < V; ++i) BASE_COST += abs(H[i]);\n\n    if (BASE_COST == 0) {\n        return 0;\n    }\n\n    Solution best;\n    best.cost = INFLL;\n    best.valid = false;\n\n    auto consider = [&](Solution&& sol) {\n        if (!sol.valid) return;\n        if (sol.load != 0) return;\n        if (sol.ops.size() > 100000) return;\n\n        if (!best.valid || sol.cost < best.cost) {\n            best = std::move(sol);\n        }\n    };\n\n    // Original greedy candidates.\n    vector<int> maxLoads = {0, 120, 250, 500};\n    vector<pair<int, int>> ratios = {{1, 1}, {3, 2}, {2, 1}};\n    vector<int> sourceModes = {0, 2};\n    vector<int> demandModes = {0, 1, 2};\n\n    for (int ml : maxLoads) {\n        for (auto [rn, rd] : ratios) {\n            if (ml == 0 && !(rn == 1 && rd == 1)) continue;\n\n            for (int sm : sourceModes) {\n                for (int dm : demandModes) {\n                    consider(makeGreedySolution(ml, rn, rd, sm, dm));\n                }\n            }\n        }\n    }\n\n    // Opportunistic path-servicing greedy candidates.\n    vector<int> caps = {120, 250, 500, 1000000000};\n\n    for (int cap : caps) {\n        for (auto [rn, rd] : ratios) {\n            for (int sm : sourceModes) {\n                for (int dm : {0, 1}) {\n                    consider(makeGreedyServiceSolution(cap, rn, rd, sm, dm, 2));\n                }\n            }\n        }\n    }\n\n    // A few deterministic path variants.\n    for (int pm : {0, 1}) {\n        consider(makeGreedyServiceSolution(250, 3, 2, 2, 1, pm));\n        consider(makeGreedyServiceSolution(500, 3, 2, 2, 1, pm));\n    }\n\n    // Transportation-flow based candidates.\n    for (int variant = 0; variant < 3; ++variant) {\n        vector<Flow> flows = computeMinCostFlows(variant);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // Greedy transportation variants.\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<Flow> flows = computeGreedyFlows(mode);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // New: aggregated adjacent-edge min-cost flow with chained execution.\n    for (int variant = 0; variant < 5; ++variant) {\n        consider(makeGridRelaySolution(variant));\n    }\n\n    // Hamiltonian fallback/candidate.\n    consider(makeCycleSolution());\n\n    for (const string& s : best.ops) {\n        cout << s << '\\n';\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, T;\n    int S, G;\n    int MAXV;\n\n    vector<vector<int>> X;\n    vector<int> initMax;\n\n    vector<vector<int>> neigh;\n    vector<int> degSlot;\n    vector<pair<int,int>> gridEdges;\n    vector<int> posOrder;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, int T_, const vector<vector<int>>& X_)\n        : N(N_), M(M_), T(T_), X(X_), rng(123456789) {\n        S = 2 * N * (N - 1);\n        G = N * N;\n        MAXV = M * 100;\n\n        initMax.assign(M, 1);\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n            initMax[l] = max(1, mx);\n        }\n\n        build_grid_info();\n    }\n\n    void build_grid_info() {\n        neigh.assign(S, {});\n        degSlot.assign(S, 0);\n        gridEdges.clear();\n\n        auto id = [&](int i, int j) { return i * N + j; };\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = id(i, j);\n                if (j + 1 < N) {\n                    int q = id(i, j + 1);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    gridEdges.push_back({p, q});\n                }\n                if (i + 1 < N) {\n                    int q = id(i + 1, j);\n                    neigh[p].push_back(q);\n                    neigh[q].push_back(p);\n                    gridEdges.push_back({p, q});\n                }\n            }\n        }\n\n        for (int p = 0; p < S; p++) degSlot[p] = (int)neigh[p].size();\n\n        posOrder.resize(G);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            if (degSlot[a] != degSlot[b]) return degSlot[a] > degSlot[b];\n\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n            double ca = (ai - (N - 1) / 2.0) * (ai - (N - 1) / 2.0)\n                      + (aj - (N - 1) / 2.0) * (aj - (N - 1) / 2.0);\n            double cb = (bi - (N - 1) / 2.0) * (bi - (N - 1) / 2.0)\n                      + (bj - (N - 1) / 2.0) * (bj - (N - 1) / 2.0);\n            return ca < cb;\n        });\n    }\n\n    inline double PW(const vector<double>& pairW, int a, int b) const {\n        return pairW[a * S + b];\n    }\n\n    double objective(\n        const vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        double ret = 0.0;\n\n        for (int p = 0; p < G; p++) {\n            ret += nodeCoef * degSlot[p] * nodeW[slotSeed[p]];\n        }\n\n        for (auto [p, q] : gridEdges) {\n            ret += PW(pairW, slotSeed[p], slotSeed[q]);\n        }\n\n        return ret;\n    }\n\n    double swap_delta(\n        const vector<int>& slotSeed,\n        int p,\n        int q,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        if (p == q) return 0.0;\n\n        int a = slotSeed[p];\n        int b = slotSeed[q];\n\n        double delta = 0.0;\n\n        delta += nodeCoef * degSlot[p] * (nodeW[b] - nodeW[a]);\n        delta += nodeCoef * degSlot[q] * (nodeW[a] - nodeW[b]);\n\n        for (int r : neigh[p]) {\n            if (r == q) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, b, c) - PW(pairW, a, c);\n        }\n\n        for (int r : neigh[q]) {\n            if (r == p) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, a, c) - PW(pairW, b, c);\n        }\n\n        return delta;\n    }\n\n    double local_search(\n        vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        int maxIter\n    ) const {\n        double cur = objective(slotSeed, pairW, nodeW, nodeCoef);\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            double bestD = 1e-9;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < S; p++) {\n                for (int q = p + 1; q < S; q++) {\n                    if (degSlot[p] == 0 && degSlot[q] == 0) continue;\n\n                    double d = swap_delta(slotSeed, p, q, pairW, nodeW, nodeCoef);\n                    if (d > bestD) {\n                        bestD = d;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur += bestD;\n        }\n\n        return cur;\n    }\n\n    vector<int> make_sorted_initial(const vector<double>& key, bool shuffleGrid) {\n        vector<int> seeds(S);\n        iota(seeds.begin(), seeds.end(), 0);\n\n        sort(seeds.begin(), seeds.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> slotSeed(S, -1);\n\n        for (int k = 0; k < G; k++) {\n            slotSeed[posOrder[k]] = seeds[k];\n        }\n        for (int k = G; k < S; k++) {\n            slotSeed[k] = seeds[k];\n        }\n\n        if (shuffleGrid) {\n            vector<int> planted;\n            for (int p = 0; p < G; p++) planted.push_back(slotSeed[p]);\n            shuffle(planted.begin(), planted.end(), rng);\n            for (int p = 0; p < G; p++) slotSeed[p] = planted[p];\n        }\n\n        return slotSeed;\n    }\n\n    vector<int> make_greedy_initial(\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        double noiseAmp\n    ) {\n        vector<int> slotSeed(S, -1);\n        vector<char> used(S, 0);\n\n        uniform_real_distribution<double> dist(-noiseAmp, noiseAmp);\n\n        for (int p : posOrder) {\n            int best = -1;\n            double bestScore = -1e100;\n\n            for (int s = 0; s < S; s++) {\n                if (used[s]) continue;\n\n                double sc = nodeCoef * degSlot[p] * nodeW[s];\n\n                for (int r : neigh[p]) {\n                    if (r < G && slotSeed[r] != -1) {\n                        sc += PW(pairW, s, slotSeed[r]);\n                    }\n                }\n\n                if (noiseAmp > 0) sc += dist(rng);\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = s;\n                }\n            }\n\n            slotSeed[p] = best;\n            used[best] = 1;\n        }\n\n        int out = G;\n        for (int s = 0; s < S; s++) {\n            if (!used[s]) slotSeed[out++] = s;\n        }\n\n        return slotSeed;\n    }\n\n    void compute_node_info(\n        int turn,\n        vector<int>& val,\n        vector<double>& nodeW,\n        vector<double>& criticalKey\n    ) const {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n\n        val.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) val[i] += X[i][l];\n        }\n\n        vector<double> rankBonus(S, 0.0);\n        vector<int> curMax(M, 1);\n\n        static const double rw[10] = {\n            260.0, 160.0, 100.0, 60.0, 36.0,\n            22.0, 14.0, 9.0, 6.0, 4.0\n        };\n\n        double rankScale = 1.15 - 0.25 * prog;\n\n        for (int l = 0; l < M; l++) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                return a < b;\n            });\n\n            curMax[l] = max(1, X[ids[0]][l]);\n\n            for (int r = 0; r < min(10, S); r++) {\n                int id = ids[r];\n                double frac0 = (double)X[id][l] / initMax[l];\n                double frac1 = (double)X[id][l] / curMax[l];\n                double frac = 0.6 * frac0 + 0.4 * frac1;\n                rankBonus[id] += rankScale * rw[r] * frac;\n            }\n\n            int second = X[ids[min(1, S - 1)]][l];\n            int gap = X[ids[0]][l] - second;\n            rankBonus[ids[0]] += (1.0 - 0.3 * prog) * 3.0 * gap;\n        }\n\n        nodeW.assign(S, 0.0);\n        criticalKey.assign(S, 0.0);\n\n        double quadCoef = 0.85 - 0.30 * prog;\n\n        for (int i = 0; i < S; i++) {\n            double quad = 0.0;\n            for (int l = 0; l < M; l++) {\n                quad += (double)X[i][l] * X[i][l] / initMax[l];\n            }\n\n            nodeW[i] = val[i] + quadCoef * quad + rankBonus[i];\n            criticalKey[i] = nodeW[i] + 0.75 * rankBonus[i];\n        }\n    }\n\n    vector<double> build_pair_quantile(double beta, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double mean = 0.5 * (ysum[i] + ysum[j]);\n                double var = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double d = a - b;\n                    var += 0.25 * d * d;\n                    pot += max(a, b);\n                }\n\n                double sd = sqrt(max(0.0, var));\n                double w = (1.0 - potCoef) * (mean + beta * sd) + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    vector<double> build_pair_ce(double tau, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double ce = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double mx = max(a, b);\n                    double diff = fabs(a - b);\n\n                    ce += mx + tau * log(0.5 * (1.0 + exp(-diff / tau)));\n                    pot += mx;\n                }\n\n                double w = (1.0 - potCoef) * ce + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    void build_raw_pair_stats(\n        const vector<int>& val,\n        vector<double>& mu,\n        vector<double>& sd\n    ) const {\n        mu.assign(S * S, 0.0);\n        sd.assign(S * S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            mu[i * S + i] = val[i];\n            sd[i * S + i] = 0.0;\n\n            for (int j = i + 1; j < S; j++) {\n                double m = 0.5 * (val[i] + val[j]);\n                double var = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double d = X[i][l] - X[j][l];\n                    var += 0.25 * d * d;\n                }\n\n                double s = sqrt(max(0.0, var));\n\n                mu[i * S + j] = mu[j * S + i] = m;\n                sd[i * S + j] = sd[j * S + i] = s;\n            }\n        }\n    }\n\n    static inline double normal_cdf(double z) {\n        if (z < -8.0) return 0.0;\n        if (z > 8.0) return 1.0;\n        return 0.5 * erfc(-z * 0.70710678118654752440);\n    }\n\n    double approx_expected_max_normal(\n        const vector<int>& slotSeed,\n        const vector<double>& mu,\n        const vector<double>& sd\n    ) const {\n        const int STEP = 5;\n        double ret = 0.0;\n\n        for (int s = 0; s < MAXV; s += STEP) {\n            double prod = 1.0;\n\n            for (auto [p, q] : gridEdges) {\n                int a = slotSeed[p];\n                int b = slotSeed[q];\n                double m = mu[a * S + b];\n                double sig = sd[a * S + b];\n\n                double cdf;\n                if (sig < 1e-9) {\n                    cdf = (m <= s ? 1.0 : 0.0);\n                } else {\n                    cdf = normal_cdf((s + 0.5 - m) / sig);\n                }\n\n                prod *= cdf;\n                if (prod <= 1e-15) {\n                    prod = 0.0;\n                    break;\n                }\n            }\n\n            ret += (1.0 - prod) * STEP;\n        }\n\n        return ret;\n    }\n\n    double coord_max_expectation(const vector<int>& slotSeed) const {\n        double total = 0.0;\n\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n\n            for (int th = 1; th <= mx; th++) {\n                double prod = 1.0;\n\n                for (auto [p, q] : gridEdges) {\n                    int a = X[slotSeed[p]][l];\n                    int b = X[slotSeed[q]][l];\n\n                    int ge = 0;\n                    if (a >= th) ge++;\n                    if (b >= th) ge++;\n\n                    double pLess = 1.0 - 0.5 * ge;\n\n                    if (pLess <= 0.0) {\n                        prod = 0.0;\n                        break;\n                    }\n\n                    prod *= pLess;\n                    if (prod <= 1e-15) {\n                        prod = 0.0;\n                        break;\n                    }\n                }\n\n                total += 1.0 - prod;\n            }\n        }\n\n        return total;\n    }\n\n    vector<float> build_pair_cdf() const {\n        int L = MAXV + 1;\n        vector<float> cdf(S * S * L, 0.0f);\n\n        vector<double> dp(L, 0.0), ndp(L, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i; j < S; j++) {\n                fill(dp.begin(), dp.end(), 0.0);\n                dp[0] = 1.0;\n\n                int curMaxSum = 0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = X[i][l];\n                    int b = X[j][l];\n                    int nxtMaxSum = curMaxSum + max(a, b);\n\n                    fill(ndp.begin(), ndp.begin() + nxtMaxSum + 1, 0.0);\n\n                    if (a == b) {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            ndp[s + a] += dp[s];\n                        }\n                    } else {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            double p = 0.5 * dp[s];\n                            ndp[s + a] += p;\n                            ndp[s + b] += p;\n                        }\n                    }\n\n                    dp.swap(ndp);\n                    curMaxSum = nxtMaxSum;\n                }\n\n                int idx1 = (i * S + j) * L;\n                int idx2 = (j * S + i) * L;\n\n                double cum = 0.0;\n                for (int s = 0; s <= MAXV; s++) {\n                    if (s <= curMaxSum) cum += dp[s];\n                    if (cum < 0.0) cum = 0.0;\n                    if (cum > 1.0) cum = 1.0;\n\n                    float v = (float)cum;\n                    cdf[idx1 + s] = v;\n                    cdf[idx2 + s] = v;\n                }\n            }\n        }\n\n        return cdf;\n    }\n\n    vector<double> build_pair_tail(\n        const vector<float>& cdf,\n        int threshold,\n        double scale\n    ) const {\n        int L = MAXV + 1;\n        vector<double> pairW(S * S, 0.0);\n\n        int start = max(0, threshold - 1);\n        if (start >= MAXV) return pairW;\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                int idx = (i * S + j) * L;\n\n                double tail = 0.0;\n                for (int s = start; s < MAXV; s++) {\n                    double f = cdf[idx + s];\n                    if (f < 0.0) f = 0.0;\n                    if (f > 1.0) f = 1.0;\n                    tail += 1.0 - f;\n                }\n\n                tail *= scale;\n\n                pairW[i * S + j] = pairW[j * S + i] = tail;\n            }\n        }\n\n        return pairW;\n    }\n\n    double exact_expected_max(\n        const vector<int>& slotSeed,\n        const vector<float>& cdf\n    ) const {\n        int L = MAXV + 1;\n        vector<double> prod(MAXV, 1.0);\n\n        for (auto [p, q] : gridEdges) {\n            int a = slotSeed[p];\n            int b = slotSeed[q];\n            int idx = (a * S + b) * L;\n\n            for (int s = 0; s < MAXV; s++) {\n                double f = cdf[idx + s];\n                if (f < 0.0) f = 0.0;\n                if (f > 1.0) f = 1.0;\n                prod[s] *= f;\n            }\n        }\n\n        double ret = 0.0;\n        for (int s = 0; s < MAXV; s++) {\n            ret += 1.0 - prod[s];\n        }\n\n        return ret;\n    }\n\n    vector<vector<int>> solve_turn(int turn) {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n        bool isFinal = (turn == T - 1);\n\n        vector<int> val;\n        vector<double> nodeW, criticalKey;\n        compute_node_info(turn, val, nodeW, criticalKey);\n\n        vector<double> valKey(S);\n        for (int i = 0; i < S; i++) valKey[i] = val[i];\n\n        vector<double> rawMu, rawSd;\n        build_raw_pair_stats(val, rawMu, rawSd);\n\n        double masterNodeCoef = max(0.09, 0.19 - 0.07 * prog);\n        if (isFinal) masterNodeCoef *= 0.55;\n\n        vector<double> masterPairW =\n            build_pair_quantile(\n                1.55 + 0.45 * prog,\n                0.12 + 0.10 * prog,\n                0.16 * (1.0 - prog)\n            );\n\n        vector<float> finalCDF;\n        if (isFinal) finalCDF = build_pair_cdf();\n\n        struct Work {\n            vector<double> pairW;\n            double nodeCoef;\n            int iter;\n        };\n\n        vector<Work> works;\n\n        works.push_back(Work{\n            masterPairW,\n            masterNodeCoef,\n            isFinal ? 90 : 105\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                50.0 - 20.0 * prog,\n                0.06 + 0.17 * prog,\n                0.0\n            ),\n            (isFinal ? 0.07 : max(0.11, 0.22 - 0.07 * prog)),\n            isFinal ? 75 : 85\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                2.00 + 0.45 * prog,\n                0.18 + 0.12 * prog,\n                0.10 * (1.0 - prog)\n            ),\n            (isFinal ? 0.055 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 80\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                1.05 + 0.25 * prog,\n                0.38,\n                0.20 * (1.0 - prog)\n            ),\n            (isFinal ? 0.06 : max(0.09, 0.18 - 0.05 * prog)),\n            isFinal ? 70 : 75\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                24.0 - 10.0 * prog,\n                0.08 + 0.12 * prog,\n                0.15 * (1.0 - prog)\n            ),\n            (isFinal ? 0.05 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 75\n        });\n\n        if (turn >= T - 3) {\n            works.push_back(Work{\n                build_pair_quantile(\n                    2.35 + 0.35 * prog,\n                    0.26,\n                    0.0\n                ),\n                isFinal ? 0.04 : 0.08,\n                isFinal ? 80 : 70\n            });\n        }\n\n        if (isFinal) {\n            works.push_back(Work{\n                build_pair_ce(14.0, 0.18, 0.0),\n                0.04,\n                80\n            });\n            works.push_back(Work{\n                build_pair_ce(9.0, 0.24, 0.0),\n                0.035,\n                80\n            });\n\n            int bestNow = 0;\n            for (int v : val) bestNow = max(bestNow, v);\n\n            vector<int> thresholds = {\n                bestNow - 30,\n                bestNow,\n                bestNow + 25,\n                bestNow + 50\n            };\n\n            for (int th : thresholds) {\n                works.push_back(Work{\n                    build_pair_tail(finalCDF, th, 10.0),\n                    0.02,\n                    85\n                });\n            }\n        }\n\n        double bestScore = -1e100;\n        vector<int> bestSlotSeed;\n\n        auto eval_candidate = [&](const vector<int>& slotSeed) -> double {\n            if (isFinal) {\n                return exact_expected_max(slotSeed, finalCDF);\n            } else {\n                double edgeObj = objective(slotSeed, masterPairW, nodeW, masterNodeCoef);\n                double geneObj = coord_max_expectation(slotSeed);\n                double maxObj = approx_expected_max_normal(slotSeed, rawMu, rawSd);\n\n                double geneLambda = 22.0 - 10.0 * prog;\n                double maxLambda = 13.0 + 10.0 * prog;\n\n                return edgeObj + geneLambda * geneObj + maxLambda * maxObj;\n            }\n        };\n\n        auto process = [&](vector<int> start, const Work& w) {\n            local_search(start, w.pairW, nodeW, w.nodeCoef, w.iter);\n            double sc = eval_candidate(start);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestSlotSeed = start;\n            }\n        };\n\n        uniform_real_distribution<double> noise(-1.0, 1.0);\n\n        for (int wi = 0; wi < (int)works.size(); wi++) {\n            const Work& w = works[wi];\n\n            if (wi == 0) {\n                process(make_sorted_initial(nodeW, false), w);\n                process(make_sorted_initial(valKey, false), w);\n                process(make_sorted_initial(criticalKey, false), w);\n                process(make_sorted_initial(criticalKey, true), w);\n            }\n\n            if (wi == 1) {\n                process(make_sorted_initial(nodeW, false), w);\n            }\n\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 0.0), w);\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 38.0 + 13.0 * wi), w);\n\n            if (wi < 5) {\n                vector<double> key = criticalKey;\n                double amp = 55.0 + 25.0 * wi;\n                for (int i = 0; i < S; i++) key[i] += amp * noise(rng);\n                process(make_sorted_initial(key, wi % 2), w);\n            }\n        }\n\n        if (bestSlotSeed.empty()) {\n            bestSlotSeed = make_sorted_initial(valKey, false);\n        }\n\n        vector<vector<int>> A(N, vector<int>(N));\n\n        for (int p = 0; p < G; p++) {\n            A[p / N][p % N] = bestSlotSeed[p];\n        }\n\n        return A;\n    }\n\n    void update_X(const vector<vector<int>>& nx) {\n        X = nx;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n\n    int S = 2 * N * (N - 1);\n    vector<vector<int>> X(S, vector<int>(M));\n\n    for (int i = 0; i < S; i++) {\n        for (int l = 0; l < M; l++) cin >> X[i][l];\n    }\n\n    Solver solver(N, M, T, X);\n\n    for (int t = 0; t < T; t++) {\n        auto A = solver.solve_turn(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << A[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        vector<vector<int>> nx(S, vector<int>(M));\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                if (!(cin >> nx[i][l])) return 0;\n            }\n        }\n\n        solver.update_X(nx);\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\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 Assignment {\n    int f;\n    int dir;\n    int cell;\n};\n\nstruct Estimate {\n    int cnt = 0;\n    int maxrot = 0;\n    int pairCnt = 0;\n};\n\nstruct Choice {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct NextMove {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nstruct PlanResult {\n    int Vp = 0;\n    vector<int> parent;\n    vector<int> edgeLen;\n    int initX = 0, initY = 0;\n    vector<string> ops;\n    long long score = (1LL << 60);\n    bool complete = false;\n    bool valid = false;\n    int remT = 0;\n};\n\nclass StarPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    vector<int> outLen;\n    vector<int> len;\n    vector<int> dir;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    StarPlanner(int N_, int V_,\n                const vector<unsigned char>& src0,\n                const vector<unsigned char>& tgt0,\n                const vector<int>& lengths,\n                int scoreMode_,\n                int strategy_,\n                double pairBonus_)\n        : N(N_), Vp(V_), k(V_ - 1), C(N_ * N_),\n          outLen(lengths),\n          len(V_, 0), dir(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_), pairBonus(pairBonus_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 1; i <= k; i++) len[i] = lengths[i - 1];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else runHybrid();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n        for (int i = 1; i < Vp; i++) {\n            res.parent[i] = 0;\n            res.edgeLen[i] = outLen[i - 1];\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int f, int d) const {\n        int x = rootX + DX[d] * len[f];\n        int y = rootY + DY[d] * len[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        return cellAt(rx, ry, f, dir[f]);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    Estimate estimateAtRoot(int x, int y, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int r = rotDist(dir[f], d);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) {\n            return (travel + 0.3) / cnt + 0.002 * dist;\n        } else {\n            return travel - 1.5 * (cnt - 1) + 0.01 * dist;\n        }\n    }\n\n    Choice findBestRoot(int mode) {\n        Choice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, mode);\n                if (e.cnt == 0) continue;\n\n                int dist = abs(rx - x) + abs(ry - y);\n                int travel = max(dist, max(e.maxrot, 1));\n                double sc = rootScore(travel, e.cnt, dist);\n                sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                if (!best.exists ||\n                    sc < best.score - 1e-12 ||\n                    (fabs(sc - best.score) < 1e-12 &&\n                     (e.cnt > best.cnt ||\n                      (e.cnt == best.cnt && travel < best.travel)))) {\n                    best.exists = true;\n                    best.x = x;\n                    best.y = y;\n                    best.score = sc;\n                    best.cnt = e.cnt;\n                    best.travel = travel;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, PICK);\n                if (e.cnt == 0) continue;\n\n                int travel = max(e.maxrot, 1);\n                int center = abs(x - N / 2) + abs(y - N / 2);\n                double sc = (travel + 0.3) / e.cnt\n                            - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                            + 0.0005 * center;\n\n                if (sc < bestScore - 1e-12 ||\n                    (fabs(sc - bestScore) < 1e-12 &&\n                     (e.cnt > bestCnt ||\n                      (e.cnt == bestCnt && center < bestCenter)))) {\n                    bestScore = sc;\n                    bestCnt = e.cnt;\n                    bestCenter = center;\n                    rx = x;\n                    ry = y;\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int mode) {\n        struct Edge {\n            int cellIdx;\n            int dir;\n            int rot;\n        };\n\n        vector<int> fingers;\n        vector<vector<Edge>> edges;\n        vector<int> cells;\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                edges[li].push_back({tmpIndex[cid], d, rotDist(dir[f], d)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const Edge& a, const Edge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> order(L);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return edges[a].size() < edges[b].size();\n        });\n\n        vector<int> matchCell(R, -1), matchDir(R, -1);\n        vector<unsigned char> seen(R);\n\n        function<bool(int)> dfs = [&](int li) -> bool {\n            for (const Edge& e : edges[li]) {\n                if (seen[e.cellIdx]) continue;\n                seen[e.cellIdx] = 1;\n\n                if (matchCell[e.cellIdx] == -1 || dfs(matchCell[e.cellIdx])) {\n                    matchCell[e.cellIdx] = li;\n                    matchDir[e.cellIdx] = e.dir;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int li : order) {\n            if (edges[li].empty()) continue;\n            fill(seen.begin(), seen.end(), 0);\n            dfs(li);\n        }\n\n        vector<Assignment> assigns;\n        for (int ci = 0; ci < R; ci++) {\n            if (matchCell[ci] == -1) continue;\n            int li = matchCell[ci];\n            assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n        }\n\n        sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n            return a.f < b.f;\n        });\n\n        return assigns;\n    }\n\n    NextMove fallbackNext(int mode) {\n        NextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 1; f <= k; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int d = 0; d < 4; d++) {\n                    int tx = cx - DX[d] * len[f];\n                    int ty = cy - DY[d] * len[f];\n                    if (!inside(tx, ty)) continue;\n\n                    int md = abs(rx - tx) + abs(ry - ty);\n                    int travel = max(md, max(rotDist(dir[f], d), 1));\n                    double sc = travel;\n\n                    if (!best.exists || sc < best.score) {\n                        best.exists = true;\n                        best.x = tx;\n                        best.y = ty;\n                        best.score = sc;\n                        best.assigns = {Assignment{f, d, cid}};\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    NextMove makeNext(int mode, const Choice& ch) {\n        NextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    NextMove chooseNext(int mode) {\n        return makeNext(mode, findBestRoot(mode));\n    }\n\n    int potentialForRoot(int nx, int ny,\n                         const vector<unsigned char>& selected,\n                         const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        int cnt = 0;\n\n        static const int DELTA[3] = {0, 1, 3};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(nx, ny, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                mark[cid] = st;\n                cnt++;\n                break;\n            }\n        }\n\n        return cnt;\n    }\n\n    char chooseMoveChar(int tx, int ty,\n                        const vector<unsigned char>& selected,\n                        const vector<unsigned char>& reserved) {\n        vector<pair<char, pair<int, int>>> cand;\n\n        if (rx < tx) cand.push_back({'D', {rx + 1, ry}});\n        if (rx > tx) cand.push_back({'U', {rx - 1, ry}});\n        if (ry < ty) cand.push_back({'R', {rx, ry + 1}});\n        if (ry > ty) cand.push_back({'L', {rx, ry - 1}});\n\n        if (cand.empty()) return '.';\n        if (cand.size() == 1) return cand[0].first;\n\n        int bestPot = -1;\n        char bestChar = cand[0].first;\n        int bestDimRemain = -1;\n\n        for (auto& c : cand) {\n            int pot = potentialForRoot(c.second.first, c.second.second, selected, reserved);\n            bool vertical = (c.first == 'U' || c.first == 'D');\n            int dimRemain = vertical ? abs(tx - rx) : abs(ty - ry);\n\n            if (pot > bestPot || (pot == bestPot && dimRemain > bestDimRemain)) {\n                bestPot = pot;\n                bestChar = c.first;\n                bestDimRemain = dimRemain;\n            }\n        }\n\n        return bestChar;\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenDir = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(rx, ry, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenDir = nd;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                dir[f] = chosenDir;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 1; f <= k; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetDir(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxrot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetDir[a.f] = a.dir;\n            reserved[a.cell] = 1;\n            maxrot = max(maxrot, rotDist(dir[a.f], a.dir));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max(md, max(maxrot, 1));\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty, selected, reserved);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (dir[f] != targetDir[f]) {\n                    char rc = rotateStep(dir[f], targetDir[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (dir[a.f] != a.dir) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                NextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                NextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) {\n                mode = PICK;\n            } else {\n                mode = DROP;\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n};\n\nstruct PChoice {\n    bool exists = false;\n    int x = 0, y = 0, sdir = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct PNextMove {\n    bool exists = false;\n    int x = 0, y = 0, sdir = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nclass PalmPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    int A;\n    vector<int> leafLen;\n\n    int sd = 0;\n    vector<int> rel;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus = 0.25;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    PalmPlanner(int N_, int V_,\n                const vector<unsigned char>& src0,\n                const vector<unsigned char>& tgt0,\n                int A_,\n                const vector<int>& lengths,\n                int scoreMode_,\n                int strategy_)\n        : N(N_), Vp(V_), k(V_ - 2), C(N_ * N_),\n          A(A_), leafLen(V_, 0), rel(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 0; i < k; i++) leafLen[i + 2] = lengths[i];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else runHybrid();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n\n        res.parent[1] = 0;\n        res.edgeLen[1] = A;\n        for (int f = 2; f < Vp; f++) {\n            res.parent[f] = 1;\n            res.edgeLen[f] = leafLen[f];\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int shoulderDir, int f, int absDir) const {\n        int x = rootX + DX[shoulderDir] * A + DX[absDir] * leafLen[f];\n        int y = rootY + DY[shoulderDir] * A + DY[absDir] * leafLen[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        int ad = (sd + rel[f]) & 3;\n        return cellAt(rx, ry, sd, f, ad);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    Estimate estimateAtState(int x, int y, int sdir, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 2; f < Vp; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int ad = 0; ad < 4; ad++) {\n                int cid = cellAt(x, y, sdir, f, ad);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int tr = (ad - sdir + 4) & 3;\n                int r = rotDist(rel[f], tr);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) return (travel + 0.3) / cnt + 0.002 * dist;\n        return travel - 1.4 * (cnt - 1) + 0.01 * dist;\n    }\n\n    PChoice findBestState(int mode) {\n        PChoice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    Estimate e = estimateAtState(x, y, sdir, mode);\n                    if (e.cnt == 0) continue;\n\n                    int dist = abs(rx - x) + abs(ry - y);\n                    int travel = max({dist, rotDist(sd, sdir), e.maxrot, 1});\n                    double sc = rootScore(travel, e.cnt, dist + rotDist(sd, sdir));\n                    sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                    if (!best.exists ||\n                        sc < best.score - 1e-12 ||\n                        (fabs(sc - best.score) < 1e-12 &&\n                         (e.cnt > best.cnt ||\n                          (e.cnt == best.cnt && travel < best.travel)))) {\n                        best.exists = true;\n                        best.x = x;\n                        best.y = y;\n                        best.sdir = sdir;\n                        best.score = sc;\n                        best.cnt = e.cnt;\n                        best.travel = travel;\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    Estimate e = estimateAtState(x, y, sdir, PICK);\n                    if (e.cnt == 0) continue;\n\n                    int travel = max({rotDist(0, sdir), e.maxrot, 1});\n                    int center = abs(x - N / 2) + abs(y - N / 2);\n                    double sc = (travel + 0.3) / e.cnt\n                                - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                                + 0.0005 * center;\n\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) < 1e-12 &&\n                         (e.cnt > bestCnt ||\n                          (e.cnt == bestCnt && center < bestCenter)))) {\n                        bestScore = sc;\n                        bestCnt = e.cnt;\n                        bestCenter = center;\n                        rx = x;\n                        ry = y;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int sdir, int mode) {\n        struct Edge {\n            int cellIdx;\n            int dir;\n            int rot;\n        };\n\n        vector<int> fingers;\n        vector<vector<Edge>> edges;\n        vector<int> cells;\n\n        for (int f = 2; f < Vp; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int ad = 0; ad < 4; ad++) {\n                int cid = cellAt(x, y, sdir, f, ad);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                int tr = (ad - sdir + 4) & 3;\n                edges[li].push_back({tmpIndex[cid], ad, rotDist(rel[f], tr)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const Edge& a, const Edge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> order(L);\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return edges[a].size() < edges[b].size();\n        });\n\n        vector<int> matchCell(R, -1), matchDir(R, -1);\n        vector<unsigned char> seen(R);\n\n        function<bool(int)> dfs = [&](int li) -> bool {\n            for (const Edge& e : edges[li]) {\n                if (seen[e.cellIdx]) continue;\n                seen[e.cellIdx] = 1;\n\n                if (matchCell[e.cellIdx] == -1 || dfs(matchCell[e.cellIdx])) {\n                    matchCell[e.cellIdx] = li;\n                    matchDir[e.cellIdx] = e.dir;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int li : order) {\n            if (edges[li].empty()) continue;\n            fill(seen.begin(), seen.end(), 0);\n            dfs(li);\n        }\n\n        vector<Assignment> assigns;\n        for (int ci = 0; ci < R; ci++) {\n            if (matchCell[ci] == -1) continue;\n            int li = matchCell[ci];\n            assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n        }\n\n        sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n            return a.f < b.f;\n        });\n\n        return assigns;\n    }\n\n    PNextMove fallbackNext(int mode) {\n        PNextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 2; f < Vp; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    for (int ad = 0; ad < 4; ad++) {\n                        int tx = cx - DX[sdir] * A - DX[ad] * leafLen[f];\n                        int ty = cy - DY[sdir] * A - DY[ad] * leafLen[f];\n                        if (!inside(tx, ty)) continue;\n\n                        int tr = (ad - sdir + 4) & 3;\n                        int travel = max({abs(rx - tx) + abs(ry - ty),\n                                          rotDist(sd, sdir),\n                                          rotDist(rel[f], tr),\n                                          1});\n                        double sc = travel;\n\n                        if (!best.exists || sc < best.score) {\n                            best.exists = true;\n                            best.x = tx;\n                            best.y = ty;\n                            best.sdir = sdir;\n                            best.score = sc;\n                            best.assigns = {Assignment{f, ad, cid}};\n                        }\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    PNextMove makeNext(int mode, const PChoice& ch) {\n        PNextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, ch.sdir, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.sdir = ch.sdir;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    PNextMove chooseNext(int mode) {\n        return makeNext(mode, findBestState(mode));\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    char chooseMoveChar(int tx, int ty) {\n        if (rx < tx) return 'D';\n        if (rx > tx) return 'U';\n        if (ry < ty) return 'R';\n        if (ry > ty) return 'L';\n        return '.';\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 2; f < Vp; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenRel = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nr = (rel[f] + DELTA[oi]) & 3;\n                int ad = (sd + nr) & 3;\n                int cid = cellAt(rx, ry, sd, f, ad);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenRel = nr;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                rel[f] = chosenRel;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 2; f < Vp; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, int tsd, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetRel(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxLeafRot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetRel[a.f] = (a.dir - tsd + 4) & 3;\n            reserved[a.cell] = 1;\n            maxLeafRot = max(maxLeafRot, rotDist(rel[a.f], targetRel[a.f]));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max({md, rotDist(sd, tsd), maxLeafRot, 1});\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            if (sd != tsd) {\n                char rc = rotateStep(sd, tsd);\n                cmd[1] = rc;\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (rel[f] != targetRel[f]) {\n                    char rc = rotateStep(rel[f], targetRel[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty || sd != tsd) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (rel[a.f] != targetRel[a.f]) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                PNextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                PNextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            PChoice cp, cd;\n            if (canPick) cp = findBestState(PICK);\n            if (canDrop) cd = findBestState(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) mode = PICK;\n            else mode = DROP;\n\n            PNextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            PChoice cp, cd;\n            if (canPick) cp = findBestState(PICK);\n            if (canDrop) cd = findBestState(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            PNextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\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\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    int C = N * N;\n    vector<unsigned char> src(C, 0), tgt(C, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int cid = i * N + j;\n            if (s[i][j] == '1' && t[i][j] == '0') src[cid] = 1;\n            if (s[i][j] == '0' && t[i][j] == '1') tgt[cid] = 1;\n        }\n    }\n\n    int maxL = max(1, N / 2);\n\n    auto buildLengthSets = [&](int K) {\n        vector<vector<int>> sets;\n\n        auto clampLen = [&](int x) {\n            return max(1, min(maxL, x));\n        };\n\n        auto addSet = [&](vector<int> a) {\n            if ((int)a.size() != K) return;\n            for (int& x : a) x = clampLen(x);\n            for (auto& b : sets) {\n                if (a == b) return;\n            }\n            sets.push_back(a);\n        };\n\n        if (K <= 0) return sets;\n\n        auto cycleSet = [&](int L) {\n            L = max(1, min(L, maxL));\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = 1 + (i % L);\n            return a;\n        };\n\n        auto repeatVals = [&](vector<int> vals) {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = vals[i % vals.size()];\n            return a;\n        };\n\n        addSet(cycleSet(maxL));\n        addSet(cycleSet(6));\n        addSet(cycleSet(4));\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    a[i] = (int)llround(1.0 + (double)i * (maxL - 1) / (K - 1));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                a[i] = (int)llround((i + 0.5) * maxL / K);\n                if (a[i] < 1) a[i] = 1;\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    double r = (double)i / (K - 1);\n                    a[i] = (int)llround(pow((double)maxL, r));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                if (i % 2 == 0) a[i] = 1 + (i / 2) % maxL;\n                else a[i] = maxL - (i / 2) % maxL;\n            }\n            addSet(a);\n        }\n\n        addSet(vector<int>(K, 1));\n        addSet(vector<int>(K, maxL));\n        addSet(vector<int>(K, max(1, maxL / 2)));\n\n        addSet(repeatVals(vector<int>{1, maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 2), maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 3), max(1, 2 * maxL / 3), maxL}));\n        addSet(repeatVals(vector<int>{max(1, maxL / 4), max(1, maxL / 2), max(1, 3 * maxL / 4), maxL}));\n\n        return sets;\n    };\n\n    vector<vector<int>> starLengthSets = buildLengthSets(V - 1);\n\n    auto startTime = chrono::steady_clock::now();\n\n    auto elapsedMs = [&]() {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration_cast<chrono::milliseconds>(now - startTime).count();\n    };\n\n    PlanResult best;\n\n    auto consider = [&](PlanResult&& res) {\n        if (res.valid &&\n            (res.score < best.score ||\n             (res.score == best.score && res.ops.size() < best.ops.size()))) {\n            best = std::move(res);\n        }\n    };\n\n    struct StarParam {\n        int li;\n        int sm;\n        int st;\n        double pb;\n    };\n\n    vector<StarParam> starParams;\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.0});\n\n    int split = (int)starParams.size();\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 1, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 1, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.30});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.30});\n\n    auto runStarRange = [&](int l, int r) {\n        for (int idx = l; idx < r; idx++) {\n            if (idx > l && elapsedMs() > 2760) break;\n\n            auto p = starParams[idx];\n            StarPlanner planner(N, V, src, tgt, starLengthSets[p.li], p.sm, p.st, p.pb);\n            PlanResult res = planner.run();\n            consider(std::move(res));\n        }\n    };\n\n    runStarRange(0, split);\n\n    if (elapsedMs() < 2300 && V >= 5) {\n        int kp = V - 2;\n        vector<vector<int>> palmLengthSets = buildLengthSets(kp);\n        vector<int> As = {\n            maxL,\n            max(1, (2 * maxL + 1) / 3),\n            max(1, maxL / 2)\n        };\n        sort(As.begin(), As.end());\n        As.erase(unique(As.begin(), As.end()), As.end());\n        reverse(As.begin(), As.end());\n\n        int limSets = min(5, (int)palmLengthSets.size());\n        vector<int> palmStrategies = {0, 2, 1};\n\n        for (int A : As) {\n            for (int li = 0; li < limSets; li++) {\n                for (int stg : palmStrategies) {\n                    if (elapsedMs() > 2760) goto palm_done;\n\n                    PalmPlanner planner(N, V, src, tgt, A, palmLengthSets[li], 0, stg);\n                    PlanResult res = planner.run();\n                    consider(std::move(res));\n                }\n            }\n        }\n    }\npalm_done:\n\n    if (elapsedMs() < 2760) {\n        runStarRange(split, (int)starParams.size());\n    }\n\n    if (!best.valid) {\n        best.valid = true;\n        best.Vp = V;\n        best.parent.assign(V, -1);\n        best.edgeLen.assign(V, 0);\n        vector<int> lens = starLengthSets.empty() ? vector<int>(V - 1, 1) : starLengthSets[0];\n\n        for (int i = 1; i < V; i++) {\n            best.parent[i] = 0;\n            best.edgeLen[i] = lens[i - 1];\n        }\n        best.initX = 0;\n        best.initY = 0;\n        best.ops.clear();\n    }\n\n    cout << best.Vp << '\\n';\n    for (int i = 1; i < best.Vp; i++) {\n        cout << best.parent[i] << ' ' << best.edgeLen[i] << '\\n';\n    }\n    cout << best.initX << ' ' << best.initY << '\\n';\n\n    for (const string& op : best.ops) {\n        cout << op << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing ll = long long;\nusing uchar = unsigned char;\n\nconstexpr int CMAX = 100000;\nconstexpr int MAXLEN = 400000;\nconstexpr int MAXV = 1000;\nconstexpr int INF = 1e9;\n\nstruct Fish {\n    int x, y, w;\n};\n\nstruct Candidate {\n    int approx;\n    int cat;\n    vector<pair<int,int>> poly;\n};\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nvector<Fish> fishes;\nvector<int> fishOrderY;\nvector<Candidate> candidates;\n\nvector<pair<int,int>> bestPoly;\nvector<pair<int,int>> bestSafePoly;\nint bestApprox = -1;\nint bestSafeApprox = -1;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nvector<pair<int,int>> square_poly() {\n    return {{0,0}, {CMAX,0}, {CMAX,CMAX}, {0,CMAX}};\n}\n\nuint64_t poly_hash(const vector<pair<int,int>>& p) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)p.size();\n    h *= 1099511628211ULL;\n    for (auto [x, y] : p) {\n        h ^= (uint64_t)(x + 1000003LL * y);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvoid record_candidate(const vector<pair<int,int>>& poly, int approx, int cat) {\n    if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return;\n    if (approx < 0) return;\n    if (approx == 0 && bestApprox >= 0 && !candidates.empty()) return;\n\n    if (approx > bestApprox) {\n        bestApprox = approx;\n        bestPoly = poly;\n    }\n\n    if ((cat == 0 || cat == 3) && approx > bestSafeApprox) {\n        bestSafeApprox = approx;\n        bestSafePoly = poly;\n    }\n\n    candidates.push_back({approx, cat, poly});\n\n    if (candidates.size() > 900) {\n        nth_element(candidates.begin(), candidates.begin() + 650, candidates.end(),\n                    [](const Candidate& a, const Candidate& b) {\n                        return a.approx > b.approx;\n                    });\n        candidates.resize(650);\n    }\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 <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sum(int idx) const {\n        int r = 0;\n        for (; idx > 0; idx -= idx & -idx) r += bit[idx];\n        return r;\n    }\n    int all() const {\n        return sum(n);\n    }\n};\n\nint exact_score(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n\n    int minx = CMAX, maxx = 0, miny = CMAX, maxy = 0;\n    for (auto [x, y] : poly) {\n        minx = min(minx, x);\n        maxx = max(maxx, x);\n        miny = min(miny, y);\n        maxy = max(maxy, y);\n    }\n\n    struct VEdge {\n        int x, y1, y2;\n    };\n\n    struct Event {\n        int y, xi, delta;\n        bool operator<(const Event& other) const {\n            return y < other.y;\n        }\n    };\n\n    vector<VEdge> vedges;\n    vector<int> xs;\n    unordered_map<int, vector<pair<int,int>>> vmap;\n    unordered_map<int, vector<pair<int,int>>> hmap;\n    vmap.reserve(m * 2 + 10);\n    hmap.reserve(m * 2 + 10);\n\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            if (y1 == y2) continue;\n            vedges.push_back({x1, y1, y2});\n            xs.push_back(x1);\n            vmap[x1].push_back({y1, y2});\n        } else {\n            if (x1 > x2) swap(x1, x2);\n            if (x1 == x2) continue;\n            hmap[y1].push_back({x1, x2});\n        }\n    }\n\n    for (auto& kv : vmap) sort(kv.second.begin(), kv.second.end());\n    for (auto& kv : hmap) sort(kv.second.begin(), kv.second.end());\n\n    sort(xs.begin(), xs.end());\n    xs.erase(unique(xs.begin(), xs.end()), xs.end());\n\n    vector<Event> events;\n    events.reserve(vedges.size() * 2);\n\n    for (const auto& e : vedges) {\n        int xi = lower_bound(xs.begin(), xs.end(), e.x) - xs.begin();\n        events.push_back({e.y1, xi, +1});\n        events.push_back({e.y2, xi, -1});\n    }\n\n    sort(events.begin(), events.end());\n\n    Fenwick fw((int)xs.size());\n    int ep = 0;\n    int score = 0;\n\n    auto on_boundary = [&](int px, int py) -> bool {\n        auto itv = vmap.find(px);\n        if (itv != vmap.end()) {\n            for (auto [a, b] : itv->second) {\n                if (a <= py && py <= b) return true;\n            }\n        }\n\n        auto ith = hmap.find(py);\n        if (ith != hmap.end()) {\n            for (auto [a, b] : ith->second) {\n                if (a <= px && px <= b) return true;\n            }\n        }\n\n        return false;\n    };\n\n    for (int id : fishOrderY) {\n        const auto& f = fishes[id];\n\n        if (f.y < miny) continue;\n        if (f.y > maxy) break;\n\n        while (ep < (int)events.size() && events[ep].y <= f.y) {\n            fw.add(events[ep].xi + 1, events[ep].delta);\n            ep++;\n        }\n\n        if (f.x < minx || f.x > maxx) continue;\n\n        if (on_boundary(f.x, f.y)) {\n            score += f.w;\n            continue;\n        }\n\n        int pos = upper_bound(xs.begin(), xs.end(), f.x) - xs.begin();\n        int crossings = fw.all() - fw.sum(pos);\n        if (crossings & 1) score += f.w;\n    }\n\n    return score;\n}\n\nint rect_score(int x1, int y1, int x2, int y2) {\n    if (x1 >= x2 || y1 >= y2) return -INF;\n    int s = 0;\n    for (const auto& f : fishes) {\n        if (x1 <= f.x && f.x <= x2 && y1 <= f.y && f.y <= y2) s += f.w;\n    }\n    return s;\n}\n\nvoid refine_and_record_rectangle(int x1, int y1, int x2, int y2) {\n    if (elapsed_sec() > 1.75) return;\n\n    x1 = max(0, min(CMAX, x1));\n    x2 = max(0, min(CMAX, x2));\n    y1 = max(0, min(CMAX, y1));\n    y2 = max(0, min(CMAX, y2));\n\n    if (x1 >= x2 || y1 >= y2) return;\n\n    auto opt_left = [&]() -> int {\n        int lo = 0, hi = max(0, x2 - 1);\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (y1 <= f.y && f.y <= y2 && f.x <= x2) {\n                pts.push_back({f.x, f.w});\n                if (lo <= f.x && f.x <= hi) cand.push_back(f.x);\n                if (lo <= f.x + 1 && f.x + 1 <= hi) cand.push_back(f.x + 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end(), greater<pair<int,int>>());\n        sort(cand.begin(), cand.end(), greater<int>());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = x1;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first >= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_right = [&]() -> int {\n        int lo = min(CMAX, x1 + 1), hi = CMAX;\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (y1 <= f.y && f.y <= y2 && f.x >= x1) {\n                pts.push_back({f.x, f.w});\n                if (lo <= f.x && f.x <= hi) cand.push_back(f.x);\n                if (lo <= f.x - 1 && f.x - 1 <= hi) cand.push_back(f.x - 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = x2;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first <= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_bottom = [&]() -> int {\n        int lo = 0, hi = max(0, y2 - 1);\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (x1 <= f.x && f.x <= x2 && f.y <= y2) {\n                pts.push_back({f.y, f.w});\n                if (lo <= f.y && f.y <= hi) cand.push_back(f.y);\n                if (lo <= f.y + 1 && f.y + 1 <= hi) cand.push_back(f.y + 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end(), greater<pair<int,int>>());\n        sort(cand.begin(), cand.end(), greater<int>());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = y1;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first >= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_top = [&]() -> int {\n        int lo = min(CMAX, y1 + 1), hi = CMAX;\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (x1 <= f.x && f.x <= x2 && f.y >= y1) {\n                pts.push_back({f.y, f.w});\n                if (lo <= f.y && f.y <= hi) cand.push_back(f.y);\n                if (lo <= f.y - 1 && f.y - 1 <= hi) cand.push_back(f.y - 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = y2;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first <= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    for (int it = 0; it < 4; it++) {\n        x1 = opt_left();\n        x2 = opt_right();\n        y1 = opt_bottom();\n        y2 = opt_top();\n        if (x1 >= x2 || y1 >= y2) return;\n    }\n\n    int sc = rect_score(x1, y1, x2, y2);\n    if (sc <= 0) return;\n\n    vector<pair<int,int>> poly = {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}};\n    record_candidate(poly, sc, 3);\n}\n\nstruct GridSolver {\n    int D, G, maxEdges, ncell;\n    vector<int> w;\n\n    struct Comp {\n        vector<int> cells;\n        int score = 0;\n        int perim = 0;\n    };\n\n    struct Eval {\n        int score;\n        int len;\n    };\n\n    struct Corridor {\n        int a, b;\n        bool xFirst;\n    };\n\n    GridSolver(int d) : D(d), G(CMAX / d), maxEdges(MAXLEN / d), ncell(G * G), w(ncell, 0) {\n        for (const auto& f : fishes) {\n            int x = f.x / D;\n            int y = f.y / D;\n            if (x >= G) x = G - 1;\n            if (y >= G) y = G - 1;\n            w[idx(x, y)] += f.w;\n        }\n    }\n\n    inline int idx(int x, int y) const {\n        return y * G + x;\n    }\n\n    inline bool in_grid(int x, int y) const {\n        return 0 <= x && x < G && 0 <= y && y < G;\n    }\n\n    int mask_score(const vector<uchar>& mask) const {\n        int s = 0;\n        for (int i = 0; i < ncell; i++) if (mask[i]) s += w[i];\n        return s;\n    }\n\n    int selected_neighbor_count(const vector<uchar>& mask, int x, int y) const {\n        int c = 0;\n        if (x > 0 && mask[idx(x - 1, y)]) c++;\n        if (x + 1 < G && mask[idx(x + 1, y)]) c++;\n        if (y > 0 && mask[idx(x, y - 1)]) c++;\n        if (y + 1 < G && mask[idx(x, y + 1)]) c++;\n        return c;\n    }\n\n    int selected_neighbor_count_id(const vector<uchar>& mask, int v) const {\n        return selected_neighbor_count(mask, v % G, v / G);\n    }\n\n    int boundary_edges(const vector<uchar>& mask) const {\n        int p = 0;\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n                if (x == 0 || !mask[idx(x - 1, y)]) p++;\n                if (x + 1 == G || !mask[idx(x + 1, y)]) p++;\n                if (y == 0 || !mask[idx(x, y - 1)]) p++;\n                if (y + 1 == G || !mask[idx(x, y + 1)]) p++;\n            }\n        }\n        return p;\n    }\n\n    void fix_diagonal(vector<uchar>& mask) const {\n        for (int it = 0; it < 30; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < G; y++) {\n                for (int x = 0; x + 1 < G; x++) {\n                    int a = idx(x, y);\n                    int b = idx(x + 1, y);\n                    int c = idx(x, y + 1);\n                    int d = idx(x + 1, y + 1);\n\n                    bool A = mask[a], B = mask[b], C = mask[c], DD = mask[d];\n\n                    if (A && DD && !B && !C) {\n                        int choose = (w[b] >= w[c] ? b : c);\n                        mask[choose] = 1;\n                        changed = true;\n                    } else if (B && C && !A && !DD) {\n                        int choose = (w[a] >= w[d] ? a : d);\n                        mask[choose] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void fill_holes(vector<uchar>& mask) const {\n        vector<uchar> out(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto push = [&](int x, int y) {\n            int id = idx(x, y);\n            if (!mask[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < G; x++) {\n            push(x, 0);\n            push(x, G - 1);\n        }\n        for (int y = 0; y < G; y++) {\n            push(0, y);\n            push(G - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % G, y = v / G;\n            const int dx[4] = {1, -1, 0, 0};\n            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 (!in_grid(nx, ny)) continue;\n                int ni = idx(nx, ny);\n                if (!mask[ni] && !out[ni]) {\n                    out[ni] = 1;\n                    q.push_back(ni);\n                }\n            }\n        }\n\n        for (int i = 0; i < ncell; i++) {\n            if (!mask[i] && !out[i]) mask[i] = 1;\n        }\n    }\n\n    vector<Comp> find_components(const vector<uchar>& mask, vector<int>* compIdOut = nullptr) const {\n        vector<int> compId(ncell, -1);\n        vector<Comp> comps;\n        vector<int> q;\n        q.reserve(ncell);\n\n        for (int s = 0; s < ncell; s++) {\n            if (!mask[s] || compId[s] != -1) continue;\n\n            int cid = (int)comps.size();\n            comps.push_back(Comp{});\n            compId[s] = cid;\n            q.clear();\n            q.push_back(s);\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                comps[cid].cells.push_back(v);\n                comps[cid].score += w[v];\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) {\n                        comps[cid].perim++;\n                        continue;\n                    }\n\n                    int ni = idx(nx, ny);\n                    if (!mask[ni]) {\n                        comps[cid].perim++;\n                    } else if (compId[ni] == -1) {\n                        compId[ni] = cid;\n                        q.push_back(ni);\n                    }\n                }\n            }\n        }\n\n        if (compIdOut) *compIdOut = move(compId);\n        return comps;\n    }\n\n    void trim_leaves(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        vector<uchar> inq(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto maybe_push = [&](int id) {\n            if (!mask[id] || w[id] > 0 || inq[id]) return;\n            if (selected_neighbor_count_id(mask, id) <= 1) {\n                inq[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < ncell; i++) maybe_push(i);\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            inq[v] = 0;\n            if (!mask[v] || w[v] > 0) continue;\n            if (sel <= 1) continue;\n\n            int k = selected_neighbor_count_id(mask, v);\n            if (k <= 1) {\n                mask[v] = 0;\n                sel--;\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (in_grid(nx, ny)) maybe_push(idx(nx, ny));\n                }\n            }\n        }\n    }\n\n    void add_positive_boundary(vector<uchar>& mask) const {\n        int P = boundary_edges(mask);\n\n        for (int it = 0; it < 4; it++) {\n            bool changed = false;\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool simple_removable(const vector<uchar>& mask, int v) const {\n        int x = v % G, y = v / G;\n        bool occ[3][3] = {};\n        bool vis[3][3] = {};\n        int cnt = 0;\n\n        for (int dy = -1; dy <= 1; dy++) {\n            for (int dx = -1; dx <= 1; dx++) {\n                if (dx == 0 && dy == 0) continue;\n                int nx = x + dx, ny = y + dy;\n                if (in_grid(nx, ny) && mask[idx(nx, ny)]) {\n                    occ[dy + 1][dx + 1] = true;\n                    cnt++;\n                }\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int comps = 0;\n        const int ddx[4] = {1, -1, 0, 0};\n        const int ddy[4] = {0, 0, 1, -1};\n\n        for (int sy = 0; sy < 3; sy++) {\n            for (int sx = 0; sx < 3; sx++) {\n                if (!occ[sy][sx] || vis[sy][sx]) continue;\n\n                comps++;\n                int qx[9], qy[9], h = 0, t = 0;\n                qx[t] = sx;\n                qy[t] = sy;\n                t++;\n                vis[sy][sx] = true;\n\n                while (h < t) {\n                    int cx = qx[h], cy = qy[h];\n                    h++;\n\n                    for (int dir = 0; dir < 4; dir++) {\n                        int nx = cx + ddx[dir], ny = cy + ddy[dir];\n                        if (0 <= nx && nx < 3 && 0 <= ny && ny < 3 &&\n                            occ[ny][nx] && !vis[ny][nx]) {\n                            vis[ny][nx] = true;\n                            qx[t] = nx;\n                            qy[t] = ny;\n                            t++;\n                        }\n                    }\n                }\n            }\n        }\n\n        return comps == 1;\n    }\n\n    void polish_mask(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        int P = boundary_edges(mask);\n\n        for (int pass = 0; pass < 3; pass++) {\n            if (elapsed_sec() > 1.86) break;\n\n            bool changed = false;\n\n            for (int id = 0; id < ncell; id++) {\n                if (!mask[id] || sel <= 1) continue;\n\n                int k = selected_neighbor_count_id(mask, id);\n                if (k == 4) continue;\n\n                int delta = 2 * k - 4;\n                bool ok = false;\n\n                if (w[id] < 0) {\n                    if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                } else if (w[id] == 0 && delta < 0) {\n                    ok = true;\n                }\n\n                if (ok && simple_removable(mask, id)) {\n                    mask[id] = 0;\n                    sel--;\n                    P += delta;\n                    changed = true;\n                }\n            }\n\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        sel++;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    bool extract_polygon(const vector<uchar>& mask, vector<pair<int,int>>& poly) const {\n        int V = (G + 1) * (G + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (G + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n        };\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n\n                if (y == 0 || !mask[idx(x, y - 1)]) set_edge(x, y, x + 1, y);\n                if (x + 1 == G || !mask[idx(x + 1, y)]) set_edge(x + 1, y, x + 1, y + 1);\n                if (y + 1 == G || !mask[idx(x, y + 1)]) set_edge(x + 1, y + 1, x, y + 1);\n                if (x == 0 || !mask[idx(x - 1, y)]) set_edge(x, y + 1, x, y);\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (1LL * edges * D > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n        int cur = start;\n\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int px = pv % (G + 1), py = pv / (G + 1);\n            int cx = cv % (G + 1), cy = cv / (G + 1);\n            int nx = nv % (G + 1), ny = nv / (G + 1);\n\n            if ((px == cx && cx == nx) || (py == cy && cy == ny)) continue;\n\n            poly.push_back({cx * D, cy * D});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    bool extract_rect_union(const vector<Rect>& inRects, vector<pair<int,int>>& poly) const {\n        vector<Rect> rects;\n        vector<int> xs, ys;\n        rects.reserve(inRects.size());\n        xs.reserve(inRects.size() * 2 + 4);\n        ys.reserve(inRects.size() * 2 + 4);\n\n        for (auto r : inRects) {\n            if (r.x1 > r.x2) swap(r.x1, r.x2);\n            if (r.y1 > r.y2) swap(r.y1, r.y2);\n\n            r.x1 = max(0, min(CMAX, r.x1));\n            r.x2 = max(0, min(CMAX, r.x2));\n            r.y1 = max(0, min(CMAX, r.y1));\n            r.y2 = max(0, min(CMAX, r.y2));\n\n            if (r.x1 >= r.x2 || r.y1 >= r.y2) continue;\n\n            rects.push_back(r);\n            xs.push_back(r.x1);\n            xs.push_back(r.x2);\n            ys.push_back(r.y1);\n            ys.push_back(r.y2);\n        }\n\n        if (rects.empty()) return false;\n\n        sort(xs.begin(), xs.end());\n        xs.erase(unique(xs.begin(), xs.end()), xs.end());\n        sort(ys.begin(), ys.end());\n        ys.erase(unique(ys.begin(), ys.end()), ys.end());\n\n        int NX = (int)xs.size() - 1;\n        int NY = (int)ys.size() - 1;\n        if (NX <= 0 || NY <= 0) return false;\n\n        int Wd = NX + 1;\n        vector<int> diff((NX + 1) * (NY + 1), 0);\n\n        auto did = [&](int x, int y) {\n            return y * Wd + x;\n        };\n\n        for (auto r : rects) {\n            int x1 = lower_bound(xs.begin(), xs.end(), r.x1) - xs.begin();\n            int x2 = lower_bound(xs.begin(), xs.end(), r.x2) - xs.begin();\n            int y1 = lower_bound(ys.begin(), ys.end(), r.y1) - ys.begin();\n            int y2 = lower_bound(ys.begin(), ys.end(), r.y2) - ys.begin();\n\n            diff[did(x1, y1)]++;\n            diff[did(x2, y1)]--;\n            diff[did(x1, y2)]--;\n            diff[did(x2, y2)]++;\n        }\n\n        for (int y = 0; y <= NY; y++) {\n            for (int x = 1; x <= NX; x++) {\n                diff[did(x, y)] += diff[did(x - 1, y)];\n            }\n        }\n        for (int y = 1; y <= NY; y++) {\n            for (int x = 0; x <= NX; x++) {\n                diff[did(x, y)] += diff[did(x, y - 1)];\n            }\n        }\n\n        vector<uchar> cov(NX * NY, 0);\n        for (int y = 0; y < NY; y++) {\n            for (int x = 0; x < NX; x++) {\n                if (diff[did(x, y)] > 0) cov[y * NX + x] = 1;\n            }\n        }\n\n        vector<uchar> out(NX * NY, 0);\n        vector<int> q;\n        q.reserve(NX * NY);\n\n        auto push = [&](int x, int y) {\n            if (x < 0 || x >= NX || y < 0 || y >= NY) return;\n            int id = y * NX + x;\n            if (!cov[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < NX; x++) {\n            push(x, 0);\n            push(x, NY - 1);\n        }\n        for (int y = 0; y < NY; y++) {\n            push(0, y);\n            push(NX - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % NX, y = v / NX;\n\n            const int dx[4] = {1, -1, 0, 0};\n            const int dy[4] = {0, 0, 1, -1};\n\n            for (int dir = 0; dir < 4; dir++) {\n                push(x + dx[dir], y + dy[dir]);\n            }\n        }\n\n        for (int i = 0; i < NX * NY; i++) {\n            if (!cov[i] && !out[i]) cov[i] = 1;\n        }\n\n        int V = (NX + 1) * (NY + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        long long totalLen = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (NX + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty, int len) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n            totalLen += len;\n        };\n\n        for (int y = 0; y < NY; y++) {\n            for (int x = 0; x < NX; x++) {\n                if (!cov[y * NX + x]) continue;\n\n                if (y == 0 || !cov[(y - 1) * NX + x]) {\n                    set_edge(x, y, x + 1, y, xs[x + 1] - xs[x]);\n                }\n                if (x + 1 == NX || !cov[y * NX + (x + 1)]) {\n                    set_edge(x + 1, y, x + 1, y + 1, ys[y + 1] - ys[y]);\n                }\n                if (y + 1 == NY || !cov[(y + 1) * NX + x]) {\n                    set_edge(x + 1, y + 1, x, y + 1, xs[x + 1] - xs[x]);\n                }\n                if (x == 0 || !cov[y * NX + (x - 1)]) {\n                    set_edge(x, y + 1, x, y, ys[y + 1] - ys[y]);\n                }\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (totalLen > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n\n        int cur = start;\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int pxi = pv % (NX + 1), pyi = pv / (NX + 1);\n            int cxi = cv % (NX + 1), cyi = cv / (NX + 1);\n            int nxi = nv % (NX + 1), nyi = nv / (NX + 1);\n\n            int px = xs[pxi], py = ys[pyi];\n            int cx = xs[cxi], cy = ys[cyi];\n            int nx = xs[nxi], ny = ys[nyi];\n\n            if ((px == cx && cx == nx) || (py == cy && cy == ny)) continue;\n\n            poly.push_back({cx, cy});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    void finalize_original(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.90) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        trim_leaves(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        add_positive_boundary(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc, 0);\n    }\n\n    void finalize_polish(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.88) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        polish_mask(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        polish_mask(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc, 1);\n    }\n\n    void finalize_candidate(vector<uchar> mask, int variants = 1) const {\n        if (variants & 1) {\n            auto m = mask;\n            finalize_original(move(m));\n        }\n        if ((variants & 2) && elapsed_sec() < 1.50) {\n            auto m = mask;\n            finalize_polish(move(m));\n        }\n    }\n\n    void finalize_thin(const vector<int>& selectedIds,\n                       const vector<Corridor>& corridors,\n                       const vector<Comp>& comps,\n                       int approx) const {\n        if (elapsed_sec() > 1.88) return;\n        if (selectedIds.empty()) return;\n\n        size_t rcnt = corridors.size() * 2;\n        for (int cid : selectedIds) rcnt += comps[cid].cells.size();\n\n        vector<Rect> rects;\n        rects.reserve(rcnt);\n\n        auto add_rect = [&](int x1, int y1, int x2, int y2) {\n            if (x1 > x2) swap(x1, x2);\n            if (y1 > y2) swap(y1, y2);\n\n            x1 = max(0, min(CMAX, x1));\n            x2 = max(0, min(CMAX, x2));\n            y1 = max(0, min(CMAX, y1));\n            y2 = max(0, min(CMAX, y2));\n\n            if (x1 < x2 && y1 < y2) rects.push_back({x1, y1, x2, y2});\n        };\n\n        for (int cid : selectedIds) {\n            for (int cell : comps[cid].cells) {\n                int x = cell % G;\n                int y = cell / G;\n                add_rect(x * D, y * D, (x + 1) * D, (y + 1) * D);\n            }\n        }\n\n        const int half = 1;\n\n        auto center = [&](int cell) {\n            int x = cell % G;\n            int y = cell / G;\n            return pair<int,int>{x * D + D / 2, y * D + D / 2};\n        };\n\n        auto add_h = [&](int x1, int x2, int y) {\n            if (x1 == x2) return;\n            if (x1 > x2) swap(x1, x2);\n            add_rect(x1, y - half, x2, y + half);\n        };\n\n        auto add_v = [&](int x, int y1, int y2) {\n            if (y1 == y2) return;\n            if (y1 > y2) swap(y1, y2);\n            add_rect(x - half, y1, x + half, y2);\n        };\n\n        for (const auto& c : corridors) {\n            auto [sx, sy] = center(c.a);\n            auto [tx, ty] = center(c.b);\n\n            if (c.xFirst) {\n                add_h(sx, tx, sy);\n                add_v(tx, sy, ty);\n            } else {\n                add_v(sx, sy, ty);\n                add_h(sx, tx, ty);\n            }\n        }\n\n        vector<pair<int,int>> poly;\n        if (!extract_rect_union(rects, poly)) return;\n\n        record_candidate(poly, approx, 2);\n    }\n\n    Eval eval_l_path(int src, int dst, bool xFirst,\n                     const vector<uchar>& cur,\n                     int targetCid,\n                     const vector<int>& compId) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        int score = 0, len = 0;\n\n        auto visit = [&](int x, int y) {\n            int id = idx(x, y);\n            len++;\n            if (!cur[id] && compId[id] != targetCid) score += w[id];\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, ty);\n                }\n            }\n        }\n\n        return {score, len};\n    }\n\n    vector<int> build_l_path(int src, int dst, bool xFirst) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        vector<int> res;\n        res.reserve(abs(tx - sx) + abs(ty - sy) + 1);\n\n        auto add = [&](int x, int y) {\n            res.push_back(idx(x, y));\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, ty);\n                }\n            }\n        }\n\n        return res;\n    }\n\n    void greedy_connect(const vector<Comp>& comps,\n                        const vector<int>& compId,\n                        const vector<int>& ids,\n                        int maxAdd,\n                        int compLimit,\n                        int variants) const {\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> cur(ncell, 0);\n        vector<int> curCells;\n        curCells.reserve(ncell / 4);\n\n        auto add_cell = [&](int cell) {\n            if (!cur[cell]) {\n                cur[cell] = 1;\n                curCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            for (int cell : comps[cid].cells) add_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0])) addedConsidered++;\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c == 1 || c == 2 || c == 3 || c == 5 || c == 8 ||\n                   c == 13 || c == 21 || c == 34;\n        };\n\n        finalize_candidate(cur, variants);\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : curCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                bool xFirst = true;\n                int gain = 0;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1) continue;\n                int src = root[bestCell];\n                if (src < 0) continue;\n\n                Eval e1 = eval_l_path(src, bestCell, true, cur, cid, compId);\n                Eval e2 = eval_l_path(src, bestCell, false, cur, cid, compId);\n\n                bool xf = true;\n                Eval e = e1;\n\n                if (e2.score > e1.score || (e2.score == e1.score && e2.len < e1.len)) {\n                    e = e2;\n                    xf = false;\n                }\n\n                int gain = comps[cid].score + e.score;\n                if (gain <= 0) continue;\n\n                double metric = (double)gain / (e.len + 5.0) + 0.03 * gain;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = src;\n                    best.dst = bestCell;\n                    best.xFirst = xf;\n                    best.gain = gain;\n                    best.len = e.len;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path = build_l_path(best.src, best.dst, best.xFirst);\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cell : path) add_cell(cell);\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            if (snapshot(addedConsidered)) finalize_candidate(cur, variants);\n\n            if (iter % 3 == 0 && boundary_edges(cur) > maxEdges * 3 / 2) break;\n        }\n\n        finalize_candidate(cur, variants);\n    }\n\n    void thin_greedy_connect(const vector<Comp>& comps,\n                             const vector<int>& compId,\n                             const vector<int>& ids,\n                             int maxAdd,\n                             int compLimit) const {\n        if (elapsed_sec() > 1.78) return;\n\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> network(ncell, 0);\n        vector<int> networkCells;\n        vector<int> selectedIds;\n        vector<Corridor> corridors;\n\n        int approx = 0;\n        long long roughLen = 0;\n\n        auto add_network_cell = [&](int cell) {\n            if (!network[cell]) {\n                network[cell] = 1;\n                networkCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            selectedIds.push_back(cid);\n            approx += comps[cid].score;\n            roughLen += 1LL * comps[cid].perim * D;\n            for (int cell : comps[cid].cells) add_network_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0]) && considered[ids[0]]) addedConsidered++;\n\n        finalize_thin(selectedIds, corridors, comps, approx);\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c <= 5 || c == 8 || c == 13 || c == 21 ||\n                   c == 34 || c == 55 || c == 89 || (c > 20 && c % 5 == 0);\n        };\n\n        auto path_bonus = [&](const vector<int>& path) {\n            vector<int> cs;\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && considered[cid] && comps[cid].score > 0) {\n                    cs.push_back(cid);\n                }\n            }\n\n            sort(cs.begin(), cs.end());\n            cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n            int s = 0;\n            for (int cid : cs) s += comps[cid].score;\n            return s;\n        };\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : networkCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1 || bestDist <= 0) continue;\n\n                long long addCost = 2LL * bestDist * D + 1LL * comps[cid].perim * D;\n                if (roughLen + addCost > 700000LL) continue;\n\n                double costK = addCost / 1000.0;\n                double metric = (double)comps[cid].score / (costK + 2.0) + 0.025 * comps[cid].score;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = root[bestCell];\n                    best.dst = bestCell;\n                    best.len = bestDist;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path1 = build_l_path(best.src, best.dst, true);\n            vector<int> path2 = build_l_path(best.src, best.dst, false);\n\n            int b1 = path_bonus(path1);\n            int b2 = path_bonus(path2);\n\n            bool xf = true;\n            vector<int> path;\n\n            if (b2 > b1) {\n                xf = false;\n                path = move(path2);\n            } else {\n                path = move(path1);\n            }\n\n            corridors.push_back({best.src, best.dst, xf});\n            roughLen += 2LL * (int)path.size() * D + 8;\n\n            for (int cell : path) add_network_cell(cell);\n\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && considered[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            int cnum = (int)selectedIds.size();\n            if (snapshot(cnum) || (roughLen > 300000 && cnum % 3 == 0)) {\n                finalize_thin(selectedIds, corridors, comps, approx);\n            }\n\n            if (roughLen > 620000LL) break;\n        }\n\n        finalize_thin(selectedIds, corridors, comps, approx);\n    }\n\n    void process_mask(vector<uchar> mask, int maxAdd, int compLimit, int mode = 3, int variants = 1) const {\n        if (elapsed_sec() > 1.82) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        vector<int> compId;\n        vector<Comp> comps = find_components(mask, &compId);\n        if (comps.empty()) return;\n\n        vector<int> ids;\n        for (int i = 0; i < (int)comps.size(); i++) {\n            if (comps[i].score > 0) ids.push_back(i);\n        }\n        if (ids.empty()) return;\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return comps[a].score > comps[b].score;\n        });\n\n        if (mode & 1) {\n            int alone = min(3, (int)ids.size());\n\n            for (int k = 0; k < alone; k++) {\n                vector<uchar> cur(ncell, 0);\n                for (int cell : comps[ids[k]].cells) cur[cell] = 1;\n                finalize_candidate(cur, variants);\n            }\n\n            if ((int)ids.size() >= 2) {\n                greedy_connect(comps, compId, ids, maxAdd, compLimit, variants);\n            }\n        }\n\n        if ((mode & 2) && elapsed_sec() < 1.78) {\n            int tMax = max(maxAdd, D <= 250 ? 100 : 45);\n            int tLimit = min(compLimit, D <= 250 ? 350 : 140);\n\n            thin_greedy_connect(comps, compId, ids, tMax, tLimit);\n\n            if (D <= 250 && elapsed_sec() < 1.78) {\n                vector<int> ids2 = ids;\n                sort(ids2.begin(), ids2.end(), [&](int a, int b) {\n                    long long lhs = 1LL * comps[a].score * (comps[b].perim + 1);\n                    long long rhs = 1LL * comps[b].score * (comps[a].perim + 1);\n                    if (lhs != rhs) return lhs > rhs;\n                    return comps[a].score > comps[b].score;\n                });\n\n                thin_greedy_connect(comps, compId, ids2, max(60, maxAdd / 2), min(tLimit, 180));\n            }\n        }\n    }\n\n    void run_best_rectangle(int variants = 1) const {\n        if (elapsed_sec() > 1.80) return;\n\n        int best = INT_MIN;\n        int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0;\n\n        vector<int> col(G, 0);\n\n        for (int x1 = 0; x1 < G; x1++) {\n            fill(col.begin(), col.end(), 0);\n\n            for (int x2 = x1; x2 < G; x2++) {\n                for (int y = 0; y < G; y++) col[y] += w[idx(x2, y)];\n\n                int cur = 0, st = 0;\n                for (int y = 0; y < G; y++) {\n                    if (y == 0 || cur <= 0) {\n                        cur = col[y];\n                        st = y;\n                    } else {\n                        cur += col[y];\n                    }\n\n                    if (cur > best) {\n                        best = cur;\n                        bx1 = x1;\n                        bx2 = x2;\n                        by1 = st;\n                        by2 = y;\n                    }\n                }\n            }\n        }\n\n        if (best <= 0) return;\n\n        vector<uchar> mask(ncell, 0);\n        for (int y = by1; y <= by2; y++) {\n            for (int x = bx1; x <= bx2; x++) {\n                mask[idx(x, y)] = 1;\n            }\n        }\n\n        finalize_candidate(mask, variants);\n\n        refine_and_record_rectangle(bx1 * D, by1 * D, (bx2 + 1) * D, (by2 + 1) * D);\n    }\n\n    vector<double> gaussian_blur(double sigma) const {\n        int r = max(1, (int)ceil(3.0 * sigma));\n        vector<double> ker(2 * r + 1);\n        double sum = 0.0;\n\n        for (int d = -r; d <= r; d++) {\n            double v = exp(-(double)d * d / (2.0 * sigma * sigma));\n            ker[d + r] = v;\n            sum += v;\n        }\n        for (double& v : ker) v /= sum;\n\n        vector<double> src(ncell), tmp(ncell), out(ncell);\n        for (int i = 0; i < ncell; i++) src[i] = (double)w[i];\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int nx = x + d;\n                    if (0 <= nx && nx < G) s += src[idx(nx, y)] * ker[d + r];\n                }\n                tmp[idx(x, y)] = s;\n            }\n        }\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int ny = y + d;\n                    if (0 <= ny && ny < G) s += tmp[idx(x, ny)] * ker[d + r];\n                }\n                out[idx(x, y)] = s;\n            }\n        }\n\n        return out;\n    }\n\n    void run_smoothing(const vector<double>& sigmas,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime,\n                       int mode = 1,\n                       int variants = 1) const {\n        vector<double> ratios = {-0.05, -0.02, 0.0, 0.02, 0.05, 0.10, 0.18, 0.30};\n\n        for (double sigma : sigmas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<double> blur = gaussian_blur(sigma);\n            double mx = *max_element(blur.begin(), blur.end());\n            if (mx <= 1e-12) continue;\n\n            for (double r : ratios) {\n                if (elapsed_sec() > stopTime) return;\n\n                double th = mx * r;\n                vector<uchar> mask(ncell, 0);\n                int cnt = 0;\n\n                for (int i = 0; i < ncell; i++) {\n                    if (blur[i] > th) {\n                        mask[i] = 1;\n                        cnt++;\n                    }\n                }\n\n                if (cnt == 0 || cnt == ncell) continue;\n                process_mask(move(mask), maxAdd, compLimit, mode, variants);\n            }\n        }\n    }\n\n    void run_weight_thresholds(const vector<int>& thresholds,\n                               int maxAdd,\n                               int compLimit,\n                               double stopTime,\n                               int mode = 3,\n                               int variants = 1) const {\n        for (int th : thresholds) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask(ncell, 0);\n            int cnt = 0;\n\n            for (int i = 0; i < ncell; i++) {\n                if (w[i] >= th) {\n                    mask[i] = 1;\n                    cnt++;\n                }\n            }\n\n            if (cnt == 0) continue;\n            process_mask(move(mask), maxAdd, compLimit, mode, variants);\n        }\n    }\n\n    vector<uchar> graph_cut_mask(int lam, int scale) const {\n        int S = ncell;\n        int T = ncell + 1;\n        atcoder::mf_graph<ll> g(ncell + 2);\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int v = idx(x, y);\n                ll profit = (ll)w[v] * scale;\n\n                if (profit > 0) g.add_edge(S, v, profit);\n                else if (profit < 0) g.add_edge(v, T, -profit);\n\n                int bs = 0;\n                if (x == 0) bs++;\n                if (x + 1 == G) bs++;\n                if (y == 0) bs++;\n                if (y + 1 == G) bs++;\n\n                if (bs) g.add_edge(v, T, (ll)lam * bs);\n\n                if (x + 1 < G) {\n                    int u = idx(x + 1, y);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n                if (y + 1 < G) {\n                    int u = idx(x, y + 1);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n            }\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n\n        vector<uchar> mask(ncell, 0);\n        for (int i = 0; i < ncell; i++) mask[i] = cut[i] ? 1 : 0;\n        return mask;\n    }\n\n    void run_graph_cut(const vector<int>& lambdas,\n                       int scale,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime,\n                       int mode = 3,\n                       int variants = 1) const {\n        for (int lam : lambdas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask = graph_cut_mask(lam, scale);\n            process_mask(move(mask), maxAdd, compLimit, mode, variants);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int N;\n    cin >> N;\n\n    fishes.reserve(2 * N);\n\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n\n        int w = (i < N ? 1 : -1);\n        fishes.push_back({x, y, w});\n    }\n\n    fishOrderY.resize(fishes.size());\n    iota(fishOrderY.begin(), fishOrderY.end(), 0);\n    sort(fishOrderY.begin(), fishOrderY.end(), [&](int a, int b) {\n        if (fishes[a].y != fishes[b].y) return fishes[a].y < fishes[b].y;\n        return fishes[a].x < fishes[b].x;\n    });\n\n    bestApprox = -1;\n    bestSafeApprox = -1;\n\n    record_candidate(square_poly(), 0, 0);\n\n    GridSolver g500(500);\n\n    g500.run_best_rectangle(1);\n    g500.run_weight_thresholds(vector<int>{1, 2, 3}, 32, 140, 0.56, 3, 3);\n    g500.run_smoothing(vector<double>{2.0, 3.5, 5.5, 8.0, 12.0}, 18, 90, 1.00, 1, 1);\n\n    if (elapsed_sec() < 1.25) {\n        g500.run_graph_cut(vector<int>{10, 16, 25, 40, 70, 120}, 100, 24, 120, 1.40, 3, 1);\n    }\n\n    if (elapsed_sec() < 1.62) {\n        GridSolver g400(400);\n        g400.run_best_rectangle(1);\n        g400.run_smoothing(vector<double>{2.5, 4.0, 6.5, 10.0, 14.0}, 14, 80, 1.72, 1, 1);\n    }\n\n    if (elapsed_sec() < 1.76) {\n        GridSolver g250(250);\n        g250.run_weight_thresholds(vector<int>{1, 2, 3}, 100, 350, 1.86, 2, 0);\n    }\n\n    vector<pair<int,int>> output;\n    if (!bestSafePoly.empty()) output = bestSafePoly;\n    else if (!bestPoly.empty()) output = bestPoly;\n    else output = square_poly();\n\n    if (bestApprox >= 0 && !bestPoly.empty()) {\n        candidates.push_back({bestApprox, 2, bestPoly});\n    }\n    if (bestSafeApprox >= 0 && !bestSafePoly.empty()) {\n        candidates.push_back({bestSafeApprox, 0, bestSafePoly});\n    }\n\n    if (elapsed_sec() < 1.90) {\n        int bestExact = exact_score(output);\n        vector<pair<int,int>> exactBest = output;\n\n        if (bestExact < 0) {\n            bestExact = 0;\n            exactBest = square_poly();\n        }\n\n        vector<int> order;\n        vector<char> usedIdx(candidates.size(), 0);\n\n        auto add_idx = [&](int id) {\n            if (id < 0 || id >= (int)candidates.size()) return;\n            if (usedIdx[id]) return;\n            usedIdx[id] = 1;\n            order.push_back(id);\n        };\n\n        vector<int> all(candidates.size());\n        iota(all.begin(), all.end(), 0);\n        sort(all.begin(), all.end(), [&](int a, int b) {\n            return candidates[a].approx > candidates[b].approx;\n        });\n\n        if ((int)candidates.size() <= 260) {\n            for (int id : all) add_idx(id);\n        } else {\n            for (int i = 0; i < min(120, (int)all.size()); i++) add_idx(all[i]);\n\n            for (int cat = 0; cat <= 3; cat++) {\n                vector<int> v;\n                for (int i = 0; i < (int)candidates.size(); i++) {\n                    if (candidates[i].cat == cat) v.push_back(i);\n                }\n\n                sort(v.begin(), v.end(), [&](int a, int b) {\n                    return candidates[a].approx > candidates[b].approx;\n                });\n\n                for (int i = 0; i < min(60, (int)v.size()); i++) add_idx(v[i]);\n            }\n        }\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(order.size() * 2 + 10);\n        seen.insert(poly_hash(output));\n\n        for (int id : order) {\n            if (elapsed_sec() > 1.965) break;\n\n            uint64_t h = poly_hash(candidates[id].poly);\n            if (seen.find(h) != seen.end()) continue;\n            seen.insert(h);\n\n            int sc = exact_score(candidates[id].poly);\n            if (sc > bestExact) {\n                bestExact = sc;\n                exactBest = candidates[id].poly;\n            }\n        }\n\n        output = exactBest;\n    }\n\n    cout << output.size() << '\\n';\n    for (auto [x, y] : output) {\n        cout << x << ' ' << y << '\\n';\n    }\n\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectD {\n    double w, h;\n};\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    double estScore = 1e100;\n    double baseW = 0, baseH = 0;\n    uint64_t hash = 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};\n\nstatic constexpr double TRUE_U = 100000.0;\nstatic constexpr double TRUE_L_MIN = 10000.0;\nstatic constexpr double TRUE_L_MAX = 50000.0;\nstatic constexpr double INF = 1e100;\n\nint N, T;\ndouble SIGMA;\nvector<double> sumWObs, sumHObs;\nvector<int> cntWObs, cntHObs;\n\nmt19937_64 rng(123456789);\n\ndouble normal_pdf(double x) {\n    static const double INV_SQRT_2PI = 0.39894228040143267794;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble normal_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble clamp_double(double x, double lo, double hi) {\n    return max(lo, min(hi, x));\n}\n\ndouble truncated_normal_mean(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    double a = (L - obsMean) / sd;\n    double b = (U - obsMean) / sd;\n    double Z = normal_cdf(b) - normal_cdf(a);\n    if (Z < 1e-12) return clamp_double(obsMean, L, U);\n    double m = obsMean + sd * (normal_pdf(a) - normal_pdf(b)) / Z;\n    return clamp_double(m, L, U);\n}\n\ndouble sample_truncated_normal(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    normal_distribution<double> nd(obsMean, sd);\n    for (int t = 0; t < 200; t++) {\n        double x = nd(rng);\n        if (L <= x && x <= U) return x;\n    }\n    return clamp_double(obsMean, L, U);\n}\n\ndouble estimate_L_from_current_observations() {\n    vector<double> vals;\n    vector<double> noiseVars;\n    vals.reserve(2 * N);\n    noiseVars.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        vals.push_back(sumWObs[i] / cntWObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntWObs[i]);\n        vals.push_back(sumHObs[i] / cntHObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntHObs[i]);\n    }\n\n    double mean = accumulate(vals.begin(), vals.end(), 0.0) / vals.size();\n    double L1 = 2.0 * mean - TRUE_U;\n\n    double var = 0.0;\n    for (double x : vals) var += (x - mean) * (x - mean);\n    var /= vals.size();\n\n    double avgNoise = accumulate(noiseVars.begin(), noiseVars.end(), 0.0) / noiseVars.size();\n    double trueVar = max(0.0, var - avgNoise);\n    double L2 = TRUE_U - sqrt(max(0.0, 12.0 * trueVar));\n\n    double L = 0.72 * L1 + 0.28 * L2;\n    return clamp_double(L, TRUE_L_MIN, TRUE_L_MAX);\n}\n\nvector<RectD> posterior_mean_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = truncated_normal_mean(mw, sw, L, TRUE_U);\n        res[i].h = truncated_normal_mean(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> posterior_sample_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = sample_truncated_normal(mw, sw, L, TRUE_U);\n        res[i].h = sample_truncated_normal(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nstatic inline bool overlap_interval(double l1, double r1, double l2, double r2) {\n    return max(l1, l2) < min(r1, r2) - 1e-9;\n}\n\npair<double, double> simulate_ops(const vector<Op>& ops, const vector<RectD>& rects) {\n    vector<double> x(N, 0), y(N, 0), w(N, 0), h(N, 0);\n    vector<int> placed;\n    placed.reserve(ops.size());\n\n    double W = 0, H = 0;\n\n    for (const Op& op : ops) {\n        int p = op.p;\n        double rw = op.r ? rects[p].h : rects[p].w;\n        double rh = op.r ? rects[p].w : rects[p].h;\n\n        double nx = 0, ny = 0;\n        if (op.d == 'U') {\n            nx = (op.b == -1 ? 0.0 : x[op.b] + w[op.b]);\n            ny = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(nx, nx + rw, x[q], x[q] + w[q])) {\n                    ny = max(ny, y[q] + h[q]);\n                }\n            }\n        } else {\n            ny = (op.b == -1 ? 0.0 : y[op.b] + h[op.b]);\n            nx = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(ny, ny + rh, y[q], y[q] + h[q])) {\n                    nx = max(nx, x[q] + w[q]);\n                }\n            }\n        }\n\n        x[p] = nx;\n        y[p] = ny;\n        w[p] = rw;\n        h[p] = rh;\n        placed.push_back(p);\n        W = max(W, nx + rw);\n        H = max(H, ny + rh);\n    }\n    return {W, H};\n}\n\nuint64_t splitmix64_u(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\nuint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (const Op& op : ops) {\n        uint64_t v = (uint64_t)(op.p + 1);\n        v = v * 1315423911ULL + (uint64_t)(op.r + 3);\n        v = v * 1315423911ULL + (uint64_t)(op.d == 'L' ? 7 : 11);\n        v = v * 1315423911ULL + (uint64_t)(op.b + 2);\n        h ^= splitmix64_u(v + h);\n    }\n    return h;\n}\n\nvoid add_candidate(vector<Candidate>& pool,\n                   unordered_set<uint64_t>& seen,\n                   const vector<Op>& ops,\n                   const vector<RectD>& baseRects) {\n    if ((int)ops.size() != N) return;\n\n    uint64_t hv = hash_ops(ops);\n    if (seen.find(hv) != seen.end()) return;\n    seen.insert(hv);\n\n    auto [W, H] = simulate_ops(ops, baseRects);\n    if (!isfinite(W) || !isfinite(H)) return;\n\n    Candidate c;\n    c.ops = ops;\n    c.baseW = W;\n    c.baseH = H;\n    c.estScore = W + H;\n    c.hash = hv;\n    pool.push_back(std::move(c));\n}\n\nstruct ShelfResult {\n    bool ok = false;\n    vector<Op> ops;\n};\n\n// mode 0: vertical columns using U\n// mode 1: horizontal rows using L\nShelfResult make_shelf_layout(const vector<RectD>& planRects, int mode, double cap) {\n    vector<array<double, 2>> cross(N), len(N);\n\n    for (int i = 0; i < N; i++) {\n        double w = planRects[i].w;\n        double h = planRects[i].h;\n        if (mode == 0) {\n            cross[i][0] = w; len[i][0] = h;\n            cross[i][1] = h; len[i][1] = w;\n        } else {\n            cross[i][0] = h; len[i][0] = w;\n            cross[i][1] = w; len[i][1] = h;\n        }\n    }\n\n    vector<double> vals;\n    vals.reserve(2 * N);\n    for (int i = 0; i < N; i++) {\n        vals.push_back(cross[i][0]);\n        vals.push_back(cross[i][1]);\n    }\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end(), [](double a, double b) {\n        return fabs(a - b) <= 1e-7 * max(1.0, max(fabs(a), fabs(b)));\n    }), vals.end());\n\n    int C = vals.size();\n\n    vector<vector<double>> pref(C, vector<double>(N + 1, 0.0));\n    for (int m = 0; m < C; m++) {\n        double M = vals[m];\n        for (int i = 0; i < N; i++) {\n            double bestLen = INF;\n            if (cross[i][0] <= M + 1e-7) bestLen = min(bestLen, len[i][0]);\n            if (cross[i][1] <= M + 1e-7) bestLen = min(bestLen, len[i][1]);\n            if (bestLen >= INF / 2 || pref[m][i] >= INF / 2) pref[m][i + 1] = INF;\n            else pref[m][i + 1] = min(INF, pref[m][i] + bestLen);\n        }\n    }\n\n    auto get_cost_idx = [&](int l, int r) -> int {\n        int lo = 0, hi = C;\n        while (lo < hi) {\n            int mid = (lo + hi) >> 1;\n            double s = pref[mid][r] - pref[mid][l];\n            if (s <= cap + 1e-7) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo == C) return -1;\n        return lo;\n    };\n\n    vector<double> dp(N + 1, INF);\n    vector<int> prv(N + 1, -1), prvM(N + 1, -1);\n    dp[0] = 0.0;\n\n    for (int r = 1; r <= N; r++) {\n        for (int l = 0; l < r; l++) {\n            if (dp[l] >= INF / 2) continue;\n            int mi = get_cost_idx(l, r);\n            if (mi < 0) continue;\n            double ndp = dp[l] + vals[mi];\n            if (ndp < dp[r]) {\n                dp[r] = ndp;\n                prv[r] = l;\n                prvM[r] = mi;\n            }\n        }\n    }\n\n    if (prv[N] < 0) return {};\n\n    vector<pair<int, int>> segs;\n    for (int r = N; r > 0; r = prv[r]) {\n        segs.push_back({prv[r], r});\n    }\n    reverse(segs.begin(), segs.end());\n\n    vector<int> orient(N, 0);\n    vector<int> anchorOfSeg(segs.size(), -1);\n\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        int mi = get_cost_idx(l, r);\n        double M = vals[mi];\n\n        int anchor = l;\n        double bestCross = -1.0;\n\n        for (int i = l; i < r; i++) {\n            int chosen = 0;\n            double bestLen = INF, bestCr = INF;\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (cross[i][rr] <= M + 1e-7) {\n                    if (len[i][rr] < bestLen - 1e-7 ||\n                        (fabs(len[i][rr] - bestLen) <= 1e-7 && cross[i][rr] < bestCr)) {\n                        bestLen = len[i][rr];\n                        bestCr = cross[i][rr];\n                        chosen = rr;\n                    }\n                }\n            }\n            orient[i] = chosen;\n\n            double cr = cross[i][chosen];\n            if (cr > bestCross) {\n                bestCross = cr;\n                anchor = i;\n            }\n        }\n        anchorOfSeg[si] = anchor;\n    }\n\n    vector<Op> ops;\n    ops.reserve(N);\n\n    int boundaryRef = -1;\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        for (int i = l; i < r; i++) {\n            Op op;\n            op.p = i;\n            op.r = orient[i];\n            op.d = (mode == 0 ? 'U' : 'L');\n            op.b = boundaryRef;\n            ops.push_back(op);\n        }\n        boundaryRef = anchorOfSeg[si];\n    }\n\n    ShelfResult res;\n    res.ok = true;\n    res.ops = std::move(ops);\n    return res;\n}\n\nvector<double> make_caps(const vector<RectD>& rects, int mode, int cnt) {\n    double area = 0.0;\n    double minCap = 0.0;\n    for (int i = 0; i < N; i++) {\n        area += rects[i].w * rects[i].h;\n        minCap = max(minCap, min(rects[i].w, rects[i].h));\n    }\n\n    double S = sqrt(max(1.0, area));\n    vector<double> caps;\n\n    double loF = 0.52, hiF = 2.35;\n    for (int k = 0; k < cnt; k++) {\n        double u = (cnt == 1 ? 0.5 : (double)k / (cnt - 1));\n        double f = exp(log(loF) + u * (log(hiF) - log(loF)));\n        caps.push_back(max(minCap, S * f));\n    }\n\n    // Extra dense points near square.\n    for (double f : {0.72, 0.80, 0.88, 0.96, 1.04, 1.12, 1.20, 1.32, 1.48}) {\n        caps.push_back(max(minCap, S * f));\n    }\n\n    sort(caps.begin(), caps.end());\n    vector<double> uniq;\n    for (double x : caps) {\n        if (uniq.empty() || fabs(x - uniq.back()) > 1e-6 * max(1.0, x)) uniq.push_back(x);\n    }\n    return uniq;\n}\n\ndouble min_final_perimeter_lb(double W, double H, double A) {\n    double S = sqrt(max(1.0, A));\n    double ans = INF;\n\n    if (W <= S && H <= S) ans = min(ans, 2.0 * S);\n    ans = min(ans, W + max(H, A / max(W, 1.0)));\n    ans = min(ans, H + max(W, A / max(H, 1.0)));\n    ans = max(ans, W + H);\n    return ans;\n}\n\nvector<Op> make_greedy_layout(const vector<RectD>& planRects,\n                              double aspect,\n                              double scale,\n                              double wOverflow,\n                              double wWaste,\n                              double wBal,\n                              double wLB,\n                              double jitter) {\n    vector<Op> ops;\n    ops.reserve(N);\n\n    vector<double> x(N), y(N), ww(N), hh(N);\n    double W = 0.0, H = 0.0;\n    double totalArea = 0.0;\n    for (auto &r : planRects) totalArea += r.w * r.h;\n\n    double S = sqrt(max(1.0, totalArea)) * scale;\n    double Wlim = S * sqrt(aspect);\n    double Hlim = S / sqrt(aspect);\n\n    double usedArea = 0.0;\n    uniform_real_distribution<double> ud(0.0, 1.0);\n\n    for (int i = 0; i < N; i++) {\n        double itemArea = planRects[i].w * planRects[i].h;\n\n        double bestCost = INF;\n        Op bestOp{i, 0, 'U', -1};\n        double bestX = 0, bestY = 0, bestW = 0, bestH = 0;\n        double bestBW = 0, bestBH = 0;\n\n        for (int r = 0; r < 2; r++) {\n            double rw = r ? planRects[i].h : planRects[i].w;\n            double rh = r ? planRects[i].w : planRects[i].h;\n\n            for (int dd = 0; dd < 2; dd++) {\n                char d = (dd == 0 ? 'U' : 'L');\n                for (int b = -1; b < i; b++) {\n                    double nx = 0, ny = 0;\n\n                    if (d == 'U') {\n                        nx = (b == -1 ? 0.0 : x[b] + ww[b]);\n                        ny = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(nx, nx + rw, x[q], x[q] + ww[q])) {\n                                ny = max(ny, y[q] + hh[q]);\n                            }\n                        }\n                    } else {\n                        ny = (b == -1 ? 0.0 : y[b] + hh[b]);\n                        nx = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(ny, ny + rh, y[q], y[q] + hh[q])) {\n                                nx = max(nx, x[q] + ww[q]);\n                            }\n                        }\n                    }\n\n                    double nW = max(W, nx + rw);\n                    double nH = max(H, ny + rh);\n                    double nUsed = usedArea + itemArea;\n\n                    double overflow = max(0.0, nW - Wlim) + max(0.0, nH - Hlim);\n                    double wasteLen = max(0.0, nW * nH - nUsed) / sqrt(max(1.0, nUsed));\n                    double bal = fabs(nW / Wlim - nH / Hlim) * sqrt(totalArea);\n                    double lb = min_final_perimeter_lb(nW, nH, totalArea);\n                    double progress = 0.25 + 0.75 * (double)(i + 1) / N;\n\n                    double cost =\n                        wLB * lb +\n                        progress * (nW + nH) +\n                        wOverflow * overflow +\n                        wWaste * wasteLen +\n                        wBal * bal +\n                        0.0007 * (nx + ny) +\n                        jitter * ud(rng) * sqrt(totalArea);\n\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestOp = {i, r, d, b};\n                        bestX = nx;\n                        bestY = ny;\n                        bestW = rw;\n                        bestH = rh;\n                        bestBW = nW;\n                        bestBH = nH;\n                    }\n                }\n            }\n        }\n\n        ops.push_back(bestOp);\n        x[i] = bestX;\n        y[i] = bestY;\n        ww[i] = bestW;\n        hh[i] = bestH;\n        W = bestBW;\n        H = bestBH;\n        usedArea += itemArea;\n    }\n\n    return ops;\n}\n\nvoid output_query(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const Op& 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    Timer timer;\n\n    cin >> N >> T >> SIGMA;\n\n    sumWObs.assign(N, 0.0);\n    sumHObs.assign(N, 0.0);\n    cntWObs.assign(N, 1);\n    cntHObs.assign(N, 1);\n\n    for (int i = 0; i < N; i++) {\n        long long w, h;\n        cin >> w >> h;\n        sumWObs[i] = (double)w;\n        sumHObs[i] = (double)h;\n    }\n\n    // Optional individual measurements when there are many extra turns and noise is large.\n    double noiseFactor = clamp_double((SIGMA - 3000.0) / 7000.0, 0.0, 1.0);\n    int extra = max(0, T - 2 * N);\n    int measureQ = min(N, (int)round(extra * noiseFactor));\n\n    if (measureQ > 0) {\n        double L0 = estimate_L_from_current_observations();\n        vector<RectD> base0 = posterior_mean_rects(L0);\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            double ia = base0[a].w * base0[a].h + 0.25 * (base0[a].w + base0[a].h) * sqrt(base0[a].w * base0[a].h);\n            double ib = base0[b].w * base0[b].h + 0.25 * (base0[b].w + base0[b].h) * sqrt(base0[b].w * base0[b].h);\n            return ia > ib;\n        });\n\n        for (int k = 0; k < measureQ; k++) {\n            int i = ids[k];\n            vector<Op> ops;\n            ops.push_back({i, 0, 'U', -1});\n            output_query(ops);\n\n            long long Wm, Hm;\n            if (!(cin >> Wm >> Hm)) return 0;\n\n            sumWObs[i] += (double)Wm;\n            sumHObs[i] += (double)Hm;\n            cntWObs[i]++;\n            cntHObs[i]++;\n        }\n    }\n\n    int remainingTurns = T - measureQ;\n    if (remainingTurns <= 0) return 0;\n\n    double Lest = estimate_L_from_current_observations();\n    vector<RectD> baseRects = posterior_mean_rects(Lest);\n\n    // Evaluation / posterior scenarios.\n    int randomScenarioCount = (N <= 50 ? 10 : 8);\n    if (remainingTurns <= 30) randomScenarioCount = min(randomScenarioCount, 6);\n\n    vector<vector<RectD>> scenarios;\n    scenarios.push_back(baseRects);\n    for (int s = 0; s < randomScenarioCount; s++) {\n        scenarios.push_back(posterior_sample_rects(Lest));\n    }\n    int S = scenarios.size();\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(4096);\n\n    int targetPool = max(450, min(1300, remainingTurns * 3));\n\n    // Shelf DP layouts.\n    int planScenarios = min(S, 5);\n    for (int ps = 0; ps < planScenarios; ps++) {\n        const auto& plan = scenarios[ps];\n        int capCnt = (ps == 0 ? 82 : 42);\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(plan, mode, capCnt);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Greedy BL-style layouts.\n    uniform_real_distribution<double> ud(0.0, 1.0);\n    int greedyAttempts = 0;\n    while ((int)pool.size() < targetPool && timer.elapsed() < 2.15) {\n        int ps = greedyAttempts % planScenarios;\n        const auto& plan = scenarios[ps];\n\n        double aspect = exp(log(0.48) + ud(rng) * (log(2.10) - log(0.48)));\n        double scale = 1.00 + 0.42 * ud(rng);\n\n        double wOverflow = 2.0 + 18.0 * ud(rng);\n        double wWaste = 0.05 + 2.50 * ud(rng);\n        double wBal = 0.02 + 1.10 * ud(rng);\n        double wLB = 1.0 + 6.0 * ud(rng);\n        double jitter = 0.000 + 0.035 * ud(rng);\n\n        vector<Op> ops = make_greedy_layout(plan, aspect, scale, wOverflow, wWaste, wBal, wLB, jitter);\n        add_candidate(pool, seen, ops, baseRects);\n        greedyAttempts++;\n    }\n\n    if (pool.empty()) {\n        // Extremely defensive fallback.\n        vector<Op> ops;\n        for (int i = 0; i < N; i++) ops.push_back({i, 0, 'U', -1});\n        add_candidate(pool, seen, ops, baseRects);\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.estScore < b.estScore;\n    });\n\n    int maxKeep = max(remainingTurns, min((int)pool.size(), 1200));\n    if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n\n    int C = pool.size();\n\n    // Precompute predicted W,H,score for scenario-weighted online selection.\n    vector<float> predW(C * S), predH(C * S), predScore(C * S);\n\n    for (int c = 0; c < C; c++) {\n        for (int s = 0; s < S; s++) {\n            pair<double, double> wh;\n            if (s == 0) wh = {pool[c].baseW, pool[c].baseH};\n            else wh = simulate_ops(pool[c].ops, scenarios[s]);\n            predW[c * S + s] = (float)wh.first;\n            predH[c * S + s] = (float)wh.second;\n            predScore[c * S + s] = (float)(wh.first + wh.second);\n        }\n    }\n\n    vector<double> logWeight(S, 0.0);\n    vector<double> weight(S, 1.0 / S);\n    vector<double> bestScenarioScore(S, INF);\n    vector<char> used(C, 0);\n\n    int bestBaseIdx = 0;\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        int chosen = -1;\n        double bestVal = INF;\n\n        for (int c = 0; c < C; c++) {\n            if (used[c]) continue;\n            double val = 0.0;\n            for (int s = 0; s < S; s++) {\n                double sc = predScore[c * S + s];\n                val += weight[s] * min(bestScenarioScore[s], sc);\n            }\n            val += 1e-9 * pool[c].estScore; // stable tie-breaker\n            if (val < bestVal) {\n                bestVal = val;\n                chosen = c;\n            }\n        }\n\n        if (chosen < 0) chosen = bestBaseIdx;\n\n        output_query(pool[chosen].ops);\n\n        long long Wobs, Hobs;\n        if (!(cin >> Wobs >> Hobs)) return 0;\n\n        if (chosen >= 0 && chosen < C) {\n            used[chosen] = 1;\n\n            for (int s = 0; s < S; s++) {\n                bestScenarioScore[s] = min(bestScenarioScore[s], (double)predScore[chosen * S + s]);\n            }\n\n            // Tempered likelihood: scenario set is sparse, so avoid overconfidence.\n            double effSigma = max(2500.0, 2.25 * SIGMA);\n            for (int s = 0; s < S; s++) {\n                double dw = (double)Wobs - predW[chosen * S + s];\n                double dh = (double)Hobs - predH[chosen * S + s];\n                logWeight[s] += -0.5 * (dw * dw + dh * dh) / (effSigma * effSigma);\n            }\n\n            double mx = *max_element(logWeight.begin(), logWeight.end());\n            double sm = 0.0;\n            for (int s = 0; s < S; s++) {\n                weight[s] = exp(logWeight[s] - mx);\n                sm += weight[s];\n            }\n            if (sm <= 0 || !isfinite(sm)) {\n                fill(weight.begin(), weight.end(), 1.0 / S);\n            } else {\n                for (int s = 0; s < S; s++) {\n                    weight[s] = weight[s] / sm;\n                    // Small floor for exploration / model mismatch.\n                    weight[s] = 0.965 * weight[s] + 0.035 / S;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc041":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, M, HH;\nvector<int> A;\nvector<vector<int>> adj;\nvector<int> highOrder, lowOrder;\nvector<vector<int>> dpCost;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ULL;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct State {\n    vector<int> d;\n    vector<int> cnt;\n    long long val = 0; // sum depth[v] * A[v]\n};\n\nbool hasNeighborDepth(const vector<int>& d, int v, int dep) {\n    for (int u : adj[v]) if (d[u] == dep) return true;\n    return false;\n}\n\nvoid initState(State& s, const vector<int>& depth) {\n    s.d = depth;\n    s.cnt.assign(N, 0);\n    s.val = 0;\n\n    for (int v = 0; v < N; v++) {\n        s.val += 1LL * s.d[v] * A[v];\n\n        if (s.d[v] > 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) s.cnt[v]++;\n            }\n        }\n    }\n}\n\nbool verifyState(const State& s) {\n    if ((int)s.d.size() != N) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (s.d[v] < 0 || s.d[v] > HH) return false;\n\n        if (s.d[v] > 0) {\n            bool ok = false;\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n    }\n\n    return true;\n}\n\nbool canMove(const State& s, int v, int nd) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n\n    return true;\n}\n\nvoid applyMove(State& s, int v, int nd) {\n    int od = s.d[v];\n    if (od == nd) return;\n\n    for (int w : adj[v]) {\n        if (s.d[w] > 0) {\n            if (s.d[w] - 1 == od) s.cnt[w]--;\n            if (s.d[w] - 1 == nd) s.cnt[w]++;\n        }\n    }\n\n    s.val += 1LL * (nd - od) * A[v];\n    s.d[v] = nd;\n\n    int c = 0;\n    if (nd > 0) {\n        for (int u : adj[v]) if (s.d[u] == nd - 1) c++;\n    }\n    s.cnt[v] = c;\n}\n\nbool tryRaise(State& s, int v) {\n    int od = s.d[v];\n\n    for (int nd = HH; nd > od; nd--) {\n        if (canMove(s, v, nd)) {\n            applyMove(s, v, nd);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool greedyImprove(State& s, int maxPass = 10) {\n    bool any = false;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool moved = false;\n\n        for (int v : highOrder) {\n            if (tryRaise(s, v)) {\n                moved = true;\n                any = true;\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nvector<int> aroundMark;\nint aroundStamp = 1;\n\nvoid greedyAround(State& s, int v) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n\n    auto add = [&](int x) {\n        if (aroundMark[x] != aroundStamp) {\n            aroundMark[x] = aroundStamp;\n            list.push_back(x);\n        }\n    };\n\n    add(v);\n    for (int u : adj[v]) {\n        add(u);\n        for (int w : adj[u]) add(w);\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        for (int x : list) tryRaise(s, x);\n    }\n}\n\nvoid computeDPCost() {\n    const int INF = 1e9;\n    dpCost.assign(HH, vector<int>(N, INF));\n    if (HH <= 0) return;\n\n    for (int v = 0; v < N; v++) {\n        dpCost[0][v] = HH * A[v];\n    }\n\n    for (int k = 1; k < HH; k++) {\n        for (int v = 0; v < N; v++) {\n            int best = INF;\n            for (int u : adj[v]) best = min(best, dpCost[k - 1][u]);\n            dpCost[k][v] = best + (HH - k) * A[v];\n        }\n    }\n}\n\nstruct Mode {\n    bool indepTop;\n    bool indepLower;\n    bool lookahead;\n    int kind;\n    double noise;\n    double dpWeight;\n};\n\ndouble coverScore(int cov, double cost, int future, int kind, double noise) {\n    double c = (double)cov;\n    double score;\n\n    if ((kind & 3) == 0) {\n        score = c / cost;\n    } else if ((kind & 3) == 1) {\n        score = c * c / cost;\n    } else if ((kind & 3) == 2) {\n        score = c / sqrt(cost);\n    } else {\n        score = c * sqrt(c) / cost;\n    }\n\n    score *= (1.0 + 0.025 * future);\n\n    if (noise > 0) {\n        score *= (1.0 + noise * (rng.nextDouble() - 0.5));\n    }\n\n    return score;\n}\n\nbool selectCoverLevel(\n    int k,\n    const vector<int>& target,\n    vector<int>& depth,\n    vector<char>& used,\n    bool independent,\n    const Mode& mode\n) {\n    vector<char> targetMark(N, 0), covered(N, 0), banned(N, 0);\n\n    for (int t : target) targetMark[t] = 1;\n\n    int rem = (int)target.size();\n    vector<int> selected;\n\n    auto candidateCost = [&](int c) -> double {\n        double base = (double)(HH - k) * A[c];\n\n        if (mode.dpWeight > 0 && k >= 0 && k < HH && !dpCost.empty()) {\n            double extra = max(0, dpCost[k][c] - (HH - k) * A[c]);\n            base += mode.dpWeight * extra;\n        }\n\n        return max(1.0, base);\n    };\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (used[c]) continue;\n            if (independent && banned[c]) continue;\n\n            int future = 0;\n            if (k > 0) {\n                for (int u : adj[c]) if (!used[u]) future++;\n                if (mode.lookahead && future == 0) continue;\n            }\n\n            int cov = 0;\n            if (k == HH - 1 && targetMark[c] && !covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (targetMark[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = coverScore(cov, candidateCost(c), future, mode.kind, mode.noise);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        used[best] = 1;\n        depth[best] = k;\n        selected.push_back(best);\n\n        if (independent) {\n            banned[best] = 1;\n            for (int u : adj[best]) banned[u] = 1;\n        }\n\n        auto mark = [&](int x) {\n            if (targetMark[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        if (k == HH - 1) mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    auto addCover = [&](int c, int delta) {\n        if (k == HH - 1) {\n            coverCnt[c] += delta;\n            for (int u : adj[c]) coverCnt[u] += delta;\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u]) coverCnt[u] += delta;\n            }\n        }\n    };\n\n    for (int c : selected) {\n        if (used[c] && depth[c] == k) addCover(c, 1);\n    }\n\n    for (int t : target) {\n        if (coverCnt[t] <= 0) return false;\n    }\n\n    sort(selected.begin(), selected.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selected) {\n        if (!used[c] || depth[c] != k) continue;\n\n        if (k < HH - 1 && !hasNeighborDepth(depth, c, HH - 1)) continue;\n\n        bool ok = true;\n\n        if (k == HH - 1) {\n            if (coverCnt[c] <= 1) ok = false;\n\n            if (ok) {\n                for (int u : adj[c]) {\n                    if (coverCnt[u] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u] && coverCnt[u] <= 1) {\n                    ok = false;\n                    break;\n                }\n            }\n        }\n\n        if (ok) {\n            addCover(c, -1);\n            used[c] = 0;\n            depth[c] = HH;\n        }\n    }\n\n    return true;\n}\n\nbool buildChain(vector<int>& outDepth, const Mode& mode) {\n    vector<int> depth(N, HH);\n    vector<char> used(N, 0);\n\n    for (int k = HH - 1; k >= 0; k--) {\n        vector<int> target;\n\n        if (k == HH - 1) {\n            target.resize(N);\n            iota(target.begin(), target.end(), 0);\n        } else {\n            for (int v = 0; v < N; v++) {\n                if (depth[v] == k + 1) target.push_back(v);\n            }\n        }\n\n        if (target.empty()) continue;\n\n        bool independent = (k == HH - 1 ? mode.indepTop : mode.indepLower);\n\n        if (!selectCoverLevel(k, target, depth, used, independent, mode)) {\n            return false;\n        }\n    }\n\n    State s;\n    initState(s, depth);\n\n    if (!verifyState(s)) return false;\n\n    outDepth = depth;\n    return true;\n}\n\nbool localImproveCover(\n    const vector<char>& targetMark,\n    const vector<char>& candidate,\n    vector<char>& selected,\n    const vector<char>& forced,\n    const vector<double>& cost,\n    bool topClosed,\n    int maxLoops\n) {\n    vector<vector<int>> cover(N);\n\n    for (int c = 0; c < N; c++) {\n        if (!candidate[c] && !selected[c]) continue;\n\n        if (topClosed && targetMark[c]) cover[c].push_back(c);\n\n        for (int u : adj[c]) {\n            if (targetMark[u]) cover[c].push_back(u);\n        }\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    for (int c = 0; c < N; c++) {\n        if (!selected[c]) continue;\n        for (int t : cover[c]) coverCnt[t]++;\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    vector<int> candList;\n    for (int c = 0; c < N; c++) {\n        if (candidate[c]) candList.push_back(c);\n    }\n\n    auto removableActual = [&](int c) -> bool {\n        if (forced[c]) return false;\n        if (cost[c] <= 1e-9 || cost[c] > 1e17) return false;\n\n        for (int t : cover[c]) {\n            if (coverCnt[t] <= 1) return false;\n        }\n\n        return true;\n    };\n\n    auto pruneActual = [&]() {\n        vector<int> sels;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c]) sels.push_back(c);\n        }\n\n        sort(sels.begin(), sels.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        for (int c : sels) {\n            if (!selected[c]) continue;\n            if (!removableActual(c)) continue;\n\n            selected[c] = 0;\n            for (int t : cover[c]) coverCnt[t]--;\n        }\n    };\n\n    pruneActual();\n\n    if (maxLoops <= 0) {\n        for (int t = 0; t < N; t++) {\n            if (targetMark[t] && coverCnt[t] <= 0) return false;\n        }\n        return true;\n    }\n\n    vector<int> tmpCnt(N);\n\n    // Add one candidate, then remove multiple redundant selected vertices.\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                selOrder.push_back(c);\n            }\n        }\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        double bestGain = 1e-6;\n        int bestC = -1;\n        vector<int> bestRem;\n\n        for (int c : candList) {\n            if (selected[c]) continue;\n            if (cover[c].empty()) continue;\n            if (cost[c] <= 1e-9 || cost[c] > 1e17) continue;\n\n            copy(coverCnt.begin(), coverCnt.end(), tmpCnt.begin());\n\n            for (int t : cover[c]) tmpCnt[t]++;\n\n            double gain = -cost[c];\n            vector<int> rems;\n\n            for (int s : selOrder) {\n                bool ok = true;\n\n                for (int t : cover[s]) {\n                    if (tmpCnt[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    for (int t : cover[s]) tmpCnt[t]--;\n                    gain += cost[s];\n                    rems.push_back(s);\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestC = c;\n                bestRem.swap(rems);\n            }\n        }\n\n        if (bestC == -1) break;\n\n        selected[bestC] = 1;\n        for (int t : cover[bestC]) coverCnt[t]++;\n\n        for (int r : bestRem) {\n            if (!selected[r]) continue;\n\n            selected[r] = 0;\n            for (int t : cover[r]) coverCnt[t]--;\n        }\n\n        pruneActual();\n    }\n\n    // Delete one expensive selected vertex and greedily repair by adding multiple cheap vertices.\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                selOrder.push_back(c);\n            }\n        }\n\n        if (selOrder.empty()) break;\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        int trialLimit = min((int)selOrder.size(), 80 + 20 * maxLoops);\n\n        double bestGain = 1e-6;\n        vector<char> bestSel;\n        vector<int> bestCnt;\n\n        for (int ii = 0; ii < trialLimit; ii++) {\n            int r = selOrder[ii];\n\n            vector<char> tmpSel = selected;\n            vector<int> tc = coverCnt;\n\n            tmpSel[r] = 0;\n            for (int t : cover[r]) tc[t]--;\n\n            vector<char> need(N, 0);\n            int rem = 0;\n\n            for (int t : cover[r]) {\n                if (tc[t] == 0 && !need[t]) {\n                    need[t] = 1;\n                    rem++;\n                }\n            }\n\n            double addCost = 0.0;\n            bool fail = false;\n            int steps = 0;\n\n            while (rem > 0 && steps < 12) {\n                int bestA = -1;\n                int bestCov = 0;\n                double bestScore = -1;\n\n                for (int c : candList) {\n                    if (tmpSel[c]) continue;\n                    if (cost[c] <= 1e-9 || cost[c] > 1e17) continue;\n\n                    int cov = 0;\n                    for (int t : cover[c]) {\n                        if (need[t]) cov++;\n                    }\n\n                    if (cov == 0) continue;\n\n                    double sc = (double)cov * cov / cost[c];\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestA = c;\n                        bestCov = cov;\n                    }\n                }\n\n                if (bestA == -1 || bestCov == 0) {\n                    fail = true;\n                    break;\n                }\n\n                tmpSel[bestA] = 1;\n                addCost += cost[bestA];\n\n                for (int t : cover[bestA]) {\n                    tc[t]++;\n                    if (need[t]) {\n                        need[t] = 0;\n                        rem--;\n                    }\n                }\n\n                steps++;\n            }\n\n            if (fail || rem > 0) continue;\n\n            double gain = cost[r] - addCost;\n\n            vector<int> tmpOrder;\n            for (int c = 0; c < N; c++) {\n                if (tmpSel[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                    tmpOrder.push_back(c);\n                }\n            }\n\n            sort(tmpOrder.begin(), tmpOrder.end(), [&](int a, int b) {\n                return cost[a] > cost[b];\n            });\n\n            for (int c : tmpOrder) {\n                if (!tmpSel[c]) continue;\n\n                bool ok = true;\n                for (int t : cover[c]) {\n                    if (tc[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    tmpSel[c] = 0;\n                    for (int t : cover[c]) tc[t]--;\n                    gain += cost[c];\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestSel.swap(tmpSel);\n                bestCnt.swap(tc);\n            }\n        }\n\n        if (bestGain > 1e-6) {\n            selected.swap(bestSel);\n            coverCnt.swap(bestCnt);\n            pruneActual();\n        } else {\n            break;\n        }\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    return true;\n}\n\nbool reoptTop(State& s, int improveLoops) {\n    if (HH == 0) return false;\n\n    int k = HH - 1;\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0), candidate(N, 0), selected(N, 0), covered(N, 0), forced(N, 0);\n    vector<double> cost(N, 1e18);\n\n    int rem = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] >= k) {\n            target[v] = 1;\n            rem++;\n        }\n    }\n\n    if (rem == 0) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (!target[v]) continue;\n\n        if (k == 0 || hasNeighborDepth(d, v, k - 1)) {\n            candidate[v] = 1;\n            cost[v] = A[v];\n        }\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            if (target[c] && !covered[c]) cov++;\n\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = (double)cov / A[c];\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n\n        auto mark = [&](int x) {\n            if (target[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, true, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n\n    for (int v = 0; v < N; v++) {\n        if (target[v]) nd[v] = HH;\n    }\n\n    for (int v = 0; v < N; v++) {\n        if (selected[v]) nd[v] = k;\n    }\n\n    State ns;\n    initState(ns, nd);\n\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n\n    return false;\n}\n\nbool reoptLevel(State& s, int k, int improveLoops) {\n    if (k < 0 || k >= HH - 1) return false;\n\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0);\n    int targetCount = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k + 1) {\n            target[v] = 1;\n            targetCount++;\n        }\n    }\n\n    if (targetCount == 0) return false;\n\n    vector<char> candidate(N, 0), selected(N, 0), forced(N, 0), covered(N, 0);\n    vector<double> cost(N, 1e18);\n    vector<int> retireDepth(N, -1);\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            candidate[v] = 1;\n            selected[v] = 0;\n\n            int bestRetire = -1;\n\n            // Refined point:\n            // if this depth-k support is no longer needed as support,\n            // it may still be able to move to an intermediate depth, not necessarily H.\n            for (int dep = HH; dep >= k + 2; dep--) {\n                if (hasNeighborDepth(d, v, dep - 1)) {\n                    bestRetire = dep;\n                    break;\n                }\n            }\n\n            if (bestRetire == -1) {\n                forced[v] = 1;\n                selected[v] = 1;\n                retireDepth[v] = k;\n                cost[v] = 0;\n            } else {\n                retireDepth[v] = bestRetire;\n                cost[v] = (bestRetire - k) * A[v];\n            }\n        } else if (d[v] == HH) {\n            bool supp = (k == 0) || hasNeighborDepth(d, v, k - 1);\n\n            if (supp) {\n                candidate[v] = 1;\n                cost[v] = (HH - k) * A[v];\n            }\n        }\n    }\n\n    int rem = targetCount;\n\n    auto markBy = [&](int c) {\n        for (int u : adj[c]) {\n            if (target[u] && !covered[u]) {\n                covered[u] = 1;\n                rem--;\n            }\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (forced[v]) markBy(v);\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = (double)cov / max(1.0, cost[c]);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n        markBy(best);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, false, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            if (selected[v]) {\n                nd[v] = k;\n            } else {\n                if (retireDepth[v] == -1) return false;\n                nd[v] = retireDepth[v];\n            }\n        } else if (d[v] == HH && selected[v]) {\n            nd[v] = k;\n        }\n    }\n\n    State ns;\n    initState(ns, nd);\n\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n\n    return false;\n}\n\nbool supportReplaceImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n    vector<int> childIndex(N, -1);\n    vector<int> candMark(N, 0);\n    int stamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n\n        for (int p : highOrder) {\n            if ((chk++ & 31) == 0 && elapsed() > stopTime) return any;\n\n            int k = s.d[p];\n            if (k >= HH) continue;\n\n            vector<int> childs;\n\n            for (int w : adj[p]) {\n                if (s.d[w] == k + 1 && s.cnt[w] <= 1) {\n                    childs.push_back(w);\n                }\n            }\n\n            if (childs.empty()) {\n                if (tryRaise(s, p)) {\n                    moved = true;\n                    any = true;\n                }\n                continue;\n            }\n\n            int C = (int)childs.size();\n            if (C > 8) continue;\n\n            for (int i = 0; i < C; i++) childIndex[childs[i]] = i;\n\n            if (++stamp == INT_MAX) {\n                fill(candMark.begin(), candMark.end(), 0);\n                stamp = 1;\n            }\n\n            vector<int> raw;\n\n            for (int w : childs) {\n                for (int u : adj[w]) {\n                    if (u == p) continue;\n                    if (s.d[u] == k) continue;\n                    if (s.d[u] == k + 1) continue;\n\n                    if (candMark[u] != stamp) {\n                        candMark[u] = stamp;\n                        raw.push_back(u);\n                    }\n                }\n            }\n\n            vector<int> cands, masks, deltas;\n\n            for (int u : raw) {\n                if (!canMove(s, u, k)) continue;\n\n                int mask = 0;\n                for (int x : adj[u]) {\n                    int idx = childIndex[x];\n                    if (idx >= 0) mask |= 1 << idx;\n                }\n\n                if (mask == 0) continue;\n\n                cands.push_back(u);\n                masks.push_back(mask);\n                deltas.push_back((k - s.d[u]) * A[u]);\n            }\n\n            for (int x : childs) childIndex[x] = -1;\n\n            int K = (int)cands.size();\n            if (K == 0) continue;\n\n            int S = 1 << C;\n            int FULL = S - 1;\n            const int NEG = -1000000000;\n\n            vector<vector<int>> dp(K + 1, vector<int>(S, NEG));\n            vector<vector<unsigned char>> take(K + 1, vector<unsigned char>(S, 0));\n            vector<vector<int>> pre(K + 1, vector<int>(S, -1));\n\n            dp[0][0] = 0;\n\n            for (int i = 0; i < K; i++) {\n                for (int m = 0; m < S; m++) {\n                    if (dp[i][m] <= NEG / 2) continue;\n\n                    if (dp[i][m] > dp[i + 1][m]) {\n                        dp[i + 1][m] = dp[i][m];\n                    }\n\n                    int nm = m | masks[i];\n                    if (nm == m) continue;\n\n                    int nv = dp[i][m] + deltas[i];\n                    if (nv > dp[i + 1][nm]) {\n                        dp[i + 1][nm] = nv;\n                        take[i + 1][nm] = 1;\n                        pre[i + 1][nm] = m;\n                    }\n                }\n            }\n\n            if (dp[K][FULL] <= NEG / 2) continue;\n\n            vector<int> chosen;\n            int mask = FULL;\n\n            for (int i = K; i >= 1; i--) {\n                if (take[i][mask]) {\n                    chosen.push_back(cands[i - 1]);\n                    mask = pre[i][mask];\n                }\n            }\n\n            vector<pair<int, int>> oldDepth;\n            bool ok = true;\n            int altDelta = 0;\n\n            for (int u : chosen) {\n                int od = s.d[u];\n                oldDepth.push_back({u, od});\n\n                if (!canMove(s, u, k)) {\n                    ok = false;\n                    break;\n                }\n\n                applyMove(s, u, k);\n                altDelta += (k - od) * A[u];\n            }\n\n            int bestNd = -1;\n\n            if (ok) {\n                for (int nd = HH; nd > k; nd--) {\n                    if (canMove(s, p, nd)) {\n                        bestNd = nd;\n                        break;\n                    }\n                }\n            }\n\n            bool accepted = false;\n\n            if (bestNd != -1) {\n                int net = altDelta + (bestNd - k) * A[p];\n\n                if (net > 0) {\n                    applyMove(s, p, bestNd);\n                    greedyAround(s, p);\n                    moved = true;\n                    any = true;\n                    accepted = true;\n                }\n            }\n\n            if (!accepted) {\n                for (int i = (int)oldDepth.size() - 1; i >= 0; i--) {\n                    applyMove(s, oldDepth[i].first, oldDepth[i].second);\n                }\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nvoid polish(State& s, int passes, int improveLoops, double stopTime) {\n    for (int p = 0; p < passes; p++) {\n        if (elapsed() > stopTime) return;\n\n        reoptTop(s, improveLoops);\n\n        for (int k = HH - 2; k >= 0; k--) {\n            if (elapsed() > stopTime) return;\n            reoptLevel(s, k, improveLoops);\n        }\n\n        greedyImprove(s, 8);\n\n        if (improveLoops > 0 && elapsed() < stopTime) {\n            supportReplaceImprove(s, 1, stopTime);\n            greedyImprove(s, 4);\n        }\n    }\n}\n\nState makeFallback() {\n    vector<int> dist(N, -1);\n    queue<int> q;\n\n    dist[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u : adj[v]) {\n            if (dist[u] == -1) {\n                dist[u] = dist[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    vector<int> depth(N, 0);\n\n    for (int v = 0; v < N; v++) {\n        if (dist[v] < 0) depth[v] = 0;\n        else depth[v] = dist[v] % (HH + 1);\n    }\n\n    State s;\n    initState(s, depth);\n\n    if (!verifyState(s)) {\n        fill(depth.begin(), depth.end(), 0);\n        initState(s, depth);\n    }\n\n    greedyImprove(s, 12);\n    return s;\n}\n\nvoid anneal(State& best, double endTime) {\n    State cur = best;\n\n    double st = elapsed();\n    double duration = max(0.001, endTime - st);\n\n    double T0 = 120.0;\n    double T1 = 0.8;\n    double T = T0;\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 4095) == 0) {\n            double now = elapsed();\n\n            if (now >= endTime) break;\n\n            double prog = min(1.0, (now - st) / duration);\n            T = T0 * pow(T1 / T0, prog);\n\n            if ((iter & 65535) == 0 && iter > 0) {\n                greedyImprove(cur, 3);\n                if (cur.val > best.val) best = cur;\n                if (cur.val + 7000 < best.val) cur = best;\n            }\n        }\n\n        iter++;\n\n        int v = -1, nd = -1;\n        bool prechecked = false;\n\n        int type = rng.nextInt(100);\n\n        if (type < 30) {\n            int w = -1;\n\n            for (int t = 0; t < 6; t++) {\n                int cand = rng.nextInt(N);\n\n                if (cur.d[cand] > 0 && cur.cnt[cand] <= 1) {\n                    w = cand;\n                    break;\n                }\n            }\n\n            if (w == -1) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] == 0) continue;\n                w = cand;\n            }\n\n            nd = cur.d[w] - 1;\n\n            int bestU = -1;\n            int bestDelta = INT_MIN;\n\n            for (int u : adj[w]) {\n                if (cur.d[u] == nd) continue;\n                if (!canMove(cur, u, nd)) continue;\n\n                int delta = (nd - cur.d[u]) * A[u];\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestU = u;\n                }\n            }\n\n            if (bestU == -1) continue;\n\n            v = bestU;\n            prechecked = true;\n        } else if (type < 55) {\n            int K = min(N, 450);\n            v = lowOrder[rng.nextInt(K)];\n            if (cur.d[v] == 0) continue;\n            nd = rng.nextInt(cur.d[v]);\n        } else if (type < 85) {\n            int K = min(N, 750);\n            v = highOrder[rng.nextInt(K)];\n\n            if (cur.d[v] == HH) continue;\n\n            nd = -1;\n\n            for (int x = HH; x > cur.d[v]; x--) {\n                if (canMove(cur, v, x)) {\n                    nd = x;\n                    break;\n                }\n            }\n\n            if (nd == -1) continue;\n            prechecked = true;\n        } else {\n            v = rng.nextInt(N);\n            nd = rng.nextInt(HH + 1);\n            if (nd == cur.d[v]) continue;\n        }\n\n        if (!prechecked && !canMove(cur, v, nd)) continue;\n\n        int delta = (nd - cur.d[v]) * A[v];\n\n        bool accept = false;\n\n        if (delta >= 0) {\n            accept = true;\n        } else {\n            if (delta > -30.0 * T) {\n                double prob = exp(delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n        }\n\n        if (!accept) continue;\n\n        applyMove(cur, v, nd);\n\n        if (delta < 0) {\n            greedyAround(cur, v);\n        }\n\n        if (cur.val > best.val) {\n            best = cur;\n        }\n    }\n\n    greedyImprove(best, 10);\n}\n\nbool isBad(const State& s, int v) {\n    return s.d[v] > 0 && s.cnt[v] <= 0;\n}\n\nvoid repairState(State& s) {\n    deque<int> q;\n    vector<char> inq(N, 0);\n\n    auto push = [&](int v) {\n        if (!inq[v]) {\n            inq[v] = 1;\n            q.push_back(v);\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (isBad(s, v)) push(v);\n    }\n\n    int guard = 0;\n\n    while (!q.empty() && guard < 50000) {\n        int v = q.front();\n        q.pop_front();\n        inq[v] = 0;\n\n        if (!isBad(s, v)) continue;\n\n        int old = s.d[v];\n        int nd = 0;\n\n        for (int x = old - 1; x >= 1; x--) {\n            bool ok = false;\n\n            for (int u : adj[v]) {\n                if (s.d[u] == x - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n\n            if (ok) {\n                nd = x;\n                break;\n            }\n        }\n\n        applyMove(s, v, nd);\n\n        push(v);\n        for (int u : adj[v]) push(u);\n\n        guard++;\n    }\n\n    if (!verifyState(s)) {\n        vector<int> zero(N, 0);\n        initState(s, zero);\n    }\n}\n\nvoid lns(State& best, double endTime) {\n    State base = best;\n\n    while (elapsed() < endTime) {\n        State s = (rng.nextInt(100) < 85 ? best : base);\n\n        int remCnt = 2 + rng.nextInt(12);\n        if (rng.nextInt(100) < 15) remCnt += rng.nextInt(20);\n\n        for (int i = 0; i < remCnt; i++) {\n            int v = -1;\n\n            for (int t = 0; t < 60; t++) {\n                int cand;\n\n                if (rng.nextInt(100) < 65) {\n                    cand = highOrder[rng.nextInt(min(N, 800))];\n                } else {\n                    cand = rng.nextInt(N);\n                }\n\n                if (s.d[cand] < HH) {\n                    v = cand;\n                    break;\n                }\n            }\n\n            if (v != -1) {\n                applyMove(s, v, HH);\n            }\n        }\n\n        int addCnt = 4 + rng.nextInt(24);\n\n        for (int i = 0; i < addCnt; i++) {\n            int K = min(N, 250 + rng.nextInt(550));\n            int v = lowOrder[rng.nextInt(K)];\n\n            int nd;\n\n            if (rng.nextInt(100) < 70) {\n                nd = rng.nextInt(HH);\n            } else {\n                nd = max(0, s.d[v] - 1 - rng.nextInt(3));\n            }\n\n            if (nd < 0) nd = 0;\n            if (nd > HH) nd = HH;\n\n            applyMove(s, v, nd);\n        }\n\n        for (int t = 0; t < 35; t++) {\n            int v = rng.nextInt(N);\n\n            if (!isBad(s, v)) continue;\n\n            int need = s.d[v] - 1;\n            if (need < 0) continue;\n\n            int bu = -1;\n            int bestCost = INT_MAX;\n\n            for (int u : adj[v]) {\n                int c = abs(s.d[u] - need) * A[u] + A[u];\n\n                if (c < bestCost) {\n                    bestCost = c;\n                    bu = u;\n                }\n            }\n\n            if (bu != -1) {\n                applyMove(s, bu, need);\n            }\n        }\n\n        repairState(s);\n\n        if (!verifyState(s)) continue;\n\n        greedyImprove(s, 5);\n\n        if (s.val > best.val - 3000 && elapsed() < endTime - 0.03) {\n            polish(s, 1, 1, endTime);\n        }\n\n        if (s.val > best.val) {\n            best = s;\n            base = s;\n        } else if (s.val > base.val || rng.nextInt(100) < 5) {\n            base = s;\n        }\n    }\n\n    greedyImprove(best, 8);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> HH;\n\n    A.resize(N);\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        cin >> A[i];\n        seed = seed * 1000003ULL + A[i] + 97;\n    }\n\n    adj.assign(N, {});\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n\n        seed ^= (uint64_t)(u + 1) * 1000000007ULL + (uint64_t)(v + 1) * 1000003ULL;\n    }\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n\n        seed ^= ((uint64_t)x << 32) ^ (uint64_t)y ^ ((uint64_t)i * 11995408973635179863ULL);\n    }\n\n    if (seed == 0) seed = 88172645463325252ULL;\n    rng.x = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    highOrder.resize(N);\n    lowOrder.resize(N);\n\n    iota(highOrder.begin(), highOrder.end(), 0);\n    iota(lowOrder.begin(), lowOrder.end(), 0);\n\n    sort(highOrder.begin(), highOrder.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    sort(lowOrder.begin(), lowOrder.end(), [&](int a, int b) {\n        return A[a] < A[b];\n    });\n\n    aroundMark.assign(N, 0);\n\n    computeDPCost();\n\n    State best = makeFallback();\n    polish(best, 1, 0, 0.20);\n\n    vector<State> pool;\n\n    auto addPool = [&](const State& s) {\n        if (!verifyState(s)) return;\n\n        const int POOL_SIZE = 4;\n\n        if ((int)pool.size() < POOL_SIZE) {\n            pool.push_back(s);\n            return;\n        }\n\n        int worst = 0;\n        for (int i = 1; i < POOL_SIZE; i++) {\n            if (pool[i].val < pool[worst].val) worst = i;\n        }\n\n        if (s.val > pool[worst].val) {\n            pool[worst] = s;\n        }\n    };\n\n    addPool(best);\n\n    const double CONSTRUCT_LIMIT = 0.70;\n    int attempt = 0;\n\n    double dpWs[] = {0.0, 0.0, 0.015, 0.03, 0.06, 0.10};\n\n    while (attempt < 220 && elapsed() < CONSTRUCT_LIMIT) {\n        Mode mode;\n\n        if (attempt < 24) {\n            mode.indepTop = (attempt & 1);\n            mode.indepLower = (attempt & 2);\n            mode.kind = (attempt / 6) & 3;\n            mode.noise = 0.0;\n            mode.dpWeight = dpWs[(attempt / 4) % 6];\n        } else {\n            mode.indepTop = (rng.nextInt(100) < 45);\n            mode.indepLower = (rng.nextInt(100) < 25);\n            mode.kind = rng.nextInt(4);\n            mode.noise = 0.20 + 0.70 * rng.nextDouble();\n            mode.dpWeight = dpWs[rng.nextInt(6)] * (0.7 + 0.8 * rng.nextDouble());\n        }\n\n        mode.lookahead = true;\n\n        vector<int> depth;\n\n        if (buildChain(depth, mode)) {\n            State s;\n            initState(s, depth);\n\n            polish(s, 1, 0, CONSTRUCT_LIMIT);\n\n            if (s.val > best.val) best = s;\n            addPool(s);\n        }\n\n        attempt++;\n    }\n\n    for (State s : pool) {\n        if (elapsed() > 0.95) break;\n\n        polish(s, 1, 4, 0.98);\n\n        if (s.val > best.val) best = s;\n    }\n\n    polish(best, 1, 5, 1.08);\n\n    anneal(best, 1.56);\n\n    polish(best, 1, 4, 1.67);\n\n    lns(best, 1.83);\n\n    polish(best, 1, 6, 1.875);\n    supportReplaceImprove(best, 1, 1.89);\n    greedyImprove(best, 10);\n\n    if (!verifyState(best)) {\n        best = makeFallback();\n    }\n\n    vector<int> parent(N, -1);\n    bool ok = true;\n\n    for (int v = 0; v < N; v++) {\n        if (best.d[v] == 0) {\n            parent[v] = -1;\n        } else {\n            int p = -1;\n\n            for (int u : adj[v]) {\n                if (best.d[u] == best.d[v] - 1) {\n                    p = u;\n                    break;\n                }\n            }\n\n            if (p == -1) {\n                ok = false;\n                break;\n            }\n\n            parent[v] = p;\n        }\n    }\n\n    if (!ok) {\n        for (int i = 0; i < N; i++) parent[i] = -1;\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N;\nuint32_t FULL;\nconst int MAXN = 20;\n\nstruct Op {\n    char d;\n    int p;\n};\n\nstruct GAct {\n    char d;\n    int p;\n    int k;\n};\n\nstruct State {\n    array<uint32_t, MAXN> x{}, o{};\n    int xcnt = 0;\n};\n\nState INIT;\nvector<pair<int,int>> initialXs;\nint idxAt[MAXN][MAXN];\n\nchrono::steady_clock::time_point START;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nint popc(uint32_t v) {\n    return __builtin_popcount(v);\n}\n\nint firstBit(uint32_t m) {\n    return m ? __builtin_ctz(m) : N;\n}\n\nint lastBit(uint32_t m) {\n    return m ? 31 - __builtin_clz(m) : -1;\n}\n\nchar invDir(char d) {\n    if (d == 'L') return 'R';\n    if (d == 'R') return 'L';\n    if (d == 'U') return 'D';\n    return 'U';\n}\n\nvoid appendOps(vector<Op>& ops, char d, int p, int k) {\n    for (int i = 0; i < k; i++) ops.push_back({d, p});\n}\n\nbool edgeO(const State& s, const Op& op) {\n    int p = op.p;\n    uint32_t bit = 1u << p;\n    if (op.d == 'L') return s.o[p] & 1u;\n    if (op.d == 'R') return s.o[p] & (1u << (N - 1));\n    if (op.d == 'U') return s.o[0] & bit;\n    return s.o[N - 1] & bit;\n}\n\ninline void setBit(uint32_t& m, uint32_t bit, bool v) {\n    if (v) m |= bit;\n    else m &= ~bit;\n}\n\nvoid applyOp(State& s, const Op& op) {\n    int p = op.p;\n    if (op.d == 'L') {\n        if (s.x[p] & 1u) s.xcnt--;\n        s.x[p] >>= 1;\n        s.o[p] >>= 1;\n    } else if (op.d == 'R') {\n        if (s.x[p] & (1u << (N - 1))) s.xcnt--;\n        s.x[p] = (s.x[p] << 1) & FULL;\n        s.o[p] = (s.o[p] << 1) & FULL;\n    } else if (op.d == 'U') {\n        uint32_t bit = 1u << p;\n        if (s.x[0] & bit) s.xcnt--;\n        for (int i = 0; i < N - 1; i++) {\n            bool xb = s.x[i + 1] & bit;\n            bool ob = s.o[i + 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[N - 1] &= ~bit;\n        s.o[N - 1] &= ~bit;\n    } else {\n        uint32_t bit = 1u << p;\n        if (s.x[N - 1] & bit) s.xcnt--;\n        for (int i = N - 1; i >= 1; i--) {\n            bool xb = s.x[i - 1] & bit;\n            bool ob = s.o[i - 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[0] &= ~bit;\n        s.o[0] &= ~bit;\n    }\n}\n\nvoid applyGAct(State& s, const GAct& a) {\n    Op op{a.d, a.p};\n    for (int i = 0; i < a.k; i++) applyOp(s, op);\n}\n\nvector<Op> expandGSeq(const vector<GAct>& gs) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& g : gs) total += g.k;\n    ops.reserve(total);\n    for (auto& g : gs) appendOps(ops, g.d, g.p, g.k);\n    return ops;\n}\n\nbool isPerfectFull(const vector<Op>& ops) {\n    if ((int)ops.size() > 4 * N * N) return false;\n    State s = INIT;\n    for (auto& op : ops) {\n        if (edgeO(s, op)) return false;\n        applyOp(s, op);\n    }\n    return s.xcnt == 0;\n}\n\nbool truncateToPerfectPrefix(vector<Op>& ops) {\n    if (INIT.xcnt == 0) {\n        ops.clear();\n        return true;\n    }\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) {\n            ops.resize(t + 1);\n            return true;\n        }\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkip(const vector<Op>& ops, int l, int r) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (l <= t && t < r) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkipTwo(const vector<Op>& ops, int a, int b) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (t == a || t == b) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nvoid pruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n\n        int maxLen = min(55, (int)seq.size());\n        for (int len = maxLen; len >= 2 && elapsed() < until; len--) {\n            for (int i = 0; i + len <= (int)seq.size() && elapsed() < until; ) {\n                if (canPerfectSkip(seq, i, i + len)) {\n                    seq.erase(seq.begin() + i, seq.begin() + i + len);\n                    truncateToPerfectPrefix(seq);\n                    changed = true;\n                    i = max(0, i - len);\n                } else {\n                    i++;\n                }\n            }\n        }\n\n        for (int i = 0; i < (int)seq.size() && elapsed() < until; ) {\n            if (canPerfectSkip(seq, i, i + 1)) {\n                seq.erase(seq.begin() + i);\n                truncateToPerfectPrefix(seq);\n                changed = true;\n                if (i > 0) i--;\n            } else {\n                i++;\n            }\n        }\n    }\n}\n\nvoid pairPruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n        int n = (int)seq.size();\n\n        for (int pass = 0; pass < 2 && !changed && elapsed() < until; pass++) {\n            for (int i = 0; i < n && !changed && elapsed() < until; i++) {\n                for (int j = n - 1; j > i && elapsed() < until; j--) {\n                    bool invSameLine = (seq[i].p == seq[j].p && invDir(seq[i].d) == seq[j].d);\n                    if (pass == 0 && !invSameLine) continue;\n                    if (pass == 1 && invSameLine) continue;\n\n                    if (canPerfectSkipTwo(seq, i, j)) {\n                        seq.erase(seq.begin() + j);\n                        seq.erase(seq.begin() + i);\n                        truncateToPerfectPrefix(seq);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nstruct OInfo {\n    int firstRow[MAXN], lastRow[MAXN], rowCnt[MAXN];\n    int firstCol[MAXN], lastCol[MAXN], colCnt[MAXN];\n};\n\nvoid computeOInfo(const State& s, OInfo& info) {\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.o[i];\n        info.firstRow[i] = firstBit(m);\n        info.lastRow[i] = lastBit(m);\n        info.rowCnt[i] = popc(m);\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t cm = 0;\n        uint32_t bit = 1u << j;\n        for (int i = 0; i < N; i++) {\n            if (s.o[i] & bit) cm |= 1u << i;\n        }\n        info.firstCol[j] = firstBit(cm);\n        info.lastCol[j] = lastBit(cm);\n        info.colCnt[j] = popc(cm);\n    }\n}\n\nstruct Analysis {\n    int xcnt = 0;\n    int invis = 0;\n    double sumMin = 0;\n};\n\nAnalysis analyzeState(const State& s) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    Analysis a;\n    a.xcnt = s.xcnt;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            int md = 100;\n\n            if (j < info.firstRow[i]) vis++, md = min(md, j + 1);\n            if (j > info.lastRow[i]) vis++, md = min(md, N - j);\n            if (i < info.firstCol[j]) vis++, md = min(md, i + 1);\n            if (i > info.lastCol[j]) vis++, md = min(md, N - i);\n\n            if (vis == 0) {\n                a.invis++;\n                a.sumMin += N;\n            } else {\n                a.sumMin += md;\n            }\n        }\n    }\n    return a;\n}\n\nstruct GenParam {\n    double alpha = 1.0;\n    double critW = 6.0;\n    double twoW = 2.0;\n    double multiW = 1.0;\n    double damageW = 0.0;\n};\n\nstruct Cand {\n    char d;\n    int p, k;\n    int cnt;\n    double benefit;\n    double score;\n};\n\nvector<Cand> genCandidates(const State& s, const GenParam& gp) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    static double w[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) w[i][j] = 0.0;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            if (j < info.firstRow[i]) vis++;\n            if (j > info.lastRow[i]) vis++;\n            if (i < info.firstCol[j]) vis++;\n            if (i > info.lastCol[j]) vis++;\n\n            if (vis == 1) w[i][j] = gp.critW;\n            else if (vis == 2) w[i][j] = gp.twoW;\n            else if (vis >= 3) w[i][j] = gp.multiW;\n        }\n    }\n\n    vector<Cand> res;\n    res.reserve(160);\n\n    auto addCand = [&](char d, int p, int k, int cnt, double benefit, int movedO) {\n        if (cnt <= 0) return;\n        double b = max(1e-9, benefit);\n        double sc = (double)k / pow(b, gp.alpha) + gp.damageW * movedO * k;\n        res.push_back({d, p, k, cnt, benefit, sc});\n    };\n\n    for (int i = 0; i < N; i++) {\n        {\n            int clear = info.firstRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int j = 0; j < clear; j++) {\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('L', i, j + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n        {\n            int clear = N - 1 - info.lastRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int j = N - 1 - t;\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('R', i, t + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n        {\n            int clear = info.firstCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int i = 0; i < clear; i++) {\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('U', j, i + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n        {\n            int clear = N - 1 - info.lastCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int i = N - 1 - t;\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('D', j, t + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\n// ---------- Guaranteed cover construction ----------\n\nstruct CoverCand {\n    char d;\n    int p, k;\n    uint64_t mask;\n};\n\nvector<CoverCand> buildCoverCandidates() {\n    vector<CoverCand> cands;\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        for (int j = 0; j < N; j++) {\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'L', i, j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int j = N - 1 - t;\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'R', i, t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n\n        uint64_t mask = 0;\n        for (int i = 0; i < N; i++) {\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'U', j, i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int i = N - 1 - t;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'D', j, t + 1, mask});\n            }\n        }\n    }\n\n    return cands;\n}\n\nuint64_t unionIds(const vector<int>& ids, const vector<CoverCand>& cands) {\n    uint64_t m = 0;\n    for (int id : ids) m |= cands[id].mask;\n    return m;\n}\n\nint objectiveCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    if (ids.empty()) return 0;\n    int sum = 0, mx = 0;\n    for (int id : ids) {\n        sum += 2 * cands[id].k;\n        mx = max(mx, cands[id].k);\n    }\n    return sum - mx;\n}\n\nvoid removeRedundant(vector<int>& ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int a = 0; a < (int)ids.size(); a++) {\n            uint64_t u = 0;\n            for (int b = 0; b < (int)ids.size(); b++) if (a != b) {\n                u |= cands[ids[b]].mask;\n            }\n            if (u == ALL) {\n                ids.erase(ids.begin() + a);\n                changed = true;\n                break;\n            }\n        }\n    }\n}\n\ndouble coverScore(const CoverCand& c, int nc, int mode) {\n    int cost = 2 * c.k;\n    if (mode == 0) return cost / (double)nc;\n    if (mode == 1) return cost / pow((double)nc, 1.3);\n    if (mode == 2) return (cost - 0.3 * c.k) / pow((double)nc, 1.1);\n    if (mode == 3) return cost / (double)(nc * nc);\n    return (cost + 0.05 * __builtin_popcountll(c.mask)) / pow((double)nc, 1.5);\n}\n\nvector<int> greedyCoverMulti(vector<int> ids, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    uint64_t covered = unionIds(ids, cands);\n\n    while (covered != ALL) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            uint64_t nm = cands[i].mask & ~covered;\n            if (!nm) continue;\n\n            int nc = __builtin_popcountll(nm);\n            double sc = coverScore(cands[i], nc, mode);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) break;\n        ids.push_back(best);\n        covered |= cands[best].mask;\n    }\n\n    removeRedundant(ids, cands, ALL);\n    return ids;\n}\n\nvector<int> greedyCover(int pre, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    vector<int> ids;\n    if (pre >= 0) ids.push_back(pre);\n    return greedyCoverMulti(ids, mode, cands, ALL);\n}\n\nvector<int> improveCoverPlan(vector<int> ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    removeRedundant(ids, cands, ALL);\n\n    for (int iter = 0; iter < 6; iter++) {\n        int curObj = objectiveCover(ids, cands);\n        vector<int> bestIds = ids;\n        int bestObj = curObj;\n\n        vector<char> in(cands.size(), 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int c = 0; c < (int)cands.size(); c++) {\n            if (in[c]) continue;\n            vector<int> tmp = ids;\n            tmp.push_back(c);\n            removeRedundant(tmp, cands, ALL);\n            if (unionIds(tmp, cands) != ALL) continue;\n\n            int obj = objectiveCover(tmp, cands);\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestIds = tmp;\n            }\n        }\n\n        for (int r = 0; r < (int)ids.size(); r++) {\n            vector<int> base = ids;\n            base.erase(base.begin() + r);\n\n            for (int mode = 0; mode < 5; mode++) {\n                vector<int> tmp = greedyCoverMulti(base, mode, cands, ALL);\n                if (unionIds(tmp, cands) != ALL) continue;\n\n                int obj = objectiveCover(tmp, cands);\n                if (obj < bestObj) {\n                    bestObj = obj;\n                    bestIds = tmp;\n                }\n            }\n        }\n\n        if (bestObj < curObj) ids = bestIds;\n        else break;\n    }\n\n    return ids;\n}\n\nstruct Plan {\n    vector<int> ids;\n    int obj;\n};\n\nstring keyIds(vector<int> ids) {\n    sort(ids.begin(), ids.end());\n    string s;\n    for (int id : ids) {\n        s += to_string(id);\n        s += ',';\n    }\n    return s;\n}\n\nvector<Plan> generateCoverPlans(const vector<CoverCand>& cands) {\n    int M = (int)initialXs.size();\n    uint64_t ALL = ((1ULL << M) - 1);\n\n    vector<Plan> plans;\n    unordered_set<string> seen;\n\n    auto addPlan = [&](vector<int> ids) {\n        if (ids.empty()) return;\n        removeRedundant(ids, cands, ALL);\n        if (unionIds(ids, cands) != ALL) return;\n        string key = keyIds(ids);\n        if (seen.insert(key).second) {\n            plans.push_back({ids, objectiveCover(ids, cands)});\n        }\n    };\n\n    for (int mode = 0; mode < 5; mode++) {\n        addPlan(greedyCover(-1, mode, cands, ALL));\n        for (int pre = 0; pre < (int)cands.size(); pre++) {\n            addPlan(greedyCover(pre, mode, cands, ALL));\n        }\n    }\n\n    vector<pair<double,int>> rank;\n    for (int i = 0; i < (int)cands.size(); i++) {\n        int pc = max(1, __builtin_popcountll(cands[i].mask));\n        double sc = (2.0 * cands[i].k) / pow((double)pc, 1.25) - 0.05 * cands[i].k;\n        rank.push_back({sc, i});\n    }\n    sort(rank.begin(), rank.end());\n\n    int P = min(22, (int)rank.size());\n    for (int mode = 0; mode < 4; mode++) {\n        for (int a = 0; a < P; a++) {\n            for (int b = a + 1; b < P; b++) {\n                addPlan(greedyCoverMulti({rank[a].second, rank[b].second}, mode, cands, ALL));\n            }\n        }\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    int top = min(25, (int)plans.size());\n    for (int i = 0; i < top; i++) {\n        addPlan(improveCoverPlan(plans[i].ids, cands, ALL));\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    if ((int)plans.size() > 70) plans.resize(70);\n    return plans;\n}\n\nvector<int> orderedIds(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = plan.ids;\n\n    if (variant == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k > cands[b].k;\n        });\n    } else if (variant == 3) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (cands[a].d != cands[b].d) return cands[a].d < cands[b].d;\n            if (cands[a].p != cands[b].p) return cands[a].p < cands[b].p;\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant >= 4) {\n        for (int i = (int)ids.size() - 1; i >= 1; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ids[i], ids[j]);\n        }\n    }\n\n    return ids;\n}\n\nvector<Op> buildRoundTripOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n    if (ids.empty()) return ops;\n\n    int maxK = -1;\n    vector<int> finals;\n    for (int id : ids) {\n        if (cands[id].k > maxK) {\n            maxK = cands[id].k;\n            finals.clear();\n            finals.push_back(id);\n        } else if (cands[id].k == maxK) {\n            finals.push_back(id);\n        }\n    }\n\n    int finalId = finals[variant % finals.size()];\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += 2 * cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        if (id == finalId) continue;\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n        appendOps(ops, invDir(c.d), c.p, c.k);\n    }\n\n    auto& f = cands[finalId];\n    appendOps(ops, f.d, f.p, f.k);\n    return ops;\n}\n\nvector<Op> buildOneWayOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n    }\n    return ops;\n}\n\nvector<Op> makeHintSequence() {\n    vector<Op> ops;\n\n    for (auto [i, j] : initialXs) {\n        int bestK = 1e9;\n        char bestD = 'L';\n\n        auto upd = [&](char d, int k) {\n            if (k < bestK) {\n                bestK = k;\n                bestD = d;\n            }\n        };\n\n        uint32_t leftMask = (j == 0 ? 0u : ((1u << j) - 1));\n        if ((INIT.o[i] & leftMask) == 0) upd('L', j + 1);\n\n        uint32_t rightMask = FULL & ~((1u << (j + 1)) - 1);\n        if ((INIT.o[i] & rightMask) == 0) upd('R', N - j);\n\n        uint32_t bit = 1u << j;\n\n        bool ok = true;\n        for (int r = 0; r < i; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('U', i + 1);\n\n        ok = true;\n        for (int r = i + 1; r < N; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('D', N - i);\n\n        if (bestK < 1e9) {\n            appendOps(ops, bestD, (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n            appendOps(ops, invDir(bestD), (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n        }\n    }\n\n    return ops;\n}\n\n// ---------- Direct search ----------\n\nuint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nuint64_t hashState(const State& s) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (int i = 0; i < N; i++) {\n        uint64_t v = ((uint64_t)s.x[i] << 32) ^ s.o[i] ^ (uint64_t)i * 0x9e3779b97f4a7c15ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\ndouble stateHeuristic(const State& s) {\n    Analysis a = analyzeState(s);\n    return 0.32 * a.sumMin + 4.5 * a.invis + 0.15 * a.xcnt;\n}\n\nstruct TrialParam {\n    GenParam gen;\n    double noise = 0.0;\n    int topK = 1;\n    double topBias = 2.0;\n    double lookInvW = 0.0;\n    double lookSumW = 0.0;\n};\n\nTrialParam makeTrialParam(int t, RNG& rng) {\n    TrialParam p;\n\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.lookInvW = 4.0;\n        p.lookSumW = 0.015;\n    } else if (t == 1) {\n        p.gen = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.lookInvW = 3.0;\n        p.lookSumW = 0.010;\n    } else if (t == 2) {\n        p.gen = {1.5, 4.0, 1.8, 1.0, 0.02};\n    } else if (t == 3) {\n        p.gen = {0.85, 10.0, 2.5, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.15;\n        p.lookInvW = 2.0;\n    } else if (t == 4) {\n        p.gen = {1.2, 8.0, 3.0, 1.0, 0.03};\n        p.topK = 2;\n    } else if (t == 5) {\n        p.gen = {0.55, 5.0, 1.5, 1.0, 0.00};\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.9;\n        p.gen.critW = 3.0 + rng.nextDouble() * 8.0;\n        p.gen.twoW = 1.2 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.04;\n        p.noise = 0.15 + rng.nextDouble() * 0.9;\n        p.topK = 1 + rng.nextInt(8);\n        p.topBias = 1.5 + rng.nextDouble() * 3.0;\n\n        if (t % 7 == 0) {\n            p.lookInvW = 1.5 + rng.nextDouble() * 3.0;\n            p.lookSumW = 0.004 + rng.nextDouble() * 0.012;\n        }\n    }\n\n    return p;\n}\n\nvector<Op> directTrialFrom(const State& start, const TrialParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n\n        vector<Cand> viable;\n        viable.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            double score = c.score;\n\n            if (tp.lookInvW > 0 || tp.lookSumW > 0) {\n                State tmp = st;\n                applyGAct(tmp, {c.d, c.p, c.k});\n                Analysis a = analyzeState(tmp);\n\n                if (a.xcnt > 0 && a.invis == a.xcnt) score += 1e6;\n                score += tp.lookInvW * a.invis;\n                score += tp.lookSumW * a.sumMin;\n            }\n\n            if (tp.noise > 0) {\n                double z = tp.noise * (2.0 * rng.nextDouble() - 1.0);\n                score *= exp(z);\n            }\n\n            c.score = score;\n            viable.push_back(c);\n        }\n\n        if (viable.empty()) return {};\n\n        sort(viable.begin(), viable.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        int m = min(tp.topK, (int)viable.size());\n        int idx = 0;\n        if (m > 1) {\n            idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.topBias) * m));\n        }\n\n        Cand ch = viable[idx];\n\n        GAct ga{ch.d, ch.p, ch.k};\n        applyGAct(st, ga);\n        seq.push_back(ga);\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nvector<Op> directTrial(const TrialParam& tp, int moveLimit, RNG& rng) {\n    return directTrialFrom(INIT, tp, moveLimit, rng);\n}\n\nstruct BeamState {\n    State st;\n    int g;\n    vector<GAct> seq;\n    double eval;\n    uint64_t h;\n};\n\nvector<Op> beamSearch(int moveLimit, double until, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    GenParam gp;\n    gp.alpha = 1.15;\n    gp.critW = 7.5;\n    gp.twoW = 2.4;\n    gp.multiW = 1.0;\n    gp.damageW = 0.015;\n\n    const int WIDTH = 260;\n    const int PER_STATE = 12;\n\n    vector<BeamState> beam;\n    beam.push_back({INIT, 0, {}, stateHeuristic(INIT), hashState(INIT)});\n\n    int bestG = INT_MAX;\n    vector<GAct> bestSeq;\n\n    for (int depth = 0; depth < 45 && elapsed() < until; depth++) {\n        vector<BeamState> next;\n        next.reserve(WIDTH * PER_STATE);\n\n        for (auto& bs : beam) {\n            if (elapsed() >= until) break;\n            if (bs.st.xcnt == 0) {\n                if (bs.g < bestG) {\n                    bestG = bs.g;\n                    bestSeq = bs.seq;\n                }\n                continue;\n            }\n\n            vector<Cand> cands = genCandidates(bs.st, gp);\n            if (cands.empty()) continue;\n\n            sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                return a.score < b.score;\n            });\n\n            int take = min(PER_STATE, (int)cands.size());\n            for (int ci = 0; ci < take; ci++) {\n                const Cand& c = cands[ci];\n                int ng = bs.g + c.k;\n                if (ng > moveLimit) continue;\n\n                State ns = bs.st;\n                applyGAct(ns, {c.d, c.p, c.k});\n\n                BeamState child;\n                child.st = ns;\n                child.g = ng;\n                child.seq = bs.seq;\n                child.seq.push_back({c.d, c.p, c.k});\n                child.h = hashState(ns);\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestG) {\n                        bestG = ng;\n                        bestSeq = child.seq;\n                    }\n                    continue;\n                }\n\n                child.eval = ng + stateHeuristic(ns);\n                next.push_back(std::move(child));\n            }\n        }\n\n        if (next.empty()) break;\n\n        sort(next.begin(), next.end(), [](const BeamState& a, const BeamState& b) {\n            return a.eval < b.eval;\n        });\n\n        vector<BeamState> nb;\n        nb.reserve(WIDTH);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(WIDTH * 2);\n\n        for (auto& s : next) {\n            if (seen.insert(s.h).second) {\n                nb.push_back(std::move(s));\n                if ((int)nb.size() >= WIDTH) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    if (bestG < INT_MAX) return expandGSeq(bestSeq);\n    return {};\n}\n\n// ---------- Tail improvement ----------\n\nstruct MAct {\n    char d;\n    int p;\n    int k;\n    bool rt;\n    int cost;\n    double score;\n};\n\nvoid applyMAct(State& s, const MAct& m) {\n    if (!m.rt) {\n        applyGAct(s, {m.d, m.p, m.k});\n        return;\n    }\n\n    int k = m.k;\n    if (m.d == 'L') {\n        uint32_t mask = (1u << k) - 1;\n        uint32_t rem = s.x[m.p] & mask;\n        s.xcnt -= popc(rem);\n        s.x[m.p] &= ~mask;\n    } else if (m.d == 'R') {\n        uint32_t mask = FULL & ~((1u << (N - k)) - 1);\n        uint32_t rem = s.x[m.p] & mask;\n        s.xcnt -= popc(rem);\n        s.x[m.p] &= ~mask;\n    } else if (m.d == 'U') {\n        uint32_t bit = 1u << m.p;\n        for (int i = 0; i < k; i++) {\n            if (s.x[i] & bit) {\n                s.x[i] &= ~bit;\n                s.xcnt--;\n            }\n        }\n    } else {\n        uint32_t bit = 1u << m.p;\n        for (int i = N - k; i < N; i++) {\n            if (s.x[i] & bit) {\n                s.x[i] &= ~bit;\n                s.xcnt--;\n            }\n        }\n    }\n}\n\nvector<Op> expandMActs(const vector<MAct>& ms) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& m : ms) total += m.cost;\n    ops.reserve(total);\n\n    for (auto& m : ms) {\n        appendOps(ops, m.d, m.p, m.k);\n        if (m.rt) appendOps(ops, invDir(m.d), m.p, m.k);\n    }\n\n    return ops;\n}\n\nint dirId(char d) {\n    if (d == 'L') return 0;\n    if (d == 'R') return 1;\n    if (d == 'U') return 2;\n    return 3;\n}\n\nvector<MAct> genTailMacros(const State& s) {\n    GenParam gp{1.1, 8.0, 2.4, 1.0, 0.012};\n    vector<Cand> cs = genCandidates(s, gp);\n\n    vector<MAct> ms;\n    unordered_set<int> seen;\n    seen.reserve(cs.size() * 2 + 10);\n\n    for (auto& c : cs) {\n        int baseCode = ((dirId(c.d) * N + c.p) * (N + 1) + c.k) * 2;\n\n        if (seen.insert(baseCode).second) {\n            ms.push_back({c.d, c.p, c.k, false, c.k, c.score});\n        }\n\n        if (c.cnt < s.xcnt) {\n            int code = baseCode | 1;\n            if (seen.insert(code).second) {\n                ms.push_back({c.d, c.p, c.k, true, 2 * c.k, c.score * 1.8 + 0.08 * c.k});\n            }\n        }\n    }\n\n    sort(ms.begin(), ms.end(), [](const MAct& a, const MAct& b) {\n        return a.score < b.score;\n    });\n\n    if ((int)ms.size() > 95) ms.resize(95);\n    return ms;\n}\n\nint boardLowerBound(const State& s) {\n    int lb = 0;\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n            int d = min(min(i + 1, N - i), min(j + 1, N - j));\n            lb = max(lb, d);\n        }\n    }\n    return lb;\n}\n\nstruct TailNode {\n    State st;\n    int g;\n    int parent;\n    MAct act;\n    uint64_t key;\n};\n\nstruct TailItem {\n    double f;\n    int idx;\n    bool operator<(const TailItem& other) const {\n        return f > other.f;\n    }\n};\n\nvector<Op> tailMacroSearch(const State& start, int limit, double until) {\n    if (start.xcnt == 0) return {};\n    if (limit <= 0) return {};\n\n    vector<TailNode> nodes;\n    nodes.reserve(30000);\n\n    priority_queue<TailItem> pq;\n    unordered_map<uint64_t, int> dist;\n    dist.reserve(50000);\n\n    uint64_t skey = hashState(start);\n    nodes.push_back({start, 0, -1, MAct(), skey});\n    dist[skey] = 0;\n    pq.push({0.35 * stateHeuristic(start), 0});\n\n    int bestCost = limit + 1;\n    int bestIdx = -1;\n\n    while (!pq.empty() && elapsed() < until && (int)nodes.size() < 36000) {\n        auto it = pq.top();\n        pq.pop();\n\n        int idx = it.idx;\n        TailNode& nd = nodes[idx];\n\n        auto dit = dist.find(nd.key);\n        if (dit == dist.end() || dit->second != nd.g) continue;\n        if (nd.g >= bestCost) continue;\n        if (nd.g + boardLowerBound(nd.st) >= bestCost) continue;\n\n        if (nd.st.xcnt == 0) {\n            if (nd.g < bestCost) {\n                bestCost = nd.g;\n                bestIdx = idx;\n            }\n            continue;\n        }\n\n        vector<MAct> acts = genTailMacros(nd.st);\n        if (acts.empty()) continue;\n\n        for (auto& a : acts) {\n            int ng = nd.g + a.cost;\n            if (ng >= bestCost || ng > limit) continue;\n\n            State ns = nd.st;\n            applyMAct(ns, a);\n\n            int lb = boardLowerBound(ns);\n            if (ng + lb >= bestCost) continue;\n\n            uint64_t key = hashState(ns);\n            auto dit2 = dist.find(key);\n            if (dit2 != dist.end() && dit2->second <= ng) continue;\n\n            int ni = (int)nodes.size();\n            nodes.push_back({ns, ng, idx, a, key});\n            dist[key] = ng;\n\n            if (ns.xcnt == 0) {\n                if (ng < bestCost) {\n                    bestCost = ng;\n                    bestIdx = ni;\n                }\n            } else {\n                double f = ng + 0.35 * stateHeuristic(ns);\n                pq.push({f, ni});\n            }\n        }\n    }\n\n    if (bestIdx < 0) return {};\n\n    vector<MAct> ms;\n    for (int v = bestIdx; nodes[v].parent != -1; v = nodes[v].parent) {\n        ms.push_back(nodes[v].act);\n    }\n    reverse(ms.begin(), ms.end());\n\n    return expandMActs(ms);\n}\n\nstruct SNode {\n    State st;\n    int g;\n    int parent;\n    Op act;\n    uint64_t key;\n};\n\nstruct SItem {\n    double f;\n    int idx;\n    bool operator<(const SItem& other) const {\n        return f > other.f;\n    }\n};\n\nvector<Op> singleTailSearch(const State& start, int limit, double until) {\n    if (start.xcnt == 0) return {};\n    if (limit <= 0) return {};\n\n    vector<SNode> nodes;\n    nodes.reserve(50000);\n\n    priority_queue<SItem> pq;\n    unordered_map<uint64_t, int> dist;\n    dist.reserve(80000);\n\n    uint64_t skey = hashState(start);\n    nodes.push_back({start, 0, -1, Op(), skey});\n    dist[skey] = 0;\n    pq.push({0.40 * stateHeuristic(start), 0});\n\n    int bestCost = limit + 1;\n    int bestIdx = -1;\n\n    while (!pq.empty() && elapsed() < until && (int)nodes.size() < 55000) {\n        auto item = pq.top();\n        pq.pop();\n\n        int idx = item.idx;\n        SNode& nd = nodes[idx];\n\n        auto dit = dist.find(nd.key);\n        if (dit == dist.end() || dit->second != nd.g) continue;\n        if (nd.g >= bestCost) continue;\n        if (nd.g + boardLowerBound(nd.st) >= bestCost) continue;\n\n        if (nd.st.xcnt == 0) {\n            if (nd.g < bestCost) {\n                bestCost = nd.g;\n                bestIdx = idx;\n            }\n            continue;\n        }\n\n        for (int p = 0; p < N; p++) {\n            Op ops[4] = {{'L', p}, {'R', p}, {'U', p}, {'D', p}};\n            for (auto op : ops) {\n                if (edgeO(nd.st, op)) continue;\n\n                int ng = nd.g + 1;\n                if (ng >= bestCost || ng > limit) continue;\n\n                State ns = nd.st;\n                applyOp(ns, op);\n\n                int lb = boardLowerBound(ns);\n                if (ng + lb >= bestCost) continue;\n\n                uint64_t key = hashState(ns);\n                auto dit2 = dist.find(key);\n                if (dit2 != dist.end() && dit2->second <= ng) continue;\n\n                int ni = (int)nodes.size();\n                nodes.push_back({ns, ng, idx, op, key});\n                dist[key] = ng;\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestCost) {\n                        bestCost = ng;\n                        bestIdx = ni;\n                    }\n                } else {\n                    double f = ng + 0.40 * stateHeuristic(ns);\n                    pq.push({f, ni});\n                }\n            }\n        }\n    }\n\n    if (bestIdx < 0) return {};\n\n    vector<Op> ops;\n    for (int v = bestIdx; nodes[v].parent != -1; v = nodes[v].parent) {\n        ops.push_back(nodes[v].act);\n    }\n    reverse(ops.begin(), ops.end());\n    return ops;\n}\n\nvector<State> buildPrefixStates(const vector<Op>& ops) {\n    vector<State> states;\n    states.reserve(ops.size() + 1);\n\n    State s = INIT;\n    states.push_back(s);\n\n    for (auto& op : ops) {\n        if (edgeO(s, op)) break;\n        applyOp(s, op);\n        states.push_back(s);\n        if (s.xcnt == 0) break;\n    }\n\n    return states;\n}\n\nvoid suffixDirectImprove(vector<Op>& best, double until, RNG& rng) {\n    bool improved = true;\n    int globalAttempt = 0;\n\n    while (improved && elapsed() < until) {\n        improved = false;\n\n        vector<State> states = buildPrefixStates(best);\n        if ((int)states.size() <= 1) return;\n\n        vector<int> cuts;\n\n        auto addCut = [&](int t) {\n            if (t <= 0 || t >= (int)states.size()) return;\n            int rem = states[t].xcnt;\n            if (rem <= 0 || rem > 24) return;\n            if ((int)best.size() - t <= 2) return;\n            cuts.push_back(t);\n        };\n\n        int prev = states[0].xcnt;\n        for (int t = 1; t < (int)states.size(); t++) {\n            if (states[t].xcnt < prev) {\n                addCut(t);\n                prev = states[t].xcnt;\n            }\n        }\n\n        int st = max(1, (int)states.size() - 70);\n        for (int t = st; t + 1 < (int)states.size(); t += 4) {\n            addCut(t);\n        }\n\n        sort(cuts.begin(), cuts.end());\n        cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n        sort(cuts.begin(), cuts.end(), [&](int a, int b) {\n            int ra = states[a].xcnt, rb = states[b].xcnt;\n            if (ra != rb) return ra < rb;\n            return a > b;\n        });\n\n        if ((int)cuts.size() > 26) cuts.resize(26);\n\n        for (int cut : cuts) {\n            if (elapsed() >= until) break;\n\n            int limit = (int)best.size() - cut - 1;\n            if (limit <= 0) continue;\n\n            for (int z = 0; z < 4 && elapsed() < until; z++) {\n                TrialParam tp;\n                if (z < 3) tp = makeTrialParam(z, rng);\n                else tp = makeTrialParam(100 + globalAttempt, rng);\n\n                vector<Op> comp = directTrialFrom(states[cut], tp, limit, rng);\n                globalAttempt++;\n\n                if (!comp.empty()) {\n                    vector<Op> ops;\n                    ops.reserve(cut + comp.size());\n                    ops.insert(ops.end(), best.begin(), best.begin() + cut);\n                    ops.insert(ops.end(), comp.begin(), comp.end());\n\n                    if (truncateToPerfectPrefix(ops) && isPerfectFull(ops) && ops.size() < best.size()) {\n                        best = std::move(ops);\n                        pruneSequence(best, min(until, elapsed() + 0.012));\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n\n            if (improved) break;\n        }\n    }\n}\n\nvoid tailImprove(vector<Op>& best, double until, RNG& rng) {\n    (void)rng;\n    bool improved = true;\n\n    while (improved && elapsed() < until) {\n        improved = false;\n\n        vector<State> states = buildPrefixStates(best);\n        if ((int)states.size() <= 1) return;\n\n        vector<int> cuts;\n        auto addCut = [&](int t) {\n            if (t <= 0 || t >= (int)states.size()) return;\n            if (states[t].xcnt <= 0 || states[t].xcnt > 14) return;\n            if ((int)best.size() - t <= 1) return;\n            cuts.push_back(t);\n        };\n\n        int prev = states[0].xcnt;\n        for (int t = 1; t < (int)states.size(); t++) {\n            if (states[t].xcnt < prev) {\n                addCut(t);\n                prev = states[t].xcnt;\n            }\n        }\n\n        int st = max(1, (int)states.size() - 45);\n        for (int t = st; t + 1 < (int)states.size(); t += 3) {\n            if (states[t].xcnt <= 10) addCut(t);\n        }\n\n        sort(cuts.begin(), cuts.end());\n        cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n        sort(cuts.begin(), cuts.end(), [&](int a, int b) {\n            if (states[a].xcnt != states[b].xcnt) return states[a].xcnt < states[b].xcnt;\n            return a > b;\n        });\n\n        if ((int)cuts.size() > 26) cuts.resize(26);\n\n        for (int cut : cuts) {\n            if (elapsed() >= until) break;\n\n            int rem = states[cut].xcnt;\n            int limit = (int)best.size() - cut - 1;\n            if (limit <= 0) continue;\n\n            vector<Op> comp;\n\n            if (rem <= 6 && elapsed() < until) {\n                comp = singleTailSearch(states[cut], limit, min(until, elapsed() + 0.026));\n            }\n\n            if (comp.empty() && elapsed() < until) {\n                comp = tailMacroSearch(states[cut], limit, min(until, elapsed() + 0.026));\n            }\n\n            if (!comp.empty()) {\n                vector<Op> ops;\n                ops.reserve(cut + comp.size());\n                ops.insert(ops.end(), best.begin(), best.begin() + cut);\n                ops.insert(ops.end(), comp.begin(), comp.end());\n\n                if (truncateToPerfectPrefix(ops) && isPerfectFull(ops) && ops.size() < best.size()) {\n                    best = std::move(ops);\n                    pruneSequence(best, min(until, elapsed() + 0.015));\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n}\n\n// ---------- Main ----------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START = chrono::steady_clock::now();\n\n    cin >> N;\n    FULL = (1u << N) - 1;\n\n    INIT.x.fill(0);\n    INIT.o.fill(0);\n    INIT.xcnt = 0;\n    memset(idxAt, -1, sizeof(idxAt));\n\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') {\n                idxAt[i][j] = (int)initialXs.size();\n                initialXs.push_back({i, j});\n                INIT.x[i] |= 1u << j;\n                INIT.xcnt++;\n            } else if (C[i][j] == 'o') {\n                INIT.o[i] |= 1u << j;\n            }\n        }\n    }\n\n    uint64_t seed = hashState(INIT) ^ 0xa5a5a5a5deadbeefULL;\n    RNG rng(seed);\n\n    const double HARD = 1.90;\n\n    vector<Op> best = makeHintSequence();\n    truncateToPerfectPrefix(best);\n\n    vector<CoverCand> coverCands = buildCoverCandidates();\n    vector<Plan> plans = generateCoverPlans(coverCands);\n\n    auto consider = [&](vector<Op> ops, double pruneUntil) {\n        if (ops.empty()) return;\n        if (!truncateToPerfectPrefix(ops)) return;\n        if (pruneUntil > elapsed()) pruneSequence(ops, pruneUntil);\n        if (isPerfectFull(ops) && ops.size() < best.size()) {\n            best = std::move(ops);\n        }\n    };\n\n    if (!plans.empty()) {\n        vector<Op> ops = buildRoundTripOps(plans[0], coverCands, 0, rng);\n        consider(ops, 0.20);\n    }\n\n    pruneSequence(best, min(0.22, HARD));\n\n    for (int pi = 0; pi < (int)plans.size() && pi < 10 && elapsed() < 0.45; pi++) {\n        for (int v = 0; v < 6 && elapsed() < 0.45; v++) {\n            {\n                vector<Op> ops = buildOneWayOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.020));\n            }\n            {\n                vector<Op> ops = buildRoundTripOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.025));\n            }\n        }\n    }\n\n    pruneSequence(best, min(0.50, HARD));\n\n    if (elapsed() < 1.05) {\n        vector<Op> bops = beamSearch((int)best.size() + 70, 1.05, rng);\n        consider(bops, min(1.15, elapsed() + 0.08));\n    }\n\n    int trial = 0;\n    int pruneCnt = 0;\n    while (elapsed() < 1.70) {\n        TrialParam tp = makeTrialParam(trial, rng);\n        int limit = min(4 * N * N, (int)best.size() + 70);\n\n        vector<Op> ops = directTrial(tp, limit, rng);\n        if (!ops.empty()) {\n            double until = elapsed();\n            if ((int)ops.size() < (int)best.size() + 50 && pruneCnt < 26) {\n                until = min(1.715, elapsed() + 0.017);\n                pruneCnt++;\n            }\n            consider(ops, until);\n        }\n\n        trial++;\n    }\n\n    if (elapsed() < 1.73) {\n        pruneSequence(best, min(1.73, HARD));\n    }\n\n    if (elapsed() < 1.80) {\n        suffixDirectImprove(best, 1.80, rng);\n    }\n\n    if (elapsed() < 1.86) {\n        tailImprove(best, 1.86, rng);\n    }\n\n    if (elapsed() < 1.885) {\n        pairPruneSequence(best, 1.885);\n    }\n\n    if (elapsed() < HARD) {\n        pruneSequence(best, HARD);\n    }\n\n    if (!isPerfectFull(best)) {\n        best = makeHintSequence();\n        truncateToPerfectPrefix(best);\n    }\n\n    for (auto& op : best) {\n        cout << op.d << ' ' << op.p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 100;\nconstexpr int MAXE = 200;\n\nint N, L;\narray<int, MAXN> T;\narray<int, MAXN> Cdes;\narray<int, MAXN> demandIn;\n\nvector<int> activeChoices;\nvector<int> validZs;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n} rng;\n\ntemplate<class Tvec>\nvoid shuffle_vec(vector<Tvec>& v) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nchrono::steady_clock::time_point st_time;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - st_time).count();\n}\n\nstruct Cand {\n    array<int, MAXN> a, b;\n    array<unsigned char, MAXE> prot;\n};\n\nstruct SimResult {\n    long long err;\n    array<int, MAXN> cnt;\n    int last;\n};\n\nstruct Entry {\n    long long err;\n    Cand cand;\n    SimResult res;\n};\n\nCand bestCand;\nSimResult bestRes;\nlong long bestErr = (1LL << 60);\nvector<Entry> pool;\n\ninline long long absl(long long x) {\n    return x >= 0 ? x : -x;\n}\n\nlong long cellCost(long long diff, int mode) {\n    long long a = absl(diff);\n    if (mode == 0) return diff * diff;\n    if (mode == 1) return a;\n    return diff * diff + 1000LL * a;\n}\n\nvoid getDest(const Cand& c, array<int, MAXE>& dest) {\n    for (int i = 0; i < N; ++i) {\n        dest[2 * i] = c.a[i];\n        dest[2 * i + 1] = c.b[i];\n    }\n}\n\nvoid setEdge(Cand& c, int e, int to) {\n    int v = e / 2;\n    if (e & 1) c.b[v] = to;\n    else c.a[v] = to;\n}\n\nSimResult simulate(const Cand& c) {\n    SimResult r;\n    r.cnt.fill(0);\n\n    int x = 0;\n    r.cnt[0] = 1;\n\n    for (int step = 1; step < L; ++step) {\n        int nx = (r.cnt[x] & 1) ? c.a[x] : c.b[x];\n        x = nx;\n        ++r.cnt[x];\n    }\n\n    r.last = x;\n\n    long long e = 0;\n    for (int i = 0; i < N; ++i) {\n        e += llabs((long long)r.cnt[i] - T[i]);\n    }\n    r.err = e;\n    return r;\n}\n\nbool addEvaluated(const Cand& c, const SimResult& r) {\n    bool improved = false;\n\n    if (r.err < bestErr) {\n        bestErr = r.err;\n        bestCand = c;\n        bestRes = r;\n        improved = true;\n    }\n\n    if ((int)pool.size() < 16 || r.err < pool.back().err) {\n        pool.push_back({r.err, c, r});\n        sort(pool.begin(), pool.end(), [](const Entry& x, const Entry& y) {\n            return x.err < y.err;\n        });\n        while ((int)pool.size() > 16) pool.pop_back();\n    }\n\n    return improved;\n}\n\nbool consider(const Cand& c) {\n    SimResult r = simulate(c);\n    return addEvaluated(c, r);\n}\n\nlong long moveDeltaCost(\n    const array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int e,\n    int y\n) {\n    int old = dest[e];\n    int ww = w[e];\n\n    if (old == y) return 0;\n\n    return\n        cellCost(loads[old] - ww - dem[old], objMode) +\n        cellCost(loads[y] + ww - dem[y], objMode) -\n        cellCost(loads[old] - dem[old], objMode) -\n        cellCost(loads[y] - dem[y], objMode);\n}\n\nvoid applyMove(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    int e,\n    int y\n) {\n    int old = dest[e];\n    if (old == y) return;\n\n    int ww = w[e];\n    loads[old] -= ww;\n    loads[y] += ww;\n    dest[e] = y;\n}\n\nvoid optimizeItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty() || items.empty()) return;\n\n    vector<int> order = items;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        bool improved = false;\n\n        if (randomize) shuffle_vec(order);\n\n        for (int e : order) {\n            int ww = w[e];\n            if (ww == 0) continue;\n\n            int old = dest[e];\n            long long oldCostOld = cellCost(loads[old] - dem[old], objMode);\n            long long bestDelta = 0;\n            int bestY = old;\n\n            for (int y : choices) {\n                if (y == old) continue;\n\n                long long delta =\n                    cellCost(loads[old] - ww - dem[old], objMode) +\n                    cellCost(loads[y] + ww - dem[y], objMode) -\n                    oldCostOld -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestY = y;\n                }\n            }\n\n            if (bestY != old) {\n                loads[old] -= ww;\n                loads[bestY] += ww;\n                dest[e] = bestY;\n                improved = true;\n            }\n        }\n\n        int M = (int)order.size();\n\n        for (int ii = 0; ii < M; ++ii) {\n            int e = order[ii];\n            int we = w[e];\n            if (we == 0) continue;\n\n            for (int jj = ii + 1; jj < M; ++jj) {\n                int f = order[jj];\n                int wf = w[f];\n\n                if (wf == 0 || we == wf) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n\n                if (x == y) continue;\n\n                long long nx = loads[x] - we + wf;\n                long long ny = loads[y] - wf + we;\n\n                long long delta =\n                    cellCost(nx - dem[x], objMode) +\n                    cellCost(ny - dem[y], objMode) -\n                    cellCost(loads[x] - dem[x], objMode) -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < 0) {\n                    loads[x] = nx;\n                    loads[y] = ny;\n                    swap(dest[e], dest[f]);\n                    improved = true;\n                }\n            }\n        }\n\n        if (randomize && M >= 3) {\n            int attempts = 1600;\n\n            for (int at = 0; at < attempts; ++at) {\n                int i = rng.randint(M);\n                int j = rng.randint(M);\n                int k = rng.randint(M);\n                if (i == j || j == k || k == i) continue;\n\n                int e = order[i];\n                int f = order[j];\n                int g = order[k];\n\n                int we = w[e];\n                int wf = w[f];\n                int wg = w[g];\n\n                if (we == 0 || wf == 0 || wg == 0) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n                int z = dest[g];\n\n                if (x == y || y == z || z == x) continue;\n\n                {\n                    long long nx = loads[x] - we + wg;\n                    long long ny = loads[y] - wf + we;\n                    long long nz = loads[z] - wg + wf;\n\n                    long long delta =\n                        cellCost(nx - dem[x], objMode) +\n                        cellCost(ny - dem[y], objMode) +\n                        cellCost(nz - dem[z], objMode) -\n                        cellCost(loads[x] - dem[x], objMode) -\n                        cellCost(loads[y] - dem[y], objMode) -\n                        cellCost(loads[z] - dem[z], objMode);\n\n                    if (delta < 0) {\n                        loads[x] = nx;\n                        loads[y] = ny;\n                        loads[z] = nz;\n\n                        dest[e] = y;\n                        dest[f] = z;\n                        dest[g] = x;\n\n                        improved = true;\n                        continue;\n                    }\n                }\n\n                {\n                    long long nx = loads[x] - we + wf;\n                    long long ny = loads[y] - wf + wg;\n                    long long nz = loads[z] - wg + we;\n\n                    long long delta =\n                        cellCost(nx - dem[x], objMode) +\n                        cellCost(ny - dem[y], objMode) +\n                        cellCost(nz - dem[z], objMode) -\n                        cellCost(loads[x] - dem[x], objMode) -\n                        cellCost(loads[y] - dem[y], objMode) -\n                        cellCost(loads[z] - dem[z], objMode);\n\n                    if (delta < 0) {\n                        loads[x] = nx;\n                        loads[y] = ny;\n                        loads[z] = nz;\n\n                        dest[e] = z;\n                        dest[f] = x;\n                        dest[g] = y;\n\n                        improved = true;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid assignItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty()) return;\n\n    vector<int> order = items;\n\n    if (randomize) shuffle_vec(order);\n\n    stable_sort(order.begin(), order.end(), [&](int e1, int e2) {\n        return w[e1] > w[e2];\n    });\n\n    int root = choices[0];\n\n    for (int e : order) {\n        int ww = w[e];\n\n        if (ww == 0) {\n            dest[e] = root;\n            continue;\n        }\n\n        vector<pair<long long, int>> cand;\n        cand.reserve(choices.size());\n\n        for (int y : choices) {\n            long long delta =\n                cellCost(loads[y] + ww - dem[y], objMode) -\n                cellCost(loads[y] - dem[y], objMode);\n            cand.push_back({delta, y});\n        }\n\n        int take = min((int)cand.size(), max(1, topR));\n\n        nth_element(cand.begin(), cand.begin() + take - 1, cand.end());\n        sort(cand.begin(), cand.begin() + take);\n\n        int idx = 0;\n        if (randomize && take > 1) {\n            int r = rng.randint(100);\n            if (r >= 70) idx = 1 + rng.randint(take - 1);\n        }\n\n        int y = cand[idx].second;\n        dest[e] = y;\n        loads[y] += ww;\n    }\n\n    optimizeItems(dest, w, items, choices, loads, dem, objMode, maxPass, randomize);\n}\n\nint computeSCC(\n    const array<int, MAXE>& dest,\n    vector<int>& comp,\n    vector<vector<int>>& comps\n) {\n    comp.assign(N, -1);\n    comps.clear();\n\n    if (activeChoices.empty()) return 0;\n\n    array<char, MAXN> active{};\n    active.fill(0);\n    for (int v : activeChoices) active[v] = 1;\n\n    vector<int> g[MAXN], rg[MAXN];\n\n    for (int v : activeChoices) {\n        for (int p = 0; p < 2; ++p) {\n            int to = dest[2 * v + p];\n            if (0 <= to && to < N && active[to]) {\n                g[v].push_back(to);\n                rg[to].push_back(v);\n            }\n        }\n    }\n\n    vector<int> order;\n    array<char, MAXN> vis{};\n    vis.fill(0);\n\n    function<void(int)> dfs1 = [&](int v) {\n        vis[v] = 1;\n        for (int to : g[v]) {\n            if (!vis[to]) dfs1(to);\n        }\n        order.push_back(v);\n    };\n\n    function<void(int, int)> dfs2 = [&](int v, int id) {\n        comp[v] = id;\n        comps[id].push_back(v);\n        for (int to : rg[v]) {\n            if (comp[to] == -1) dfs2(to, id);\n        }\n    };\n\n    for (int v : activeChoices) {\n        if (!vis[v]) dfs1(v);\n    }\n\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            comps.push_back({});\n            dfs2(v, (int)comps.size() - 1);\n        }\n    }\n\n    return (int)comps.size();\n}\n\nstruct EdgeChoice {\n    long long delta;\n    int e;\n    int y;\n};\n\nEdgeChoice findBestChange(\n    int A,\n    int B,\n    const vector<vector<int>>& comps,\n    const array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    const array<unsigned char, MAXE>* banned = nullptr\n) {\n    const long long INF = (1LL << 60);\n\n    EdgeChoice best{INF, -1, -1};\n\n    if (A == B) return best;\n\n    for (int positivePass = 0; positivePass < 2; ++positivePass) {\n        best = {INF, -1, -1};\n\n        for (int s : comps[A]) {\n            for (int p = 0; p < 2; ++p) {\n                int e = 2 * s + p;\n                if (banned && (*banned)[e]) continue;\n                if (positivePass == 0 && w[e] == 0) continue;\n\n                for (int y : comps[B]) {\n                    long long delta = moveDeltaCost(dest, w, loads, dem, objMode, e, y);\n\n                    if (\n                        delta < best.delta ||\n                        (delta == best.delta && (best.e == -1 || w[e] < w[best.e]))\n                    ) {\n                        best = {delta, e, y};\n                    }\n                }\n            }\n        }\n\n        if (best.e != -1) return best;\n    }\n\n    return best;\n}\n\nvoid applyEdgeChoice(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    array<unsigned char, MAXE>& prot,\n    const EdgeChoice& ch\n) {\n    if (ch.e == -1) return;\n\n    applyMove(dest, w, loads, ch.e, ch.y);\n    prot[ch.e] = 1;\n}\n\nvoid repairStrongFull(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 4; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        sort(order.begin(), order.end(), [&](int x, int y) {\n            long long sx = 0;\n            long long sy = 0;\n\n            for (int v : comps[x]) sx += dem[v];\n            for (int v : comps[y]) sy += dem[v];\n\n            long long lhs = sx * (long long)comps[y].size();\n            long long rhs = sy * (long long)comps[x].size();\n\n            if (lhs != rhs) return lhs > rhs;\n            return x < y;\n        });\n\n        array<unsigned char, MAXE> used{};\n        used.fill(0);\n\n        bool changed = false;\n\n        for (int i = 0; i < K; ++i) {\n            int A = order[i];\n            int B = order[(i + 1) % K];\n\n            EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode, &used);\n            if (ch.e == -1) continue;\n\n            int old = dest[ch.e];\n\n            applyEdgeChoice(dest, w, loads, prot, ch);\n            used[ch.e] = 1;\n\n            if (old != ch.y) changed = true;\n        }\n\n        if (!changed) return;\n    }\n}\n\nvoid repairStrongSmart(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 6; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        vector<vector<int>> cg(K);\n        vector<int> indeg(K, 0), outdeg(K, 0);\n\n        for (int v : activeChoices) {\n            int cv = comp[v];\n\n            for (int p = 0; p < 2; ++p) {\n                int to = dest[2 * v + p];\n                if (to < 0 || to >= N) continue;\n\n                int cu = comp[to];\n                if (cu == -1 || cu == cv) continue;\n\n                cg[cv].push_back(cu);\n                ++outdeg[cv];\n                ++indeg[cu];\n            }\n        }\n\n        vector<int> sources, sinks;\n\n        for (int c = 0; c < K; ++c) {\n            if (indeg[c] == 0) sources.push_back(c);\n            if (outdeg[c] == 0) sinks.push_back(c);\n        }\n\n        if (sources.empty() || sinks.empty()) {\n            repairStrongFull(dest, w, loads, dem, objMode, prot);\n            return;\n        }\n\n        vector<int> indegTopo(K, 0);\n\n        for (int c = 0; c < K; ++c) {\n            for (int to : cg[c]) ++indegTopo[to];\n        }\n\n        queue<int> q;\n        for (int c = 0; c < K; ++c) {\n            if (indegTopo[c] == 0) q.push(c);\n        }\n\n        vector<int> topo;\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            topo.push_back(v);\n\n            for (int to : cg[v]) {\n                --indegTopo[to];\n                if (indegTopo[to] == 0) q.push(to);\n            }\n        }\n\n        vector<int> pos(K, 0);\n        for (int i = 0; i < (int)topo.size(); ++i) {\n            pos[topo[i]] = i;\n        }\n\n        sort(sources.begin(), sources.end(), [&](int x, int y) {\n            return pos[x] < pos[y];\n        });\n        sort(sinks.begin(), sinks.end(), [&](int x, int y) {\n            return pos[x] < pos[y];\n        });\n\n        int M = max((int)sources.size(), (int)sinks.size());\n\n        vector<int> seqS(M), seqZ(M);\n\n        for (int i = 0; i < M; ++i) {\n            seqS[i] = sources[i % sources.size()];\n            seqZ[i] = sinks[i % sinks.size()];\n        }\n\n        const long long INF = (1LL << 60);\n\n        int bestShift = -1;\n        long long bestTotal = INF;\n\n        for (int shift = 0; shift < M; ++shift) {\n            long long total = 0;\n            bool ok = true;\n\n            for (int i = 0; i < M; ++i) {\n                int A = seqZ[i];\n                int B = seqS[(i + 1 + shift) % M];\n\n                if (A == B) {\n                    ok = false;\n                    break;\n                }\n\n                EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode);\n                if (ch.e == -1) {\n                    ok = false;\n                    break;\n                }\n\n                total += ch.delta;\n                if (total > bestTotal) break;\n            }\n\n            if (ok && total < bestTotal) {\n                bestTotal = total;\n                bestShift = shift;\n            }\n        }\n\n        if (bestShift == -1) bestShift = 0;\n\n        array<unsigned char, MAXE> used{};\n        used.fill(0);\n\n        bool changed = false;\n\n        for (int i = 0; i < M; ++i) {\n            int A = seqZ[i];\n            int B = seqS[(i + 1 + bestShift) % M];\n\n            if (A == B) {\n                for (int s : sources) {\n                    if (s != A) {\n                        B = s;\n                        break;\n                    }\n                }\n                if (A == B) continue;\n            }\n\n            EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode, &used);\n            if (ch.e == -1) continue;\n\n            int old = dest[ch.e];\n\n            applyEdgeChoice(dest, w, loads, prot, ch);\n            used[ch.e] = 1;\n\n            if (old != ch.y) changed = true;\n        }\n\n        if (!changed) {\n            repairStrongFull(dest, w, loads, dem, objMode, prot);\n            return;\n        }\n    }\n\n    repairStrongFull(dest, w, loads, dem, objMode, prot);\n}\n\nvoid optimizeNonProtected(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot,\n    int passes,\n    bool randomize\n) {\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (!prot[e] && w[e] > 0) items.push_back(e);\n    }\n\n    if (!items.empty()) {\n        optimizeItems(dest, w, items, activeChoices, loads, dem,\n                      objMode, passes, randomize);\n    }\n}\n\nvoid applyRepairType(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot,\n    int repairType,\n    bool randomize\n) {\n    if (repairType == 0) return;\n\n    if (repairType == 1) {\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n        optimizeNonProtected(dest, w, loads, dem, objMode, prot, 2, randomize);\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n    } else {\n        repairStrongFull(dest, w, loads, dem, objMode, prot);\n        optimizeNonProtected(dest, w, loads, dem, objMode, prot, 2, randomize);\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n    }\n}\n\nCand buildSimpleCycle(bool activeOnly) {\n    Cand c;\n    c.prot.fill(0);\n\n    if (activeOnly && !activeChoices.empty()) {\n        int root = activeChoices[0];\n\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = root;\n            c.b[i] = root;\n        }\n\n        int m = (int)activeChoices.size();\n\n        for (int k = 0; k < m; ++k) {\n            int v = activeChoices[k];\n            int to = activeChoices[(k + 1) % m];\n\n            c.a[v] = to;\n            c.b[v] = to;\n        }\n    } else {\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = (i + 1) % N;\n            c.b[i] = (i + 1) % N;\n        }\n    }\n\n    return c;\n}\n\nCand buildFree(\n    int z,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    int repairType\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] > 0) items.push_back(e);\n        else dest[e] = root;\n    }\n\n    assignItems(dest, w, items, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand buildBackbone(\n    int fixedParity,\n    int z,\n    int K,\n    int noiseAmp,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct NK {\n        int key;\n        int dem;\n        int node;\n    };\n\n    vector<NK> keys;\n    keys.reserve(activeChoices.size());\n\n    for (int v : activeChoices) {\n        int key = demandIn[v];\n\n        if (noiseAmp > 0) {\n            key += rng.randint(2 * noiseAmp + 1) - noiseAmp;\n        }\n\n        keys.push_back({key, demandIn[v], v});\n    }\n\n    sort(keys.begin(), keys.end(), [](const NK& x, const NK& y) {\n        if (x.key != y.key) return x.key > y.key;\n        if (x.dem != y.dem) return x.dem > y.dem;\n        return x.node < y.node;\n    });\n\n    vector<int> base;\n    for (auto& x : keys) base.push_back(x.node);\n\n    vector<int> order;\n    int m = (int)base.size();\n\n    if (m == 0) {\n        order.push_back(0);\n    } else {\n        K = max(1, min(K, m));\n\n        for (int r = 0; r < K; ++r) {\n            for (int idx = r; idx < m; idx += K) {\n                order.push_back(base[idx]);\n            }\n        }\n    }\n\n    root = order[0];\n    dest.fill(root);\n\n    array<char, MAXN> isAct{};\n    isAct.fill(0);\n    for (int v : order) isAct[v] = 1;\n\n    vector<int> flexItems;\n    flexItems.reserve(MAXE);\n\n    for (int k = 0; k < (int)order.size(); ++k) {\n        int s = order[k];\n        int to = order[(k + 1) % order.size()];\n\n        int fixedIdx = 2 * s + fixedParity;\n        int flexIdx = 2 * s + (1 - fixedParity);\n\n        dest[fixedIdx] = to;\n        prot[fixedIdx] = 1;\n        loads[to] += w[fixedIdx];\n\n        flexItems.push_back(flexIdx);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (isAct[i]) continue;\n\n        for (int p = 0; p < 2; ++p) {\n            int e = 2 * i + p;\n\n            if (w[e] > 0) flexItems.push_back(e);\n            else dest[e] = root;\n        }\n    }\n\n    assignItems(dest, w, flexItems, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand rebalanceCandidate(\n    const Entry& base,\n    bool fullReassign,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    int repairType\n) {\n    array<int, MAXE> dest;\n    getDest(base.cand, dest);\n\n    array<unsigned char, MAXE> prot = base.cand.prot;\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = base.res.cnt[i] - (base.res.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    array<long long, MAXN> loads;\n    loads.fill(0);\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n\n    if (fullReassign) {\n        for (int e = 0; e < 2 * N; ++e) {\n            if (prot[e]) {\n                loads[dest[e]] += w[e];\n            } else {\n                items.push_back(e);\n                dest[e] = root;\n            }\n        }\n\n        assignItems(dest, w, items, activeChoices, loads, demandIn,\n                    objMode, topR, maxPass, randomize);\n    } else {\n        for (int e = 0; e < 2 * N; ++e) {\n            loads[dest[e]] += w[e];\n\n            if (!prot[e]) {\n                items.push_back(e);\n            }\n        }\n\n        optimizeItems(dest, w, items, activeChoices, loads, demandIn,\n                      objMode, maxPass, randomize);\n    }\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nbool validZ(int z) {\n    if (z < 0 || z >= N) return false;\n    if (Cdes[z] <= 0) return false;\n    if (z == 0 && Cdes[0] <= 1) return false;\n    return true;\n}\n\nint randomZ() {\n    if (!validZs.empty()) {\n        return validZs[rng.randint((int)validZs.size())];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (Cdes[i] > 0) return i;\n    }\n\n    return 0;\n}\n\nbool tryLocalImprove(double TL) {\n    if (activeChoices.empty()) return false;\n\n    array<int, MAXE> dest;\n    getDest(bestCand, dest);\n\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = bestRes.cnt[i] - (bestRes.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct Change {\n        long long delta;\n        int type;\n        int e;\n        int f;\n        int y;\n    };\n\n    vector<Change> moves;\n    moves.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        int ww = w[e];\n        if (ww == 0) continue;\n\n        int old = dest[e];\n\n        for (int y : activeChoices) {\n            if (y == old) continue;\n\n            long long delta =\n                llabs((long long)bestRes.cnt[old] - ww - T[old]) +\n                llabs((long long)bestRes.cnt[y] + ww - T[y]) -\n                llabs((long long)bestRes.cnt[old] - T[old]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) {\n                moves.push_back({delta, 0, e, -1, y});\n            }\n        }\n    }\n\n    sort(moves.begin(), moves.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    int testLimit = min(48, (int)moves.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n        setEdge(c, moves[i].e, moves[i].y);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    vector<Change> swaps;\n    swaps.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] == 0) continue;\n\n        for (int f = e + 1; f < 2 * N; ++f) {\n            if (w[f] == 0) continue;\n\n            int x = dest[e];\n            int y = dest[f];\n\n            if (x == y) continue;\n\n            int we = w[e];\n            int wf = w[f];\n\n            if (we == wf) continue;\n\n            long long nx = (long long)bestRes.cnt[x] - we + wf;\n            long long ny = (long long)bestRes.cnt[y] - wf + we;\n\n            long long delta =\n                llabs(nx - T[x]) +\n                llabs(ny - T[y]) -\n                llabs((long long)bestRes.cnt[x] - T[x]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) {\n                swaps.push_back({delta, 1, e, f, -1});\n            }\n        }\n    }\n\n    sort(swaps.begin(), swaps.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    testLimit = min(48, (int)swaps.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n\n        int e = swaps[i].e;\n        int f = swaps[i].f;\n\n        setEdge(c, e, dest[f]);\n        setEdge(c, f, dest[e]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\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    cin >> N >> L;\n\n    uint64_t seed = 123456789;\n\n    for (int i = 0; i < N; ++i) {\n        cin >> T[i];\n        seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    }\n\n    rng = RNG(seed);\n    st_time = chrono::steady_clock::now();\n\n    Cdes = T;\n\n    if (T[0] == 0) {\n        Cdes[0] = 1;\n\n        int k = 1;\n        for (int i = 1; i < N; ++i) {\n            if (T[i] > T[k]) k = i;\n        }\n\n        --Cdes[k];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        demandIn[i] = Cdes[i];\n    }\n\n    --demandIn[0];\n\n    if (demandIn[0] < 0) demandIn[0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (demandIn[i] > 0) {\n            activeChoices.push_back(i);\n        }\n    }\n\n    if (activeChoices.empty()) {\n        int k = max_element(Cdes.begin(), Cdes.begin() + N) - Cdes.begin();\n        activeChoices.push_back(k);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (validZ(i)) validZs.push_back(i);\n    }\n\n    if (validZs.empty()) {\n        for (int i = 0; i < N; ++i) {\n            if (Cdes[i] > 0) validZs.push_back(i);\n        }\n    }\n\n    consider(buildSimpleCycle(false));\n    consider(buildSimpleCycle(true));\n\n    vector<int> zlist;\n\n    auto addZ = [&](int z) {\n        if (!validZ(z)) return;\n        if (find(zlist.begin(), zlist.end(), z) == zlist.end()) {\n            zlist.push_back(z);\n        }\n    };\n\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        return Cdes[x] > Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) {\n        addZ(ids[i]);\n    }\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        if ((Cdes[x] > 0) != (Cdes[y] > 0)) return Cdes[x] > 0;\n        return Cdes[x] < Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) {\n        addZ(ids[i]);\n    }\n\n    addZ(0);\n\n    if (zlist.empty() && !validZs.empty()) {\n        zlist.push_back(validZs[0]);\n    }\n\n    const double TL = 1.88;\n    const double PHASE_FREE_DET = 0.55;\n    const double PHASE_FREE_RAND = 1.04;\n    const double PHASE_REBAL = 1.58;\n\n    for (int z : zlist) {\n        if (elapsed_sec() > PHASE_FREE_DET) break;\n\n        for (int repairType : {1, 0, 2}) {\n            if (elapsed_sec() > PHASE_FREE_DET) break;\n\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() > PHASE_FREE_DET) break;\n\n                Cand c = buildFree(z, mode, 1, 8, false, repairType);\n                consider(c);\n            }\n        }\n    }\n\n    for (int z : zlist) {\n        if (elapsed_sec() > 0.78) break;\n\n        for (int fixed = 0; fixed < 2; ++fixed) {\n            if (elapsed_sec() > 0.78) break;\n\n            for (int K = 1; K <= 4; ++K) {\n                if (elapsed_sec() > 0.78) break;\n\n                Cand c = buildBackbone(fixed, z, K, 0, 0, 1, 4, false);\n                consider(c);\n            }\n        }\n    }\n\n    while (elapsed_sec() < PHASE_FREE_RAND) {\n        int z = randomZ();\n        int mode = rng.randint(3);\n        int topR = 1 + rng.randint(5);\n        int maxPass = 3 + rng.randint(5);\n\n        int r = rng.randint(100);\n        int repairType;\n\n        if (r < 72) repairType = 1;\n        else if (r < 90) repairType = 2;\n        else repairType = 0;\n\n        Cand c = buildFree(z, mode, topR, maxPass, true, repairType);\n        consider(c);\n    }\n\n    for (int rep = 0; rep < 4 && elapsed_sec() < 1.25 && !pool.empty(); ++rep) {\n        Entry base = pool[0];\n\n        for (int fullInt = 0; fullInt < 2; ++fullInt) {\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() >= 1.25) break;\n\n                bool full = fullInt != 0;\n                int maxPass = full ? 7 : 10;\n\n                Cand c = rebalanceCandidate(base, full, mode, 1, maxPass, false, 1);\n                consider(c);\n            }\n        }\n    }\n\n    int it = 0;\n\n    while (elapsed_sec() < PHASE_REBAL && !pool.empty()) {\n        Entry base;\n\n        if (it % 3 == 0) {\n            base = pool[0];\n        } else {\n            base = pool[rng.randint((int)pool.size())];\n        }\n\n        bool full = (it % 3 != 1);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? (4 + rng.randint(4)) : (6 + rng.randint(4));\n\n        int repairType = (rng.randint(100) < 85) ? 1 : 2;\n\n        Cand c = rebalanceCandidate(base, full, mode, topR, maxPass, true, repairType);\n        consider(c);\n\n        ++it;\n    }\n\n    bool localAllowed = true;\n\n    while (elapsed_sec() < TL) {\n        if (bestErr == 0) break;\n\n        if (localAllowed) {\n            if (tryLocalImprove(TL)) {\n                localAllowed = true;\n                continue;\n            }\n\n            localAllowed = false;\n        }\n\n        if (pool.empty() || elapsed_sec() >= TL) break;\n\n        Entry base = pool[rng.randint((int)pool.size())];\n\n        bool full = rng.randint(2);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? 4 : 7;\n\n        int repairType = (rng.randint(100) < 88) ? 1 : 2;\n\n        bool imp = consider(\n            rebalanceCandidate(base, full, mode, topR, maxPass, true, repairType)\n        );\n\n        if (imp) localAllowed = true;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestCand.a[i] << ' ' << bestCand.b[i] << '\\n';\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, varp, norm2;\n    vector<int> sx_int, sy_int;\n    vector<unsigned long long> hilb;\n\n    vector<float> distBase;\n    vector<float> distRank;\n    vector<unsigned char> known;\n\n    vector<float> bonusMat;\n    vector<vector<pair<int, float>>> bonusAdj;\n\n    unordered_set<unsigned long long> usedQueries;\n    unordered_map<unsigned long long, vector<pair<int,int>>> responseMap;\n\n    int queryCount = 0;\n    float knownEvalFactor;\n    float knownFinalFactor;\n\n    mt19937 rng{1234567};\n\n    int ID(int i, int j) const { return i * N + j; }\n\n    static unsigned long long hilbertOrder(int x, int y) {\n        const int B = 14;\n        const int SZ = 1 << B;\n        unsigned long long d = 0;\n\n        for (int s = SZ / 2; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (unsigned long long)s * (unsigned long long)s * ((3 * rx) ^ ry);\n\n            if (ry == 0) {\n                if (rx == 1) {\n                    x = SZ - 1 - x;\n                    y = SZ - 1 - y;\n                }\n                swap(x, y);\n            }\n        }\n\n        return d;\n    }\n\n    unsigned long long subsetHash(vector<int> s) const {\n        sort(s.begin(), s.end());\n\n        unsigned long long h = 1469598103934665603ULL;\n        h ^= (unsigned long long)s.size();\n        h *= 1099511628211ULL;\n\n        for (int v : s) {\n            h ^= (unsigned long long)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n\n        return h;\n    }\n\n    void readInput() {\n        cin >> N >> M >> Q >> L >> W;\n\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N);\n        rx.resize(N);\n        ly.resize(N);\n        ry.resize(N);\n        cx.resize(N);\n        cy.resize(N);\n        varp.resize(N);\n        norm2.resize(N);\n        sx_int.resize(N);\n        sy_int.resize(N);\n        hilb.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n\n            double wx = rx[i] - lx[i];\n            double wy = ry[i] - ly[i];\n\n            varp[i] = (wx * wx + wy * wy) / 12.0;\n            norm2[i] = cx[i] * cx[i] + cy[i] * cy[i];\n        }\n\n        const int SZ = 1 << 14;\n\n        for (int i = 0; i < N; i++) {\n            sx_int[i] = min(SZ - 1, max(0, (int)llround(cx[i] * (SZ - 1) / 10000.0)));\n            sy_int[i] = min(SZ - 1, max(0, (int)llround(cy[i] * (SZ - 1) / 10000.0)));\n            hilb[i] = hilbertOrder(sx_int[i], sy_int[i]);\n        }\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        knownEvalFactor = (float)(0.72 - 0.22 * unc);\n        knownFinalFactor = (float)(0.82 - 0.22 * unc);\n    }\n\n    void computeDistances() {\n        distBase.assign(N * N, 0.0f);\n        distRank.assign(N * N, 0.0f);\n\n        vector<array<double, 9>> qx(N), qy(N), qw(N);\n\n        const double p[3] = {\n            -sqrt(3.0 / 5.0),\n            0.0,\n            sqrt(3.0 / 5.0)\n        };\n\n        const double w1[3] = {\n            5.0 / 18.0,\n            8.0 / 18.0,\n            5.0 / 18.0\n        };\n\n        for (int i = 0; i < N; i++) {\n            double mx = 0.5 * (lx[i] + rx[i]);\n            double my = 0.5 * (ly[i] + ry[i]);\n            double hx = 0.5 * (rx[i] - lx[i]);\n            double hy = 0.5 * (ry[i] - ly[i]);\n\n            int id = 0;\n            for (int a = 0; a < 3; a++) {\n                for (int b = 0; b < 3; b++) {\n                    qx[i][id] = mx + hx * p[a];\n                    qy[i][id] = my + hy * p[b];\n                    qw[i][id] = w1[a] * w1[b];\n                    id++;\n                }\n            }\n        }\n\n        const double alpha = 0.70;\n\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 cd = sqrt(dx * dx + dy * dy);\n\n                double oldBase = sqrt(dx * dx + dy * dy + alpha * (varp[i] + varp[j]));\n\n                double quad = 0.0;\n                for (int a = 0; a < 9; a++) {\n                    for (int b = 0; b < 9; b++) {\n                        double ddx = qx[i][a] - qx[j][b];\n                        double ddy = qy[i][a] - qy[j][b];\n                        quad += qw[i][a] * qw[j][b] * sqrt(ddx * ddx + ddy * ddy);\n                    }\n                }\n\n                double base = 0.80 * quad + 0.20 * oldBase;\n\n                double gx = 0.0, gy = 0.0;\n\n                if (rx[i] < lx[j]) gx = lx[j] - rx[i];\n                else if (rx[j] < lx[i]) gx = lx[i] - rx[j];\n\n                if (ry[i] < ly[j]) gy = ly[j] - ry[i];\n                else if (ry[j] < ly[i]) gy = ly[i] - ry[j];\n\n                double minRect = sqrt(gx * gx + gy * gy);\n                double rankd = 0.70 * minRect + 0.30 * cd;\n\n                distBase[ID(i, j)] = distBase[ID(j, i)] = (float)base;\n                distRank[ID(i, j)] = distRank[ID(j, i)] = (float)rankd;\n            }\n        }\n\n        known.assign(N * N, 0);\n    }\n\n    vector<pair<int,int>> askNew(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        usedQueries.insert(h);\n\n        cout << \"? \" << subset.size();\n        for (int v : subset) cout << ' ' << v;\n        cout << '\\n';\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        int l = (int)subset.size();\n        ret.reserve(l - 1);\n\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            if (a > b) swap(a, b);\n            ret.emplace_back(a, b);\n        }\n\n        queryCount++;\n        responseMap[h] = ret;\n        return ret;\n    }\n\n    vector<pair<int,int>> getOrAsk(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        auto it = responseMap.find(h);\n\n        if (it != responseMap.end() && (int)it->second.size() == (int)subset.size() - 1) {\n            return it->second;\n        }\n\n        if (queryCount >= Q) return {};\n        return askNew(subset);\n    }\n\n    void addKnownEdges(const vector<pair<int,int>>& es) {\n        for (auto [a, b] : es) {\n            if (a > b) swap(a, b);\n            known[ID(a, b)] = known[ID(b, a)] = 1;\n        }\n    }\n\n    vector<int> buildSubsetGlobal(int center, int variant, int mode) {\n        vector<pair<float,int>> arr;\n        arr.reserve(N - 1);\n\n        for (int v = 0; v < N; v++) {\n            if (v == center) continue;\n            float d = (mode == 0 ? distRank[ID(center, v)] : distBase[ID(center, v)]);\n            arr.emplace_back(d, v);\n        }\n\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n\n            for (int i = 0; i < common; i++) {\n                sub.push_back(arr[i].second);\n            }\n\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n\n        return sub;\n    }\n\n    vector<int> buildSubsetInGroup(int center, const vector<int>& group, int variant) {\n        vector<pair<float,int>> arr;\n        arr.reserve(group.size());\n\n        for (int v : group) {\n            if (v == center) continue;\n            arr.emplace_back(distBase[ID(center, v)], v);\n        }\n\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n\n            for (int i = 0; i < common; i++) {\n                sub.push_back(arr[i].second);\n            }\n\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n\n        return sub;\n    }\n\n    int reserveFinalQueryCount() const {\n        int res = 0;\n        int chunk = L - 1;\n\n        for (int g : G) {\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                res++;\n            } else {\n                int total = g - 1;\n                int full = total / chunk;\n                int rem = total % chunk;\n\n                res += full;\n                if (rem >= 2) res++;\n            }\n        }\n\n        return min(res, Q);\n    }\n\n    void performPrequeries(int targetQueries) {\n        if (targetQueries <= 0) return;\n\n        vector<int> byUnc(N), byHilb(N);\n        iota(byUnc.begin(), byUnc.end(), 0);\n        iota(byHilb.begin(), byHilb.end(), 0);\n\n        sort(byUnc.begin(), byUnc.end(), [&](int a, int b) {\n            if (varp[a] != varp[b]) return varp[a] > varp[b];\n            return a < b;\n        });\n\n        sort(byHilb.begin(), byHilb.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n\n        vector<int> centers;\n        vector<char> seen(N, 0);\n\n        for (int t = 0; t < N; t++) {\n            int c1 = byUnc[t];\n\n            if (!seen[c1]) {\n                seen[c1] = 1;\n                centers.push_back(c1);\n            }\n\n            int c2 = byHilb[(t * 37) % N];\n\n            if (!seen[c2]) {\n                seen[c2] = 1;\n                centers.push_back(c2);\n            }\n        }\n\n        for (int c : centers) {\n            if (queryCount >= targetQueries) break;\n\n            for (int v = 0; v < 4 && queryCount < targetQueries; v++) {\n                int mode = v & 1;\n                int variant = v / 2;\n\n                auto sub = buildSubsetGlobal(c, variant, mode);\n                if ((int)sub.size() < 2) continue;\n\n                unsigned long long h = subsetHash(sub);\n                if (usedQueries.count(h)) continue;\n\n                auto ret = askNew(sub);\n                addKnownEdges(ret);\n                break;\n            }\n        }\n\n        int attempts = 0;\n\n        while (queryCount < targetQueries && attempts < 5000) {\n            int c = attempts % N;\n            int variant = (attempts / N) % 6;\n            int mode = (attempts / (N * 6)) & 1;\n            attempts++;\n\n            auto sub = buildSubsetGlobal(c, variant, mode);\n            if ((int)sub.size() < 2) continue;\n\n            unsigned long long h = subsetHash(sub);\n            if (usedQueries.count(h)) continue;\n\n            auto ret = askNew(sub);\n            addKnownEdges(ret);\n        }\n    }\n\n    float evalWeight(int u, int v) const {\n        float d = distBase[ID(u, v)];\n        if (known[ID(u, v)]) d *= knownEvalFactor;\n        return d;\n    }\n\n    double primCostEval(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        if (n <= 1) return 0.0;\n\n        vector<float> best(n, 1e30f);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\n\n        double cost = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n\n            used[v] = 1;\n            cost += best[v];\n\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    float w = evalWeight(vs[v], vs[u]);\n                    if (w < best[u]) best[u] = w;\n                }\n            }\n        }\n\n        return cost;\n    }\n\n    double evalCandidate(const vector<int>& gid) const {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n\n        for (int i = 0; i < N; i++) {\n            if (gid[i] < 0 || gid[i] >= M) return 1e100;\n            groups[gid[i]].push_back(i);\n        }\n\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) return 1e100;\n        }\n\n        double score = 0.0;\n        for (int k = 0; k < M; k++) score += primCostEval(groups[k]);\n\n        return score;\n    }\n\n    vector<vector<int>> makeCityOrders() {\n        vector<vector<int>> orders;\n        const int S = (1 << 14) - 1;\n\n        auto addHilbert = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n\n                    if (type == 1) {\n                        tx = y;\n                        ty = x;\n                    } else if (type == 2) {\n                        tx = S - x;\n                        ty = y;\n                    } else if (type == 3) {\n                        tx = x;\n                        ty = S - y;\n                    } else if (type == 4) {\n                        tx = S - x;\n                        ty = S - y;\n                    } else if (type == 5) {\n                        tx = S - y;\n                        ty = x;\n                    }\n\n                    return hilbertOrder(tx, ty);\n                };\n\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 6; t++) addHilbert(t);\n\n        auto addSort = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                double ka, kb;\n\n                if (type == 0) {\n                    ka = cx[a] * 10001.0 + cy[a];\n                    kb = cx[b] * 10001.0 + cy[b];\n                } else if (type == 1) {\n                    ka = cy[a] * 10001.0 + cx[a];\n                    kb = cy[b] * 10001.0 + cx[b];\n                } else if (type == 2) {\n                    ka = cx[a] + cy[a];\n                    kb = cx[b] + cy[b];\n                } else {\n                    ka = cx[a] - cy[a];\n                    kb = cx[b] - cy[b];\n                }\n\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addSort(t);\n\n        return orders;\n    }\n\n    vector<vector<int>> makeGroupOrders() {\n        vector<vector<int>> orders;\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n\n        orders.push_back(ids);\n\n        vector<int> asc = ids;\n        vector<int> desc = ids;\n\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        orders.push_back(asc);\n        orders.push_back(desc);\n\n        for (int r = 0; r < 6; r++) {\n            vector<int> p = ids;\n            shuffle(p.begin(), p.end(), rng);\n            orders.push_back(p);\n        }\n\n        return orders;\n    }\n\n    vector<int> partitionCandidate(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n        vector<int> gid(N, -1);\n        int pos = 0;\n\n        for (int g : groupOrder) {\n            for (int t = 0; t < G[g]; t++) {\n                gid[cityOrder[pos++]] = g;\n            }\n        }\n\n        return gid;\n    }\n\n    struct EP {\n        float w;\n        int u, v;\n\n        bool operator<(const EP& other) const {\n            if (w != other.w) return w < other.w;\n            if (u != other.u) return u < other.u;\n            return v < other.v;\n        }\n    };\n\n    vector<EP> makeSortedPairs() {\n        vector<EP> ps;\n        ps.reserve(N * (N - 1) / 2);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                ps.push_back({evalWeight(i, j), i, j});\n            }\n        }\n\n        sort(ps.begin(), ps.end());\n        return ps;\n    }\n\n    vector<int> greedyCandidate(const vector<int>& groupOrder, const vector<EP>& pairs) {\n        vector<int> gid(N, -1);\n        vector<char> alive(N, 1);\n        int rem = N;\n        int ptr = 0;\n\n        auto addCity = [&](vector<int>& sel, int v) {\n            if (!alive[v]) return;\n            alive[v] = 0;\n            rem--;\n            sel.push_back(v);\n        };\n\n        for (int gr : groupOrder) {\n            int need = G[gr];\n            vector<int> sel;\n            sel.reserve(need);\n\n            if (need == rem) {\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        gid[i] = gr;\n                        alive[i] = 0;\n                    }\n                }\n                rem = 0;\n                continue;\n            }\n\n            if (need == 1) {\n                double mx = 0.0, my = 0.0;\n\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        mx += cx[i];\n                        my += cy[i];\n                    }\n                }\n\n                mx /= rem;\n                my /= rem;\n\n                int best = -1;\n                double bestVal = -1.0;\n\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        double dx = cx[i] - mx;\n                        double dy = cy[i] - my;\n                        double val = dx * dx + dy * dy + 0.05 * varp[i];\n\n                        if (val > bestVal) {\n                            bestVal = val;\n                            best = i;\n                        }\n                    }\n                }\n\n                addCity(sel, best);\n            } else {\n                while (ptr < (int)pairs.size() && !(alive[pairs[ptr].u] && alive[pairs[ptr].v])) {\n                    ptr++;\n                }\n\n                if (ptr < (int)pairs.size()) {\n                    addCity(sel, pairs[ptr].u);\n                    addCity(sel, pairs[ptr].v);\n                } else {\n                    for (int i = 0; i < N && (int)sel.size() < min(2, need); i++) {\n                        if (alive[i]) addCity(sel, i);\n                    }\n                }\n\n                vector<float> best(N, 1e30f);\n\n                for (int v = 0; v < N; v++) {\n                    if (alive[v]) {\n                        for (int s : sel) {\n                            best[v] = min(best[v], evalWeight(v, s));\n                        }\n                    }\n                }\n\n                while ((int)sel.size() < need) {\n                    int bv = -1;\n\n                    for (int v = 0; v < N; v++) {\n                        if (alive[v]) {\n                            if (bv == -1 || best[v] < best[bv]) bv = v;\n                        }\n                    }\n\n                    if (bv == -1) break;\n\n                    addCity(sel, bv);\n\n                    for (int v = 0; v < N; v++) {\n                        if (alive[v]) {\n                            best[v] = min(best[v], evalWeight(v, bv));\n                        }\n                    }\n                }\n            }\n\n            for (int v : sel) gid[v] = gr;\n        }\n\n        return gid;\n    }\n\n    void kdRec(vector<int> cities, vector<int> gids, vector<int>& assign, int depth, int mode, mt19937& rr) {\n        if (gids.size() == 1) {\n            int g = gids[0];\n            for (int c : cities) assign[c] = g;\n            return;\n        }\n\n        int n = (int)cities.size();\n\n        double minx = 1e100, maxx = -1e100;\n        double miny = 1e100, maxy = -1e100;\n\n        for (int c : cities) {\n            minx = min(minx, cx[c]);\n            maxx = max(maxx, cx[c]);\n            miny = min(miny, cy[c]);\n            maxy = max(maxy, cy[c]);\n        }\n\n        double rxr = maxx - minx;\n        double ryr = maxy - miny;\n\n        int axis;\n\n        if (mode % 3 == 0) axis = (rxr >= ryr ? 0 : 1);\n        else if (mode % 3 == 1) axis = depth & 1;\n        else axis = (rxr < ryr ? 0 : 1);\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            double ka = axis == 0 ? cx[a] : cy[a];\n            double kb = axis == 0 ? cx[b] : cy[b];\n\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        vector<int> order = gids;\n\n        if (mode >= 3) {\n            shuffle(order.begin(), order.end(), rr);\n        } else if (mode == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] > G[b];\n                return a < b;\n            });\n        } else if (mode == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] < G[b];\n                return a < b;\n            });\n        }\n\n        vector<char> dp(n + 1, 0);\n        vector<int> parS(n + 1, -1), parG(n + 1, -1);\n\n        dp[0] = 1;\n\n        for (int g : order) {\n            int s = G[g];\n\n            for (int sum = n - s; sum >= 0; sum--) {\n                if (dp[sum] && !dp[sum + s]) {\n                    dp[sum + s] = 1;\n                    parS[sum + s] = sum;\n                    parG[sum + s] = g;\n                }\n            }\n        }\n\n        int target = n / 2;\n        int best = -1;\n        int bd = 1e9;\n\n        for (int s = 1; s < n; s++) {\n            if (dp[s]) {\n                int d = abs(s - target);\n\n                if (d < bd) {\n                    bd = d;\n                    best = s;\n                }\n            }\n        }\n\n        if (best == -1) best = G[gids[0]];\n\n        vector<char> selected(M, 0);\n        int cur = best;\n\n        while (cur > 0) {\n            int g = parG[cur];\n            if (g < 0) break;\n            selected[g] = 1;\n            cur = parS[cur];\n        }\n\n        vector<int> leftG, rightG;\n\n        for (int g : gids) {\n            if (selected[g]) leftG.push_back(g);\n            else rightG.push_back(g);\n        }\n\n        if (leftG.empty() || rightG.empty()) {\n            leftG.clear();\n            rightG.clear();\n\n            int acc = 0;\n            for (int g : gids) {\n                if (acc + G[g] <= best && leftG.empty() == false) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else if (acc < best) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else {\n                    rightG.push_back(g);\n                }\n            }\n\n            if (leftG.empty() || rightG.empty()) {\n                leftG = {gids[0]};\n                rightG.assign(gids.begin() + 1, gids.end());\n                best = G[gids[0]];\n            }\n        }\n\n        bool flip = (mode >= 3 && ((depth + mode) & 1));\n\n        vector<int> leftC, rightC;\n\n        if (!flip) {\n            leftC.assign(cities.begin(), cities.begin() + best);\n            rightC.assign(cities.begin() + best, cities.end());\n        } else {\n            leftC.assign(cities.end() - best, cities.end());\n            rightC.assign(cities.begin(), cities.end() - best);\n        }\n\n        kdRec(leftC, leftG, assign, depth + 1, mode, rr);\n        kdRec(rightC, rightG, assign, depth + 1, mode, rr);\n    }\n\n    vector<int> kdCandidate(int mode) {\n        vector<int> cities(N), gids(M), assign(N, -1);\n\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        mt19937 rr(1000 + mode * 97);\n        kdRec(cities, gids, assign, 0, mode, rr);\n\n        return assign;\n    }\n\n    void buildBonus() {\n        bonusMat.assign(N * N, 0.0f);\n        bonusAdj.assign(N, {});\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        double coef = 0.20 + 0.30 * unc;\n        double cap = 2.0e6;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (!known[ID(i, j)]) continue;\n\n                double d = distBase[ID(i, j)];\n                float b = (float)min(cap, coef * d * d);\n\n                bonusMat[ID(i, j)] = bonusMat[ID(j, i)] = b;\n                bonusAdj[i].push_back({j, b});\n                bonusAdj[j].push_back({i, b});\n            }\n        }\n    }\n\n    void localSearch(vector<int>& gid, int maxPass) {\n        vector<double> sxg(M, 0.0), syg(M, 0.0), sqg(M, 0.0);\n\n        for (int i = 0; i < N; i++) {\n            int g = gid[i];\n\n            sxg[g] += cx[i];\n            syg[g] += cy[i];\n            sqg[g] += norm2[i];\n        }\n\n        vector<float> ktg((size_t)N * M, 0.0f);\n\n        for (int u = 0; u < N; u++) {\n            for (auto [v, b] : bonusAdj[u]) {\n                if (u < v) {\n                    ktg[(size_t)u * M + gid[v]] += b;\n                    ktg[(size_t)v * M + gid[u]] += b;\n                }\n            }\n        }\n\n        auto deltaReplace = [&](int g, int out, int in) -> double {\n            double nsx = sxg[g] - cx[out] + cx[in];\n            double nsy = syg[g] - cy[out] + cy[in];\n\n            double oldS2 = sxg[g] * sxg[g] + syg[g] * syg[g];\n            double newS2 = nsx * nsx + nsy * nsy;\n\n            return (-norm2[out] + norm2[in]) - (newS2 - oldS2) / G[g];\n        };\n\n        auto applySwap = [&](int i, int j, int A, int B) {\n            sxg[A] += -cx[i] + cx[j];\n            syg[A] += -cy[i] + cy[j];\n            sqg[A] += -norm2[i] + norm2[j];\n\n            sxg[B] += -cx[j] + cx[i];\n            syg[B] += -cy[j] + cy[i];\n            sqg[B] += -norm2[j] + norm2[i];\n\n            for (auto [t, b] : bonusAdj[i]) {\n                ktg[(size_t)t * M + A] -= b;\n                ktg[(size_t)t * M + B] += b;\n            }\n\n            for (auto [t, b] : bonusAdj[j]) {\n                ktg[(size_t)t * M + B] -= b;\n                ktg[(size_t)t * M + A] += b;\n            }\n\n            gid[i] = B;\n            gid[j] = A;\n        };\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            int swaps = 0;\n\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    int A = gid[i];\n                    int B = gid[j];\n\n                    if (A == B) continue;\n\n                    double ds = deltaReplace(A, i, j) + deltaReplace(B, j, i);\n\n                    float bij = bonusMat[ID(i, j)];\n                    double before = ktg[(size_t)i * M + A] + ktg[(size_t)j * M + B];\n                    double after = ktg[(size_t)i * M + B] + ktg[(size_t)j * M + A] - 2.0 * bij;\n\n                    double delta = ds - (after - before);\n\n                    if (delta < -1e-7) {\n                        applySwap(i, j, A, B);\n                        swaps++;\n                    }\n                }\n            }\n\n            if (swaps == 0) break;\n        }\n    }\n\n    vector<int> makeGrouping() {\n        if (M == 1) return vector<int>(N, 0);\n\n        struct Cand {\n            double score;\n            vector<int> gid;\n        };\n\n        vector<Cand> top;\n        const int TOPK = 8;\n\n        auto addCand = [&](vector<int> gid) {\n            double sc = evalCandidate(gid);\n            if (sc > 1e90) return;\n\n            if ((int)top.size() < TOPK) {\n                top.push_back({sc, move(gid)});\n            } else {\n                int worst = 0;\n\n                for (int i = 1; i < (int)top.size(); i++) {\n                    if (top[i].score > top[worst].score) worst = i;\n                }\n\n                if (sc < top[worst].score) {\n                    top[worst] = {sc, move(gid)};\n                }\n            }\n        };\n\n        auto cityOrders = makeCityOrders();\n        auto groupOrders = makeGroupOrders();\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                addCand(partitionCandidate(co, go));\n            }\n        }\n\n        auto pairs = makeSortedPairs();\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n\n        vector<int> asc = ids;\n        vector<int> desc = ids;\n\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        addCand(greedyCandidate(asc, pairs));\n        addCand(greedyCandidate(ids, pairs));\n        addCand(greedyCandidate(desc, pairs));\n\n        for (int mode = 0; mode < 6; mode++) {\n            addCand(kdCandidate(mode));\n        }\n\n        if (top.empty()) {\n            auto co = cityOrders[0];\n            auto go = groupOrders[0];\n            return partitionCandidate(co, go);\n        }\n\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        buildBonus();\n\n        vector<int> best = top[0].gid;\n        double bestScore = top[0].score;\n\n        int lim = min(6, (int)top.size());\n        int passes = (M > 250 ? 12 : 9);\n\n        for (int i = 0; i < lim; i++) {\n            vector<int> gid = top[i].gid;\n\n            localSearch(gid, passes);\n\n            double sc = evalCandidate(gid);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = move(gid);\n            }\n        }\n\n        return best;\n    }\n\n    vector<vector<int>> buildGroups(const vector<int>& gid) {\n        vector<vector<int>> groups(M);\n\n        for (int k = 0; k < M; k++) {\n            groups[k].reserve(G[k]);\n        }\n\n        for (int i = 0; i < N; i++) {\n            groups[gid[i]].push_back(i);\n        }\n\n        bool ok = true;\n\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) ok = false;\n        }\n\n        if (!ok) {\n            groups.assign(M, {});\n\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n\n            int pos = 0;\n\n            for (int k = 0; k < M; k++) {\n                for (int t = 0; t < G[k]; t++) {\n                    groups[k].push_back(ids[pos++]);\n                }\n            }\n        }\n\n        return groups;\n    }\n\n    struct FinalTask {\n        double priority;\n        int type; // 0: exact whole group, 1: large group chunk\n        int group;\n        vector<int> subset;\n    };\n\n    void performFinalQueries(\n        vector<vector<int>>& groups,\n        vector<char>& exact,\n        vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        exact.assign(M, 0);\n        exactEdges.assign(M, {});\n\n        vector<FinalTask> tasks;\n        tasks.reserve(1000);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                FinalTask task;\n                task.priority = 1.20 * (g - 1);\n                task.type = 0;\n                task.group = k;\n                task.subset = groups[k];\n\n                tasks.push_back(move(task));\n            } else {\n                vector<int> ord = groups[k];\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                    return a < b;\n                });\n\n                int connector = ord[0];\n                int pos = 1;\n\n                while (pos < g) {\n                    int s = min(L - 1, g - pos);\n\n                    if (s >= 2) {\n                        FinalTask task;\n                        task.priority = 0.80 * s;\n                        task.type = 1;\n                        task.group = k;\n                        task.subset.reserve(s + 1);\n                        task.subset.push_back(connector);\n\n                        for (int t = 0; t < s; t++) {\n                            task.subset.push_back(ord[pos + t]);\n                        }\n\n                        tasks.push_back(move(task));\n                    }\n\n                    connector = ord[pos + s - 1];\n                    pos += s;\n                }\n            }\n        }\n\n        sort(tasks.begin(), tasks.end(), [](const FinalTask& a, const FinalTask& b) {\n            if (a.priority != b.priority) return a.priority > b.priority;\n            if (a.type != b.type) return a.type < b.type;\n            return a.group < b.group;\n        });\n\n        for (auto& task : tasks) {\n            if (queryCount >= Q) {\n                unsigned long long h = subsetHash(task.subset);\n                if (responseMap.find(h) == responseMap.end()) break;\n            }\n\n            auto ret = getOrAsk(task.subset);\n            if (ret.empty()) continue;\n\n            addKnownEdges(ret);\n\n            if (task.type == 0) {\n                int k = task.group;\n                int g = (int)groups[k].size();\n\n                if ((int)ret.size() == g - 1) {\n                    exact[k] = 1;\n                    exactEdges[k] = ret;\n                }\n            }\n        }\n\n        if (queryCount >= Q) return;\n\n        vector<int> candGroups;\n        int maxG = 0;\n        vector<vector<int>> ords(M);\n\n        for (int k = 0; k < M; k++) {\n            if (exact[k]) continue;\n\n            int g = (int)groups[k].size();\n            if (g < 3) continue;\n\n            candGroups.push_back(k);\n            ords[k] = groups[k];\n\n            sort(ords[k].begin(), ords[k].end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n\n            maxG = max(maxG, g);\n        }\n\n        for (int variant = 0; variant < 5 && queryCount < Q; variant++) {\n            for (int r = 0; r < maxG && queryCount < Q; r++) {\n                for (int k : candGroups) {\n                    if (queryCount >= Q) break;\n                    if (r >= (int)ords[k].size()) continue;\n\n                    int center = ords[k][r];\n                    auto sub = buildSubsetInGroup(center, groups[k], variant);\n\n                    if ((int)sub.size() < 3) continue;\n\n                    unsigned long long h = subsetHash(sub);\n                    if (usedQueries.count(h)) continue;\n\n                    auto ret = askNew(sub);\n                    addKnownEdges(ret);\n                }\n            }\n        }\n    }\n\n    vector<pair<int,int>> finalPrimEdges(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        vector<pair<int,int>> edges;\n\n        if (n <= 1) return edges;\n\n        vector<float> best(n, 1e30f);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n\n        best[0] = 0.0f;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) {\n                    v = i;\n                }\n            }\n\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                edges.push_back({vs[v], vs[par[v]]});\n            }\n\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    int a = vs[v];\n                    int b = vs[u];\n\n                    float w = distBase[ID(a, b)];\n                    if (known[ID(a, b)]) w *= knownFinalFactor;\n\n                    if (w < best[u]) {\n                        best[u] = w;\n                        par[u] = v;\n                    }\n                }\n            }\n        }\n\n        return edges;\n    }\n\n    void outputAnswer(\n        const vector<vector<int>>& groups,\n        const vector<char>& exact,\n        const vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        vector<vector<pair<int,int>>> ansEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n\n            if (g <= 1) {\n                ansEdges[k] = {};\n            } else if (g == 2) {\n                ansEdges[k] = {{groups[k][0], groups[k][1]}};\n            } else if (exact[k]) {\n                ansEdges[k] = exactEdges[k];\n            } else {\n                ansEdges[k] = finalPrimEdges(groups[k]);\n            }\n        }\n\n        cout << \"!\\n\";\n\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << '\\n';\n\n            for (auto [a, b] : ansEdges[k]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n\n        cout.flush();\n    }\n\n    void solve() {\n        readInput();\n        computeDistances();\n\n        usedQueries.reserve(Q * 4 + 10);\n        responseMap.reserve(Q * 4 + 10);\n\n        int reserveQ = reserveFinalQueryCount();\n        int preBudget = max(0, Q - reserveQ);\n\n        performPrequeries(preBudget);\n\n        vector<int> gid = makeGrouping();\n        auto groups = buildGroups(gid);\n\n        vector<char> exact;\n        vector<vector<pair<int,int>>> exactEdges;\n\n        performFinalQueries(groups, exact, exactEdges);\n\n        outputAnswer(groups, exact, exactEdges);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 20;\nstatic const int MAXV = 400;\nstatic const int INF = 1e9;\n\nstruct Grid {\n    uint32_t row[MAXN];\n    uint32_t col[MAXN];\n    int cnt;\n    uint64_t hash;\n    Grid() {\n        memset(row, 0, sizeof(row));\n        memset(col, 0, sizeof(col));\n        cnt = 0;\n        hash = 0;\n    }\n};\n\nstruct Solver {\n    int N, M, V;\n    int LIMIT;\n    uint32_t FULL;\n    vector<int> pos;\n\n    int rr[MAXV], cc[MAXV];\n    int mv[MAXV][4];\n\n    int dr[4] = {-1, 1, 0, 0};\n    int dc[4] = {0, 0, -1, 1};\n    int opp[4] = {1, 0, 3, 2};\n\n    bool future[45][MAXV];\n    int adjVal[45][MAXV];\n\n    uint64_t zob[MAXV];\n    uint64_t rngState;\n\n    int seen[MAXV], distArr[MAXV], prevArr[MAXV], que[MAXV];\n    unsigned char actArr[MAXV];\n    int stamp = 1;\n\n    int validBits[45], inBits[45];\n    bool isPlanOpt[45][16];\n    vector<int> planOpts[45];\n\n    struct Plan2Opt {\n        int mask;\n        int leave; // -1: no, 0..3: move direction then block previous target\n    };\n    vector<Plan2Opt> plan2Opts[45];\n\n    chrono::steady_clock::time_point startTime;\n\n    vector<string> candidates;\n    string pureFallback;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    uint64_t rnd() {\n        uint64_t z = (rngState += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    inline char enc(int type, int d) const {\n        return char(type * 4 + d);\n    }\n\n    inline bool isBlocked(const Grid& g, int v) const {\n        return (g.row[rr[v]] >> cc[v]) & 1u;\n    }\n\n    inline void setBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (!(g.row[r] & br)) {\n            g.row[r] |= br;\n            g.col[c] |= (1u << r);\n            g.cnt++;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void clearBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (g.row[r] & br) {\n            g.row[r] &= ~br;\n            g.col[c] &= ~(1u << r);\n            g.cnt--;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void toggleBlock(Grid& g, int v) {\n        if (isBlocked(g, v)) clearBlock(g, v);\n        else setBlock(g, v);\n    }\n\n    inline int highestBit(uint32_t x) const {\n        return 31 - __builtin_clz(x);\n    }\n\n    inline int slideDestRC(const Grid& g, int r, int c, int d) const {\n        if (d == 0) {\n            uint32_t mask = g.col[c] & ((1u << r) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return (b + 1) * N + c;\n            }\n            return c;\n        } else if (d == 1) {\n            uint32_t mask = g.col[c] & (FULL ^ ((1u << (r + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return (b - 1) * N + c;\n            }\n            return (N - 1) * N + c;\n        } else if (d == 2) {\n            uint32_t mask = g.row[r] & ((1u << c) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return r * N + (b + 1);\n            }\n            return r * N;\n        } else {\n            uint32_t mask = g.row[r] & (FULL ^ ((1u << (c + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return r * N + (b - 1);\n            }\n            return r * N + (N - 1);\n        }\n    }\n\n    inline int slideDest(const Grid& g, int v, int d) const {\n        return slideDestRC(g, rr[v], cc[v], d);\n    }\n\n    void nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n    }\n\n    int bfsSearch(const Grid& g, int s, int t, bool storePath) {\n        if (s < 0 || t < 0) return INF;\n        if (isBlocked(g, s) || isBlocked(g, t)) return INF;\n        if (s == t) return 0;\n\n        nextStamp();\n        int head = 0, tail = 0;\n        que[tail++] = s;\n        seen[s] = stamp;\n        distArr[s] = 0;\n        if (storePath) prevArr[s] = -1;\n\n        while (head < tail) {\n            int v = que[head++];\n            int nd = distArr[v] + 1;\n            int r = rr[v], c = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDestRC(g, r, c, d);\n                if (to == v) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(1, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[v][d];\n                if (to < 0 || isBlocked(g, to)) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(0, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n        }\n        return INF;\n    }\n\n    int bfsDist(const Grid& g, int s, int t) {\n        return bfsSearch(g, s, t, false);\n    }\n\n    bool bfsPath(const Grid& g, int s, int t, string& out) {\n        int d = bfsSearch(g, s, t, true);\n        if (d >= INF) return false;\n        out.clear();\n        int v = t;\n        while (v != s) {\n            out.push_back(char(actArr[v]));\n            v = prevArr[v];\n            if (v < 0) return false;\n        }\n        reverse(out.begin(), out.end());\n        return true;\n    }\n\n    int gridValue(const Grid& g, int stage) const {\n        if (stage < 0) stage = 0;\n        if (stage >= M) stage = M - 1;\n        int val = 0;\n        for (int r = 0; r < N; r++) {\n            uint32_t bits = g.row[r];\n            while (bits) {\n                int c = __builtin_ctz(bits);\n                val += adjVal[stage][r * N + c];\n                bits &= bits - 1;\n            }\n        }\n        return val;\n    }\n\n    void init() {\n        V = N * N;\n        LIMIT = 2 * N * M;\n        FULL = (1u << N) - 1u;\n\n        for (int v = 0; v < V; v++) {\n            rr[v] = v / N;\n            cc[v] = v % N;\n        }\n\n        for (int v = 0; v < V; v++) {\n            for (int d = 0; d < 4; d++) {\n                int nr = rr[v] + dr[d];\n                int nc = cc[v] + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) mv[v][d] = nr * N + nc;\n                else mv[v][d] = -1;\n            }\n        }\n\n        memset(future, 0, sizeof(future));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                future[k][pos[t]] = true;\n            }\n        }\n\n        memset(adjVal, 0, sizeof(adjVal));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                int w = max(1, 8 - (t - k));\n                for (int d = 0; d < 4; d++) {\n                    int v = mv[pos[t]][d];\n                    if (v >= 0) adjVal[k][v] += w;\n                }\n            }\n        }\n\n        rngState = 1234567891234567ULL;\n        for (int p : pos) {\n            rngState ^= uint64_t(p + 1009) * 0x9e3779b97f4a7c15ULL;\n            rnd();\n        }\n        for (int i = 0; i < V; i++) zob[i] = rnd();\n\n        memset(seen, 0, sizeof(seen));\n\n        memset(isPlanOpt, 0, sizeof(isPlanOpt));\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            inBits[k] = 0;\n            validBits[k] = 0;\n            for (int d = 0; d < 4; d++) {\n                int q = mv[p][d];\n                if (q < 0) continue;\n                inBits[k] |= (1 << d);\n                if (!future[k][q]) validBits[k] |= (1 << d);\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~validBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planOpts[k].push_back(sub);\n                isPlanOpt[k][sub] = true;\n            }\n            if (planOpts[k].empty()) {\n                planOpts[k].push_back(0);\n                isPlanOpt[k][0] = true;\n            }\n\n            for (int m : planOpts[k]) {\n                plan2Opts[k].push_back({m, -1});\n                for (int d = 0; d < 4; d++) {\n                    if (mv[p][d] < 0) continue;\n                    if (m & (1 << d)) continue;\n                    plan2Opts[k].push_back({m, d});\n                }\n            }\n        }\n    }\n\n    string makePureMoves() {\n        string s;\n        int cur = pos[0];\n        int r = rr[cur], c = cc[cur];\n\n        for (int k = 1; k < M; k++) {\n            int gr = rr[pos[k]], gc = cc[pos[k]];\n            while (r < gr) {\n                s.push_back(enc(0, 1));\n                r++;\n            }\n            while (r > gr) {\n                s.push_back(enc(0, 0));\n                r--;\n            }\n            while (c < gc) {\n                s.push_back(enc(0, 3));\n                c++;\n            }\n            while (c > gc) {\n                s.push_back(enc(0, 2));\n                c--;\n            }\n        }\n        return s;\n    }\n\n    int firstCompletionPrefix(const string& acts) {\n        if (M <= 1) return 0;\n\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return -1;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return -1;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(g, p, d);\n            } else {\n                int to = mv[p][d];\n                if (to < 0) return -1;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                nxt++;\n                if (nxt == M) return t + 1;\n            }\n        }\n        return -1;\n    }\n\n    void addCandidate(const string& acts) {\n        int p = firstCompletionPrefix(acts);\n        if (p < 0 || p > LIMIT) return;\n        string t = acts.substr(0, p);\n        candidates.push_back(move(t));\n    }\n\n    string greedyDelete(string a, double endTime = 1.90) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return \"\";\n        a.resize(pref);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (size_t i = 0; i < a.size();) {\n                if (elapsed() > endTime) return a;\n                string b = a;\n                b.erase(b.begin() + i);\n                int p = firstCompletionPrefix(b);\n                if (p >= 0 && p <= LIMIT) {\n                    b.resize(p);\n                    a.swap(b);\n                    changed = true;\n                    if (i > 0) --i;\n                    if (i > a.size()) i = a.size();\n                } else {\n                    ++i;\n                }\n            }\n            if (!changed) break;\n        }\n\n        for (int w = 2; w <= 3; w++) {\n            bool any = true;\n            while (any) {\n                any = false;\n                for (size_t i = 0; i + w <= a.size();) {\n                    if (elapsed() > endTime + 0.02) return a;\n                    string b = a;\n                    b.erase(i, w);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        a.swap(b);\n                        any = true;\n                        if (i > 0) --i;\n                        if (i > a.size()) i = a.size();\n                    } else {\n                        ++i;\n                    }\n                }\n            }\n        }\n\n        return a;\n    }\n\n    string replaceImprove(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        a = greedyDelete(a, min(endTime, 1.91));\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (int i = 0; i < (int)a.size() && elapsed() < endTime; i++) {\n                string bestLocal;\n                int bestLen = (int)a.size();\n\n                for (int code = 0; code < 12 && elapsed() < endTime; code++) {\n                    if (code == (unsigned char)a[i]) continue;\n\n                    string b = a;\n                    b[i] = char(code);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        } else if ((int)b.size() == (int)a.size()) {\n                            int L = max(0, i - 6);\n                            int R = min((int)b.size(), i + 12);\n                            for (int j = L; j < R && elapsed() < endTime; j++) {\n                                string c = b;\n                                c.erase(c.begin() + j);\n                                int pp = firstCompletionPrefix(c);\n                                if (pp >= 0 && pp <= LIMIT) {\n                                    c.resize(pp);\n                                    if ((int)c.size() < bestLen) {\n                                        bestLen = (int)c.size();\n                                        bestLocal = c;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                if (i + 1 < (int)a.size() && elapsed() < endTime) {\n                    string b = a;\n                    swap(b[i], b[i + 1]);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        }\n                    }\n                }\n\n                if (!bestLocal.empty() && bestLen < (int)a.size()) {\n                    string del = greedyDelete(bestLocal, min(endTime, 1.93));\n                    int pp = firstCompletionPrefix(del);\n                    if (pp >= 0 && pp <= LIMIT) {\n                        del.resize(pp);\n                        if (del.size() < bestLocal.size()) bestLocal.swap(del);\n                    }\n                    if (bestLocal.size() < a.size()) {\n                        a.swap(bestLocal);\n                        changed = true;\n                        i = max(-1, i - 6);\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n        return a;\n    }\n\n    int dirToward(int a, int b) const {\n        int vr = rr[b] - rr[a];\n        int vc = cc[b] - cc[a];\n        if (abs(vr) >= abs(vc)) {\n            if (vr < 0) return 0;\n            if (vr > 0) return 1;\n        }\n        if (vc < 0) return 2;\n        if (vc > 0) return 3;\n        return 0;\n    }\n\n    int evalPlan(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int dist = bfsDist(g, p, pos[k + 1]);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    bool buildFromMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            int bestDir = -1;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    if (isBlocked(tg, p)) continue;\n                    setBlock(tg, p);\n\n                    int dist = bfsDist(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                acts.push_back(enc(0, bestDir));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> makeZeroMasks() {\n        return vector<int>(M - 1, 0);\n    }\n\n    vector<int> makeDenseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeExitMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int m = validBits[k];\n            int ex = dirToward(pos[k], pos[k + 1]);\n            m &= ~(1 << ex);\n\n            while (!isPlanOpt[k][m]) {\n                bool removed = false;\n                for (int d = 0; d < 4; d++) {\n                    if (m & (1 << d)) {\n                        m &= ~(1 << d);\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) {\n                    m = 0;\n                    break;\n                }\n            }\n            masks[k] = m;\n        }\n        return masks;\n    }\n\n    vector<int> makeSparseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 100;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = abs(pc - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeValueMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n            for (int m : planOpts[k]) {\n                int val = 0;\n                int pc = __builtin_popcount((unsigned)m);\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q >= 0) val += adjVal[k][q];\n                }\n                int sc = val * 4 - pc * 5;\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planOpts[k].size());\n            masks[k] = planOpts[k][id];\n        }\n        return masks;\n    }\n\n    pair<int, vector<int>> coordinateDescent(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlan(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlan(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    int evalPlan2(const vector<int>& masks, const vector<int>& leaves, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p) || isBlocked(g, goal)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int ld = leaves[k];\n            if (ld >= 0) {\n                int nb = mv[p][ld];\n                if (nb < 0 || isBlocked(g, nb)) return INF;\n                cost++; // Move out\n                setBlock(g, p);\n                cost++; // Alter back\n                if (cost >= cutoff) return cost;\n\n                int dist = bfsDist(g, nb, goal);\n                if (dist >= INF) return INF;\n                cost += dist;\n            } else {\n                int dist = bfsDist(g, p, goal);\n                if (dist >= INF) return INF;\n                cost += dist;\n            }\n\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    vector<int> makeGreedyLeaves(const vector<int>& masks, double beta) {\n        vector<int> leaves(M - 1, -1);\n        Grid g;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) break;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) setBlock(g, q);\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n            int bestDir = -1;\n\n            for (int d = 0; d < 4; d++) {\n                int nb = mv[p][d];\n                if (nb < 0 || isBlocked(g, nb)) continue;\n\n                Grid tg = g;\n                setBlock(tg, p);\n                int dist = bfsDist(tg, nb, goal);\n                if (dist >= INF) continue;\n\n                double score = double(2 + dist) - beta;\n                if (score < bestScore - 1e-9) {\n                    bestScore = score;\n                    bestDir = d;\n                }\n            }\n\n            leaves[k] = bestDir;\n            if (bestDir >= 0) setBlock(g, p);\n        }\n\n        return leaves;\n    }\n\n    struct Plan2Result {\n        int cost;\n        vector<int> masks;\n        vector<int> leaves;\n    };\n\n    Plan2Result coordinateDescent2(vector<int> masks, vector<int> leaves, int maxPass, double endTime) {\n        int curr = evalPlan2(masks, leaves);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldM = masks[k];\n                int oldL = leaves[k];\n                int bestM = oldM;\n                int bestL = oldL;\n                int bestCost = curr;\n\n                for (const auto& op : plan2Opts[k]) {\n                    if (op.mask == oldM && op.leave == oldL) continue;\n                    masks[k] = op.mask;\n                    leaves[k] = op.leave;\n                    int c = evalPlan2(masks, leaves, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestM = op.mask;\n                        bestL = op.leave;\n                    }\n                }\n\n                masks[k] = bestM;\n                leaves[k] = bestL;\n\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks, leaves};\n    }\n\n    bool buildPlan2(const vector<int>& masks, const vector<int>& leaves, string& acts) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int ld = leaves[k];\n            if (ld >= 0) {\n                int nb = mv[p][ld];\n                if (nb < 0 || isBlocked(g, nb)) return false;\n\n                acts.push_back(enc(0, ld));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[ld]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            } else {\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    struct Node {\n        int parent;\n        string add;\n    };\n\n    struct BeamState {\n        Grid g;\n        int cost;\n        int node;\n        int val;\n    };\n\n    string solveBeam(int keepCount, int keepValue) {\n        vector<Node> nodes;\n        nodes.push_back({-1, \"\"});\n\n        BeamState init;\n        init.cost = 0;\n        init.node = 0;\n        init.val = 0;\n\n        vector<BeamState> beam;\n        beam.push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            vector<BeamState> gen;\n            gen.reserve(beam.size() * 45);\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(beam.size() * 90 + 100);\n            mp.max_load_factor(0.7);\n\n            int p = pos[k];\n            int goal = pos[k + 1];\n\n            auto addState = [&](const BeamState& parent, const Grid& ng, int newCost, const string& app) {\n                if (newCost > LIMIT) return;\n\n                auto it = mp.find(ng.hash);\n                if (it != mp.end()) {\n                    int idx = it->second;\n                    if (newCost >= gen[idx].cost) return;\n                }\n\n                int nodeId = (int)nodes.size();\n                nodes.push_back({parent.node, app});\n\n                BeamState ns;\n                ns.g = ng;\n                ns.cost = newCost;\n                ns.node = nodeId;\n                ns.val = gridValue(ng, k + 1);\n\n                if (it == mp.end()) {\n                    mp[ng.hash] = (int)gen.size();\n                    gen.push_back(ns);\n                } else {\n                    gen[it->second] = ns;\n                }\n            };\n\n            for (const BeamState& st : beam) {\n                int candBits = 0;\n                for (int d = 0; d < 4; d++) {\n                    int q = mv[p][d];\n                    if (q < 0) continue;\n                    bool blk = isBlocked(st.g, q);\n                    if (blk || !future[k][q]) candBits |= (1 << d);\n                }\n\n                for (int sub = candBits;; sub = (sub - 1) & candBits) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    string path;\n                    if (bfsPath(ng, p, goal, path)) {\n                        string app = prep + path;\n                        addState(st, ng, st.cost + (int)app.size(), app);\n                    }\n\n                    if (sub == 0) break;\n                }\n\n                vector<int> backSubs;\n                backSubs.push_back(0);\n                for (int d = 0; d < 4; d++) {\n                    if (candBits & (1 << d)) backSubs.push_back(1 << d);\n                }\n\n                for (int sub : backSubs) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    if (isBlocked(ng, p)) continue;\n\n                    for (int e = 0; e < 4; e++) {\n                        int nb = mv[p][e];\n                        if (nb < 0 || isBlocked(ng, nb)) continue;\n\n                        Grid bg = ng;\n                        setBlock(bg, p);\n\n                        string path;\n                        if (!bfsPath(bg, nb, goal, path)) continue;\n\n                        string app = prep;\n                        app.push_back(enc(0, e));\n                        app.push_back(enc(2, opp[e]));\n                        app += path;\n\n                        addState(st, bg, st.cost + (int)app.size(), app);\n                    }\n                }\n            }\n\n            if (gen.empty()) return \"\";\n\n            if (k == M - 2) {\n                int best = 0;\n                for (int i = 1; i < (int)gen.size(); i++) {\n                    if (gen[i].cost < gen[best].cost) best = i;\n                }\n\n                vector<int> chain;\n                for (int id = gen[best].node; id != -1; id = nodes[id].parent) {\n                    chain.push_back(id);\n                }\n                reverse(chain.begin(), chain.end());\n\n                string res;\n                for (int id : chain) res += nodes[id].add;\n                return res;\n            }\n\n            struct Key {\n                int bc;\n                int bv;\n                int K;\n            };\n\n            vector<Key> keys = {\n                {0, 0, keepCount},\n                {70, 0, keepCount},\n                {130, 0, keepCount},\n                {190, 0, keepCount},\n                {250, 0, keepCount},\n                {0, 18, keepValue},\n                {50, 10, keepValue},\n                {100, 12, keepValue},\n                {150, 16, keepValue},\n                {0, 28, keepValue}\n            };\n\n            vector<char> mark(gen.size(), 0);\n            vector<int> idx(gen.size());\n            iota(idx.begin(), idx.end(), 0);\n\n            for (auto key : keys) {\n                if (key.K <= 0) continue;\n                int K = min(key.K, (int)idx.size());\n\n                auto comp = [&](int a, int b) {\n                    long long ea = 100LL * gen[a].cost - 1LL * key.bc * gen[a].g.cnt - 1LL * key.bv * gen[a].val;\n                    long long eb = 100LL * gen[b].cost - 1LL * key.bc * gen[b].g.cnt - 1LL * key.bv * gen[b].val;\n                    if (ea != eb) return ea < eb;\n                    if (gen[a].cost != gen[b].cost) return gen[a].cost < gen[b].cost;\n                    return gen[a].val > gen[b].val;\n                };\n\n                if (K < (int)idx.size()) {\n                    nth_element(idx.begin(), idx.begin() + K, idx.end(), comp);\n                }\n\n                for (int i = 0; i < K; i++) mark[idx[i]] = 1;\n            }\n\n            vector<BeamState> nxt;\n            nxt.reserve(keepCount * 5 + keepValue * 5 + 5);\n\n            for (int i = 0; i < (int)gen.size(); i++) {\n                if (mark[i]) nxt.push_back(gen[i]);\n            }\n\n            if (nxt.empty()) {\n                int best = min_element(gen.begin(), gen.end(), [](const BeamState& a, const BeamState& b) {\n                    return a.cost < b.cost;\n                }) - gen.begin();\n                nxt.push_back(gen[best]);\n            }\n\n            beam.swap(nxt);\n        }\n\n        return \"\";\n    }\n\n    struct LocalNode {\n        Grid g;\n        int p;\n        int parent;\n        int dist;\n        int altCnt;\n        int valDelta;\n        unsigned char act;\n    };\n\n    inline uint64_t localKey(uint64_t h, int p) const {\n        return h ^ (0x9e3779b97f4a7c15ULL * uint64_t(p + 1));\n    }\n\n    bool localSegmentSearch(\n        const Grid& startG,\n        int s,\n        int goal,\n        int k,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& path,\n        Grid& outG\n    ) {\n        if (elapsed() > endTime) return false;\n        if (isBlocked(startG, s) || isBlocked(startG, goal)) return false;\n        if (s == goal) {\n            path.clear();\n            outG = startG;\n            return true;\n        }\n\n        int base = bfsDist(startG, s, goal);\n        int maxDepth = 24;\n        if (base < INF) maxDepth = min(24, base + slack + 3);\n        maxDepth = max(maxDepth, 8);\n\n        vector<LocalNode> nodes;\n        nodes.reserve(maxNodes + 5);\n        vector<int> q;\n        q.reserve(maxNodes + 5);\n\n        unordered_map<uint64_t, int> mp;\n        mp.reserve(maxNodes * 2 + 100);\n        mp.max_load_factor(0.7);\n\n        LocalNode root;\n        root.g = startG;\n        root.p = s;\n        root.parent = -1;\n        root.dist = 0;\n        root.altCnt = 0;\n        root.valDelta = 0;\n        root.act = 255;\n        nodes.push_back(root);\n        q.push_back(0);\n        mp[localKey(startG.hash, s)] = 0;\n\n        int startCnt = startG.cnt;\n        int bestGoalId = -1;\n        int bestGoalDist = INF;\n        int bestGoalCost = INF;\n        double bestScore = 1e100;\n\n        auto recordGoal = [&](int id) {\n            const LocalNode& nd = nodes[id];\n            bestGoalDist = min(bestGoalDist, nd.dist);\n            double sc = double(nd.dist)\n                - betaCnt * double(nd.g.cnt - startCnt)\n                - betaVal * double(nd.valDelta);\n            if (sc < bestScore - 1e-9 ||\n                (fabs(sc - bestScore) <= 1e-9 && nd.dist < bestGoalCost)) {\n                bestScore = sc;\n                bestGoalId = id;\n                bestGoalCost = nd.dist;\n            }\n        };\n\n        auto addNode = [&](const Grid& ng, int np, int parent, unsigned char act, int ndist, int nalt, int nval) -> int {\n            if ((int)nodes.size() >= maxNodes) return -1;\n            uint64_t key = localKey(ng.hash, np);\n            if (mp.find(key) != mp.end()) return -1;\n\n            int id = (int)nodes.size();\n            LocalNode node;\n            node.g = ng;\n            node.p = np;\n            node.parent = parent;\n            node.dist = ndist;\n            node.altCnt = nalt;\n            node.valDelta = nval;\n            node.act = act;\n            nodes.push_back(node);\n            mp[key] = id;\n            q.push_back(id);\n\n            if (np == goal) recordGoal(id);\n            return id;\n        };\n\n        int head = 0;\n        while (head < (int)q.size()) {\n            if (elapsed() > endTime) return false;\n\n            int id = q[head++];\n            LocalNode cur = nodes[id];\n\n            if (cur.p == goal) continue;\n            if (cur.dist >= maxDepth) continue;\n            if (bestGoalDist < INF && cur.dist >= bestGoalDist + slack) continue;\n\n            int ndist = cur.dist + 1;\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDest(cur.g, cur.p, d);\n                if (to == cur.p) continue;\n                addNode(cur.g, to, id, enc(1, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[cur.p][d];\n                if (to < 0 || isBlocked(cur.g, to)) continue;\n                addNode(cur.g, to, id, enc(0, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int cell = mv[cur.p][d];\n                if (cell < 0) continue;\n\n                bool blk = isBlocked(cur.g, cell);\n                if (!blk && future[k][cell]) continue;\n\n                bool startBlk = isBlocked(startG, cell);\n                bool beforeDiff = (blk != startBlk);\n                int nalt = cur.altCnt + (beforeDiff ? -1 : 1);\n                if (nalt > maxAlt) continue;\n\n                Grid ng = cur.g;\n                toggleBlock(ng, cell);\n\n                int nval = cur.valDelta + (blk ? -adjVal[k][cell] : adjVal[k][cell]);\n                addNode(ng, cur.p, id, enc(2, d), ndist, nalt, nval);\n            }\n        }\n\n        if (bestGoalId < 0) return false;\n\n        path.clear();\n        for (int id = bestGoalId; nodes[id].parent != -1; id = nodes[id].parent) {\n            path.push_back(char(nodes[id].act));\n        }\n        reverse(path.begin(), path.end());\n        outG = nodes[bestGoalId].g;\n        return true;\n    }\n\n    bool buildGreedyActionWithMasks(\n        const vector<int>* masksPtr,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& acts\n    ) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            if (elapsed() > endTime) return false;\n\n            if (masksPtr) {\n                int p = pos[k];\n                if (isBlocked(g, p)) return false;\n\n                int mask = (*masksPtr)[k] & validBits[k];\n                for (int d = 0; d < 4; d++) {\n                    if (!(mask & (1 << d))) continue;\n                    int q = mv[p][d];\n                    if (q < 0 || future[k][q]) continue;\n                    if (!isBlocked(g, q)) {\n                        setBlock(g, q);\n                        acts.push_back(enc(2, d));\n                    }\n                }\n            }\n\n            string seg;\n            Grid ng;\n            bool ok = localSegmentSearch(\n                g, pos[k], pos[k + 1], k,\n                betaCnt, betaVal, maxAlt, slack, maxNodes,\n                endTime, seg, ng\n            );\n\n            if (!ok) {\n                if (!bfsPath(g, pos[k], pos[k + 1], seg)) return false;\n                ng = g;\n            }\n\n            acts += seg;\n            g = ng;\n            if ((int)acts.size() > LIMIT) return false;\n        }\n        return true;\n    }\n\n    void solve() {\n        cin >> N >> M;\n        pos.resize(M);\n        for (int i = 0; i < M; i++) {\n            int r, c;\n            cin >> r >> c;\n            pos[i] = r * N + c;\n        }\n\n        startTime = chrono::steady_clock::now();\n        init();\n\n        pureFallback = makePureMoves();\n        addCandidate(pureFallback);\n\n        string beamAns = solveBeam(25, 8);\n        if (!beamAns.empty()) addCandidate(beamAns);\n\n        vector<pair<int, vector<int>>> maskCands;\n\n        vector<vector<int>> starts;\n        starts.push_back(makeZeroMasks());\n        starts.push_back(makeDenseMasks());\n        starts.push_back(makeExitMasks());\n        starts.push_back(makeSparseMasks());\n        starts.push_back(makeValueMasks());\n        for (int i = 0; i < 5; i++) starts.push_back(makeRandomMasks());\n\n        double planEnd = 1.43;\n\n        for (auto st : starts) {\n            if (elapsed() > planEnd) break;\n            auto res = coordinateDescent(st, 3, planEnd);\n            maskCands.push_back(res);\n        }\n\n        if (maskCands.empty()) {\n            vector<int> z = makeZeroMasks();\n            maskCands.push_back({evalPlan(z), z});\n        }\n\n        sort(maskCands.begin(), maskCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedMaskKeys;\n        vector<double> backBetas = {-1.0, 0.0, 1.0, 1.5, 2.0, 2.5, 3.0};\n\n        int used = 0;\n        for (auto& pr : maskCands) {\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedMaskKeys.count(key)) continue;\n            usedMaskKeys.insert(key);\n\n            for (double beta : backBetas) {\n                string acts;\n                if (buildFromMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            used++;\n            if (used >= 8) break;\n        }\n\n        double plan2End = 1.66;\n        set<string> usedPlan2Keys;\n        int plan2Runs = 0;\n\n        for (int id = 0; id < (int)maskCands.size() && id < 5; id++) {\n            if (elapsed() > plan2End) break;\n\n            vector<vector<int>> leaveStarts;\n            leaveStarts.push_back(vector<int>(M - 1, -1));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 1.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 2.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 3.0));\n\n            for (auto leaves : leaveStarts) {\n                if (elapsed() > plan2End) break;\n\n                string key;\n                key.reserve(2 * (M - 1));\n                for (int k = 0; k < M - 1; k++) {\n                    key.push_back(char(maskCands[id].second[k]));\n                    key.push_back(char(leaves[k] + 1));\n                }\n                if (usedPlan2Keys.count(key)) continue;\n                usedPlan2Keys.insert(key);\n\n                auto res = coordinateDescent2(maskCands[id].second, leaves, 2, plan2End);\n                string acts;\n                if (buildPlan2(res.masks, res.leaves, acts)) {\n                    addCandidate(acts);\n                }\n\n                plan2Runs++;\n                if (plan2Runs >= 8) break;\n            }\n            if (plan2Runs >= 8) break;\n        }\n\n        vector<tuple<double, double, int, int, int>> localCfgs = {\n            {0.0, 0.00, 3, 1, 1500},\n            {0.8, 0.09, 4, 2, 2100},\n            {1.1, 0.13, 5, 3, 2500},\n        };\n\n        double localEnd = 1.77;\n        for (auto [bc, bv, ma, sl, mn] : localCfgs) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyActionWithMasks(nullptr, bc, bv, ma, sl, mn, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        for (int id = 0; id < (int)maskCands.size() && id < 2; id++) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyActionWithMasks(&maskCands[id].second, 0.7, 0.08, 4, 2, 1800, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        if (candidates.empty()) candidates.push_back(pureFallback);\n\n        string best = candidates[0];\n        for (const string& s : candidates) {\n            if (s.size() < best.size()) best = s;\n        }\n\n        vector<int> order(candidates.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return candidates[a].size() < candidates[b].size();\n        });\n\n        for (int id : order) {\n            if (elapsed() > 1.88) break;\n            string improved = greedyDelete(candidates[id], 1.88);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        if (elapsed() < 1.94) {\n            string improved = replaceImprove(best, 1.96);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        int pp = firstCompletionPrefix(best);\n        if (pp >= 0 && pp <= LIMIT) {\n            best.resize(pp);\n        } else {\n            best = pureFallback;\n        }\n\n        const string A = \"MSA\";\n        const string D = \"UDLR\";\n\n        for (unsigned char ch : best) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            cout << A[type] << ' ' << D[d] << '\\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\n    return 0;\n}"},"8":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    int nextInt(int n) {\n        return (int)(nextU64() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (nextU64() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Rect {\n    int a, b, c, d;\n};\n\nstatic uint64_t splitmix64_hash(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nclass Solver {\n    static constexpr int SZ = 10000;\n    static constexpr double TIME_LIMIT = 4.83;\n\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    vector<double> rd, invR;\n    FastRNG rng;\n    Timer timer;\n\n    struct State {\n        vector<Rect> rect;\n        vector<double> val;\n        double total = 0.0;\n    };\n\n    struct Move {\n        bool ok = false;\n        int dir = 0;\n        int coord = 0;\n        double newScore = 0.0;\n        double delta = 0.0;\n    };\n\n    struct PairMove {\n        bool ok = false;\n        int orient = 0;\n        int i = -1, j = -1;\n        int coord = 0;\n        double newScoreI = 0.0;\n        double newScoreJ = 0.0;\n        double delta = 0.0;\n    };\n\n    struct LineComp {\n        int orient = 0;\n        int coord = -1;\n        vector<int> A;\n        vector<int> B;\n    };\n\n    struct LineMove {\n        bool ok = false;\n        int orient = 0;\n        int coord = -1;\n        int newCoord = 0;\n        vector<int> A, B;\n        double delta = 0.0;\n    };\n\n    struct SplitCand {\n        int orient;\n        int k;\n        int t;\n        double cost;\n    };\n\n    long long rectArea(const Rect& rc) const {\n        return 1LL * (rc.c - rc.a) * (rc.d - rc.b);\n    }\n\n    double scoreOne(int i, long long s) const {\n        double ratio;\n        if (s <= r[i]) ratio = (double)s * invR[i];\n        else ratio = rd[i] / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    static double scoreRatio(long long s, long long target) {\n        double ratio;\n        if (s <= target) ratio = (double)s / (double)target;\n        else ratio = (double)target / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    State makeState(const vector<Rect>& rects) const {\n        State st;\n        st.rect = rects;\n        st.val.assign(n, 0.0);\n        st.total = 0.0;\n        for (int i = 0; i < n; i++) {\n            st.val[i] = scoreOne(i, rectArea(st.rect[i]));\n            st.total += st.val[i];\n        }\n        return st;\n    }\n\n    int clampLL(long long v, int lo, int hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return (int)v;\n    }\n\n    bool yOverlap(const Rect& p, const Rect& q) const {\n        return max(p.b, q.b) < min(p.d, q.d);\n    }\n\n    bool xOverlap(const Rect& p, const Rect& q) const {\n        return max(p.a, q.a) < min(p.c, q.c);\n    }\n\n    bool overlapRect(const Rect& p, const Rect& q) const {\n        return xOverlap(p, q) && yOverlap(p, q);\n    }\n\n    void sortIds(vector<int>& ord, int orient) const {\n        if (orient == 0) {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (x[u] != x[v]) return x[u] < x[v];\n                return y[u] < y[v];\n            });\n        } else {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (y[u] != y[v]) return y[u] < y[v];\n                return x[u] < x[v];\n            });\n        }\n    }\n\n    vector<SplitCand> generateSplitCands(const vector<int>& ids, const Rect& box) const {\n        int m = (int)ids.size();\n        vector<SplitCand> cands;\n        if (m <= 1) return cands;\n\n        long long totalR = 0;\n        for (int id : ids) totalR += r[id];\n\n        long long A = rectArea(box);\n        int W = box.c - box.a;\n        int H = box.d - box.b;\n\n        cands.reserve(m * 40);\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<int> ord = ids;\n            sortIds(ord, orient);\n\n            long long pref = 0;\n            for (int k = 1; k < m; k++) {\n                pref += r[ord[k - 1]];\n\n                int lo, hi;\n                if (orient == 0) {\n                    int xl = x[ord[k - 1]];\n                    int xr = x[ord[k]];\n                    lo = max(box.a + 1, xl + 1);\n                    hi = min(box.c - 1, xr);\n                } else {\n                    int yl = y[ord[k - 1]];\n                    int yr = y[ord[k]];\n                    lo = max(box.b + 1, yl + 1);\n                    hi = min(box.d - 1, yr);\n                }\n\n                if (lo > hi) continue;\n\n                vector<int> ts;\n                ts.reserve(32);\n\n                auto addT = [&](int t) {\n                    if (t < lo || t > hi) return;\n                    for (int u : ts) if (u == t) return;\n                    ts.push_back(t);\n                };\n\n                auto addReal = [&](long double real) {\n                    long long f = (long long)floorl(real);\n                    for (long long v = f - 2; v <= f + 2; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                    long long rr = (long long)llroundl(real);\n                    for (long long v = rr - 1; v <= rr + 1; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                };\n\n                if (orient == 0) {\n                    long double prop = box.a + ((long double)A * pref / totalR) / H;\n                    long double exactL = box.a + (long double)pref / H;\n                    long double exactR = box.a + ((long double)A - (long double)(totalR - pref)) / H;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                } else {\n                    long double prop = box.b + ((long double)A * pref / totalR) / W;\n                    long double exactL = box.b + (long double)pref / W;\n                    long double exactR = box.b + ((long double)A - (long double)(totalR - pref)) / W;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                }\n\n                addT(lo);\n                addT(hi);\n\n                for (int t : ts) {\n                    long long leftA;\n                    if (orient == 0) leftA = 1LL * (t - box.a) * H;\n                    else leftA = 1LL * W * (t - box.b);\n\n                    long long rightA = A - leftA;\n                    if (leftA <= 0 || rightA <= 0) continue;\n\n                    double sc =\n                        k * scoreRatio(leftA, pref) +\n                        (m - k) * scoreRatio(rightA, totalR - pref);\n\n                    double loss = 1.0 - sc / m;\n\n                    auto aspectPenalty = [&](int ww, int hh, int cnt) -> double {\n                        if (cnt <= 1) return 0.0;\n                        double ar = max((double)ww / hh, (double)hh / ww);\n                        return 0.00025 * (cnt / (double)m) * max(0.0, log(ar) - 2.0);\n                    };\n\n                    double cost = loss;\n                    cost += 0.00020 * abs(m - 2 * k) / (double)m;\n\n                    if (orient == 0) {\n                        cost += aspectPenalty(t - box.a, H, k);\n                        cost += aspectPenalty(box.c - t, H, m - k);\n                    } else {\n                        cost += aspectPenalty(W, t - box.b, k);\n                        cost += aspectPenalty(W, box.d - t, m - k);\n                    }\n\n                    cands.push_back({orient, k, t, cost});\n                }\n            }\n        }\n\n        return cands;\n    }\n\n    void buildRec(const vector<int>& ids, const Rect& box, vector<Rect>& out, double temp) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return;\n        }\n\n        vector<SplitCand> cands = generateSplitCands(ids, box);\n\n        if (cands.empty()) {\n            for (int id : ids) {\n                out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            }\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int chosen = 0;\n        if (temp > 1e-12) {\n            double bestCost = cands[0].cost;\n            double maxDiff = max(0.03, temp * 12.0);\n\n            vector<pair<int, double>> cumulative;\n            double sum = 0.0;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                double diff = cands[i].cost - bestCost;\n                if (diff > maxDiff) continue;\n                double w = exp(-diff / temp);\n                if (w < 1e-12) continue;\n                sum += w;\n                cumulative.push_back({i, sum});\n            }\n\n            if (sum > 0.0) {\n                double z = rng.nextDouble() * sum;\n                for (auto [idx, cum] : cumulative) {\n                    if (z <= cum) {\n                        chosen = idx;\n                        break;\n                    }\n                }\n            }\n        }\n\n        SplitCand sp = cands[chosen];\n\n        vector<int> ord = ids;\n        sortIds(ord, sp.orient);\n\n        vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n        vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n        if (sp.orient == 0) {\n            Rect L{box.a, box.b, sp.t, box.d};\n            Rect R{sp.t, box.b, box.c, box.d};\n            buildRec(leftIds, L, out, temp);\n            buildRec(rightIds, R, out, temp);\n        } else {\n            Rect B{box.a, box.b, box.c, sp.t};\n            Rect T{box.a, sp.t, box.c, box.d};\n            buildRec(leftIds, B, out, temp);\n            buildRec(rightIds, T, out, temp);\n        }\n    }\n\n    double scoreIds(const vector<Rect>& rects, const vector<int>& ids) const {\n        double s = 0.0;\n        for (int id : ids) s += scoreOne(id, rectArea(rects[id]));\n        return s;\n    }\n\n    double buildRecBeam(const vector<int>& ids, const Rect& box, vector<Rect>& out, double stopTime) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return scoreOne(ids[0], rectArea(box));\n        }\n\n        if (timer.elapsed() > stopTime) {\n            buildRec(ids, box, out, 0.0);\n            return scoreIds(out, ids);\n        }\n\n        vector<SplitCand> cands = generateSplitCands(ids, box);\n        if (cands.empty()) {\n            for (int id : ids) out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            return scoreIds(out, ids);\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int width;\n        if (m <= 3) width = 10;\n        else if (m <= 5) width = 5;\n        else width = 3;\n\n        width = min(width, (int)cands.size());\n\n        double best = -1e100;\n        vector<Rect> bestOut = out;\n\n        for (int ci = 0; ci < width; ci++) {\n            if (timer.elapsed() > stopTime) break;\n\n            SplitCand sp = cands[ci];\n            vector<int> ord = ids;\n            sortIds(ord, sp.orient);\n\n            vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n            vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n            vector<Rect> tmp = out;\n            double sc = 0.0;\n\n            if (sp.orient == 0) {\n                Rect L{box.a, box.b, sp.t, box.d};\n                Rect R{sp.t, box.b, box.c, box.d};\n                sc += buildRecBeam(leftIds, L, tmp, stopTime);\n                sc += buildRecBeam(rightIds, R, tmp, stopTime);\n            } else {\n                Rect B{box.a, box.b, box.c, sp.t};\n                Rect T{box.a, sp.t, box.c, box.d};\n                sc += buildRecBeam(leftIds, B, tmp, stopTime);\n                sc += buildRecBeam(rightIds, T, tmp, stopTime);\n            }\n\n            if (sc > best) {\n                best = sc;\n                bestOut = std::move(tmp);\n            }\n        }\n\n        if (best < -1e90) {\n            buildRec(ids, box, out, 0.0);\n            return scoreIds(out, ids);\n        }\n\n        out = std::move(bestOut);\n        return best;\n    }\n\n    vector<Rect> buildRecursive(double temp) {\n        vector<Rect> out(n);\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        buildRec(ids, Rect{0, 0, SZ, SZ}, out, temp);\n        return out;\n    }\n\n    vector<Rect> buildUnit() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; i++) {\n            rects[i] = {x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        return rects;\n    }\n\n    pair<int, int> legalInterval(const State& st, int i, int dir) const {\n        const Rect& ri = st.rect[i];\n\n        if (dir == 0) {\n            int lo = 0;\n            int hi = min(x[i], ri.c - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.a < ri.c) {\n                    lo = max(lo, rj.c);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 1) {\n            int lo = max(x[i] + 1, ri.a + 1);\n            int hi = SZ;\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.c > ri.a) {\n                    hi = min(hi, rj.a);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 2) {\n            int lo = 0;\n            int hi = min(y[i], ri.d - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (xOverlap(ri, rj) && rj.b < ri.d) {\n                    lo = max(lo, rj.d);\n                }\n            }\n            return {lo, hi};\n        }\n\n        int lo = max(y[i] + 1, ri.b + 1);\n        int hi = SZ;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& rj = st.rect[j];\n            if (xOverlap(ri, rj) && rj.d > ri.b) {\n                hi = min(hi, rj.b);\n            }\n        }\n        return {lo, hi};\n    }\n\n    int getCoord(const Rect& rc, int dir) const {\n        if (dir == 0) return rc.a;\n        if (dir == 1) return rc.c;\n        if (dir == 2) return rc.b;\n        return rc.d;\n    }\n\n    void setCoord(Rect& rc, int dir, int v) {\n        if (dir == 0) rc.a = v;\n        else if (dir == 1) rc.c = v;\n        else if (dir == 2) rc.b = v;\n        else rc.d = v;\n    }\n\n    long long areaAfterCoord(const Rect& rc, int dir, int coord) const {\n        if (dir == 0) return 1LL * (rc.c - coord) * (rc.d - rc.b);\n        if (dir == 1) return 1LL * (coord - rc.a) * (rc.d - rc.b);\n        if (dir == 2) return 1LL * (rc.c - rc.a) * (rc.d - coord);\n        return 1LL * (rc.c - rc.a) * (coord - rc.b);\n    }\n\n    Move bestEdgeDir(const State& st, int i, int dir) const {\n        Move mv;\n        mv.ok = false;\n\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return mv;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n\n        mv.ok = true;\n        mv.dir = dir;\n        mv.coord = cur;\n        mv.newScore = st.val[i];\n        mv.delta = 0.0;\n\n        int cand[48];\n        int cnt = 0;\n\n        auto addCand = [&](int v) {\n            if (v < lo) v = lo;\n            if (v > hi) v = hi;\n            for (int k = 0; k < cnt; k++) if (cand[k] == v) return;\n            cand[cnt++] = v;\n        };\n\n        addCand(cur);\n        addCand(lo);\n        addCand(hi);\n\n        long double real;\n        if (dir == 0 || dir == 1) {\n            int h = rc.d - rc.b;\n            long double wantW = (long double)r[i] / h;\n            if (dir == 0) real = rc.c - wantW;\n            else real = rc.a + wantW;\n        } else {\n            int w = rc.c - rc.a;\n            long double wantH = (long double)r[i] / w;\n            if (dir == 2) real = rc.d - wantH;\n            else real = rc.b + wantH;\n        }\n\n        long long f = (long long)floorl(real);\n        for (long long v = f - 5; v <= f + 5; v++) {\n            addCand(clampLL(v, lo, hi));\n        }\n\n        double bestScore = st.val[i];\n        int bestCoord = cur;\n\n        for (int k = 0; k < cnt; k++) {\n            int v = cand[k];\n            long long ar = areaAfterCoord(rc, dir, v);\n            double ns = scoreOne(i, ar);\n            if (ns > bestScore + 1e-15) {\n                bestScore = ns;\n                bestCoord = v;\n            }\n        }\n\n        mv.coord = bestCoord;\n        mv.newScore = bestScore;\n        mv.delta = bestScore - st.val[i];\n        return mv;\n    }\n\n    Move bestMove(const State& st, int i) const {\n        Move best;\n        best.ok = false;\n        best.delta = 0.0;\n        best.newScore = st.val[i];\n\n        for (int dir = 0; dir < 4; dir++) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) continue;\n            if (!best.ok || mv.delta > best.delta) best = mv;\n        }\n        return best;\n    }\n\n    void applyCoord(State& st, int i, int dir, int coord, double newScore) {\n        setCoord(st.rect[i], dir, coord);\n        st.total += newScore - st.val[i];\n        st.val[i] = newScore;\n    }\n\n    void applyMove(State& st, int i, const Move& mv) {\n        applyCoord(st, i, mv.dir, mv.coord, mv.newScore);\n    }\n\n    PairMove bestPairVertical(const State& st, int li, int ri) const {\n        PairMove pm;\n        pm.ok = false;\n        pm.orient = 0;\n        pm.i = li;\n        pm.j = ri;\n\n        if (li == ri) return pm;\n        const Rect& L = st.rect[li];\n        const Rect& R = st.rect[ri];\n\n        if (L.c > R.a) return pm;\n        if (!yOverlap(L, R)) return pm;\n\n        int lo1 = max(x[li] + 1, L.a + 1);\n        int hi1 = SZ;\n\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(L, K) && K.c > L.a) {\n                hi1 = min(hi1, K.a);\n            }\n        }\n\n        int lo2 = 0;\n        int hi2 = min(x[ri], R.c - 1);\n\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(R, K) && K.a < R.c) {\n                lo2 = max(lo2, K.c);\n            }\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int hL = L.d - L.b;\n        int hR = R.d - R.b;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * (t - L.a) * hL;\n            long long a2 = 1LL * (R.c - t) * hR;\n            return scoreOne(li, a1) + scoreOne(ri, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(L.c, lo, hi));\n        test(clampLL(R.a, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) {\n                test(clampLL(v, lo, hi));\n            }\n        };\n\n        addReal((long double)L.a + (long double)r[li] / hL);\n        addReal((long double)R.c - (long double)r[ri] / hR);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * (bestT - L.a) * hL;\n        long long a2 = 1LL * (R.c - bestT) * hR;\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(li, a1);\n        pm.newScoreJ = scoreOne(ri, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[li] - st.val[ri];\n        return pm;\n    }\n\n    PairMove bestPairHorizontal(const State& st, int bi, int ti) const {\n        PairMove pm;\n        pm.ok = false;\n        pm.orient = 1;\n        pm.i = bi;\n        pm.j = ti;\n\n        if (bi == ti) return pm;\n        const Rect& B = st.rect[bi];\n        const Rect& T = st.rect[ti];\n\n        if (B.d > T.b) return pm;\n        if (!xOverlap(B, T)) return pm;\n\n        int lo1 = max(y[bi] + 1, B.b + 1);\n        int hi1 = SZ;\n\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(B, K) && K.d > B.b) {\n                hi1 = min(hi1, K.b);\n            }\n        }\n\n        int lo2 = 0;\n        int hi2 = min(y[ti], T.d - 1);\n\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(T, K) && K.b < T.d) {\n                lo2 = max(lo2, K.d);\n            }\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int wB = B.c - B.a;\n        int wT = T.c - T.a;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * wB * (t - B.b);\n            long long a2 = 1LL * wT * (T.d - t);\n            return scoreOne(bi, a1) + scoreOne(ti, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(B.d, lo, hi));\n        test(clampLL(T.b, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) {\n                test(clampLL(v, lo, hi));\n            }\n        };\n\n        addReal((long double)B.b + (long double)r[bi] / wB);\n        addReal((long double)T.d - (long double)r[ti] / wT);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * wB * (bestT - B.b);\n        long long a2 = 1LL * wT * (T.d - bestT);\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(bi, a1);\n        pm.newScoreJ = scoreOne(ti, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[bi] - st.val[ti];\n        return pm;\n    }\n\n    void applyPair(State& st, const PairMove& pm) {\n        int i = pm.i;\n        int j = pm.j;\n\n        if (pm.orient == 0) {\n            st.rect[i].c = pm.coord;\n            st.rect[j].a = pm.coord;\n        } else {\n            st.rect[i].d = pm.coord;\n            st.rect[j].b = pm.coord;\n        }\n\n        st.total += pm.newScoreI - st.val[i];\n        st.total += pm.newScoreJ - st.val[j];\n\n        st.val[i] = pm.newScoreI;\n        st.val[j] = pm.newScoreJ;\n    }\n\n    void shuffleVector(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int selectBad(const State& st) {\n        int best = rng.nextInt(n);\n        double bv = st.val[best];\n\n        int K = min(n, 6);\n        for (int k = 1; k < K; k++) {\n            int j = rng.nextInt(n);\n            if (st.val[j] < bv) {\n                bv = st.val[j];\n                best = j;\n            }\n        }\n        return best;\n    }\n\n    bool greedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ord);\n\n            bool any = false;\n            for (int id : ord) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairGreedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            shuffleVector(ord);\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < n; ai++) {\n                int i = ord[ai];\n                for (int bj = ai + 1; bj < n; bj++) {\n                    if ((checks++ & 255) == 0 && timer.elapsed() > stopTime) {\n                        return globalAny;\n                    }\n\n                    int j = ord[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.ok = false;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    vector<LineComp> buildLineComponents(const State& st, int orient) const {\n        vector<int> coords;\n        coords.reserve(2 * n);\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = st.rect[i];\n            if (orient == 0) {\n                if (0 < rc.c && rc.c < SZ) coords.push_back(rc.c);\n                if (0 < rc.a && rc.a < SZ) coords.push_back(rc.a);\n            } else {\n                if (0 < rc.d && rc.d < SZ) coords.push_back(rc.d);\n                if (0 < rc.b && rc.b < SZ) coords.push_back(rc.b);\n            }\n        }\n\n        sort(coords.begin(), coords.end());\n        coords.erase(unique(coords.begin(), coords.end()), coords.end());\n\n        vector<LineComp> comps;\n\n        for (int coord : coords) {\n            vector<int> A, B;\n            for (int i = 0; i < n; i++) {\n                const Rect& rc = st.rect[i];\n                if (orient == 0) {\n                    if (rc.c == coord) A.push_back(i);\n                    if (rc.a == coord) B.push_back(i);\n                } else {\n                    if (rc.d == coord) A.push_back(i);\n                    if (rc.b == coord) B.push_back(i);\n                }\n            }\n\n            if (A.empty() || B.empty()) continue;\n\n            int na = (int)A.size();\n            int nb = (int)B.size();\n            vector<vector<int>> adj(na + nb);\n\n            for (int i = 0; i < na; i++) {\n                for (int j = 0; j < nb; j++) {\n                    bool ov = (orient == 0)\n                        ? yOverlap(st.rect[A[i]], st.rect[B[j]])\n                        : xOverlap(st.rect[A[i]], st.rect[B[j]]);\n                    if (ov) {\n                        adj[i].push_back(na + j);\n                        adj[na + j].push_back(i);\n                    }\n                }\n            }\n\n            vector<char> vis(na + nb, 0);\n            for (int s = 0; s < na + nb; s++) {\n                if (vis[s]) continue;\n\n                vector<int> q = {s};\n                vis[s] = 1;\n                for (int qi = 0; qi < (int)q.size(); qi++) {\n                    int v = q[qi];\n                    for (int to : adj[v]) {\n                        if (!vis[to]) {\n                            vis[to] = 1;\n                            q.push_back(to);\n                        }\n                    }\n                }\n\n                LineComp cp;\n                cp.orient = orient;\n                cp.coord = coord;\n\n                for (int v : q) {\n                    if (v < na) cp.A.push_back(A[v]);\n                    else cp.B.push_back(B[v - na]);\n                }\n\n                if (!cp.A.empty() && !cp.B.empty()) {\n                    comps.push_back(std::move(cp));\n                }\n            }\n        }\n\n        return comps;\n    }\n\n    bool componentInternalOK(const State& st, const LineComp& cp) const {\n        vector<unsigned char> side(n, 0);\n\n        for (int id : cp.A) {\n            if (side[id] & 1) return false;\n            side[id] |= 1;\n        }\n        for (int id : cp.B) {\n            if (side[id] & 2) return false;\n            if (side[id] & 1) return false;\n            side[id] |= 2;\n        }\n\n        auto perpOverlap = [&](int u, int v) -> bool {\n            if (cp.orient == 0) return yOverlap(st.rect[u], st.rect[v]);\n            else return xOverlap(st.rect[u], st.rect[v]);\n        };\n\n        for (int i = 0; i < (int)cp.A.size(); i++) {\n            for (int j = i + 1; j < (int)cp.A.size(); j++) {\n                if (perpOverlap(cp.A[i], cp.A[j])) return false;\n            }\n        }\n        for (int i = 0; i < (int)cp.B.size(); i++) {\n            for (int j = i + 1; j < (int)cp.B.size(); j++) {\n                if (perpOverlap(cp.B[i], cp.B[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\n    vector<LineComp> buildFrontierComponents(const State& st, int orient) const {\n        const int INF = 1e9;\n        vector<int> bestA(n, INF), bestB(n, INF);\n\n        auto canFace = [&](int i, int j, int& gap) -> bool {\n            if (i == j) return false;\n            const Rect& P = st.rect[i];\n            const Rect& Q = st.rect[j];\n\n            if (orient == 0) {\n                if (!yOverlap(P, Q)) return false;\n                if (P.c <= Q.a) {\n                    gap = Q.a - P.c;\n                    return true;\n                }\n            } else {\n                if (!xOverlap(P, Q)) return false;\n                if (P.d <= Q.b) {\n                    gap = Q.b - P.d;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int gap;\n                if (canFace(i, j, gap)) {\n                    bestA[i] = min(bestA[i], gap);\n                    bestB[j] = min(bestB[j], gap);\n                }\n            }\n        }\n\n        vector<vector<int>> adj(2 * n);\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int gap;\n                if (canFace(i, j, gap)) {\n                    if (gap == bestA[i] && gap == bestB[j]) {\n                        adj[i].push_back(n + j);\n                        adj[n + j].push_back(i);\n                    }\n                }\n            }\n        }\n\n        vector<LineComp> comps;\n        vector<char> vis(2 * n, 0);\n\n        for (int s = 0; s < 2 * n; s++) {\n            if (vis[s] || adj[s].empty()) continue;\n\n            vector<int> q = {s};\n            vis[s] = 1;\n\n            for (int qi = 0; qi < (int)q.size(); qi++) {\n                int v = q[qi];\n                for (int to : adj[v]) {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q.push_back(to);\n                    }\n                }\n            }\n\n            LineComp cp;\n            cp.orient = orient;\n            cp.coord = -1;\n\n            for (int v : q) {\n                if (v < n) cp.A.push_back(v);\n                else cp.B.push_back(v - n);\n            }\n\n            if (cp.A.empty() || cp.B.empty()) continue;\n            if (!componentInternalOK(st, cp)) continue;\n\n            bool sameCoord = true;\n            int common = -1;\n\n            auto feedCoord = [&](int z) {\n                if (common < 0) common = z;\n                else if (common != z) sameCoord = false;\n            };\n\n            if (orient == 0) {\n                for (int id : cp.A) feedCoord(st.rect[id].c);\n                for (int id : cp.B) feedCoord(st.rect[id].a);\n            } else {\n                for (int id : cp.A) feedCoord(st.rect[id].d);\n                for (int id : cp.B) feedCoord(st.rect[id].b);\n            }\n\n            if (sameCoord) continue;\n            comps.push_back(std::move(cp));\n        }\n\n        return comps;\n    }\n\n    LineMove bestBoundaryComponent(const State& st, const LineComp& cp, double stopTime) {\n        LineMove lm;\n        lm.ok = false;\n        lm.orient = cp.orient;\n        lm.coord = cp.coord;\n        lm.A = cp.A;\n        lm.B = cp.B;\n\n        if (cp.A.empty() || cp.B.empty()) return lm;\n        if (!componentInternalOK(st, cp)) return lm;\n\n        if (cp.coord >= 0) {\n            if (cp.orient == 0) {\n                for (int id : cp.A) if (st.rect[id].c != cp.coord) return lm;\n                for (int id : cp.B) if (st.rect[id].a != cp.coord) return lm;\n            } else {\n                for (int id : cp.A) if (st.rect[id].d != cp.coord) return lm;\n                for (int id : cp.B) if (st.rect[id].b != cp.coord) return lm;\n            }\n        }\n\n        vector<char> moved(n, 0);\n        double curScore = 0.0;\n\n        for (int id : cp.A) {\n            if (!moved[id]) {\n                moved[id] = 1;\n                curScore += st.val[id];\n            }\n        }\n        for (int id : cp.B) {\n            if (!moved[id]) {\n                moved[id] = 1;\n                curScore += st.val[id];\n            }\n        }\n\n        int lo = 0;\n        int hi = SZ;\n\n        if (cp.orient == 0) {\n            for (int id : cp.A) {\n                const Rect& ri = st.rect[id];\n                lo = max(lo, max(x[id] + 1, ri.a + 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (yOverlap(ri, rk) && rk.c > ri.a) {\n                        hi = min(hi, rk.a);\n                    }\n                }\n            }\n\n            for (int id : cp.B) {\n                const Rect& ri = st.rect[id];\n                hi = min(hi, min(x[id], ri.c - 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (yOverlap(ri, rk) && rk.a < ri.c) {\n                        lo = max(lo, rk.c);\n                    }\n                }\n            }\n        } else {\n            for (int id : cp.A) {\n                const Rect& ri = st.rect[id];\n                lo = max(lo, max(y[id] + 1, ri.b + 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (xOverlap(ri, rk) && rk.d > ri.b) {\n                        hi = min(hi, rk.b);\n                    }\n                }\n            }\n\n            for (int id : cp.B) {\n                const Rect& ri = st.rect[id];\n                hi = min(hi, min(y[id], ri.d - 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (xOverlap(ri, rk) && rk.b < ri.d) {\n                        lo = max(lo, rk.d);\n                    }\n                }\n            }\n        }\n\n        if (lo > hi) return lm;\n\n        auto eval = [&](int t) -> double {\n            double sc = 0.0;\n\n            if (cp.orient == 0) {\n                for (int id : cp.A) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (t - rc.a) * (rc.d - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n                for (int id : cp.B) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - t) * (rc.d - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n            } else {\n                for (int id : cp.A) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - rc.a) * (t - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n                for (int id : cp.B) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - rc.a) * (rc.d - t);\n                    sc += scoreOne(id, ar);\n                }\n            }\n\n            return sc;\n        };\n\n        double bestScore = curScore;\n        int bestT = (cp.coord >= 0 ? clampLL(cp.coord, lo, hi) : lo);\n\n        for (int t = lo; t <= hi; t++) {\n            if (((t - lo) & 1023) == 0 && timer.elapsed() > stopTime) break;\n\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        }\n\n        lm.ok = true;\n        lm.newCoord = bestT;\n        lm.delta = bestScore - curScore;\n        return lm;\n    }\n\n    void applyLineMove(State& st, const LineMove& lm) {\n        int t = lm.newCoord;\n\n        if (lm.orient == 0) {\n            for (int id : lm.A) st.rect[id].c = t;\n            for (int id : lm.B) st.rect[id].a = t;\n        } else {\n            for (int id : lm.A) st.rect[id].d = t;\n            for (int id : lm.B) st.rect[id].b = t;\n        }\n\n        vector<char> upd(n, 0);\n        for (int id : lm.A) {\n            if (!upd[id]) {\n                upd[id] = 1;\n                double ns = scoreOne(id, rectArea(st.rect[id]));\n                st.total += ns - st.val[id];\n                st.val[id] = ns;\n            }\n        }\n        for (int id : lm.B) {\n            if (!upd[id]) {\n                upd[id] = 1;\n                double ns = scoreOne(id, rectArea(st.rect[id]));\n                st.total += ns - st.val[id];\n                st.val[id] = ns;\n            }\n        }\n    }\n\n    bool boundarySequentialPass(State& st, int orient, bool includeFrontier, double stopTime) {\n        vector<LineComp> comps = buildLineComponents(st, orient);\n\n        if (includeFrontier) {\n            vector<LineComp> extra = buildFrontierComponents(st, orient);\n            for (auto& cp : extra) comps.push_back(std::move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [](const LineComp& p, const LineComp& q) {\n            int sp = (int)p.A.size() + (int)p.B.size();\n            int sq = (int)q.A.size() + (int)q.B.size();\n            if (sp != sq) return sp > sq;\n            bool lp = p.coord >= 0;\n            bool lq = q.coord >= 0;\n            if (lp != lq) return lp > lq;\n            return p.coord < q.coord;\n        });\n\n        bool any = false;\n\n        for (const LineComp& cp : comps) {\n            if (timer.elapsed() > stopTime) break;\n\n            LineMove mv = bestBoundaryComponent(st, cp, stopTime);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyLineMove(st, mv);\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool boundaryGreedyPasses(State& st, int passes, double stopTime, bool includeFrontier) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n\n            bool any = false;\n            if (rng.nextInt(2) == 0) {\n                any |= boundarySequentialPass(st, 0, includeFrontier, stopTime);\n                any |= boundarySequentialPass(st, 1, includeFrontier, stopTime);\n            } else {\n                any |= boundarySequentialPass(st, 1, includeFrontier, stopTime);\n                any |= boundarySequentialPass(st, 0, includeFrontier, stopTime);\n            }\n\n            if (!any) break;\n            globalAny = true;\n        }\n\n        return globalAny;\n    }\n\n    Rect groupBoundingBox(const State& st, const vector<int>& ids) const {\n        Rect box{SZ, SZ, 0, 0};\n        for (int id : ids) {\n            const Rect& rc = st.rect[id];\n            box.a = min(box.a, rc.a);\n            box.b = min(box.b, rc.b);\n            box.c = max(box.c, rc.c);\n            box.d = max(box.d, rc.d);\n        }\n        return box;\n    }\n\n    bool bboxClearForGroup(const State& st, const vector<int>& ids, const Rect& box) const {\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n        for (int i = 0; i < n; i++) {\n            if (in[i]) continue;\n            if (overlapRect(st.rect[i], box)) return false;\n        }\n        return true;\n    }\n\n    long long desiredSum(const vector<int>& ids) const {\n        long long s = 0;\n        for (int id : ids) s += r[id];\n        return s;\n    }\n\n    bool boxUsableForGroup(const State& st, const vector<int>& ids, const Rect& box) const {\n        if (!(0 <= box.a && box.a < box.c && box.c <= SZ)) return false;\n        if (!(0 <= box.b && box.b < box.d && box.d <= SZ)) return false;\n\n        for (int id : ids) {\n            if (!(box.a <= x[id] && x[id] + 1 <= box.c)) return false;\n            if (!(box.b <= y[id] && y[id] + 1 <= box.d)) return false;\n        }\n\n        return bboxClearForGroup(st, ids, box);\n    }\n\n    vector<Rect> alternativeRepackBoxes(const State& st, const vector<int>& ids, const Rect& orig) const {\n        vector<Rect> res;\n\n        long long S = 0;\n        int minX = SZ, minY = SZ, maxX1 = 0, maxY1 = 0;\n\n        for (int id : ids) {\n            S += r[id];\n            minX = min(minX, x[id]);\n            minY = min(minY, y[id]);\n            maxX1 = max(maxX1, x[id] + 1);\n            maxY1 = max(maxY1, y[id] + 1);\n        }\n\n        int pW = max(1, maxX1 - minX);\n        int pH = max(1, maxY1 - minY);\n        int oW = orig.c - orig.a;\n        int oH = orig.d - orig.b;\n\n        auto sameBox = [](const Rect& u, const Rect& v) {\n            return u.a == v.a && u.b == v.b && u.c == v.c && u.d == v.d;\n        };\n\n        auto addRect = [&](const Rect& bx) {\n            if ((int)res.size() >= 4) return;\n            if (sameBox(bx, orig)) return;\n            if (!boxUsableForGroup(st, ids, bx)) return;\n            for (const Rect& e : res) if (sameBox(e, bx)) return;\n            res.push_back(bx);\n        };\n\n        auto ceilDiv = [](long long a, long long b) -> long long {\n            return (a + b - 1) / b;\n        };\n\n        auto trySize = [&](long long W0, long long H0) {\n            if ((int)res.size() >= 4) return;\n            if (W0 <= 0 || H0 <= 0) return;\n\n            long long W = max<long long>(W0, pW);\n            long long H = max<long long>(H0, pH);\n\n            if (W > SZ) return;\n\n            long long needH = ceilDiv(S, W);\n            if (H < needH) H = needH;\n\n            if (H > SZ) {\n                H = SZ;\n                long long needW = ceilDiv(S, H);\n                if (W < needW) W = needW;\n            }\n\n            if (W > SZ || H > SZ) return;\n\n            int w = (int)W;\n            int h = (int)H;\n\n            auto placements = [&](bool inside) {\n                int alo = max(0, maxX1 - w);\n                int ahi = min(minX, SZ - w);\n                int blo = max(0, maxY1 - h);\n                int bhi = min(minY, SZ - h);\n\n                if (inside) {\n                    alo = max(alo, orig.a);\n                    ahi = min(ahi, orig.c - w);\n                    blo = max(blo, orig.b);\n                    bhi = min(bhi, orig.d - h);\n                }\n\n                if (alo > ahi || blo > bhi) return;\n\n                vector<int> As, Bs;\n                auto addA = [&](long long v) {\n                    int z = clampLL(v, alo, ahi);\n                    for (int q : As) if (q == z) return;\n                    As.push_back(z);\n                };\n                auto addB = [&](long long v) {\n                    int z = clampLL(v, blo, bhi);\n                    for (int q : Bs) if (q == z) return;\n                    Bs.push_back(z);\n                };\n\n                addA(((long long)orig.a + orig.c - w) / 2);\n                addA(orig.a);\n                addA((long long)orig.c - w);\n                addA((long long)minX - w / 2);\n\n                addB(((long long)orig.b + orig.d - h) / 2);\n                addB(orig.b);\n                addB((long long)orig.d - h);\n                addB((long long)minY - h / 2);\n\n                for (int a : As) {\n                    for (int b : Bs) {\n                        addRect(Rect{a, b, a + w, b + h});\n                        if ((int)res.size() >= 4) return;\n                    }\n                }\n            };\n\n            bool inside = (w <= oW && h <= oH);\n            placements(inside);\n            if (!inside) placements(false);\n        };\n\n        trySize(oW, ceilDiv(S, max(1, oW)));\n        trySize(ceilDiv(S, max(1, oH)), oH);\n\n        {\n            long double asp = max(0.05L, min(20.0L, (long double)oW / max(1, oH)));\n            long long w = max(1LL, (long long)llroundl(sqrtl((long double)S * asp)));\n            trySize(w, ceilDiv(S, w));\n        }\n\n        {\n            long long w = max(1LL, (long long)llroundl(sqrtl((long double)S)));\n            trySize(w, ceilDiv(S, w));\n        }\n\n        {\n            long double asp = max(0.05L, min(20.0L, (long double)pW / max(1, pH)));\n            long long w = max(1LL, (long long)llroundl(sqrtl((long double)S * asp)));\n            trySize(w, ceilDiv(S, w));\n        }\n\n        trySize(pW, ceilDiv(S, max(1, pW)));\n        trySize(ceilDiv(S, max(1, pH)), pH);\n\n        return res;\n    }\n\n    bool closureGroup(const State& st, vector<int> ids, int maxK, vector<int>& out) const {\n        if (ids.empty()) return false;\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if ((int)ids.size() > maxK) return false;\n\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n\n        Rect box = groupBoundingBox(st, ids);\n\n        bool changed = true;\n        while (changed) {\n            changed = false;\n\n            for (int i = 0; i < n; i++) {\n                if (in[i]) continue;\n\n                if (overlapRect(st.rect[i], box)) {\n                    in[i] = 1;\n                    ids.push_back(i);\n\n                    if ((int)ids.size() > maxK) return false;\n\n                    const Rect& rc = st.rect[i];\n                    box.a = min(box.a, rc.a);\n                    box.b = min(box.b, rc.b);\n                    box.c = max(box.c, rc.c);\n                    box.d = max(box.d, rc.d);\n\n                    changed = true;\n                }\n            }\n        }\n\n        sort(ids.begin(), ids.end());\n        out = ids;\n        return true;\n    }\n\n    bool validSubsetRects(const vector<Rect>& v, const vector<int>& ids) const {\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int id : ids) {\n            const Rect& rc = v[id];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[id] && x[id] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[id] && y[id] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            for (int j = i + 1; j < (int)ids.size(); j++) {\n                if (overlapRect(v[ids[i]], v[ids[j]])) return false;\n            }\n        }\n\n        for (int id : ids) {\n            for (int j = 0; j < n; j++) {\n                if (in[j]) continue;\n                if (overlapRect(v[id], v[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\n    void recomputeSubset(State& st, const vector<int>& ids) {\n        for (int id : ids) {\n            double ns = scoreOne(id, rectArea(st.rect[id]));\n            st.total += ns - st.val[id];\n            st.val[id] = ns;\n        }\n    }\n\n    bool greedySubset(State& st, vector<int> ids, int passes, double stopTime) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ids);\n\n            bool any = false;\n            for (int id : ids) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairSubsetPass(State& st, vector<int> ids, int passes, double stopTime) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ids);\n\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < (int)ids.size(); ai++) {\n                int i = ids[ai];\n                for (int bj = ai + 1; bj < (int)ids.size(); bj++) {\n                    if ((checks++ & 63) == 0 && timer.elapsed() > stopTime) {\n                        return globalAny;\n                    }\n\n                    int j = ids[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.ok = false;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool tryRepackGroup(State& st, vector<int> ids, double stopTime, int trials) {\n        if (timer.elapsed() > stopTime) return false;\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if ((int)ids.size() < 2 || (int)ids.size() > 8) return false;\n\n        Rect box = groupBoundingBox(st, ids);\n        if (!(box.a < box.c && box.b < box.d)) return false;\n        if (!bboxClearForGroup(st, ids, box)) return false;\n\n        State bestLocal = st;\n\n        double beforeScore = 0.0;\n        for (int id : ids) beforeScore += st.val[id];\n\n        long long desire = desiredSum(ids);\n        double mismatch = fabs((double)rectArea(box) - (double)desire) / max(1.0, (double)desire);\n        double loss = (double)ids.size() - beforeScore;\n\n        auto consider = [&](const vector<Rect>& fullRects) {\n            if (timer.elapsed() > stopTime) return;\n            if (!validSubsetRects(fullRects, ids)) return;\n\n            State tr = st;\n            for (int id : ids) tr.rect[id] = fullRects[id];\n            recomputeSubset(tr, ids);\n\n            greedySubset(tr, ids, 2, stopTime);\n            pairSubsetPass(tr, ids, 1, stopTime);\n            greedySubset(tr, ids, 1, stopTime);\n\n            if (tr.total > bestLocal.total + 1e-12) {\n                bestLocal = std::move(tr);\n            }\n        };\n\n        if ((int)ids.size() <= 6 && timer.elapsed() + 0.004 < stopTime) {\n            vector<Rect> rects = st.rect;\n            buildRecBeam(ids, box, rects, stopTime);\n            consider(rects);\n        }\n\n        {\n            vector<Rect> rects = st.rect;\n            buildRec(ids, box, rects, 0.0);\n            consider(rects);\n        }\n\n        if ((loss > 0.015 || mismatch > 0.08) && timer.elapsed() + 0.005 < stopTime) {\n            vector<Rect> altBoxes = alternativeRepackBoxes(st, ids, box);\n\n            int used = 0;\n            for (const Rect& bx : altBoxes) {\n                if (used >= 3) break;\n                if (timer.elapsed() + 0.003 > stopTime) break;\n\n                {\n                    vector<Rect> rects = st.rect;\n                    if ((int)ids.size() <= 5 && timer.elapsed() + 0.004 < stopTime) {\n                        buildRecBeam(ids, bx, rects, stopTime);\n                    } else {\n                        buildRec(ids, bx, rects, 0.0);\n                    }\n                    consider(rects);\n                }\n\n                if (trials >= 4 && (int)ids.size() <= 4 && timer.elapsed() + 0.004 < stopTime) {\n                    vector<Rect> rects = st.rect;\n                    double temp = 0.0005 * pow(500.0, rng.nextDouble());\n                    buildRec(ids, bx, rects, temp);\n                    consider(rects);\n                }\n\n                used++;\n            }\n        }\n\n        if (trials >= 3 && timer.elapsed() < stopTime) {\n            vector<Rect> rects = st.rect;\n            for (int id : ids) rects[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            consider(rects);\n        }\n\n        for (int t = 0; t < trials && timer.elapsed() < stopTime; t++) {\n            vector<Rect> rects = st.rect;\n            double temp = 0.0005 * pow(500.0, rng.nextDouble());\n            buildRec(ids, box, rects, temp);\n            consider(rects);\n        }\n\n        if (bestLocal.total > st.total + 1e-12) {\n            st = std::move(bestLocal);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool tryRepackGroupClosure(State& st, vector<int> ids, double stopTime, int trials, int maxK = 8) {\n        vector<int> cl;\n        if (!closureGroup(st, std::move(ids), maxK, cl)) return false;\n        return tryRepackGroup(st, cl, stopTime, trials);\n    }\n\n    bool componentRepackPass(State& st, double stopTime, int maxGroups) {\n        struct GC {\n            double key;\n            vector<int> ids;\n        };\n\n        vector<GC> groups;\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<LineComp> comps = buildLineComponents(st, orient);\n            for (const LineComp& cp : comps) {\n                vector<int> ids = cp.A;\n                for (int id : cp.B) ids.push_back(id);\n\n                vector<int> cl;\n                if (!closureGroup(st, ids, 8, cl)) continue;\n\n                int k = (int)cl.size();\n                if (k < 2 || k > 8) continue;\n\n                double loss = 0.0;\n                for (int id : cl) loss += 1.0 - st.val[id];\n\n                double key = loss + 0.0015 * k + 1e-5 * rng.nextDouble();\n                groups.push_back({key, cl});\n            }\n        }\n\n        sort(groups.begin(), groups.end(), [](const GC& p, const GC& q) {\n            return p.key > q.key;\n        });\n\n        bool any = false;\n        int tried = 0;\n\n        for (auto& g : groups) {\n            if (timer.elapsed() > stopTime) break;\n            if (tried++ >= maxGroups) break;\n\n            int k = (int)g.ids.size();\n            int trials = (k <= 3 ? 5 : 3);\n\n            if (tryRepackGroup(st, g.ids, stopTime, trials)) {\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    int rectGap(const Rect& A, const Rect& B) const {\n        int dx = 0;\n        if (A.c < B.a) dx = B.a - A.c;\n        else if (B.c < A.a) dx = A.a - B.c;\n\n        int dy = 0;\n        if (A.d < B.b) dy = B.b - A.d;\n        else if (B.d < A.b) dy = A.b - B.d;\n\n        int penalty = (dx > 0 && dy > 0) ? 10000 : 0;\n        return dx + dy + penalty;\n    }\n\n    bool pairBlockRepackPass(State& st, double stopTime, int maxGroups) {\n        struct PC {\n            double key;\n            int i, j;\n        };\n\n        vector<PC> cand;\n        bool stop = false;\n\n        for (int i = 0; i < n && !stop; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (((int)cand.size() & 511) == 0 && timer.elapsed() > stopTime) {\n                    stop = true;\n                    break;\n                }\n\n                int g = rectGap(st.rect[i], st.rect[j]);\n                double loss = (1.0 - st.val[i]) + (1.0 - st.val[j]);\n\n                if (g > 8000 && loss < 0.05) continue;\n\n                double key = loss - 0.0000015 * g + 0.0001 / (1.0 + g) + 1e-5 * rng.nextDouble();\n                cand.push_back({key, i, j});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [](const PC& p, const PC& q) {\n            return p.key > q.key;\n        });\n\n        bool any = false;\n        int lim = min(maxGroups, (int)cand.size());\n\n        for (int t = 0; t < lim; t++) {\n            if (timer.elapsed() > stopTime) break;\n            if (tryRepackGroupClosure(st, vector<int>{cand[t].i, cand[t].j}, stopTime, 3, 8)) {\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool neighborClosureRepackPass(State& st, double stopTime, int maxBase) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int u, int v) {\n            return st.val[u] < st.val[v];\n        });\n\n        bool any = false;\n        int bases = min(maxBase, n);\n\n        for (int bi = 0; bi < bases && timer.elapsed() < stopTime; bi++) {\n            int base = ord[bi];\n\n            vector<pair<int, int>> near;\n            near.reserve(n - 1);\n            for (int j = 0; j < n; j++) {\n                if (j == base) continue;\n                near.push_back({rectGap(st.rect[base], st.rect[j]), j});\n            }\n            sort(near.begin(), near.end());\n\n            int lim = min(4, (int)near.size());\n            for (int t = 0; t < lim && timer.elapsed() < stopTime; t++) {\n                if (tryRepackGroupClosure(st, vector<int>{base, near[t].second}, stopTime, 3, 8)) {\n                    any = true;\n                }\n            }\n\n            if (near.size() >= 2 && timer.elapsed() < stopTime) {\n                vector<int> g{base, near[0].second, near[1].second};\n                if (tryRepackGroupClosure(st, g, stopTime, 3, 8)) any = true;\n            }\n\n            if (near.size() >= 3 && timer.elapsed() < stopTime) {\n                vector<int> g{base, near[0].second, near[1].second, near[2].second};\n                if (tryRepackGroupClosure(st, g, stopTime, 2, 8)) any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool randomBlockRepackAttempts(State& st, double stopTime, int attempts) {\n        bool any = false;\n\n        for (int at = 0; at < attempts && timer.elapsed() < stopTime; at++) {\n            int base;\n            if (rng.nextDouble() < 0.75) base = selectBad(st);\n            else base = rng.nextInt(n);\n\n            vector<int> group{base};\n            vector<char> used(n, 0);\n            used[base] = 1;\n\n            int target = 2 + rng.nextInt(4);\n\n            for (int step = 1; step < target && timer.elapsed() < stopTime; step++) {\n                vector<pair<double, int>> cands;\n\n                for (int j = 0; j < n; j++) {\n                    if (used[j]) continue;\n\n                    int g = 1e9;\n                    for (int id : group) {\n                        g = min(g, rectGap(st.rect[id], st.rect[j]));\n                    }\n\n                    double key = (double)g - 1800.0 * (1.0 - st.val[j]) + 20.0 * rng.nextDouble();\n                    cands.push_back({key, j});\n                }\n\n                if (cands.empty()) break;\n                sort(cands.begin(), cands.end());\n\n                int lim = min(6, (int)cands.size());\n                int pick = 0;\n                if (rng.nextDouble() > 0.70) pick = rng.nextInt(lim);\n\n                int add = cands[pick].second;\n                used[add] = 1;\n                group.push_back(add);\n\n                if ((int)group.size() >= 2) {\n                    if (tryRepackGroupClosure(st, group, stopTime, 3, 8)) {\n                        any = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        return any;\n    }\n\n    void randomGreedyOps(State& st, int ops, double stopTime) {\n        for (int op = 0; op < ops; op++) {\n            if ((op & 255) == 0 && timer.elapsed() > stopTime) break;\n\n            int i;\n            if (rng.nextDouble() < 0.85) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Move mv = bestMove(st, i);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyMove(st, i, mv);\n            }\n        }\n    }\n\n    bool randomPairMove(State& st) {\n        int i;\n        if (rng.nextDouble() < 0.80) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n\n        static constexpr int K = 8;\n        int cand[K];\n        int gap[K];\n        int cnt = 0;\n\n        auto addCand = [&](int j, int g) {\n            if (cnt < K) {\n                cand[cnt] = j;\n                gap[cnt] = g;\n                cnt++;\n            } else {\n                int worst = 0;\n                for (int t = 1; t < K; t++) {\n                    if (gap[t] > gap[worst]) worst = t;\n                }\n                if (g < gap[worst] || rng.nextDouble() < 0.02) {\n                    cand[worst] = j;\n                    gap[worst] = g;\n                }\n            }\n        };\n\n        const Rect& R = st.rect[i];\n\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = st.rect[j];\n\n            if (dir == 0) {\n                if (Q.c <= R.a && yOverlap(Q, R)) addCand(j, R.a - Q.c);\n            } else if (dir == 1) {\n                if (R.c <= Q.a && yOverlap(R, Q)) addCand(j, Q.a - R.c);\n            } else if (dir == 2) {\n                if (Q.d <= R.b && xOverlap(Q, R)) addCand(j, R.b - Q.d);\n            } else {\n                if (R.d <= Q.b && xOverlap(R, Q)) addCand(j, Q.b - R.d);\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int pos = 0;\n        for (int t = 1; t < cnt; t++) {\n            if (gap[t] < gap[pos]) pos = t;\n        }\n        if (rng.nextDouble() < 0.35) pos = rng.nextInt(cnt);\n\n        int j = cand[pos];\n\n        PairMove mv;\n        if (dir == 0) mv = bestPairVertical(st, j, i);\n        else if (dir == 1) mv = bestPairVertical(st, i, j);\n        else if (dir == 2) mv = bestPairHorizontal(st, j, i);\n        else mv = bestPairHorizontal(st, i, j);\n\n        if (mv.ok && mv.delta > 1e-12) {\n            applyPair(st, mv);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomResize(State& st, double temp, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.55) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return false;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n        if (lo == hi) return false;\n\n        int coord = cur;\n        double q = rng.nextDouble();\n\n        if (q < 0.25) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) return false;\n            coord = mv.coord;\n        } else if (q < 0.80) {\n            long long ar = rectArea(rc);\n            bool under = ar < r[i];\n            bool preferImprove = rng.nextDouble() < 0.72;\n\n            int sign;\n            if (dir == 0 || dir == 2) {\n                sign = under ? -1 : +1;\n            } else {\n                sign = under ? +1 : -1;\n            }\n            if (!preferImprove) sign = -sign;\n\n            int maxd = (sign < 0 ? cur - lo : hi - cur);\n            if (maxd <= 0) {\n                sign = -sign;\n                maxd = (sign < 0 ? cur - lo : hi - cur);\n            }\n\n            if (maxd > 0) {\n                int step = 1 + (int)(3000.0 * (1.0 - progress) * (1.0 - progress));\n                int d = 1 + rng.nextInt(min(maxd, step));\n                coord = cur + sign * d;\n            } else {\n                coord = lo + rng.nextInt(hi - lo + 1);\n            }\n        } else {\n            coord = lo + rng.nextInt(hi - lo + 1);\n        }\n\n        if (coord == cur) return false;\n\n        long long newArea = areaAfterCoord(rc, dir, coord);\n        double ns = scoreOne(i, newArea);\n        double delta = ns - st.val[i];\n\n        if (delta >= 0.0 || rng.nextDouble() < exp(delta / max(temp, 1e-9))) {\n            applyCoord(st, i, dir, coord, ns);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomShift(State& st, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.5) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int orient = rng.nextInt(2);\n        Rect& ri = st.rect[i];\n\n        int lo, hi;\n\n        if (orient == 0) {\n            lo = max(-ri.a, x[i] + 1 - ri.c);\n            hi = min(SZ - ri.c, x[i] - ri.a);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!yOverlap(ri, rj)) continue;\n\n                if (rj.c <= ri.a) lo = max(lo, rj.c - ri.a);\n                else if (rj.a >= ri.c) hi = min(hi, rj.a - ri.c);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.a += d;\n            ri.c += d;\n            return true;\n        } else {\n            lo = max(-ri.b, y[i] + 1 - ri.d);\n            hi = min(SZ - ri.d, y[i] - ri.b);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!xOverlap(ri, rj)) continue;\n\n                if (rj.d <= ri.b) lo = max(lo, rj.d - ri.b);\n                else if (rj.b >= ri.d) hi = min(hi, rj.b - ri.d);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.b += d;\n            ri.d += d;\n            return true;\n        }\n    }\n\n    bool randomReshape(State& st, double progress) {\n        for (int attempt = 0; attempt < 3; attempt++) {\n            int i;\n            if (rng.nextDouble() < 0.25) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Rect oldRect = st.rect[i];\n            double oldVal = st.val[i];\n            double oldTotal = st.total;\n\n            int dir1 = rng.nextInt(4);\n            int dir2;\n            if (dir1 < 2) dir2 = 2 + rng.nextInt(2);\n            else dir2 = rng.nextInt(2);\n\n            auto [lo, hi] = legalInterval(st, i, dir1);\n            if (lo > hi) continue;\n\n            int cur = getCoord(st.rect[i], dir1);\n            if (lo == hi) continue;\n\n            int coord = cur;\n            double q = rng.nextDouble();\n\n            if (q < 0.22) {\n                coord = (rng.nextInt(2) ? lo : hi);\n            } else {\n                int step = 1 + (int)(2600.0 * (1.0 - progress) + 80.0);\n                int L = max(lo, cur - step);\n                int R = min(hi, cur + step);\n                if (L > R) {\n                    L = lo;\n                    R = hi;\n                }\n                coord = L + rng.nextInt(R - L + 1);\n            }\n\n            if (coord == cur) {\n                if (cur > lo) coord = cur - 1;\n                else if (cur < hi) coord = cur + 1;\n                else continue;\n            }\n\n            long long ar1 = areaAfterCoord(st.rect[i], dir1, coord);\n            double ns1 = scoreOne(i, ar1);\n            applyCoord(st, i, dir1, coord, ns1);\n\n            Move mv = bestEdgeDir(st, i, dir2);\n            if (mv.ok) applyMove(st, i, mv);\n\n            bool changed =\n                st.rect[i].a != oldRect.a || st.rect[i].b != oldRect.b ||\n                st.rect[i].c != oldRect.c || st.rect[i].d != oldRect.d;\n\n            if (changed && st.val[i] + 1e-12 >= oldVal) {\n                return true;\n            }\n\n            st.rect[i] = oldRect;\n            st.val[i] = oldVal;\n            st.total = oldTotal;\n        }\n\n        return false;\n    }\n\n    State initialSolution() {\n        constexpr double INIT_END = 0.80;\n\n        State best;\n        bool hasBest = false;\n\n        auto consider = [&](const State& st) {\n            if (!hasBest || st.total > best.total) {\n                best = st;\n                hasBest = true;\n            }\n        };\n\n        {\n            vector<Rect> rects = buildRecursive(0.0);\n            State st = makeState(rects);\n            greedyPasses(st, 5, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            boundaryGreedyPasses(st, 1, INIT_END, false);\n            randomGreedyOps(st, 5 * n, INIT_END);\n            consider(st);\n        }\n\n        if (timer.elapsed() < INIT_END) {\n            vector<Rect> rects = buildUnit();\n            State st = makeState(rects);\n            greedyPasses(st, 7, INIT_END);\n            randomGreedyOps(st, 12 * n, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            consider(st);\n        }\n\n        while (timer.elapsed() < INIT_END) {\n            double temp = 0.00035 * pow(180.0, rng.nextDouble());\n            vector<Rect> rects = buildRecursive(temp);\n            State st = makeState(rects);\n\n            greedyPasses(st, 2, INIT_END);\n            randomGreedyOps(st, 3 * n, INIT_END);\n            consider(st);\n        }\n\n        return best;\n    }\n\n    State improve(State bestState) {\n        State cur = bestState;\n\n        double preEnd = min(TIME_LIMIT - 0.72, timer.elapsed() + 0.38);\n        boundaryGreedyPasses(cur, 2, preEnd, true);\n        pairGreedyPasses(cur, 1, preEnd);\n        greedyPasses(cur, 2, preEnd);\n        boundaryGreedyPasses(cur, 1, preEnd, true);\n\n        if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n        double saStart = timer.elapsed();\n        double saEnd = TIME_LIMIT - 0.50;\n\n        int iter = 0;\n        double progress = 0.0;\n        double temp = 0.05;\n\n        while (true) {\n            if ((iter & 1023) == 0) {\n                double now = timer.elapsed();\n                if (now > saEnd) break;\n\n                progress = (now - saStart) / max(1e-9, saEnd - saStart);\n                progress = min(1.0, max(0.0, progress));\n\n                double T0 = 0.050;\n                double T1 = 0.00001;\n                temp = T0 * pow(T1 / T0, progress);\n            }\n\n            double q = rng.nextDouble();\n\n            if (q < 0.05) {\n                randomShift(cur, progress);\n            } else if (q < 0.12) {\n                randomReshape(cur, progress);\n            } else if (q < 0.34) {\n                int i;\n                if (rng.nextDouble() < 0.82) i = selectBad(cur);\n                else i = rng.nextInt(n);\n\n                Move mv = bestMove(cur, i);\n                if (mv.ok && mv.delta > 1e-12) {\n                    applyMove(cur, i, mv);\n                }\n            } else if (q < 0.62) {\n                randomPairMove(cur);\n            } else {\n                randomResize(cur, temp, progress);\n            }\n\n            if (cur.total > bestState.total + 1e-12) {\n                bestState = cur;\n            }\n\n            if ((iter & 65535) == 0) {\n                double threshold = max(1.0, 0.015 * n);\n                if (cur.total < bestState.total - threshold) {\n                    cur = bestState;\n                }\n            }\n\n            iter++;\n        }\n\n        cur = bestState;\n\n        int stagnant = 0;\n        while (timer.elapsed() < TIME_LIMIT) {\n            bool imp = false;\n\n            imp |= boundaryGreedyPasses(cur, 1, TIME_LIMIT, true);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            imp |= pairGreedyPasses(cur, 1, TIME_LIMIT);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            imp |= greedyPasses(cur, 1, TIME_LIMIT);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            double rem = TIME_LIMIT - timer.elapsed();\n            if (rem > 0.18) {\n                double blockStop = min(TIME_LIMIT - 0.06, timer.elapsed() + 0.13);\n\n                imp |= componentRepackPass(cur, blockStop, 24);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= neighborClosureRepackPass(cur, blockStop, 7);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= pairBlockRepackPass(cur, blockStop, 20);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= randomBlockRepackAttempts(cur, blockStop, 7);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n            }\n\n            for (int k = 0; k < 240 && timer.elapsed() < TIME_LIMIT; k++) {\n                double q = rng.nextDouble();\n\n                if (q < 0.28) {\n                    if (randomPairMove(cur)) imp = true;\n                } else if (q < 0.40) {\n                    if (randomReshape(cur, 1.0)) imp = true;\n                } else {\n                    int i;\n                    if (rng.nextDouble() < 0.90) i = selectBad(cur);\n                    else i = rng.nextInt(n);\n\n                    Move mv = bestMove(cur, i);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(cur, i, mv);\n                        imp = true;\n                    }\n                }\n\n                if (cur.total > bestState.total + 1e-12) {\n                    bestState = cur;\n                }\n            }\n\n            if (!imp) {\n                stagnant++;\n                if (stagnant >= 4) break;\n            } else {\n                stagnant = 0;\n            }\n        }\n\n        return bestState;\n    }\n\n    bool validateRects(const vector<Rect>& v) const {\n        if ((int)v.size() != n) return false;\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = v[i];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[i] && x[i] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[i] && y[i] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (xOverlap(v[i], v[j]) && yOverlap(v[i], v[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n);\n        y.resize(n);\n        r.resize(n);\n        rd.resize(n);\n        invR.resize(n);\n\n        uint64_t seed = 1234567891234567ULL;\n        for (int i = 0; i < n; i++) {\n            cin >> x[i] >> y[i] >> r[i];\n            rd[i] = (double)r[i];\n            invR[i] = 1.0 / rd[i];\n\n            uint64_t z = ((uint64_t)x[i] << 32) ^ ((uint64_t)y[i] << 16) ^ (uint64_t)r[i];\n            seed ^= splitmix64_hash(z + seed);\n        }\n        rng = FastRNG(seed);\n\n        timer.reset();\n\n        State bestState = initialSolution();\n        bestState = improve(bestState);\n\n        if (!validateRects(bestState.rect)) {\n            bestState = makeState(buildUnit());\n        }\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = bestState.rect[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc002":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int V = N * N;\n    static constexpr int MAXT = V + 5;\n    static constexpr int MAXB = (V + 63) / 64;\n    static constexpr int POOL_LIMIT = 14;\n\n    using Bits = array<uint64_t, MAXB>;\n\n    int si, sj;\n    int startCell;\n    int M;\n\n    int tile[V];\n    int val[V];\n    int tilePot[MAXT];\n\n    int adj[V][4];\n    int adjN[V];\n    int borderDist[V];\n\n    int vis[MAXT];\n    int visitToken = 1;\n\n    int seenCell[V];\n    int seenTile[MAXT];\n    int seenBest[MAXT];\n    int bfsStamp = 1;\n    int que[V];\n\n    int pathIndex[V];\n    int rotSeen[V];\n    int rotStamp = 1;\n\n    Timer timer;\n    RNG rng;\n\n    double TL = 1.93;\n\n    vector<int> bestCells;\n    vector<int> bestCum;\n    int bestScore = -1;\n\n    vector<int> curCells;\n\n    struct PathCand {\n        vector<int> cells;\n        vector<int> cum;\n        int score;\n        uint64_t hash;\n    };\n\n    vector<PathCand> pool;\n\n    struct Params {\n        int reachW = 0;\n        int scoreW = 0;\n        int degW = 0;\n        int noise = 0;\n        int locW = 0;\n        int lossW = 0;\n        int endPenalty = 0;\n        int borderW = 0;\n        int straightW = 0;\n        int cntW = 0;\n    };\n\n    struct FloodResult {\n        int pot;\n        int cnt;\n    };\n\n    void buildAdj() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                adjN[c] = 0;\n                borderDist[c] = min(min(i, N - 1 - i), min(j, N - 1 - j));\n\n                if (i > 0) adj[c][adjN[c]++] = c - N;\n                if (i + 1 < N) adj[c][adjN[c]++] = c + N;\n                if (j > 0) adj[c][adjN[c]++] = c - 1;\n                if (j + 1 < N) adj[c][adjN[c]++] = c + 1;\n            }\n        }\n    }\n\n    void read() {\n        cin >> si >> sj;\n        startCell = si * N + sj;\n\n        uint64_t h = 0x123456789abcdefULL;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix(si);\n        mix(sj);\n\n        int maxTid = -1;\n        for (int i = 0; i < V; i++) {\n            cin >> tile[i];\n            maxTid = max(maxTid, tile[i]);\n            mix((uint64_t)tile[i] + 1009);\n        }\n\n        M = maxTid + 1;\n\n        for (int i = 0; i < V; i++) {\n            cin >> val[i];\n            mix((uint64_t)val[i] + 9176);\n        }\n\n        fill(tilePot, tilePot + MAXT, 0);\n        for (int i = 0; i < V; i++) {\n            tilePot[tile[i]] = max(tilePot[tile[i]], val[i]);\n        }\n\n        memset(vis, 0, sizeof(vis));\n        memset(seenCell, 0, sizeof(seenCell));\n        memset(seenTile, 0, sizeof(seenTile));\n        memset(rotSeen, 0, sizeof(rotSeen));\n\n        rng = RNG(h);\n        buildAdj();\n    }\n\n    int newVisitToken() {\n        ++visitToken;\n        if (visitToken == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            visitToken = 1;\n        }\n        return visitToken;\n    }\n\n    int newBfsStamp() {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            memset(seenCell, 0, sizeof(seenCell));\n            memset(seenTile, 0, sizeof(seenTile));\n            bfsStamp = 1;\n        }\n        return bfsStamp;\n    }\n\n    int newRotStamp() {\n        ++rotStamp;\n        if (rotStamp == INT_MAX) {\n            memset(rotSeen, 0, sizeof(rotSeen));\n            rotStamp = 1;\n        }\n        return rotStamp;\n    }\n\n    inline bool bitTest(const Bits& bits, int tid) const {\n        return (bits[tid >> 6] >> (tid & 63)) & 1ULL;\n    }\n\n    inline void bitSet(Bits& bits, int tid) const {\n        bits[tid >> 6] |= 1ULL << (tid & 63);\n    }\n\n    inline void bitClear(Bits& bits, int tid) const {\n        bits[tid >> 6] &= ~(1ULL << (tid & 63));\n    }\n\n    inline bool adjacentCell(int a, int b) const {\n        int d = abs(a - b);\n        if (d == N) return true;\n        if (d == 1 && a / N == b / N) return true;\n        return false;\n    }\n\n    inline int manhattanCell(int a, int b) const {\n        return abs(a / N - b / N) + abs(a % N - b % N);\n    }\n\n    void makeBitsFromPath(const vector<int>& path, Bits& bits) const {\n        bits.fill(0);\n        for (int c : path) {\n            bitSet(bits, tile[c]);\n        }\n    }\n\n    uint64_t calcPathHash(const vector<int>& cells) const {\n        uint64_t h = 0xcbf29ce484222325ULL;\n        for (int c : cells) {\n            h ^= (uint64_t)c + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n            h *= 0x100000001b3ULL;\n        }\n        h ^= (uint64_t)cells.size() * 0x9e3779b97f4a7c15ULL;\n        return h;\n    }\n\n    void sortPool() {\n        sort(pool.begin(), pool.end(), [](const PathCand& a, const PathCand& b) {\n            if (a.score != b.score) return a.score > b.score;\n            return a.cells.size() > b.cells.size();\n        });\n\n        vector<PathCand> np;\n        np.reserve(POOL_LIMIT);\n\n        for (auto& pc : pool) {\n            bool dup = false;\n            for (auto& q : np) {\n                if (q.hash == pc.hash && q.cells.size() == pc.cells.size()) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                np.push_back(std::move(pc));\n                if ((int)np.size() >= POOL_LIMIT) break;\n            }\n        }\n\n        pool.swap(np);\n    }\n\n    void addCandidate(const vector<int>& cells, int /*scoreHint*/ = -1) {\n        if (cells.empty()) return;\n\n        vector<int> cum(cells.size());\n        int s = 0;\n        for (int i = 0; i < (int)cells.size(); i++) {\n            s += val[cells[i]];\n            cum[i] = s;\n        }\n\n        uint64_t h = calcPathHash(cells);\n\n        if (s > bestScore || (s == bestScore && cells.size() > bestCells.size())) {\n            bestScore = s;\n            bestCells = cells;\n            bestCum = cum;\n        }\n\n        bool good = false;\n        if ((int)pool.size() < POOL_LIMIT) good = true;\n        else if (s + 2500 >= pool.back().score) good = true;\n        else if (s + 4500 >= bestScore) good = true;\n\n        if (!good) return;\n\n        PathCand pc;\n        pc.cells = cells;\n        pc.cum = std::move(cum);\n        pc.score = s;\n        pc.hash = h;\n\n        pool.push_back(std::move(pc));\n        sortPool();\n    }\n\n    void setBestFrom(const vector<int>& cells, int score) {\n        addCandidate(cells, score);\n    }\n\n    void considerCurrent(int score) {\n        addCandidate(curCells, score);\n    }\n\n    int choosePoolIndex() {\n        if (pool.empty()) return -1;\n\n        int n = (int)pool.size();\n        int r = rng.nextInt(100);\n\n        if (r < 58) return 0;\n        if (r < 82) return rng.nextInt(min(n, 4));\n        if (r < 95) return rng.nextInt(min(n, 8));\n        return rng.nextInt(n);\n    }\n\n    inline int degreeAfterToken(int cell, int forbidTid, int token) {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localNeighborSumToken(int cell, int forbidTid, int token) {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int degreeAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localSumAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int countUnvisitedMoves(const Bits& bits, int cell) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) cnt++;\n        }\n        return cnt;\n    }\n\n    inline int sumUnvisitedMoveValues(const Bits& bits, int cell) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) s += val[nb];\n        }\n        return s;\n    }\n\n    FloodResult floodPotential(int start, int forbidTid, int token) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (tid == forbidTid) continue;\n                if (vis[tid] == token) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    FloodResult floodPotentialBits(int start, const Bits& bits) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (bitTest(bits, tid)) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    Params makeParams(bool flood) {\n        Params p;\n\n        if (flood) {\n            int rwArr[4] = {6, 8, 10, 12};\n            int exArr[5] = {0, 0, 2, 4, 6};\n\n            p.reachW = rwArr[rng.nextInt(4)];\n            p.scoreW = p.reachW + exArr[rng.nextInt(5)];\n\n            if (rng.nextInt(10) < 8) {\n                p.degW = 40 + rng.nextInt(260);\n            } else {\n                p.degW = -(20 + rng.nextInt(100));\n            }\n\n            p.noise = 20 + rng.nextInt(250);\n            p.locW = (rng.nextInt(4) == 0 ? 1 : 0);\n            p.cntW = rng.nextInt(6);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(16) : -rng.nextInt(8));\n            p.straightW = rng.nextInt(101) - 50;\n        } else {\n            p.scoreW = 4 + rng.nextInt(18);\n\n            int mode = rng.nextInt(10);\n            if (mode < 5) {\n                p.degW = 200 + rng.nextInt(700);\n            } else if (mode < 8) {\n                p.degW = 50 + rng.nextInt(250);\n            } else {\n                p.degW = -(20 + rng.nextInt(120));\n            }\n\n            p.noise = 100 + rng.nextInt(900);\n            p.locW = rng.nextInt(4);\n            p.lossW = rng.nextInt(8);\n            p.endPenalty = 3000 + rng.nextInt(7000);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(25) : -rng.nextInt(10));\n            p.straightW = rng.nextInt(121) - 60;\n        }\n\n        return p;\n    }\n\n    Params makePilotParam() {\n        Params p;\n        p.scoreW = 8 + rng.nextInt(22);\n\n        int mode = rng.nextInt(100);\n        if (mode < 55) {\n            p.degW = 180 + rng.nextInt(620);\n        } else if (mode < 85) {\n            p.degW = 30 + rng.nextInt(220);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = rng.nextInt(5);\n        p.lossW = rng.nextInt(9);\n        p.endPenalty = 3500 + rng.nextInt(8000);\n        p.borderW = (rng.nextInt(100) < 82 ? rng.nextInt(26) : -rng.nextInt(12));\n        p.straightW = rng.nextInt(151) - 75;\n        p.noise = 0;\n        return p;\n    }\n\n    Params makePosaParam() {\n        Params p;\n        p.scoreW = 10 + rng.nextInt(25);\n\n        int mode = rng.nextInt(100);\n        if (mode < 70) {\n            p.degW = 80 + rng.nextInt(500);\n        } else if (mode < 90) {\n            p.degW = rng.nextInt(120);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = 1 + rng.nextInt(4);\n        p.lossW = 3 + rng.nextInt(8);\n        p.endPenalty = 1000 + rng.nextInt(5000);\n        p.borderW = (rng.nextInt(100) < 75 ? rng.nextInt(20) : -rng.nextInt(8));\n        p.straightW = rng.nextInt(81) - 40;\n        p.noise = 50 + rng.nextInt(600);\n        return p;\n    }\n\n    int chooseCutLength(int L) {\n        if (L <= 1) return 0;\n\n        int r = rng.nextInt(100);\n\n        if (r < 22) return 0;\n\n        int cut = 0;\n\n        if (r < 66) {\n            int maxSuf = min(L - 1, 900);\n            int a = 1 + rng.nextInt(maxSuf);\n            int b = 1 + rng.nextInt(maxSuf);\n            int suf;\n            if (rng.nextInt(100) < 75) {\n                suf = min(a, b);\n            } else {\n                suf = max(a, b);\n            }\n            cut = L - 1 - suf;\n        } else if (r < 88) {\n            int a = rng.nextInt(L - 1);\n            int b = rng.nextInt(L - 1);\n            cut = max(a, b);\n        } else {\n            cut = rng.nextInt(L - 1);\n        }\n\n        return max(0, min(cut, L - 2));\n    }\n\n    int chooseSmartCut(const vector<int>& cells, const vector<int>& cum) {\n        int L = (int)cells.size();\n        if (L <= 2) return chooseCutLength(L);\n\n        Bits bits;\n        bits.fill(0);\n\n        long long bestEval = LLONG_MIN;\n        int bestCut = -1;\n\n        for (int i = 0; i < L - 1; i++) {\n            bitSet(bits, tile[cells[i]]);\n\n            int nextTid = tile[cells[i + 1]];\n            int altCnt = 0;\n            int altSum = 0;\n            int altMax = 0;\n\n            for (int k = 0; k < adjN[cells[i]]; k++) {\n                int nb = adj[cells[i]][k];\n                int tid = tile[nb];\n\n                if (bitTest(bits, tid)) continue;\n                if (tid == nextTid) continue;\n\n                altCnt++;\n                altSum += val[nb];\n                altMax = max(altMax, val[nb]);\n            }\n\n            if (altCnt == 0) continue;\n\n            int suffixLoss = cum[L - 1] - cum[i];\n\n            long long ev = 0;\n            ev += 15000LL * altCnt;\n            ev += 180LL * altSum;\n            ev += 280LL * altMax;\n            ev -= 2LL * suffixLoss;\n            ev += cum[i] / 3;\n            ev += rng.nextInt(30000);\n\n            if (ev > bestEval) {\n                bestEval = ev;\n                bestCut = i;\n            }\n        }\n\n        if (bestCut >= 0) return bestCut;\n        return chooseCutLength(L);\n    }\n\n    int chooseCutForBase(const PathCand& base, int zeroProb, int smartProb) {\n        int L = (int)base.cells.size();\n        if (L <= 1) return 0;\n\n        if (rng.nextInt(100) < zeroProb) return 0;\n        if (rng.nextInt(100) < smartProb) return chooseSmartCut(base.cells, base.cum);\n\n        return chooseCutLength(L);\n    }\n\n    void posaExtendLocal(vector<int>& path, int& score, Bits& bits, double stopTime, const Params& par) {\n        if (path.empty()) return;\n\n        fill(pathIndex, pathIndex + V, -1);\n        for (int i = 0; i < (int)path.size(); i++) {\n            pathIndex[path[i]] = i;\n        }\n\n        int stamp = newRotStamp();\n        rotSeen[path.back()] = stamp;\n\n        int rotationsSinceAppend = 0;\n        int rotLimit = 25 + rng.nextInt(65);\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() < M) {\n            int L = (int)path.size();\n            int pos = path.back();\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc > 0) {\n                int prev = (L >= 2 ? path[L - 2] : -1);\n                int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n                long long bestEval = LLONG_MIN;\n                int bestIdx = 0;\n\n                for (int a = 0; a < nc; a++) {\n                    int cell = candCell[a];\n                    int tid = candTid[a];\n\n                    int deg = degreeAfterBits(bits, cell, tid);\n                    int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                    long long ev = 0;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n                    ev -= 1LL * par.borderW * borderDist[cell];\n\n                    if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                    if (prev != -1 && cell - pos == lastDiff) ev += par.straightW;\n                    if (par.noise > 0) ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n\n                    if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                        bestEval = ev;\n                        bestIdx = a;\n                    }\n                }\n\n                int nxt = candCell[bestIdx];\n                int tid = candTid[bestIdx];\n\n                pathIndex[nxt] = L;\n                path.push_back(nxt);\n                bitSet(bits, tid);\n                score += val[nxt];\n\n                rotationsSinceAppend = 0;\n                rotLimit = 25 + rng.nextInt(65);\n                stamp = newRotStamp();\n                rotSeen[path.back()] = stamp;\n\n                continue;\n            }\n\n            if (L < 3) break;\n\n            int opts[4];\n            long long evs[4];\n            int no = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int idx = pathIndex[nb];\n\n                if (idx >= 0 && idx <= L - 3) {\n                    int newEnd = path[idx + 1];\n                    int cnt = countUnvisitedMoves(bits, newEnd);\n                    int sum = sumUnvisitedMoveValues(bits, newEnd);\n\n                    long long ev = 0;\n                    ev += 100000LL * cnt;\n                    ev += 120LL * sum;\n                    ev += 5LL * val[newEnd];\n                    ev -= 8LL * borderDist[newEnd];\n                    ev += rng.nextInt(10000);\n\n                    if (rotSeen[newEnd] == stamp) ev -= 60000;\n\n                    opts[no] = idx;\n                    evs[no] = ev;\n                    no++;\n                }\n            }\n\n            if (no == 0) break;\n\n            int bestOpt = 0;\n            for (int i = 1; i < no; i++) {\n                if (evs[i] > evs[bestOpt]) bestOpt = i;\n            }\n\n            int idx = opts[bestOpt];\n            int l = idx + 1;\n\n            reverse(path.begin() + l, path.end());\n\n            for (int i = l; i < L; i++) {\n                pathIndex[path[i]] = i;\n            }\n\n            rotSeen[path.back()] = stamp;\n\n            rotationsSinceAppend++;\n            if (rotationsSinceAppend > rotLimit) break;\n        }\n    }\n\n    int runGreedyFromPath(\n        const vector<int>& prefix,\n        int prefixScore,\n        bool useFlood,\n        const Params& par,\n        bool allowPosa = false\n    ) {\n        int token = newVisitToken();\n\n        curCells = prefix;\n\n        for (int c : curCells) {\n            vis[tile[c]] = token;\n        }\n\n        int score = prefixScore;\n        int pos = curCells.back();\n\n        int iter = 0;\n\n        while (true) {\n            if ((iter++ & 15) == 0 && timer.elapsed() > TL) break;\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (vis[tid] != token) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int prev = -1;\n            int lastDiff = 999999;\n            if ((int)curCells.size() >= 2) {\n                prev = curCells[(int)curCells.size() - 2];\n                lastDiff = pos - prev;\n            }\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterToken(cell, tid, token);\n                int loc = (par.locW ? localNeighborSumToken(cell, tid, token) : 0);\n\n                long long ev = 0;\n\n                if (useFlood) {\n                    FloodResult fr = floodPotential(cell, tid, token);\n                    ev += 1LL * par.reachW * fr.pot;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.cntW * fr.cnt;\n                } else {\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                    if (deg == 0 && nc > 1) {\n                        ev -= par.endPenalty;\n                    }\n                }\n\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                if (par.noise > 0) {\n                    ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n                }\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            vis[tid] = token;\n            score += val[nxt];\n            curCells.push_back(nxt);\n            pos = nxt;\n        }\n\n        if (allowPosa && timer.elapsed() < TL - 0.025 && score + 3500 >= bestScore) {\n            Bits bits;\n            makeBitsFromPath(curCells, bits);\n            Params pp = makePosaParam();\n            double stop = min(TL, timer.elapsed() + 0.012 + (rng.nextInt(100) < 30 ? 0.018 : 0.0));\n            posaExtendLocal(curCells, score, bits, stop, pp);\n        }\n\n        return score;\n    }\n\n    int runGreedyBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        bool useFlood,\n        const Params& par,\n        bool allowPosa = false\n    ) {\n        int L = (int)baseCells.size();\n        if (L == 0) return 0;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> prefix;\n        prefix.reserve(cut + 1);\n\n        for (int i = 0; i <= cut; i++) {\n            prefix.push_back(baseCells[i]);\n        }\n\n        return runGreedyFromPath(prefix, baseCum[cut], useFlood, par, allowPosa);\n    }\n\n    int runGreedy(int cut, bool useFlood, const Params& par) {\n        return runGreedyBase(bestCells, bestCum, cut, useFlood, par, false);\n    }\n\n    int rolloutScore(Bits& bits, int prev, int pos, int score, const Params& par, vector<int>* suffix) const {\n        while (true) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterBits(bits, cell, tid);\n                int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                long long ev = 0;\n                ev += 1LL * par.scoreW * val[cell];\n                ev -= 1LL * par.degW * deg;\n                ev += 1LL * par.locW * loc;\n                ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) {\n                    ev += par.straightW;\n                }\n\n                if (ev > bestEval || (ev == bestEval && cell < candCell[bestIdx])) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            if (suffix) suffix->push_back(nxt);\n\n            prev = pos;\n            pos = nxt;\n        }\n\n        return score;\n    }\n\n    void considerRolloutPath(\n        const vector<int>& prefix,\n        int cand,\n        const Bits& bitsAfterCand,\n        int prev,\n        int scoreAfterCand,\n        const Params& par,\n        int estimatedScore\n    ) {\n        if (estimatedScore + 1800 < bestScore) return;\n\n        Bits b = bitsAfterCand;\n        vector<int> suffix;\n        suffix.reserve(1000);\n\n        int exactScore = rolloutScore(b, prev, cand, scoreAfterCand, par, &suffix);\n\n        if (exactScore + 2500 >= bestScore) {\n            vector<int> full;\n            full.reserve(prefix.size() + 1 + suffix.size());\n            full.insert(full.end(), prefix.begin(), prefix.end());\n            full.push_back(cand);\n            full.insert(full.end(), suffix.begin(), suffix.end());\n            addCandidate(full, exactScore);\n        }\n    }\n\n    int runPilotFromPath(\n        const vector<int>& initialPath,\n        int initialScore,\n        int variants,\n        bool allowPosa = false,\n        bool useReach = false\n    ) {\n        if (initialPath.empty()) return 0;\n\n        vector<int> path = initialPath;\n        path.reserve(V);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        int score = initialScore;\n        int pos = path.back();\n\n        Params pars[4];\n        variants = max(1, min(variants, 4));\n        for (int i = 0; i < variants; i++) pars[i] = makePilotParam();\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                Bits bitsAfter = bits;\n                bitSet(bitsAfter, tid);\n\n                int scoreAfter = score + val[cell];\n                int bestSim = -1;\n                int bestPar = 0;\n\n                for (int r = 0; r < variants; r++) {\n                    Bits b = bitsAfter;\n                    int simScore = rolloutScore(b, pos, cell, scoreAfter, pars[r], nullptr);\n\n                    if (simScore > bestSim) {\n                        bestSim = simScore;\n                        bestPar = r;\n                    }\n                }\n\n                FloodResult fr{0, 0};\n                if (useReach) {\n                    fr = floodPotentialBits(cell, bitsAfter);\n                }\n\n                if (bestSim + (useReach ? fr.pot / 30 : 0) >= bestScore - 1800) {\n                    considerRolloutPath(path, cell, bitsAfter, pos, scoreAfter, pars[bestPar], bestSim);\n                }\n\n                long long ev = 1LL * bestSim * 1000;\n                ev += 3LL * val[cell];\n\n                if (useReach) {\n                    ev += 32LL * fr.pot;\n                    ev += 180LL * fr.cnt;\n                }\n\n                ev += rng.nextInt(1001) - 500;\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            path.push_back(nxt);\n            pos = nxt;\n\n            if (score > bestScore || (score == bestScore && path.size() > bestCells.size())) {\n                setBestFrom(path, score);\n            }\n\n            if ((++iter & 7) == 0 && timer.elapsed() > TL) break;\n        }\n\n        if (allowPosa && timer.elapsed() < TL - 0.025 && score + 6000 >= bestScore) {\n            Params pp = makePosaParam();\n            double stop = min(TL, timer.elapsed() + 0.010 + (rng.nextInt(100) < 40 ? 0.018 : 0.0));\n            posaExtendLocal(path, score, bits, stop, pp);\n        }\n\n        addCandidate(path, score);\n        return score;\n    }\n\n    int runPilotBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        int variants,\n        bool allowPosa = false,\n        bool useReach = false\n    ) {\n        int L = (int)baseCells.size();\n        if (L == 0) return 0;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> prefix;\n        prefix.reserve(cut + 1);\n\n        for (int i = 0; i <= cut; i++) {\n            prefix.push_back(baseCells[i]);\n        }\n\n        return runPilotFromPath(prefix, baseCum[cut], variants, allowPosa, useReach);\n    }\n\n    int runPilot(int cut, int variants, bool allowPosa = false, bool useReach = false) {\n        return runPilotBase(bestCells, bestCum, cut, variants, allowPosa, useReach);\n    }\n\n    void runPosaFromBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        double budget\n    ) {\n        if (timer.elapsed() >= TL || budget <= 0) return;\n\n        int L = (int)baseCells.size();\n        if (L == 0) return;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> path;\n        path.reserve(V);\n        for (int i = 0; i <= cut; i++) path.push_back(baseCells[i]);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        int score = baseCum[cut];\n\n        Params p = makePosaParam();\n        double stop = min(TL, timer.elapsed() + budget);\n        posaExtendLocal(path, score, bits, stop, p);\n\n        addCandidate(path, score);\n    }\n\n    bool runRotationExtendFromBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        bool pilotMode\n    ) {\n        if (timer.elapsed() >= TL) return false;\n\n        int L0 = (int)baseCells.size();\n        if (L0 < 3) return false;\n\n        cut = max(0, min(cut, L0 - 1));\n        if (cut < 2) return false;\n\n        vector<int> path;\n        path.reserve(V);\n        for (int i = 0; i <= cut; i++) path.push_back(baseCells[i]);\n\n        int score = baseCum[cut];\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        fill(pathIndex, pathIndex + V, -1);\n        for (int i = 0; i < (int)path.size(); i++) {\n            pathIndex[path[i]] = i;\n        }\n\n        int stamp = newRotStamp();\n        rotSeen[path.back()] = stamp;\n\n        int maxRot = 1 + rng.nextInt(8);\n        bool rotated = false;\n\n        for (int step = 0; step < maxRot && timer.elapsed() < TL; step++) {\n            int L = (int)path.size();\n            if (L < 3) break;\n\n            int pos = path.back();\n\n            int opts[4];\n            long long evs[4];\n            int no = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int idx = pathIndex[nb];\n\n                if (idx >= 0 && idx <= L - 3) {\n                    int newEnd = path[idx + 1];\n                    int cnt = countUnvisitedMoves(bits, newEnd);\n                    int sum = sumUnvisitedMoveValues(bits, newEnd);\n\n                    long long ev = 0;\n                    ev += 100000LL * cnt;\n                    ev += 150LL * sum;\n                    ev += 5LL * val[newEnd];\n                    ev -= 6LL * borderDist[newEnd];\n                    ev += rng.nextInt(12000);\n\n                    if (rotSeen[newEnd] == stamp) ev -= 70000;\n\n                    opts[no] = idx;\n                    evs[no] = ev;\n                    no++;\n                }\n            }\n\n            if (no == 0) break;\n\n            int bestOpt = 0;\n            for (int i = 1; i < no; i++) {\n                if (evs[i] > evs[bestOpt]) bestOpt = i;\n            }\n\n            int idx = opts[bestOpt];\n            int l = idx + 1;\n\n            reverse(path.begin() + l, path.end());\n\n            for (int i = l; i < (int)path.size(); i++) {\n                pathIndex[path[i]] = i;\n            }\n\n            rotated = true;\n            rotSeen[path.back()] = stamp;\n\n            if (countUnvisitedMoves(bits, path.back()) > 0 && rng.nextInt(100) < 75) {\n                break;\n            }\n        }\n\n        if (!rotated) return false;\n        if (timer.elapsed() >= TL) return false;\n        if (countUnvisitedMoves(bits, path.back()) == 0) return false;\n\n        if (pilotMode) {\n            int variants = (timer.elapsed() < 0.95 && rng.nextInt(100) < 45 ? 2 : 1);\n            bool useReach = rng.nextInt(100) < 15;\n            runPilotFromPath(path, score, variants, rng.nextInt(100) < 35, useReach);\n        } else {\n            Params p = makeParams(false);\n            int sc = runGreedyFromPath(path, score, false, p, true);\n            considerCurrent(sc);\n        }\n\n        return true;\n    }\n\n    // ---------- Suffix-preserving augmentation ----------\n\n    int countFreeForInsert(const Bits& bits, int cell, int target) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (nb == target) {\n                cnt++;\n            } else if (!bitTest(bits, tile[nb])) {\n                cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int sumFreeForInsert(const Bits& bits, int cell, int target) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (nb == target) continue;\n            if (!bitTest(bits, tile[nb])) s += val[nb];\n        }\n        return s;\n    }\n\n    bool targetReachableFrom(int start, int target, const Bits& bits) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        while (head < tail) {\n            int v = que[head++];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n\n                if (nb == target) return true;\n\n                int tid = tile[nb];\n                if (bitTest(bits, tid)) continue;\n                if (tid == tile[v]) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n            }\n        }\n\n        return false;\n    }\n\n    bool tryRectangleOnce(vector<int>& path, int& score, Bits& bits) {\n        int L = (int)path.size();\n        if (L + 2 > M) return false;\n\n        int bestI = -1;\n        int bestC = -1;\n        int bestD = -1;\n        long long bestEval = LLONG_MIN;\n\n        auto checkPair = [&](int i, int c, int d) {\n            if (c < 0 || c >= V || d < 0 || d >= V) return;\n\n            int tc = tile[c];\n            int td = tile[d];\n\n            if (tc == td) return;\n            if (bitTest(bits, tc)) return;\n            if (bitTest(bits, td)) return;\n\n            if (!adjacentCell(path[i], c)) return;\n            if (!adjacentCell(c, d)) return;\n            if (!adjacentCell(d, path[i + 1])) return;\n\n            int gain = val[c] + val[d];\n            if (gain <= 0) return;\n\n            long long ev = 1000LL * gain + rng.nextInt(1000);\n\n            if (ev > bestEval) {\n                bestEval = ev;\n                bestI = i;\n                bestC = c;\n                bestD = d;\n            }\n        };\n\n        for (int i = 0; i + 1 < L; i++) {\n            int a = path[i];\n            int b = path[i + 1];\n            int diff = b - a;\n\n            if (diff == 1 || diff == -1) {\n                if (a / N != b / N) continue;\n\n                if (a >= N && b >= N) {\n                    checkPair(i, a - N, b - N);\n                }\n                if (a + N < V && b + N < V) {\n                    checkPair(i, a + N, b + N);\n                }\n            } else if (diff == N || diff == -N) {\n                if (a % N > 0 && b % N > 0) {\n                    checkPair(i, a - 1, b - 1);\n                }\n                if (a % N + 1 < N && b % N + 1 < N) {\n                    checkPair(i, a + 1, b + 1);\n                }\n            }\n        }\n\n        if (bestI < 0) return false;\n\n        path.insert(path.begin() + bestI + 1, bestD);\n        path.insert(path.begin() + bestI + 1, bestC);\n\n        bitSet(bits, tile[bestC]);\n        bitSet(bits, tile[bestD]);\n        score += val[bestC] + val[bestD];\n\n        return true;\n    }\n\n    void augmentRectangles(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() + 2 <= M) {\n            if (!tryRectangleOnce(path, score, bits)) break;\n        }\n    }\n\n    bool buildDetourForEdge(vector<int>& path, int& score, Bits& bits, int edgeIdx, double stopTime) {\n        int L = (int)path.size();\n        if (edgeIdx < 0 || edgeIdx + 1 >= L) return false;\n        if (L >= M) return false;\n\n        int a = path[edgeIdx];\n        int target = path[edgeIdx + 1];\n\n        Bits usedTmp = bits;\n\n        vector<int> det;\n        vector<int> bestDet;\n        det.reserve(160);\n        bestDet.reserve(160);\n\n        int pos = a;\n        int gain = 0;\n        int bestGain = -1;\n\n        int maxSteps = min(M - L, 25 + rng.nextInt(100));\n\n        struct Cand {\n            int cell;\n            long long ev;\n        };\n\n        for (int step = 0; step < maxSteps && timer.elapsed() < stopTime && timer.elapsed() < TL; step++) {\n            if (!det.empty() && adjacentCell(pos, target)) {\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestDet = det;\n                }\n            }\n\n            Cand cand[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n\n                if (nb == target) continue;\n\n                int tid = tile[nb];\n                if (bitTest(usedTmp, tid)) continue;\n\n                Bits tmp = usedTmp;\n                bitSet(tmp, tid);\n\n                if (!targetReachableFrom(nb, target, tmp)) continue;\n\n                int deg = countFreeForInsert(tmp, nb, target);\n                int loc = sumFreeForInsert(tmp, nb, target);\n                int dist = manhattanCell(nb, target);\n\n                long long ev = 0;\n                ev += 1000LL * val[nb];\n                ev -= 260LL * deg;\n                ev += 3LL * loc;\n                ev += 22LL * dist;\n                ev -= 8LL * borderDist[nb];\n\n                if (adjacentCell(nb, target) && (int)det.size() < 5) {\n                    ev -= 1500;\n                }\n\n                ev += rng.nextInt(5000);\n\n                cand[nc++] = {nb, ev};\n            }\n\n            if (nc == 0) break;\n\n            int bi = 0;\n            for (int i = 1; i < nc; i++) {\n                if (cand[i].ev > cand[bi].ev) bi = i;\n            }\n\n            int nxt = cand[bi].cell;\n            int tid = tile[nxt];\n\n            bitSet(usedTmp, tid);\n            det.push_back(nxt);\n            gain += val[nxt];\n            pos = nxt;\n        }\n\n        if (!det.empty() && adjacentCell(pos, target)) {\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestDet = det;\n            }\n        }\n\n        if (bestGain <= 0 || bestDet.empty()) return false;\n\n        for (int c : bestDet) {\n            if (bitTest(bits, tile[c])) return false;\n        }\n\n        path.insert(path.begin() + edgeIdx + 1, bestDet.begin(), bestDet.end());\n\n        for (int c : bestDet) {\n            bitSet(bits, tile[c]);\n            score += val[c];\n        }\n\n        return true;\n    }\n\n    bool tryDetourInsertionOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L >= M) return false;\n\n        struct EdgeOpt {\n            int idx;\n            long long ev;\n        };\n\n        vector<EdgeOpt> opts;\n        opts.reserve(L);\n\n        for (int i = 0; i + 1 < L; i++) {\n            int a = path[i];\n            int b = path[i + 1];\n\n            int ca = countUnvisitedMoves(bits, a);\n            int cb = countUnvisitedMoves(bits, b);\n\n            if (ca == 0 || cb == 0) continue;\n\n            int sa = sumUnvisitedMoveValues(bits, a);\n            int sb = sumUnvisitedMoveValues(bits, b);\n\n            long long ev = 0;\n            ev += 120000LL * min(ca, cb);\n            ev += 160LL * (sa + sb);\n            ev += rng.nextInt(50000);\n\n            opts.push_back({i, ev});\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(16, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const EdgeOpt& a, const EdgeOpt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const EdgeOpt& a, const EdgeOpt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(8, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildDetourForEdge(path, score, bits, opts[t].idx, stopTime)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void augmentDetours(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int success = 0;\n        int fail = 0;\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() < M) {\n            if (tryDetourInsertionOnce(path, score, bits, stopTime)) {\n                success++;\n                fail = 0;\n\n                augmentRectangles(path, score, bits, min(stopTime, timer.elapsed() + 0.006));\n\n                if (success >= 20) break;\n            } else {\n                fail++;\n                if (fail >= 2) break;\n            }\n        }\n    }\n\n    bool buildSegmentReroute(vector<int>& path, int& score, Bits& bits, int i, int j, double stopTime) {\n        int L = (int)path.size();\n        if (i < 0 || j >= L || j <= i + 1) return false;\n\n        int oldLen = j - i - 1;\n        if (oldLen <= 0) return false;\n\n        Bits base = bits;\n        int oldGain = 0;\n\n        for (int k = i + 1; k < j; k++) {\n            bitClear(base, tile[path[k]]);\n            oldGain += val[path[k]];\n        }\n\n        int capacity = M - (L - oldLen);\n        if (capacity <= 0) return false;\n\n        int a = path[i];\n        int target = path[j];\n\n        Bits usedTmp = base;\n\n        vector<int> det;\n        vector<int> bestDet;\n        det.reserve(200);\n        bestDet.reserve(200);\n\n        int pos = a;\n        int gain = 0;\n        int bestGain = -1;\n\n        int maxSteps = min(capacity, oldLen + 45 + rng.nextInt(90));\n\n        struct Cand {\n            int cell;\n            long long ev;\n        };\n\n        for (int step = 0; step < maxSteps && timer.elapsed() < stopTime && timer.elapsed() < TL; step++) {\n            if (!det.empty() && adjacentCell(pos, target)) {\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestDet = det;\n                }\n            }\n\n            Cand cand[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n\n                if (nb == target) continue;\n\n                int tid = tile[nb];\n                if (bitTest(usedTmp, tid)) continue;\n\n                Bits tmp = usedTmp;\n                bitSet(tmp, tid);\n\n                if (!targetReachableFrom(nb, target, tmp)) continue;\n\n                int deg = countFreeForInsert(tmp, nb, target);\n                int loc = sumFreeForInsert(tmp, nb, target);\n                int dist = manhattanCell(nb, target);\n\n                long long ev = 0;\n                ev += 1000LL * val[nb];\n                ev -= 230LL * deg;\n                ev += 4LL * loc;\n                ev -= 8LL * borderDist[nb];\n\n                if (step * 3 < maxSteps * 2) {\n                    ev += 20LL * dist;\n                } else {\n                    ev -= 70LL * dist;\n                }\n\n                if (adjacentCell(nb, target) && gain + val[nb] <= oldGain + 80) {\n                    ev -= 3500;\n                }\n\n                if (adjacentCell(nb, target) && step < 3) {\n                    ev -= 1200;\n                }\n\n                ev += rng.nextInt(6000);\n\n                cand[nc++] = {nb, ev};\n            }\n\n            if (nc == 0) break;\n\n            int bi = 0;\n            for (int t = 1; t < nc; t++) {\n                if (cand[t].ev > cand[bi].ev) bi = t;\n            }\n\n            int nxt = cand[bi].cell;\n            int tid = tile[nxt];\n\n            bitSet(usedTmp, tid);\n            det.push_back(nxt);\n            gain += val[nxt];\n            pos = nxt;\n        }\n\n        if (!det.empty() && adjacentCell(pos, target)) {\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestDet = det;\n            }\n        }\n\n        if (bestGain <= oldGain || bestDet.empty()) return false;\n\n        Bits check = base;\n        for (int c : bestDet) {\n            int tid = tile[c];\n            if (bitTest(check, tid)) return false;\n            bitSet(check, tid);\n        }\n\n        bits = check;\n        score += bestGain - oldGain;\n\n        path.erase(path.begin() + i + 1, path.begin() + j);\n        path.insert(path.begin() + i + 1, bestDet.begin(), bestDet.end());\n\n        return true;\n    }\n\n    bool trySegmentRerouteOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L < 4) return false;\n\n        struct Opt {\n            int i;\n            int j;\n            long long ev;\n        };\n\n        vector<Opt> opts;\n        opts.reserve(256);\n\n        int maxSpan = 4 + rng.nextInt(18);\n\n        for (int i = 0; i + 2 < L; i++) {\n            int oldGain = 0;\n\n            for (int span = 2; span <= maxSpan && i + span < L; span++) {\n                oldGain += val[path[i + span - 1]];\n\n                int j = i + span;\n                int oldLen = span - 1;\n\n                int a = path[i];\n                int b = path[j];\n\n                int releasedEndVal = val[path[i + 1]];\n                if (j - 1 != i + 1) releasedEndVal += val[path[j - 1]];\n\n                int ca = countUnvisitedMoves(bits, a) + countUnvisitedMoves(bits, b) + (oldLen == 1 ? 1 : 2);\n                int sa = sumUnvisitedMoveValues(bits, a) + sumUnvisitedMoveValues(bits, b) + releasedEndVal;\n                int dist = manhattanCell(a, b);\n\n                long long ev = 0;\n                ev += 100000LL * ca;\n                ev += 170LL * sa;\n                ev -= 460LL * oldGain;\n                ev += 11500LL * oldLen;\n                ev -= 1200LL * dist;\n                ev += rng.nextInt(65000);\n\n                opts.push_back({i, j, ev});\n            }\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(18, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const Opt& a, const Opt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(7, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildSegmentReroute(path, score, bits, opts[t].i, opts[t].j, stopTime)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void augmentReroutes(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int success = 0;\n        int fail = 0;\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && success < 8) {\n            if (trySegmentRerouteOnce(path, score, bits, stopTime)) {\n                success++;\n                fail = 0;\n                augmentRectangles(path, score, bits, min(stopTime, timer.elapsed() + 0.006));\n            } else {\n                fail++;\n                if (fail >= 2) break;\n            }\n        }\n    }\n\n    // ---------- Beam detour / reroute ----------\n\n    struct DetourResult {\n        vector<int> cells;\n        int gain = -1;\n    };\n\n    DetourResult beamDetourSearch(\n        const Bits& baseBits,\n        int start,\n        int target,\n        int maxLen,\n        double stopTime,\n        int oldGain,\n        int width,\n        bool segmentMode\n    ) {\n        DetourResult res;\n        if (maxLen <= 0) return res;\n\n        struct Node {\n            int parent;\n            int cell;\n        };\n\n        struct State {\n            Bits bits;\n            int pos;\n            int gain;\n            int node;\n            int len;\n            long long eval;\n        };\n\n        vector<Node> nodes;\n        nodes.reserve(width * maxLen * 3 + 16);\n\n        vector<State> cur, cand;\n        cur.reserve(width);\n        cand.reserve(width * 4 + 8);\n\n        State init;\n        init.bits = baseBits;\n        init.pos = start;\n        init.gain = 0;\n        init.node = -1;\n        init.len = 0;\n        init.eval = 0;\n        cur.push_back(init);\n\n        int bestGain = oldGain;\n        int bestNode = -1;\n        int bestLen = 0;\n\n        for (int depth = 0; depth < maxLen && !cur.empty(); depth++) {\n            if (timer.elapsed() >= stopTime || timer.elapsed() >= TL) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                if (st.len > 0 && adjacentCell(st.pos, target)) {\n                    if (st.gain > bestGain || (st.gain == bestGain && st.len > bestLen)) {\n                        bestGain = st.gain;\n                        bestNode = st.node;\n                        bestLen = st.len;\n                    }\n                }\n\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    if (nb == target) continue;\n\n                    int tid = tile[nb];\n                    if (bitTest(st.bits, tid)) continue;\n\n                    int newLen = st.len + 1;\n                    int dist = manhattanCell(nb, target);\n\n                    if (dist - 1 > maxLen - newLen) continue;\n\n                    State ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.pos = nb;\n                    ch.gain = st.gain + val[nb];\n                    ch.len = newLen;\n\n                    nodes.push_back({st.node, nb});\n                    ch.node = (int)nodes.size() - 1;\n\n                    int deg = countFreeForInsert(ch.bits, nb, target);\n                    int loc = sumFreeForInsert(ch.bits, nb, target);\n\n                    long long ev = 0;\n                    ev += 1000LL * ch.gain;\n                    ev += 4LL * loc;\n                    ev -= 220LL * deg;\n                    ev -= 7LL * borderDist[nb];\n\n                    if (newLen * 3 < maxLen * 2) {\n                        ev += (segmentMode ? 18LL : 26LL) * dist;\n                    } else {\n                        ev -= (segmentMode ? 80LL : 95LL) * dist;\n                    }\n\n                    if (adjacentCell(nb, target)) {\n                        if (ch.gain > bestGain || (ch.gain == bestGain && ch.len > bestLen)) {\n                            bestGain = ch.gain;\n                            bestNode = ch.node;\n                            bestLen = ch.len;\n                        }\n\n                        if (ch.gain <= oldGain + 100) ev -= 2500;\n                        else ev += 1200;\n                    }\n\n                    ev += rng.nextInt(4500);\n                    ch.eval = ev;\n\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const State& a, const State& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            cur.swap(cand);\n        }\n\n        if (bestGain <= oldGain || bestNode < 0) return res;\n\n        vector<int> rev;\n        int x = bestNode;\n        while (x != -1) {\n            rev.push_back(nodes[x].cell);\n            x = nodes[x].parent;\n        }\n        reverse(rev.begin(), rev.end());\n\n        res.cells = std::move(rev);\n        res.gain = bestGain;\n        return res;\n    }\n\n    bool buildBeamDetourForEdge(vector<int>& path, int& score, Bits& bits, int edgeIdx, double stopTime) {\n        int L = (int)path.size();\n        if (edgeIdx < 0 || edgeIdx + 1 >= L) return false;\n        if (L >= M) return false;\n\n        int a = path[edgeIdx];\n        int target = path[edgeIdx + 1];\n\n        int maxLen = min(M - L, 55 + rng.nextInt(55));\n        int width = 18 + rng.nextInt(10);\n\n        DetourResult dr = beamDetourSearch(bits, a, target, maxLen, stopTime, 0, width, false);\n\n        if (dr.gain <= 0 || dr.cells.empty()) return false;\n        if (!adjacentCell(a, dr.cells.front())) return false;\n        if (!adjacentCell(dr.cells.back(), target)) return false;\n\n        Bits check = bits;\n        for (int c : dr.cells) {\n            int tid = tile[c];\n            if (bitTest(check, tid)) return false;\n            bitSet(check, tid);\n        }\n\n        bits = check;\n        path.insert(path.begin() + edgeIdx + 1, dr.cells.begin(), dr.cells.end());\n        score += dr.gain;\n\n        return true;\n    }\n\n    bool tryBeamDetourInsertionOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L >= M) return false;\n\n        struct EdgeOpt {\n            int idx;\n            long long ev;\n        };\n\n        vector<EdgeOpt> opts;\n        opts.reserve(L);\n\n        for (int i = 0; i + 1 < L; i++) {\n            int a = path[i];\n            int b = path[i + 1];\n\n            int ca = countUnvisitedMoves(bits, a);\n            int cb = countUnvisitedMoves(bits, b);\n            if (ca == 0 || cb == 0) continue;\n\n            int sa = sumUnvisitedMoveValues(bits, a);\n            int sb = sumUnvisitedMoveValues(bits, b);\n\n            long long ev = 0;\n            ev += 150000LL * min(ca, cb);\n            ev += 190LL * (sa + sb);\n            ev += rng.nextInt(70000);\n\n            opts.push_back({i, ev});\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(12, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const EdgeOpt& a, const EdgeOpt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const EdgeOpt& a, const EdgeOpt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(5, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildBeamDetourForEdge(path, score, bits, opts[t].idx, stopTime)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    bool buildBeamSegmentReroute(vector<int>& path, int& score, Bits& bits, int i, int j, double stopTime) {\n        int L = (int)path.size();\n        if (i < 0 || j >= L || j <= i + 1) return false;\n\n        int oldLen = j - i - 1;\n        if (oldLen <= 0) return false;\n\n        Bits base = bits;\n        int oldGain = 0;\n\n        for (int k = i + 1; k < j; k++) {\n            bitClear(base, tile[path[k]]);\n            oldGain += val[path[k]];\n        }\n\n        int capacity = M - (L - oldLen);\n        if (capacity <= 0) return false;\n\n        int a = path[i];\n        int target = path[j];\n\n        int maxLen = min(capacity, oldLen + 55 + rng.nextInt(60));\n        int width = 18 + rng.nextInt(12);\n\n        DetourResult dr = beamDetourSearch(base, a, target, maxLen, stopTime, oldGain, width, true);\n\n        if (dr.gain <= oldGain || dr.cells.empty()) return false;\n        if (!adjacentCell(a, dr.cells.front())) return false;\n        if (!adjacentCell(dr.cells.back(), target)) return false;\n\n        Bits check = base;\n        for (int c : dr.cells) {\n            int tid = tile[c];\n            if (bitTest(check, tid)) return false;\n            bitSet(check, tid);\n        }\n\n        bits = check;\n        score += dr.gain - oldGain;\n\n        path.erase(path.begin() + i + 1, path.begin() + j);\n        path.insert(path.begin() + i + 1, dr.cells.begin(), dr.cells.end());\n\n        return true;\n    }\n\n    bool tryBeamSegmentRerouteOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L < 4) return false;\n\n        struct Opt {\n            int i;\n            int j;\n            long long ev;\n        };\n\n        vector<Opt> opts;\n        opts.reserve(256);\n\n        int maxSpan = 3 + rng.nextInt(16);\n\n        for (int i = 0; i + 2 < L; i++) {\n            int oldGain = 0;\n\n            for (int span = 2; span <= maxSpan && i + span < L; span++) {\n                oldGain += val[path[i + span - 1]];\n\n                int j = i + span;\n                int oldLen = span - 1;\n\n                int a = path[i];\n                int b = path[j];\n\n                int releasedEndVal = val[path[i + 1]];\n                if (j - 1 != i + 1) releasedEndVal += val[path[j - 1]];\n\n                int ca = countUnvisitedMoves(bits, a) + countUnvisitedMoves(bits, b) + (oldLen == 1 ? 1 : 2);\n                int sa = sumUnvisitedMoveValues(bits, a) + sumUnvisitedMoveValues(bits, b) + releasedEndVal;\n                int dist = manhattanCell(a, b);\n\n                long long ev = 0;\n                ev += 115000LL * ca;\n                ev += 185LL * sa;\n                ev -= 500LL * oldGain;\n                ev += 13000LL * oldLen;\n                ev -= 1000LL * dist;\n                ev += rng.nextInt(80000);\n\n                opts.push_back({i, j, ev});\n            }\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(12, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const Opt& a, const Opt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(5, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildBeamSegmentReroute(path, score, bits, opts[t].i, opts[t].j, stopTime)) {\n                return true;\n            }\n        }\n\n        return false;\n    }\n\n    void augmentBeamLocal(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int success = 0;\n        int fail = 0;\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && success < 5) {\n            bool ok = false;\n\n            if ((int)path.size() < M && rng.nextInt(100) < 42) {\n                ok = tryBeamDetourInsertionOnce(path, score, bits, stopTime);\n                if (!ok && timer.elapsed() < stopTime) {\n                    ok = tryBeamSegmentRerouteOnce(path, score, bits, stopTime);\n                }\n            } else {\n                ok = tryBeamSegmentRerouteOnce(path, score, bits, stopTime);\n                if (!ok && (int)path.size() < M && timer.elapsed() < stopTime) {\n                    ok = tryBeamDetourInsertionOnce(path, score, bits, stopTime);\n                }\n            }\n\n            if (ok) {\n                success++;\n                fail = 0;\n                augmentRectangles(path, score, bits, min(stopTime, timer.elapsed() + 0.006));\n            } else {\n                fail++;\n                if (fail >= 3) break;\n            }\n        }\n    }\n\n    void augmentPathLocal(vector<int>& path, int& score, double stopTime) {\n        if (path.empty()) return;\n\n        path.reserve(V);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        double start = timer.elapsed();\n        double budget = max(0.0, stopTime - start);\n\n        augmentRectangles(path, score, bits, min(stopTime, start + min(0.018, budget * 0.12)));\n\n        if (timer.elapsed() < stopTime) {\n            augmentDetours(path, score, bits, min(stopTime, start + budget * 0.46));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentReroutes(path, score, bits, min(stopTime, start + budget * 0.68));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentBeamLocal(path, score, bits, min(stopTime, start + budget * 0.88));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentDetours(path, score, bits, min(stopTime, start + budget * 0.97));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentRectangles(path, score, bits, stopTime);\n        }\n    }\n\n    void finalAugment(double budget) {\n        if (budget <= 0 || pool.empty()) return;\n\n        double endTime = min(TL, timer.elapsed() + budget);\n\n        vector<PathCand> bases = pool;\n        sort(bases.begin(), bases.end(), [](const PathCand& a, const PathCand& b) {\n            if (a.score != b.score) return a.score > b.score;\n            return a.cells.size() > b.cells.size();\n        });\n\n        int tries = min<int>(4, bases.size());\n\n        for (int i = 0; i < tries && timer.elapsed() < endTime; i++) {\n            double remain = endTime - timer.elapsed();\n            if (remain <= 0.003) break;\n\n            double slice = remain / (tries - i);\n            if (i == 0) slice *= 1.60;\n\n            double stop = min(endTime, timer.elapsed() + slice);\n\n            vector<int> path = bases[i].cells;\n            int score = bases[i].score;\n\n            augmentPathLocal(path, score, stop);\n\n            if (validatePath(path)) {\n                addCandidate(path, score);\n            }\n        }\n\n        if (timer.elapsed() < endTime - 0.004 && !pool.empty()) {\n            runPosaFromBase(pool[0].cells, pool[0].cum, (int)pool[0].cells.size() - 1, endTime - timer.elapsed());\n        }\n    }\n\n    struct BeamNode {\n        int parent;\n        int cell;\n        int score;\n    };\n\n    struct BeamState {\n        Bits bits;\n        int pos;\n        int prev;\n        int score;\n        int node;\n        long long eval;\n    };\n\n    void runBeam(double endTime, int width) {\n        if (timer.elapsed() >= endTime) return;\n\n        vector<BeamNode> nodes;\n        nodes.reserve(width * 1200);\n\n        vector<BeamState> cur, nxt, cand;\n        cur.reserve(width);\n        nxt.reserve(width);\n        cand.reserve(width * 4 + 10);\n\n        BeamState init;\n        init.bits.fill(0);\n        bitSet(init.bits, tile[startCell]);\n        init.pos = startCell;\n        init.prev = -1;\n        init.score = val[startCell];\n        init.node = 0;\n        init.eval = init.score;\n\n        nodes.push_back({-1, startCell, val[startCell]});\n        cur.push_back(init);\n\n        int localBestScore = val[startCell];\n        int localBestNode = 0;\n\n        int degBias = -120 + rng.nextInt(241);\n        int noise = 2000 + rng.nextInt(4000);\n\n        for (int depth = 0; depth < M && !cur.empty(); depth++) {\n            if (timer.elapsed() >= endTime) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    int tid = tile[nb];\n\n                    if (bitTest(st.bits, tid)) continue;\n\n                    BeamState ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.prev = st.pos;\n                    ch.pos = nb;\n                    ch.score = st.score + val[nb];\n                    ch.node = st.node;\n\n                    int deg = degreeAfterBits(st.bits, nb, tid);\n                    int loc = localSumAfterBits(st.bits, nb, tid);\n\n                    long long ev = 1LL * ch.score * 100;\n                    ev += 3LL * loc;\n                    ev += 1LL * degBias * deg;\n                    ev -= 10LL * borderDist[nb];\n\n                    if (deg == 0) ev -= 4000;\n                    ev += rng.nextInt(noise);\n\n                    ch.eval = ev;\n                    cand.push_back(ch);\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            nxt.clear();\n\n            for (auto& ch : cand) {\n                int parent = ch.node;\n                nodes.push_back({parent, ch.pos, ch.score});\n                ch.node = (int)nodes.size() - 1;\n\n                if (ch.score > localBestScore) {\n                    localBestScore = ch.score;\n                    localBestNode = ch.node;\n                }\n\n                nxt.push_back(std::move(ch));\n            }\n\n            cur.swap(nxt);\n        }\n\n        if (localBestScore + 2500 >= bestScore) {\n            vector<int> cells;\n            int x = localBestNode;\n            while (x != -1) {\n                cells.push_back(nodes[x].cell);\n                x = nodes[x].parent;\n            }\n            reverse(cells.begin(), cells.end());\n            addCandidate(cells, localBestScore);\n        }\n\n        if (!cur.empty() && timer.elapsed() < endTime + 0.08) {\n            int take = min<int>(20, cur.size());\n\n            if ((int)cur.size() > take) {\n                nth_element(\n                    cur.begin(),\n                    cur.begin() + take,\n                    cur.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.score > b.score;\n                    }\n                );\n            }\n\n            cur.resize(take);\n\n            for (auto& st : cur) {\n                if (timer.elapsed() > endTime + 0.10) break;\n\n                vector<int> prefix;\n                int x = st.node;\n                while (x != -1) {\n                    prefix.push_back(nodes[x].cell);\n                    x = nodes[x].parent;\n                }\n                reverse(prefix.begin(), prefix.end());\n\n                Params p = makePilotParam();\n                Bits b = st.bits;\n                vector<int> suffix;\n                suffix.reserve(1000);\n\n                int sc = rolloutScore(b, st.prev, st.pos, st.score, p, &suffix);\n\n                if (sc + 2500 >= bestScore) {\n                    vector<int> full = prefix;\n                    full.insert(full.end(), suffix.begin(), suffix.end());\n                    addCandidate(full, sc);\n                }\n            }\n        }\n    }\n\n    bool validatePath(const vector<int>& cells) const {\n        if (cells.empty()) return false;\n        if (cells[0] != startCell) return false;\n\n        vector<char> used(M, 0);\n\n        for (int i = 0; i < (int)cells.size(); i++) {\n            int c = cells[i];\n            if (c < 0 || c >= V) return false;\n\n            int tid = tile[c];\n            if (used[tid]) return false;\n            used[tid] = 1;\n\n            if (i > 0) {\n                int d = abs(cells[i] - cells[i - 1]);\n                if (!(d == 1 || d == N)) return false;\n                if (d == 1 && cells[i] / N != cells[i - 1] / N) return false;\n            }\n        }\n\n        return true;\n    }\n\n    string cellsToMoves(const vector<int>& cells) const {\n        string s;\n        s.reserve(cells.size());\n\n        for (int i = 1; i < (int)cells.size(); i++) {\n            int d = cells[i] - cells[i - 1];\n\n            if (d == -N) s.push_back('U');\n            else if (d == N) s.push_back('D');\n            else if (d == -1) s.push_back('L');\n            else if (d == 1) s.push_back('R');\n        }\n\n        return s;\n    }\n\n    string solve() {\n        timer.reset();\n\n        pool.clear();\n        bestCells.clear();\n        bestCum.clear();\n        bestScore = -1;\n\n        vector<int> init{startCell};\n        addCandidate(init, val[startCell]);\n\n        curCells.reserve(V);\n\n        for (int i = 0; i < 22 && timer.elapsed() < 0.09; i++) {\n            bool flood = (i % 6 == 0);\n            Params par = makeParams(flood);\n            int sc = runGreedy(0, flood, par);\n            considerCurrent(sc);\n        }\n\n        runBeam(0.23, 280);\n\n        if (!pool.empty() && timer.elapsed() < 0.38) {\n            runPosaFromBase(pool[0].cells, pool[0].cum, (int)pool[0].cells.size() - 1, 0.035);\n        }\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            double e = timer.elapsed();\n\n            if (TL - e < 0.165) {\n                finalAugment(max(0.0, TL - e - 0.004));\n                break;\n            }\n\n            if (pool.empty()) {\n                vector<int> init2{startCell};\n                addCandidate(init2, val[startCell]);\n            }\n\n            int mode = rng.nextInt(100);\n\n            if (e < 0.75) {\n                if (mode < 56) {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (iter <= 8 || base.cells.size() < 2 || rng.nextInt(100) < 32) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 12, 35);\n                    }\n\n                    int variants = (e < 0.60 ? 2 : (rng.nextInt(100) < 35 ? 2 : 1));\n                    bool useReach = rng.nextInt(100) < 16;\n\n                    runPilotBase(base.cells, base.cum, cut, variants, false, useReach);\n                } else if (mode < 72) {\n                    int bi = (rng.nextInt(100) < 68 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 68) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 45);\n\n                    runRotationExtendFromBase(base.cells, base.cum, cut, rng.nextInt(100) < 76);\n                } else if (mode < 82) {\n                    int bi = (rng.nextInt(100) < 75 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 75) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 45);\n\n                    runPosaFromBase(base.cells, base.cum, cut, 0.012 + 0.010 * (rng.nextInt(100) < 35));\n                } else {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int floodProb = 38;\n                    bool flood = (rng.nextInt(100) < floodProb);\n\n                    int cut;\n                    if (iter < 10 || base.cells.size() < 2 || rng.nextInt(100) < 30) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 18, 30);\n                    }\n\n                    Params par = makeParams(flood);\n                    int sc = runGreedyBase(base.cells, base.cum, cut, flood, par);\n                    considerCurrent(sc);\n                }\n            } else {\n                if (mode < 40) {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (base.cells.size() < 2 || rng.nextInt(100) < 26) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 10, 40);\n                    }\n\n                    int variants = (rng.nextInt(100) < 30 ? 2 : 1);\n                    bool allowPosa = (rng.nextInt(100) < 18);\n                    bool useReach = rng.nextInt(100) < 12;\n\n                    runPilotBase(base.cells, base.cum, cut, variants, allowPosa, useReach);\n                } else if (mode < 66) {\n                    int bi = (rng.nextInt(100) < 62 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 62) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 3, 45);\n\n                    runRotationExtendFromBase(base.cells, base.cum, cut, rng.nextInt(100) < 78);\n                } else if (mode < 86) {\n                    int bi = (rng.nextInt(100) < 80 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 80) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 40);\n\n                    runPosaFromBase(base.cells, base.cum, cut, 0.018 + 0.020 * (rng.nextInt(100) < 40));\n                } else {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int floodProb = 52;\n                    bool flood = (rng.nextInt(100) < floodProb);\n\n                    int cut;\n                    if (base.cells.size() < 2 || rng.nextInt(100) < 28) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 15, 35);\n                    }\n\n                    Params par = makeParams(flood);\n                    int sc = runGreedyBase(base.cells, base.cum, cut, flood, par);\n                    considerCurrent(sc);\n                }\n            }\n\n            iter++;\n        }\n\n        if (!validatePath(bestCells)) {\n            bool found = false;\n            for (auto& pc : pool) {\n                if (validatePath(pc.cells)) {\n                    bestCells = pc.cells;\n                    bestCum = pc.cum;\n                    bestScore = pc.score;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) return \"\";\n        }\n\n        return cellsToMoves(bestCells);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read();\n\n    cout << solver.solve() << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\n\nstatic constexpr int LINE_VARS = 2 * N;\n\nstatic constexpr int BINS = 4;\nstatic constexpr int HBIN_VARS = N * BINS;\nstatic constexpr int BIN_VARS = 2 * N * BINS;\n\nstatic constexpr int SEG_VARS = 2 * LINE_VARS;\n\nstatic constexpr int FINE_BINS = 6;\nstatic constexpr int HFINE_VARS = N * FINE_BINS;\nstatic constexpr int FINE_VARS = 2 * N * FINE_BINS;\n\nstatic constexpr int EXPLORE_TURNS = 100;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    return min(hi, max(lo, x));\n}\n\nstatic inline int popcnt(uint32_t x) {\n    return __builtin_popcount(x);\n}\n\nstatic inline uint32_t lowMask(int x) {\n    if (x <= 0) return 0;\n    return (1u << x) - 1u;\n}\n\nstruct RidgeModel {\n    int n;\n    vector<double> ata;\n    vector<double> atb;\n\n    RidgeModel(int n_ = 0) : n(n_), ata(n_ * n_, 0.0), atb(n_, 0.0) {}\n\n    void addObservation(const vector<pair<int, int>>& counts, int steps, double result) {\n        if (steps <= 0) return;\n\n        vector<pair<int, double>> f;\n        f.reserve(counts.size());\n\n        double inv_steps = 1.0 / steps;\n        for (auto [idx, cnt] : counts) {\n            if (cnt > 0) f.push_back({idx, cnt * inv_steps});\n        }\n\n        double target = result * inv_steps;\n\n        for (auto [ia, va] : f) {\n            double* row = &ata[ia * n];\n            atb[ia] += va * target;\n            for (auto [ib, vb] : f) {\n                row[ib] += va * vb;\n            }\n        }\n    }\n\n    void solve(const vector<double>& prior, double lambda, vector<double>& out) const {\n        vector<double> a = ata;\n        vector<double> b(n);\n\n        for (int i = 0; i < n; i++) {\n            a[i * n + i] += lambda;\n            b[i] = atb[i] + lambda * prior[i];\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j <= i; j++) {\n                double sum = a[i * n + j];\n                for (int k = 0; k < j; k++) {\n                    sum -= a[i * n + k] * a[j * n + k];\n                }\n\n                if (i == j) {\n                    if (sum < 1e-9) sum = 1e-9;\n                    a[i * n + j] = sqrt(sum);\n                } else {\n                    a[i * n + j] = sum / a[j * n + j];\n                }\n            }\n        }\n\n        vector<double> y(n);\n        for (int i = 0; i < n; i++) {\n            double sum = b[i];\n            for (int k = 0; k < i; k++) sum -= a[i * n + k] * y[k];\n            y[i] = sum / a[i * n + i];\n        }\n\n        out.assign(n, 0.0);\n        for (int i = n - 1; i >= 0; i--) {\n            double sum = y[i];\n            for (int k = i + 1; k < n; k++) sum -= a[k * n + i] * out[k];\n            out[i] = sum / a[i * n + i];\n            out[i] = clampd(out[i], 1000.0, 9000.0);\n        }\n    }\n};\n\nstruct Observation {\n    int result = 0;\n    int steps = 0;\n    array<uint32_t, LINE_VARS> mask;\n\n    Observation() {\n        mask.fill(0);\n    }\n};\n\nstruct Solver {\n    RidgeModel lineModel;\n    RidgeModel binModel;\n    RidgeModel fineModel;\n\n    vector<double> lineEst;\n    vector<double> binDelta;\n    vector<double> segEst;\n    vector<double> fineDelta;\n\n    array<int, LINE_VARS> lineSeen{};\n    array<int, BIN_VARS> binSeen{};\n    array<int, FINE_VARS> fineSeen{};\n    array<int, LINE_VARS> split{};\n    array<int, SEG_VARS> segSupport{};\n\n    vector<Observation> observations;\n\n    mt19937 rng;\n    int turn = 0;\n\n    double segGlobalConf = 0.0;\n\n    bool fineReady = false;\n    double fineValidationConf = 1.0;\n    deque<pair<double, double>> fineValidationWindow;\n\n    Solver()\n        : lineModel(LINE_VARS),\n          binModel(BIN_VARS),\n          fineModel(FINE_VARS),\n          lineEst(LINE_VARS, 5000.0),\n          binDelta(BIN_VARS, 0.0),\n          segEst(SEG_VARS, 5000.0),\n          fineDelta(FINE_VARS, 0.0),\n          rng(1234567) {\n        lineSeen.fill(0);\n        binSeen.fill(0);\n        fineSeen.fill(0);\n        split.fill(14);\n        segSupport.fill(0);\n    }\n\n    static int hVar(int i, int j) {\n        int q = j * BINS / (N - 1);\n        return i * BINS + q;\n    }\n\n    static int vVar(int i, int j) {\n        int q = i * BINS / (N - 1);\n        return HBIN_VARS + j * BINS + q;\n    }\n\n    static int fineHVar(int i, int j) {\n        int q = j * FINE_BINS / (N - 1);\n        return i * FINE_BINS + q;\n    }\n\n    static int fineVVar(int i, int j) {\n        int q = i * FINE_BINS / (N - 1);\n        return HFINE_VARS + j * FINE_BINS + q;\n    }\n\n    double globalWeight() const {\n        return clampd(turn / 300.0, 0.0, 1.0);\n    }\n\n    double binWeight() const {\n        return clampd((turn - 80) / 420.0, 0.0, 1.0);\n    }\n\n    double segmentWeight() const {\n        double t = clampd((turn - 110) / 390.0, 0.0, 1.0);\n        return t * segGlobalConf;\n    }\n\n    double fineWeight() const {\n        double t = clampd((turn - 300) / 500.0, 0.0, 1.0);\n        return 0.40 * t * fineValidationConf;\n    }\n\n    double rawStructH(int i, int j) const {\n        int line = i;\n        int bv = hVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (j < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        return clampd(raw, 1000.0, 9000.0);\n    }\n\n    double rawStructV(int i, int j) const {\n        int line = N + j;\n        int bv = vVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (i < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        return clampd(raw, 1000.0, 9000.0);\n    }\n\n    double hCostNoFine(int i, int j) const {\n        double raw = rawStructH(i, j);\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCostNoFine(int i, int j) const {\n        double raw = rawStructV(i, j);\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double hCost(int i, int j) const {\n        double raw = rawStructH(i, j);\n\n        if (fineReady) {\n            int fv = fineHVar(i, j);\n            double seenConf = clampd((fineSeen[fv] - 3.0) / 12.0, 0.0, 1.0);\n            double fw = fineWeight() * seenConf;\n            raw = clampd(raw + fw * fineDelta[fv], 1000.0, 9000.0);\n        }\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCost(int i, int j) const {\n        double raw = rawStructV(i, j);\n\n        if (fineReady) {\n            int fv = fineVVar(i, j);\n            double seenConf = clampd((fineSeen[fv] - 3.0) / 12.0, 0.0, 1.0);\n            double fw = fineWeight() * seenConf;\n            raw = clampd(raw + fw * fineDelta[fv], 1000.0, 9000.0);\n        }\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    static void appendVertical(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    }\n\n    static void appendHorizontal(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    }\n\n    string makeDirect(int si, int sj, int ti, int tj, bool horizontalFirst) const {\n        string s;\n        if (horizontalFirst) {\n            appendHorizontal(s, sj, tj);\n            appendVertical(s, si, ti);\n        } else {\n            appendVertical(s, si, ti);\n            appendHorizontal(s, sj, tj);\n        }\n        return s;\n    }\n\n    string makeViaRow(int si, int sj, int ti, int tj, int r) const {\n        string s;\n        appendVertical(s, si, r);\n        appendHorizontal(s, sj, tj);\n        appendVertical(s, r, ti);\n        return s;\n    }\n\n    string makeViaCol(int si, int sj, int ti, int tj, int c) const {\n        string s;\n        appendHorizontal(s, sj, c);\n        appendVertical(s, si, ti);\n        appendHorizontal(s, c, tj);\n        return s;\n    }\n\n    bool validatePath(int si, int sj, int ti, int tj, const string& path) const {\n        array<char, N * N> vis{};\n        int r = si, c = sj;\n        vis[r * N + c] = 1;\n\n        for (char ch : path) {\n            if (ch == 'U') r--;\n            else if (ch == 'D') r++;\n            else if (ch == 'L') c--;\n            else if (ch == 'R') c++;\n            else return false;\n\n            if (r < 0 || r >= N || c < 0 || c >= N) return false;\n\n            int id = r * N + c;\n            if (vis[id]) return false;\n            vis[id] = 1;\n        }\n\n        return r == ti && c == tj;\n    }\n\n    double estimatePathCost(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCost(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCost(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCost(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCost(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double estimatePathCostNoFine(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCostNoFine(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCostNoFine(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCostNoFine(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCostNoFine(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double explorationSeenScore(int si, int sj, const string& path) const {\n        array<char, LINE_VARS> lu{};\n        array<char, BIN_VARS> bu{};\n\n        int r = si, c = sj;\n\n        for (char ch : path) {\n            int line = -1, bv = -1;\n\n            if (ch == 'R') {\n                line = r;\n                bv = hVar(r, c);\n                c++;\n            } else if (ch == 'L') {\n                c--;\n                line = r;\n                bv = hVar(r, c);\n            } else if (ch == 'D') {\n                line = N + c;\n                bv = vVar(r, c);\n                r++;\n            } else if (ch == 'U') {\n                r--;\n                line = N + c;\n                bv = vVar(r, c);\n            }\n\n            if (line >= 0) lu[line] = 1;\n            if (bv >= 0) bu[bv] = 1;\n        }\n\n        double score = 0.0;\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lu[i]) score += lineSeen[i];\n        }\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (bu[i]) score += 0.35 * binSeen[i];\n        }\n\n        return score;\n    }\n\n    string chooseBestDirect(int si, int sj, int ti, int tj) const {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        return (c1 <= c2 ? p1 : p2);\n    }\n\n    string chooseExplorationPath(int si, int sj, int ti, int tj) {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        double s1 = explorationSeenScore(si, sj, p1);\n        double s2 = explorationSeenScore(si, sj, p2);\n\n        double bonus = 1500.0 * (1.0 - turn / double(EXPLORE_TURNS));\n\n        double v1 = c1 + bonus * s1;\n        double v2 = c2 + bonus * s2;\n\n        if (abs(v1 - v2) < 1e-9) {\n            return (rng() & 1) ? p1 : p2;\n        }\n        return (v1 <= v2 ? p1 : p2);\n    }\n\n    string bestCorridorPath(int si, int sj, int ti, int tj) const {\n        string best;\n        double bestCost = 1e100;\n\n        auto consider = [&](const string& p) {\n            if (!validatePath(si, sj, ti, tj, p)) return;\n\n            double c = estimatePathCost(si, sj, p);\n            if (c < bestCost - 1e-9 ||\n                (abs(c - bestCost) < 1e-9 && (best.empty() || p.size() < best.size()))) {\n                bestCost = c;\n                best = p;\n            }\n        };\n\n        consider(makeDirect(si, sj, ti, tj, true));\n        consider(makeDirect(si, sj, ti, tj, false));\n\n        for (int r = 0; r < N; r++) {\n            consider(makeViaRow(si, sj, ti, tj, r));\n        }\n        for (int c = 0; c < N; c++) {\n            consider(makeViaCol(si, sj, ti, tj, c));\n        }\n\n        if (best.empty()) best = chooseBestDirect(si, sj, ti, tj);\n        return best;\n    }\n\n    string dijkstra(int si, int sj, int ti, int tj, bool useFine) const {\n        int S = si * N + sj;\n        int T = ti * N + tj;\n\n        const double INF = 1e100;\n        vector<double> dist(N * N, INF);\n        vector<int> pre(N * N, -1);\n        vector<char> pmove(N * N, 0);\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[S] = 0.0;\n        pre[S] = S;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n\n            if (d > dist[u] + 1e-9) continue;\n            if (u == T) break;\n\n            int r = u / N;\n            int c = u % N;\n\n            int dirs[4];\n            bool used[4] = {};\n            int m = 0;\n\n            auto addDir = [&](int x) {\n                if (!used[x]) {\n                    used[x] = true;\n                    dirs[m++] = x;\n                }\n            };\n\n            if (ti < r) addDir(0);\n            if (ti > r) addDir(1);\n            if (tj < c) addDir(2);\n            if (tj > c) addDir(3);\n            for (int x = 0; x < 4; x++) addDir(x);\n\n            for (int idx = 0; idx < 4; idx++) {\n                int dir = dirs[idx];\n\n                int nr = r, nc = c;\n                char mv = '?';\n                double w = 0.0;\n\n                if (dir == 0) {\n                    if (r == 0) continue;\n                    nr = r - 1;\n                    mv = 'U';\n                    w = useFine ? vCost(r - 1, c) : vCostNoFine(r - 1, c);\n                } else if (dir == 1) {\n                    if (r == N - 1) continue;\n                    nr = r + 1;\n                    mv = 'D';\n                    w = useFine ? vCost(r, c) : vCostNoFine(r, c);\n                } else if (dir == 2) {\n                    if (c == 0) continue;\n                    nc = c - 1;\n                    mv = 'L';\n                    w = useFine ? hCost(r, c - 1) : hCostNoFine(r, c - 1);\n                } else {\n                    if (c == N - 1) continue;\n                    nc = c + 1;\n                    mv = 'R';\n                    w = useFine ? hCost(r, c) : hCostNoFine(r, c);\n                }\n\n                int v = nr * N + nc;\n                double nd = d + w;\n\n                if (nd + 1e-9 < dist[v]) {\n                    dist[v] = nd;\n                    pre[v] = u;\n                    pmove[v] = mv;\n                    pq.push({nd, v});\n                }\n            }\n        }\n\n        if (pre[T] == -1) return \"\";\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmove[cur]);\n            cur = pre[cur];\n            if (cur < 0) return \"\";\n        }\n\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    string choosePath(int si, int sj, int ti, int tj) {\n        if (turn < EXPLORE_TURNS) {\n            return chooseExplorationPath(si, sj, ti, tj);\n        }\n\n        string safe = bestCorridorPath(si, sj, ti, tj);\n        string p = dijkstra(si, sj, ti, tj, true);\n\n        if (p.empty() || !validatePath(si, sj, ti, tj, p)) {\n            return safe;\n        }\n\n        // Conservative fallback: if the fine model selects a route that the\n        // structural model dislikes a lot, use the no-fine route instead.\n        if (fineReady && turn >= 380) {\n            string pn = dijkstra(si, sj, ti, tj, false);\n\n            if (!pn.empty() && validatePath(si, sj, ti, tj, pn)) {\n                double cfP = estimatePathCost(si, sj, p);\n                double csP = estimatePathCostNoFine(si, sj, p);\n                double cfN = estimatePathCost(si, sj, pn);\n                double csN = estimatePathCostNoFine(si, sj, pn);\n\n                double trustFine = clampd(0.70 + 0.22 * fineValidationConf, 0.80, 0.92);\n\n                double scoreP = trustFine * cfP + (1.0 - trustFine) * csP;\n                double scoreN = trustFine * cfN + (1.0 - trustFine) * csN;\n\n                if (scoreN < scoreP * 0.997 && (int)pn.size() <= (int)p.size() + 40) {\n                    p = pn;\n                }\n            }\n        }\n\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        int extraLimit;\n        if (turn < 200) extraLimit = 12;\n        else if (turn < 350) extraLimit = 25;\n        else if (turn < 500) extraLimit = 45;\n        else if (turn < 700) extraLimit = 65;\n        else extraLimit = 80 + int(20.0 * segGlobalConf);\n\n        double cd = estimatePathCost(si, sj, p);\n        double cs = estimatePathCost(si, sj, safe);\n\n        int extra = int(p.size()) - manhattan;\n\n        if (extra > extraLimit) {\n            if ((int)p.size() > manhattan + 130) return safe;\n            if (cd > cs * 0.82) return safe;\n        }\n\n        int lenDiff = int(p.size()) - int(safe.size());\n        if (lenDiff > 30) {\n            double requiredRatio = 1.0 - min(0.08, 0.001 * lenDiff);\n            if (cd > cs * requiredRatio) return safe;\n        }\n\n        return p;\n    }\n\n    void updateFineValidation(int si, int sj, const string& path, int result) {\n        if (!fineReady || turn < 350 || result <= 0) return;\n\n        double ps = estimatePathCostNoFine(si, sj, path);\n        double pf = estimatePathCost(si, sj, path);\n\n        double denom = max(1.0, double(result));\n        double es = (ps - result) / denom;\n        double ef = (pf - result) / denom;\n\n        double es2 = min(0.25, es * es);\n        double ef2 = min(0.25, ef * ef);\n\n        fineValidationWindow.push_back({es2, ef2});\n        if ((int)fineValidationWindow.size() > 220) fineValidationWindow.pop_front();\n\n        if ((int)fineValidationWindow.size() < 120) {\n            fineValidationConf = 1.0;\n            return;\n        }\n\n        double ss = 0.0;\n        double sf = 0.0;\n        for (auto [a, b] : fineValidationWindow) {\n            ss += a;\n            sf += b;\n        }\n\n        ss /= fineValidationWindow.size();\n        sf /= fineValidationWindow.size();\n\n        double worse = sf - ss;\n\n        if (worse <= 0.0008) {\n            fineValidationConf = 1.0;\n        } else {\n            fineValidationConf = clampd(1.0 - (worse - 0.0008) / 0.0030 * 0.45, 0.55, 1.0);\n        }\n    }\n\n    void updateModelsWithResult(int si, int sj, const string& path, int result) {\n        updateFineValidation(si, sj, path, result);\n\n        Observation ob;\n        ob.result = result;\n        ob.steps = (int)path.size();\n\n        array<int, LINE_VARS> lineCnt{};\n        array<int, BIN_VARS> binCnt{};\n        array<int, FINE_VARS> fineCnt{};\n\n        int r = si;\n        int c = sj;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n                int fv = fineHVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                ob.mask[line] |= (1u << pos);\n\n                c++;\n            } else if (ch == 'L') {\n                c--;\n\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n                int fv = fineHVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                ob.mask[line] |= (1u << pos);\n            } else if (ch == 'D') {\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n                int fv = fineVVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                ob.mask[line] |= (1u << pos);\n\n                r++;\n            } else if (ch == 'U') {\n                r--;\n\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n                int fv = fineVVar(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                ob.mask[line] |= (1u << pos);\n            }\n        }\n\n        vector<pair<int, int>> lf;\n        vector<pair<int, int>> bf;\n        vector<pair<int, int>> ff;\n\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lineCnt[i] > 0) {\n                lf.push_back({i, lineCnt[i]});\n                lineSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (binCnt[i] > 0) {\n                bf.push_back({i, binCnt[i]});\n                binSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < FINE_VARS; i++) {\n            if (fineCnt[i] > 0) {\n                ff.push_back({i, fineCnt[i]});\n                fineSeen[i]++;\n            }\n        }\n\n        lineModel.addObservation(lf, ob.steps, result);\n        binModel.addObservation(bf, ob.steps, result);\n        fineModel.addObservation(ff, ob.steps, result);\n\n        observations.push_back(ob);\n    }\n\n    double predictObsSegment(const Observation& ob) const {\n        double sum = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            uint32_t m = ob.mask[line];\n            if (!m) continue;\n\n            int total = popcnt(m);\n            int x = split[line];\n            int cl = popcnt(m & lowMask(x));\n            int cr = total - cl;\n\n            sum += segEst[2 * line] * cl;\n            sum += segEst[2 * line + 1] * cr;\n        }\n\n        return sum / ob.steps;\n    }\n\n    void seedSplitsFromBin() {\n        static const int bounds[3] = {8, 15, 22};\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 2) continue;\n\n            double val[BINS];\n\n            for (int q = 0; q < BINS; q++) {\n                int idx;\n                if (line < N) idx = line * BINS + q;\n                else idx = HBIN_VARS + (line - N) * BINS + q;\n\n                val[q] = lineEst[line] + binDelta[idx];\n            }\n\n            double bestDiff = 0.0;\n            int bestBoundary = split[line];\n\n            for (int q = 0; q + 1 < BINS; q++) {\n                double d = abs(val[q + 1] - val[q]);\n                if (d > bestDiff) {\n                    bestDiff = d;\n                    bestBoundary = bounds[q];\n                }\n            }\n\n            double segDiff = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (bestDiff > 450.0 &&\n                (segDiff < 700.0 || observations.size() < 180)) {\n                split[line] = bestBoundary;\n            }\n        }\n    }\n\n    void solveSegmentRidge(double lambda) {\n        RidgeModel model(SEG_VARS);\n        segSupport.fill(0);\n\n        for (const auto& ob : observations) {\n            vector<pair<int, int>> f;\n            f.reserve(16);\n\n            for (int line = 0; line < LINE_VARS; line++) {\n                uint32_t m = ob.mask[line];\n                if (!m) continue;\n\n                int total = popcnt(m);\n                int x = split[line];\n                int cl = popcnt(m & lowMask(x));\n                int cr = total - cl;\n\n                if (cl > 0) {\n                    f.push_back({2 * line, cl});\n                    segSupport[2 * line] += cl;\n                }\n                if (cr > 0) {\n                    f.push_back({2 * line + 1, cr});\n                    segSupport[2 * line + 1] += cr;\n                }\n            }\n\n            model.addObservation(f, ob.steps, ob.result);\n        }\n\n        vector<double> prior(SEG_VARS);\n        for (int i = 0; i < SEG_VARS; i++) {\n            prior[i] = lineEst[i / 2];\n        }\n\n        model.solve(prior, lambda, segEst);\n    }\n\n    void refineSplits() {\n        int m = (int)observations.size();\n        if (m < 60) return;\n\n        vector<double> pred(m);\n        vector<double> target(m);\n\n        for (int i = 0; i < m; i++) {\n            pred[i] = predictObsSegment(observations[i]);\n            target[i] = observations[i].result / double(observations[i].steps);\n        }\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            double v0 = segEst[2 * line];\n            double v1 = segEst[2 * line + 1];\n\n            if (abs(v0 - v1) < 250.0) continue;\n\n            int active = 0;\n            for (const auto& ob : observations) {\n                if (ob.mask[line]) active++;\n            }\n\n            if (active < 8) continue;\n\n            int oldX = split[line];\n            uint32_t oldMask = lowMask(oldX);\n\n            double bestSSE = 1e100;\n            double oldSSE = 1e100;\n            int bestX = oldX;\n\n            for (int x = 1; x <= 28; x++) {\n                uint32_t xm = lowMask(x);\n                double sse = 0.0;\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    double baseResidualTarget = target[idx] - pred[idx] + oldContr;\n\n                    int newLeft = popcnt(mask & xm);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    double res = baseResidualTarget - newContr;\n                    sse += res * res;\n                }\n\n                if (x == oldX) oldSSE = sse;\n\n                if (sse < bestSSE) {\n                    bestSSE = sse;\n                    bestX = x;\n                }\n            }\n\n            double threshold = max(20000.0, 0.001 * oldSSE);\n\n            if (bestX != oldX && bestSSE + threshold < oldSSE) {\n                uint32_t newMask = lowMask(bestX);\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    int newLeft = popcnt(mask & newMask);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    pred[idx] += newContr - oldContr;\n                }\n\n                split[line] = bestX;\n            }\n        }\n    }\n\n    void updateSegmentConfidence() {\n        int strong = 0;\n        int usable = 0;\n        double sumConf = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 3) continue;\n            if (segSupport[2 * line] < 6) continue;\n            if (segSupport[2 * line + 1] < 6) continue;\n\n            usable++;\n\n            double d = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (d > 900.0) strong++;\n            sumConf += clampd((d - 500.0) / 1500.0, 0.0, 1.0);\n        }\n\n        double c1 = clampd((strong - 4) / 18.0, 0.0, 1.0);\n\n        double c2 = 0.0;\n        if (usable > 0) {\n            double avg = sumConf / usable;\n            c2 = clampd((avg - 0.12) / 0.38, 0.0, 1.0);\n        }\n\n        segGlobalConf = max(c1, 0.8 * c2);\n    }\n\n    double priorFineValue(int line, int q) const {\n        double sum = 0.0;\n        int cnt = 0;\n\n        for (int pos = 0; pos < N - 1; pos++) {\n            int qq = pos * FINE_BINS / (N - 1);\n            if (qq != q) continue;\n\n            if (line < N) {\n                sum += rawStructH(line, pos);\n            } else {\n                int col = line - N;\n                sum += rawStructV(pos, col);\n            }\n            cnt++;\n        }\n\n        if (cnt == 0) return lineEst[line];\n        return sum / cnt;\n    }\n\n    void solveFineModel(int observationsCount) {\n        vector<double> prior(FINE_VARS, 5000.0);\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            for (int q = 0; q < FINE_BINS; q++) {\n                int idx;\n                if (line < N) idx = line * FINE_BINS + q;\n                else idx = HFINE_VARS + (line - N) * FINE_BINS + q;\n\n                prior[idx] = priorFineValue(line, q);\n            }\n        }\n\n        double prog = min(1.0, observationsCount / 900.0);\n        double lambdaFine = 1.05 - 0.45 * prog; // 1.05 -> 0.60\n\n        vector<double> absFine;\n        fineModel.solve(prior, lambdaFine, absFine);\n\n        for (int i = 0; i < FINE_VARS; i++) {\n            fineDelta[i] = clampd(absFine[i] - prior[i], -1300.0, 1300.0);\n        }\n\n        fineReady = true;\n    }\n\n    void solveModels(int observationsCount) {\n        vector<double> priorLine(LINE_VARS, 5000.0);\n        lineModel.solve(priorLine, 0.1, lineEst);\n\n        int binPeriod = (observationsCount < 300 ? 10 : 20);\n        if (observationsCount % binPeriod == 0) {\n            vector<double> priorBin(BIN_VARS);\n\n            for (int i = 0; i < N; i++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[i * BINS + q] = lineEst[i];\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[HBIN_VARS + j * BINS + q] = lineEst[N + j];\n                }\n            }\n\n            double prog = min(1.0, observationsCount / 800.0);\n            double lambdaBin = 1.5 - prog;\n\n            vector<double> absBin;\n            binModel.solve(priorBin, lambdaBin, absBin);\n\n            for (int i = 0; i < BIN_VARS; i++) {\n                binDelta[i] = absBin[i] - priorBin[i];\n            }\n        }\n\n        if (observationsCount >= 80) {\n            int segPeriod = (observationsCount < 300 ? 20 : 30);\n\n            if (observationsCount % segPeriod == 0) {\n                seedSplitsFromBin();\n\n                double prog = min(1.0, observationsCount / 900.0);\n                double lambdaSeg = 0.9 - 0.55 * prog;\n\n                solveSegmentRidge(lambdaSeg);\n                refineSplits();\n                solveSegmentRidge(lambdaSeg);\n                updateSegmentConfidence();\n            }\n        }\n\n        if (observationsCount >= 280 && (observationsCount - 280) % 80 == 0) {\n            solveFineModel(observationsCount);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.turn = k;\n\n        string path = solver.choosePath(si, sj, ti, tj);\n\n        cout << path << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.updateModelsWithResult(si, sj, path, result);\n        solver.solveModels(k + 1);\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int SZ = 20;\nstatic const int CELLS = 400;\nstatic const int POS = 800;\nstatic const int DOT = 8;\nstatic const int MAXPLEN = 20;\nstatic const int MASK_WORDS = 13;\n\nusing Mask = array<uint64_t, MASK_WORDS>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int randint(int n) { return (int)(next() % n); }\n    double drand() { return (next() >> 11) * (1.0 / 9007199254740992.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};\n\nint M_input;\nint U;\nint TOTAL;\ndouble avgLen = 0.0;\nint maxLenInput = 0;\n\nvector<string> uniqStr;\nvector<vector<uint8_t>> S;\nvector<int> Ls, W;\n\nvector<Mask> strMasks;\nvector<vector<int>> strContainsList;\nvector<int> strContainVal;\n\nuint16_t posCell[POS][MAXPLEN];\nvector<uint32_t> cellIncs[CELLS];\n\nint nearVal[13][13];\n\nXorShift rng;\n\ninline int countDotsVec(const vector<uint8_t>& g) {\n    int d = 0;\n    for (auto x : g) if (x == DOT) d++;\n    return d;\n}\n\nvoid initNearVal() {\n    memset(nearVal, 0, sizeof(nearVal));\n    for (int l = 1; l <= 12; l++) {\n        for (int m = 0; m <= l; m++) {\n            int q = l - m;\n            nearVal[l][m] = q * q * q;\n        }\n    }\n}\n\nvoid initPosCells() {\n    for (int pos = 0; pos < POS; pos++) {\n        for (int p = 0; p < MAXPLEN; p++) {\n            if (pos < 400) {\n                int r = pos / SZ;\n                int c = pos % SZ;\n                posCell[pos][p] = r * SZ + (c + p) % SZ;\n            } else {\n                int q = pos - 400;\n                int r = q / SZ;\n                int c = q % SZ;\n                posCell[pos][p] = ((r + p) % SZ) * SZ + c;\n            }\n        }\n    }\n}\n\nvoid buildIncidences() {\n    long long totalInc = 0;\n    for (int i = 0; i < U; i++) totalInc += 1LL * POS * Ls[i];\n    int reserveEach = (int)(totalInc / CELLS + 100);\n    for (int c = 0; c < CELLS; c++) cellIncs[c].reserve(reserveEach);\n\n    for (int sid = 0; sid < U; sid++) {\n        int base = sid * POS;\n        for (int pos = 0; pos < POS; pos++) {\n            int pid = base + pos;\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[pos][p];\n                uint32_t code = (uint32_t(pid) << 3) | uint32_t(S[sid][p]);\n                cellIncs[cell].push_back(code);\n            }\n        }\n    }\n}\n\nstruct State {\n    vector<uint8_t> grid;\n    vector<uint8_t> mism;\n    vector<uint16_t> cover;\n    vector<array<uint16_t, 13>> hist;\n    vector<array<int16_t, 13>> hdelta;\n\n    int obj = 0;\n\n    vector<int> markP, markS;\n    vector<int16_t> deltaM, deltaC;\n    vector<int> touchedP, touchedS;\n    int tagP = 1, tagS = 1;\n\n    void init() {\n        int Ptot = U * POS;\n        grid.assign(CELLS, DOT);\n        mism.assign(Ptot, 0);\n        cover.assign(U, 0);\n        hist.resize(U);\n        hdelta.resize(U);\n        for (auto& a : hist) a.fill(0);\n        for (auto& a : hdelta) a.fill(0);\n\n        markP.assign(Ptot, 0);\n        markS.assign(U, 0);\n        deltaM.assign(Ptot, 0);\n        deltaC.assign(U, 0);\n        touchedP.reserve(250000);\n        touchedS.reserve(U);\n    }\n\n    void nextTagP() {\n        ++tagP;\n        if (tagP == INT_MAX) {\n            fill(markP.begin(), markP.end(), 0);\n            tagP = 1;\n        }\n    }\n\n    void nextTagS() {\n        ++tagS;\n        if (tagS == INT_MAX) {\n            fill(markS.begin(), markS.end(), 0);\n            tagS = 1;\n        }\n    }\n\n    void build(const vector<uint8_t>& g) {\n        grid = g;\n        fill(cover.begin(), cover.end(), 0);\n        obj = 0;\n\n        for (int sid = 0; sid < U; sid++) {\n            hist[sid].fill(0);\n            int base = sid * POS;\n            const auto& str = S[sid];\n            int len = Ls[sid];\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = 0;\n                for (int p = 0; p < len; p++) {\n                    if (grid[posCell[pos][p]] != str[p]) m++;\n                }\n                mism[base + pos] = (uint8_t)m;\n                hist[sid][m]++;\n            }\n\n            cover[sid] = hist[sid][0];\n            if (cover[sid] > 0) obj += W[sid];\n        }\n    }\n\n    int evalChanges(const int cells[], const uint8_t vals[], int cnt) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        auto addSid = [&](int sid, int dc) {\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                deltaC[sid] = 0;\n                touchedS.push_back(sid);\n            }\n            deltaC[sid] += (int16_t)dc;\n        };\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (oldm == 0 && newm > 0) addSid(sid, -1);\n            else if (oldm > 0 && newm == 0) addSid(sid, +1);\n        }\n\n        int delta = 0;\n        for (int sid : touchedS) {\n            int cc = cover[sid];\n            int nc = cc + deltaC[sid];\n            if (cc == 0 && nc > 0) delta += W[sid];\n            else if (cc > 0 && nc == 0) delta -= W[sid];\n        }\n        return delta;\n    }\n\n    long long evalChangesSoft(const int cells[], const uint8_t vals[], int cnt, long long exactBonus) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                hdelta[sid].fill(0);\n                touchedS.push_back(sid);\n            }\n\n            hdelta[sid][oldm]--;\n            hdelta[sid][newm]++;\n        }\n\n        long long exactDelta = 0;\n        long long nearDelta = 0;\n\n        for (int sid : touchedS) {\n            int oldCov = cover[sid];\n            int newCov = hist[sid][0] + hdelta[sid][0];\n\n            if (oldCov == 0 && newCov > 0) exactDelta += W[sid];\n            else if (oldCov > 0 && newCov == 0) exactDelta -= W[sid];\n\n            int len = Ls[sid];\n\n            int oldMin = 0;\n            while (oldMin <= len && hist[sid][oldMin] == 0) oldMin++;\n\n            int newMin = 0;\n            while (newMin <= len && hist[sid][newMin] + hdelta[sid][newMin] <= 0) newMin++;\n\n            nearDelta += 1LL * W[sid] * (nearVal[len][newMin] - nearVal[len][oldMin]);\n\n            int oldRed = min(oldCov, 4);\n            int newRed = min(newCov, 4);\n            nearDelta += 80LL * W[sid] * (newRed - oldRed);\n        }\n\n        return exactDelta * exactBonus + nearDelta;\n    }\n\n    void changeCell(int cell, uint8_t newc) {\n        int oldc = grid[cell];\n        if (oldc == newc) return;\n\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            bool was = (oldc != req);\n            bool now = (newc != req);\n            if (was == now) continue;\n\n            int sid = pid / POS;\n            int m = mism[pid];\n\n            if (!was && now) {\n                hist[sid][m]--;\n                hist[sid][m + 1]++;\n\n                if (m == 0) {\n                    cover[sid]--;\n                    if (cover[sid] == 0) obj -= W[sid];\n                }\n                mism[pid] = (uint8_t)(m + 1);\n            } else {\n                hist[sid][m]--;\n                hist[sid][m - 1]++;\n\n                if (m == 1) {\n                    if (cover[sid] == 0) obj += W[sid];\n                    cover[sid]++;\n                }\n                mism[pid] = (uint8_t)(m - 1);\n            }\n        }\n\n        grid[cell] = newc;\n    }\n\n    void applyChanges(const int cells[], const uint8_t vals[], int cnt) {\n        for (int i = 0; i < cnt; i++) changeCell(cells[i], vals[i]);\n    }\n};\n\nstruct Best {\n    int obj = -1;\n    int dots = 1000000000;\n    vector<uint8_t> grid;\n\n    void consider(const State& st) {\n        int d = countDotsVec(st.grid);\n        bool upd = false;\n        if (st.obj > obj) upd = true;\n        else if (st.obj == obj) {\n            if (st.obj == TOTAL) {\n                if (d > dots) upd = true;\n            } else {\n                if (grid.empty() || d < dots) upd = true;\n            }\n        }\n\n        if (upd) {\n            obj = st.obj;\n            dots = d;\n            grid = st.grid;\n        }\n    }\n};\n\nvector<uint8_t> strToVec(const string& s) {\n    vector<uint8_t> v;\n    v.reserve(s.size());\n    for (char c : s) v.push_back((uint8_t)(c - 'A'));\n    return v;\n}\n\nstring vecToString(const vector<uint8_t>& v) {\n    string s;\n    s.reserve(v.size());\n    for (auto x : v) s.push_back(char('A' + x));\n    return s;\n}\n\nstring mergeLinear(const string& a, const string& b, int& ovOut) {\n    if (a.empty()) {\n        ovOut = 0;\n        return b;\n    }\n    if (b.empty()) {\n        ovOut = 0;\n        return a;\n    }\n\n    if (a.find(b) != string::npos) {\n        ovOut = (int)b.size();\n        return a;\n    }\n    if (b.find(a) != string::npos) {\n        ovOut = (int)a.size();\n        return b;\n    }\n\n    int bestOv = -1;\n    string best;\n\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            a.compare(a.size() - ov, ov, b, 0, ov) == 0) {\n            bestOv = ov;\n            best = a + b.substr(ov);\n            break;\n        }\n    }\n\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            b.compare(b.size() - ov, ov, a, 0, ov) == 0) {\n            if (ov > bestOv) {\n                bestOv = ov;\n                best = b + a.substr(ov);\n            }\n            break;\n        }\n    }\n\n    if (bestOv >= 0) {\n        ovOut = bestOv;\n        return best;\n    }\n\n    if ((int)a.size() + (int)b.size() <= MAXPLEN) {\n        ovOut = 0;\n        return a + b;\n    }\n\n    ovOut = -1;\n    return \"\";\n}\n\nint directedOverlap(const string& a, const string& b) {\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov > MAXPLEN) continue;\n        if (a.compare(a.size() - ov, ov, b, 0, ov) == 0) return ov;\n    }\n    return -1;\n}\n\nbool containsInSegment(const string& seg, const string& sub) {\n    if ((int)sub.size() > MAXPLEN) return false;\n    if ((int)seg.size() == SZ) {\n        string t = seg + seg.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    } else {\n        if (sub.size() > seg.size()) return false;\n        return seg.find(sub) != string::npos;\n    }\n}\n\nbool lineContains(const string& line, const string& sub) {\n    if (line.empty()) return false;\n    if ((int)line.size() == SZ) {\n        string t = line + line.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    }\n    if (sub.size() > line.size()) return false;\n    return line.find(sub) != string::npos;\n}\n\nvoid buildStringContainMasks() {\n    strMasks.assign(U, Mask{});\n    strContainsList.assign(U, {});\n    strContainVal.assign(U, 0);\n    for (int i = 0; i < U; i++) {\n        strMasks[i].fill(0);\n        for (int j = 0; j < U; j++) {\n            if (containsInSegment(uniqStr[i], uniqStr[j])) {\n                strContainsList[i].push_back(j);\n                strContainVal[i] += W[j];\n                strMasks[i][j >> 6] |= 1ULL << (j & 63);\n            }\n        }\n    }\n}\n\nstruct Segment {\n    vector<uint8_t> ch;\n    int val;\n    vector<int> contains;\n    Mask mask;\n};\n\nvector<Segment> generateSegments() {\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    unordered_set<string> seen;\n    seen.reserve(50000);\n    vector<string> cands;\n    cands.reserve(30000);\n\n    const size_t CAND_CAP = 42000;\n\n    auto addCand = [&](const string& x) {\n        if (x.size() < 2 || x.size() > MAXPLEN) return;\n        if (seen.size() >= CAND_CAP) return;\n        if (seen.insert(x).second) cands.push_back(x);\n    };\n\n    for (int id : ids) addCand(uniqStr[id]);\n\n    int minOv;\n    if (avgLen >= 8.0) minOv = 4;\n    else if (avgLen >= 6.0) minOv = 3;\n    else minOv = 2;\n\n    {\n        vector<string> segs;\n        for (int id : ids) {\n            const string& s = uniqStr[id];\n            bool contained = false;\n            int bestIdx = -1;\n            int bestOv = -1;\n            string bestMerged;\n\n            for (int i = 0; i < (int)segs.size(); i++) {\n                if (segs[i].find(s) != string::npos) {\n                    contained = true;\n                    break;\n                }\n\n                int ov;\n                string merged = mergeLinear(segs[i], s, ov);\n                if (!merged.empty() && (int)merged.size() <= MAXPLEN && ov > bestOv) {\n                    bestOv = ov;\n                    bestIdx = i;\n                    bestMerged = merged;\n                }\n            }\n\n            if (contained) continue;\n\n            if (bestIdx != -1 && bestOv >= minOv) {\n                segs[bestIdx] = bestMerged;\n            } else {\n                segs.push_back(s);\n            }\n        }\n        for (auto& x : segs) addCand(x);\n    }\n\n    int pairOv;\n    if (avgLen >= 8.0) pairOv = 4;\n    else if (avgLen >= 6.0) pairOv = 3;\n    else pairOv = 2;\n\n    for (int ai = 0; ai < U && seen.size() < CAND_CAP; ai++) {\n        const string& a = uniqStr[ai];\n        for (int bi = 0; bi < U && seen.size() < CAND_CAP; bi++) {\n            if (ai == bi) continue;\n            const string& b = uniqStr[bi];\n            int ov = directedOverlap(a, b);\n            if (ov >= pairOv) {\n                string m = a + b.substr(ov);\n                addCand(m);\n            }\n        }\n    }\n\n    int seedOv = minOv;\n    int seedLimit = U;\n    for (int si = 0; si < seedLimit && seen.size() < CAND_CAP; si++) {\n        string cur = uniqStr[ids[si]];\n        addCand(cur);\n\n        for (int step = 0; step < 6 && (int)cur.size() < MAXPLEN; step++) {\n            int bestOv = seedOv - 1;\n            int bestScore = -1;\n            string bestMerged;\n\n            for (int tid : ids) {\n                const string& t = uniqStr[tid];\n                if (cur.find(t) != string::npos) continue;\n\n                int ov;\n                string merged = mergeLinear(cur, t, ov);\n                if (merged.empty() || merged == cur || (int)merged.size() > MAXPLEN) continue;\n                if (ov < seedOv) continue;\n\n                int score = ov * 10000 + W[tid] * 100 + Ls[tid] * 10 + int(rng.next() & 31);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestOv = ov;\n                    bestMerged = merged;\n                }\n            }\n\n            if (bestScore < 0 || bestOv < seedOv) break;\n            cur = bestMerged;\n            addCand(cur);\n        }\n    }\n\n    vector<Segment> res;\n    res.reserve(cands.size());\n\n    for (auto& seg : cands) {\n        int val = 0;\n        vector<int> cont;\n        for (int i = 0; i < U; i++) {\n            if (containsInSegment(seg, uniqStr[i])) {\n                val += W[i];\n                cont.push_back(i);\n            }\n        }\n\n        if (val >= 2) {\n            Segment sg;\n            sg.ch = strToVec(seg);\n            sg.val = val;\n            sg.contains = std::move(cont);\n            sg.mask.fill(0);\n            for (int sid : sg.contains) {\n                sg.mask[sid >> 6] |= 1ULL << (sid & 63);\n            }\n            res.push_back(std::move(sg));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Segment& a, const Segment& b) {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.contains.size() != b.contains.size()) return a.contains.size() > b.contains.size();\n        return a.ch.size() > b.ch.size();\n    });\n\n    int lim = (avgLen >= 7.0 ? 440 : 540);\n    if ((int)res.size() > lim) res.resize(lim);\n    return res;\n}\n\nstruct CItem {\n    int type;\n    int idx;\n    int len;\n    int val;\n    int group;\n    uint32_t rnd;\n};\n\nconst vector<uint8_t>& getItemChars(const CItem& it, const vector<Segment>& segs) {\n    if (it.type == 0) return S[it.idx];\n    return segs[it.idx].ch;\n}\n\nvector<uint8_t> constructGreedy(int mode, const vector<Segment>& segs, Timer& timer, double endTime) {\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<CItem> items;\n\n    if (mode == 1 || mode == 2) {\n        int lim = min((int)segs.size(), avgLen >= 7.0 ? 150 : 220);\n        for (int i = 0; i < lim; i++) {\n            items.push_back({1, i, (int)segs[i].ch.size(), segs[i].val,\n                             mode == 1 ? 0 : 0, (uint32_t)rng.next()});\n        }\n    }\n\n    for (int sid = 0; sid < U; sid++) {\n        int group = (mode == 1 ? 1 : 0);\n        items.push_back({0, sid, Ls[sid], W[sid], group, (uint32_t)rng.next()});\n    }\n\n    sort(items.begin(), items.end(), [&](const CItem& a, const CItem& b) {\n        if (a.group != b.group) return a.group < b.group;\n\n        if (mode == 2) {\n            int sa = a.val * 1000 + a.len * 50 + int(a.rnd & 127);\n            int sb = b.val * 1000 + b.len * 50 + int(b.rnd & 127);\n            return sa > sb;\n        }\n\n        if (a.len != b.len) return a.len > b.len;\n        if (a.val != b.val) return a.val > b.val;\n        return a.rnd < b.rnd;\n    });\n\n    int processed = 0;\n    for (const CItem& it : items) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n\n        const auto& ch = getItemChars(it, segs);\n        int len = (int)ch.size();\n\n        int bestPos = -1;\n        int bestScore = INT_MIN;\n        bool already = false;\n\n        for (int pos = 0; pos < POS; pos++) {\n            int match = 0;\n            bool conflict = false;\n\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[pos][p];\n                int g = grid[cell];\n                if (g == DOT) continue;\n                if (g == ch[p]) match++;\n                else {\n                    conflict = true;\n                    break;\n                }\n            }\n\n            if (!conflict) {\n                if (match == len) {\n                    already = true;\n                    break;\n                }\n\n                int score = match * 10000 - (len - match) * 5 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestPos = pos;\n                }\n            }\n        }\n\n        if (already) continue;\n\n        if (bestPos != -1) {\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n    }\n\n    return grid;\n}\n\nvector<uint8_t> constructRowPack(Timer& timer, double endTime) {\n    vector<string> rows(SZ, \"\");\n\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    vector<uint32_t> rk(U);\n    for (int i = 0; i < U; i++) rk[i] = (uint32_t)rng.next();\n\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        if (W[a] != W[b]) return W[a] > W[b];\n        return rk[a] < rk[b];\n    });\n\n    int processed = 0;\n    for (int sid : ids) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n        const string& s = uniqStr[sid];\n\n        bool covered = false;\n        for (auto& row : rows) {\n            if (lineContains(row, s)) {\n                covered = true;\n                break;\n            }\n        }\n        if (covered) continue;\n\n        int bestR = -1;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        for (int r = 0; r < SZ; r++) {\n            int ov;\n            string merged;\n            if (rows[r].empty()) {\n                ov = 0;\n                merged = s;\n            } else {\n                merged = mergeLinear(rows[r], s, ov);\n            }\n\n            if (merged.empty() || (int)merged.size() > SZ) continue;\n\n            int score = ov * 1000 + (rows[r].empty() ? 0 : 100) - (int)merged.size();\n            if (score > bestScore) {\n                bestScore = score;\n                bestR = r;\n                bestMerged = merged;\n            }\n        }\n\n        if (bestR != -1) rows[bestR] = bestMerged;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nstruct RowCand {\n    string s;\n    vector<int> contains;\n    int val;\n};\n\nvector<uint8_t> constructCoverRows(const vector<Segment>& segments, Timer& timer, double endTime) {\n    unordered_set<string> seen;\n    seen.reserve(2000);\n    vector<string> candStr;\n\n    auto add = [&](const string& s) {\n        if (s.size() < 2 || s.size() > 20) return;\n        if (seen.insert(s).second) candStr.push_back(s);\n    };\n\n    for (const auto& sg : segments) add(vecToString(sg.ch));\n    for (const auto& s : uniqStr) add(s);\n\n    vector<RowCand> cands;\n    cands.reserve(candStr.size());\n\n    for (auto& cs : candStr) {\n        int val = 0;\n        vector<int> cont;\n        for (int sid = 0; sid < U; sid++) {\n            if (containsInSegment(cs, uniqStr[sid])) {\n                val += W[sid];\n                cont.push_back(sid);\n            }\n        }\n        if (val > 0) cands.push_back({cs, std::move(cont), val});\n    }\n\n    sort(cands.begin(), cands.end(), [](const RowCand& a, const RowCand& b) {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.contains.size() != b.contains.size()) return a.contains.size() > b.contains.size();\n        return a.s.size() > b.s.size();\n    });\n\n    int candLimit = avgLen <= 5.0 ? 700 : 520;\n    if ((int)cands.size() > candLimit) cands.resize(candLimit);\n\n    vector<string> rows(SZ, \"\");\n    vector<char> covered(U, 0);\n\n    int moves = 0;\n    while (timer.elapsed() < endTime && moves < 120) {\n        int bestR = -1;\n        int bestC = -1;\n        int bestGain = 0;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        int iterCnt = 0;\n        for (int ci = 0; ci < (int)cands.size(); ci++) {\n            const auto& cd = cands[ci];\n\n            int approxGain = 0;\n            for (int sid : cd.contains) if (!covered[sid]) approxGain += W[sid];\n            if (approxGain <= 0) continue;\n\n            for (int r = 0; r < SZ; r++) {\n                if (((++iterCnt) & 4095) == 0 && timer.elapsed() > endTime) break;\n\n                if ((int)rows[r].size() == SZ) {\n                    if (lineContains(rows[r], cd.s)) continue;\n                    else continue;\n                }\n\n                int ov = 0;\n                string merged = rows[r].empty() ? cd.s : mergeLinear(rows[r], cd.s, ov);\n                if (merged.empty() || (int)merged.size() > SZ) continue;\n\n                int gain = approxGain;\n                int added = (int)merged.size() - (int)rows[r].size();\n                int score = gain * 100000 + ov * 1800 - added * 120 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestGain = gain;\n                    bestR = r;\n                    bestC = ci;\n                    bestMerged = merged;\n                }\n            }\n            if (timer.elapsed() > endTime) break;\n        }\n\n        if (bestR < 0 || bestGain <= 0 || bestC < 0) break;\n\n        rows[bestR] = bestMerged;\n        for (int sid = 0; sid < U; sid++) {\n            if (!covered[sid] && lineContains(rows[bestR], uniqStr[sid])) {\n                covered[sid] = 1;\n            }\n        }\n        moves++;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nvector<uint8_t> constructCoverPlace(const vector<Segment>& segments, Timer& timer, double endTime) {\n    struct PItem {\n        int type; // 0 original, 1 segment\n        int idx;\n        int val;\n        int len;\n    };\n\n    vector<PItem> items;\n    items.reserve(U + segments.size());\n\n    int segLim = min((int)segments.size(), avgLen >= 7.0 ? 280 : 360);\n    for (int i = 0; i < segLim; i++) {\n        items.push_back({1, i, segments[i].val, (int)segments[i].ch.size()});\n    }\n    for (int sid = 0; sid < U; sid++) {\n        items.push_back({0, sid, strContainVal[sid], Ls[sid]});\n    }\n\n    auto getCh = [&](const PItem& it) -> const vector<uint8_t>& {\n        if (it.type == 0) return S[it.idx];\n        return segments[it.idx].ch;\n    };\n\n    auto getCont = [&](const PItem& it) -> const vector<int>& {\n        if (it.type == 0) return strContainsList[it.idx];\n        return segments[it.idx].contains;\n    };\n\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<char> covered(U, 0);\n\n    auto pushTop = [&](vector<pair<long long,int>>& top, long long key, int idx, int lim) {\n        if ((int)top.size() < lim) {\n            top.push_back({key, idx});\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)top.size(); i++) {\n            if (top[i].first < top[wi].first) wi = i;\n        }\n        if (key > top[wi].first) top[wi] = {key, idx};\n    };\n\n    int maxMoves = avgLen <= 5.0 ? 180 : 150;\n\n    for (int step = 0; step < maxMoves && timer.elapsed() < endTime; step++) {\n        const int TOP_ITEMS = 22;\n        vector<pair<long long,int>> top;\n        top.reserve(TOP_ITEMS);\n\n        for (int ii = 0; ii < (int)items.size(); ii++) {\n            if ((ii & 63) == 0 && timer.elapsed() > endTime) break;\n            const auto& it = items[ii];\n            const auto& cont = getCont(it);\n\n            int gain = 0;\n            for (int sid : cont) if (!covered[sid]) gain += W[sid];\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL + 1LL * it.val * 120LL\n                          + 1LL * it.len * 50LL + (long long)(rng.next() & 4095);\n            pushTop(top, key, ii, TOP_ITEMS);\n        }\n\n        if (top.empty()) break;\n\n        int bestItem = -1;\n        int bestPos = -1;\n        int bestCnt = -1;\n        long long bestScore = LLONG_MIN;\n\n        for (auto [_, ii] : top) {\n            const auto& it = items[ii];\n            const auto& ch = getCh(it);\n            const auto& cont = getCont(it);\n            int len = (int)ch.size();\n\n            int gain = 0;\n            for (int sid : cont) if (!covered[sid]) gain += W[sid];\n            if (gain <= 0) continue;\n\n            for (int pos = 0; pos < POS; pos++) {\n                if ((pos & 255) == 0 && timer.elapsed() > endTime) break;\n\n                bool conflict = false;\n                int overlap = 0;\n                int cnt = 0;\n\n                for (int p = 0; p < len; p++) {\n                    int cell = posCell[pos][p];\n                    int g = grid[cell];\n                    if (g == DOT) {\n                        cnt++;\n                    } else if (g == ch[p]) {\n                        overlap++;\n                    } else {\n                        conflict = true;\n                        break;\n                    }\n                }\n\n                if (conflict) continue;\n\n                long long score = 1LL * gain * 1000000LL\n                                + 1LL * overlap * 5000LL\n                                - 1LL * cnt * 250LL\n                                + 1LL * it.len * 20LL\n                                + (long long)(rng.next() & 1023);\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestItem = ii;\n                    bestPos = pos;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestItem < 0) break;\n\n        const auto& it = items[bestItem];\n        const auto& ch = getCh(it);\n        const auto& cont = getCont(it);\n\n        if (bestCnt > 0) {\n            for (int p = 0; p < (int)ch.size(); p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n\n        for (int sid : cont) covered[sid] = 1;\n    }\n\n    return grid;\n}\n\nint makePlacementChanges(const State& st, int sid, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    const auto& str = S[sid];\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = str[p];\n        if (st.grid[cell] != ch) {\n            cells[cnt] = cell;\n            vals[cnt] = ch;\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nint makeSequenceChanges(const State& st, const vector<uint8_t>& ch, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    int len = (int)ch.size();\n    for (int p = 0; p < len; p++) {\n        int cell = posCell[pos][p];\n        if (st.grid[cell] != ch[p]) {\n            cells[cnt] = cell;\n            vals[cnt] = ch[p];\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nbool tryInsert(State& st, int sid, int K, int maxChange, bool allowZero, double temp, int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    const int MAXK = 12;\n    K = min(K, MAXK);\n\n    int candPos[MAXK];\n    uint32_t candKey[MAXK];\n    int candN = 0;\n\n    auto updateWorst = [&]() {\n        int wi = 0;\n        for (int i = 1; i < candN; i++) {\n            if (candKey[i] > candKey[wi]) wi = i;\n        }\n        return wi;\n    };\n\n    int base = sid * POS;\n\n    for (int pos = 0; pos < POS; pos++) {\n        int m = st.mism[base + pos];\n        if (m == 0) return false;\n        if (m > maxChange) continue;\n\n        uint32_t key = (uint32_t(m) << 20) | uint32_t(rng.next() & ((1u << 20) - 1));\n        if (candN < K) {\n            candPos[candN] = pos;\n            candKey[candN] = key;\n            candN++;\n        } else {\n            int wi = updateWorst();\n            if (key < candKey[wi]) {\n                candPos[wi] = pos;\n                candKey[wi] = key;\n            }\n        }\n    }\n\n    if (candN == 0) return false;\n\n    int bestD = INT_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (int i = 0; i < candN; i++) {\n        int cnt = makePlacementChanges(st, sid, candPos[i], tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 30) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nvoid shuffleVec(vector<int>& v) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nint softCellSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    static const long long EXACT_BONUS = 3000000LL;\n\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int exactImpTotal = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int changes = 0;\n        int exactImp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            long long bestScore = 0;\n            int bestCh = old;\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                long long sc = st.evalChangesSoft(oneCell, oneVal, 1, EXACT_BONUS);\n                if (sc > bestScore || (sc == bestScore && sc > 0 && rng.randint(2) == 0)) {\n                    bestScore = sc;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestScore > 0) {\n                int before = st.obj;\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                exactImp += st.obj - before;\n                changes++;\n                if (st.obj >= best.obj) best.consider(st);\n                if (st.obj == TOTAL) return exactImpTotal + exactImp;\n            }\n        }\n\n        exactImpTotal += exactImp;\n        if (changes == 0) break;\n    }\n\n    best.consider(st);\n    return exactImpTotal;\n}\n\ninline int maskWeight(const Mask& m) {\n    int sum = 0;\n    for (int w = 0; w < MASK_WORDS; w++) {\n        uint64_t x = m[w];\n        while (x) {\n            int b = __builtin_ctzll(x);\n            int id = w * 64 + b;\n            if (id < U) sum += W[id];\n            x &= x - 1;\n        }\n    }\n    return sum;\n}\n\nvoid buildLossMasks(const State& st, vector<Mask>& masks) {\n    for (auto& m : masks) m.fill(0);\n\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] != 1) continue;\n\n        int base = sid * POS;\n        int exactPos = -1;\n        for (int pos = 0; pos < POS; pos++) {\n            if (st.mism[base + pos] == 0) {\n                exactPos = pos;\n                break;\n            }\n        }\n        if (exactPos < 0) continue;\n\n        int word = sid >> 6;\n        uint64_t bit = 1ULL << (sid & 63);\n\n        for (int p = 0; p < Ls[sid]; p++) {\n            int cell = posCell[exactPos][p];\n            masks[cell][word] |= bit;\n        }\n    }\n}\n\nint approxPlacementLoss(const State& st, const vector<Mask>& masks, int sid, int pos,\n                        int& cnt, const Mask* excludeMask = nullptr) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = S[sid][p];\n        if (st.grid[cell] == ch) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    if (excludeMask) {\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] &= ~((*excludeMask)[w]);\n    } else {\n        tmp[sid >> 6] &= ~(1ULL << (sid & 63));\n    }\n\n    return maskWeight(tmp);\n}\n\nint approxSequenceLoss(const State& st, const vector<Mask>& masks, const vector<uint8_t>& ch,\n                       int pos, int& cnt, const Mask* excludeMask = nullptr) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    int len = (int)ch.size();\n    for (int p = 0; p < len; p++) {\n        int cell = posCell[pos][p];\n        if (st.grid[cell] == ch[p]) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    if (excludeMask) {\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] &= ~((*excludeMask)[w]);\n    }\n\n    return maskWeight(tmp);\n}\n\nbool tryInsertConflict(State& st, int sid, const vector<Mask>& masks,\n                       int kLoss, int kMis, bool allowZero, double temp,\n                       int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt, &strMasks[sid]);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 250 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 1200LL - 1LL * c.cnt * 30LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 45) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nbool tryPlaceSequenceConflict(State& st, const vector<uint8_t>& ch, const vector<Mask>& masks,\n                              int kLoss, int kMis, bool allowZero, double temp,\n                              int& appliedDelta, const Mask* excludeMask = nullptr) {\n    appliedDelta = 0;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxSequenceLoss(st, masks, ch, pos, cnt, excludeMask);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 180 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 45 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makeSequenceChanges(st, ch, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 700LL - 1LL * c.cnt * 20LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 35) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nstruct SmallMove {\n    int d = INT_MIN;\n    long long score = LLONG_MIN;\n    int cnt = 0;\n    array<int, 25> cells;\n    array<uint8_t, 25> vals;\n};\n\nbool findBestInsertConflictMove(State& st, int sid, const vector<Mask>& masks,\n                                int kLoss, int kMis, SmallMove& mv) {\n    mv = SmallMove();\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos, loss, cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) if (v[i].key > v[wi].key) wi = i;\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt, &strMasks[sid]);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 220 + (rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) if (x.pos == c.pos) return;\n        cand.push_back(c);\n    };\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 700LL - 1LL * c.cnt * 20LL\n                        + (rng.next() & 1023);\n\n        if (d > mv.d || (d == mv.d && score > mv.score)) {\n            mv.d = d;\n            mv.score = score;\n            mv.cnt = cnt;\n            for (int i = 0; i < cnt; i++) {\n                mv.cells[i] = tmpCells[i];\n                mv.vals[i] = tmpVals[i];\n            }\n        }\n    }\n\n    return mv.d != INT_MIN;\n}\n\nbool findBestSequenceConflictMove(State& st, const vector<uint8_t>& ch, const vector<Mask>& masks,\n                                  int kLoss, int kMis, SmallMove& mv,\n                                  const Mask* excludeMask = nullptr) {\n    mv = SmallMove();\n\n    struct Cand {\n        int pos, loss, cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) if (v[i].key > v[wi].key) wi = i;\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxSequenceLoss(st, masks, ch, pos, cnt, excludeMask);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 150 + (rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 40 + (rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) if (x.pos == c.pos) return;\n        cand.push_back(c);\n    };\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makeSequenceChanges(st, ch, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 450LL - 1LL * c.cnt * 15LL\n                        + (rng.next() & 1023);\n\n        if (d > mv.d || (d == mv.d && score > mv.score)) {\n            mv.d = d;\n            mv.score = score;\n            mv.cnt = cnt;\n            for (int i = 0; i < cnt; i++) {\n                mv.cells[i] = tmpCells[i];\n                mv.vals[i] = tmpVals[i];\n            }\n        }\n    }\n\n    return mv.d != INT_MIN;\n}\n\nvoid greedyImproveConflict(State& st, Timer& timer, double endTime, Best& best,\n                           int maxIter, int sampleLimit) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n\n    for (int it = 0; it < maxIter && timer.elapsed() < endTime && st.obj < TOTAL; it++) {\n        buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) if (st.cover[sid] == 0) unc.push_back(sid);\n        if (unc.empty()) break;\n\n        vector<pair<int,int>> order;\n        order.reserve(unc.size());\n\n        for (int sid : unc) {\n            int minM = 13;\n            for (int m = 0; m <= Ls[sid]; m++) {\n                if (st.hist[sid][m] > 0) {\n                    minM = m;\n                    break;\n                }\n            }\n            int key = W[sid] * 200 + Ls[sid] * 80 - minM * 70 + rng.randint(200);\n            order.push_back({-key, sid});\n        }\n\n        sort(order.begin(), order.end());\n        if ((int)order.size() > sampleLimit) order.resize(sampleLimit);\n\n        SmallMove bestMv;\n        int checked = 0;\n\n        for (auto [_, sid] : order) {\n            if (((++checked) & 15) == 0 && timer.elapsed() > endTime) break;\n\n            SmallMove mv;\n            if (!findBestInsertConflictMove(st, sid, masks, 5, 3, mv)) continue;\n\n            if (mv.d > bestMv.d || (mv.d == bestMv.d && mv.score > bestMv.score)) {\n                bestMv = mv;\n            }\n        }\n\n        if (bestMv.d <= 0 || bestMv.d == INT_MIN) break;\n\n        st.applyChanges(bestMv.cells.data(), bestMv.vals.data(), bestMv.cnt);\n        best.consider(st);\n    }\n}\n\nvoid greedyImproveSegments(State& st, Timer& timer, double endTime, Best& best,\n                           const vector<Segment>& segments, int maxIter, int segSample) {\n    if (segments.empty() || st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n\n    for (int it = 0; it < maxIter && timer.elapsed() < endTime && st.obj < TOTAL; it++) {\n        buildLossMasks(st, masks);\n\n        struct Pick {\n            long long key;\n            int idx;\n        };\n\n        vector<Pick> picks;\n        picks.reserve(segments.size());\n\n        for (int i = 0; i < (int)segments.size(); i++) {\n            int gain = 0;\n            for (int sid : segments[i].contains) {\n                if (st.cover[sid] == 0) gain += W[sid];\n            }\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL + 1LL * segments[i].val * 100LL\n                          + 1LL * (int)segments[i].ch.size() * 30LL + (rng.next() & 4095);\n            picks.push_back({key, i});\n        }\n\n        if (picks.empty()) break;\n\n        sort(picks.begin(), picks.end(), [](const Pick& a, const Pick& b) {\n            return a.key > b.key;\n        });\n\n        if ((int)picks.size() > segSample) picks.resize(segSample);\n\n        SmallMove bestMv;\n\n        for (auto& p : picks) {\n            if (timer.elapsed() > endTime) break;\n\n            const Segment& sg = segments[p.idx];\n            SmallMove mv;\n            if (!findBestSequenceConflictMove(st, sg.ch, masks, 5, 3, mv, &sg.mask)) continue;\n\n            if (mv.d > bestMv.d || (mv.d == bestMv.d && mv.score > bestMv.score)) {\n                bestMv = mv;\n            }\n        }\n\n        if (bestMv.d <= 0 || bestMv.d == INT_MIN) break;\n\n        st.applyChanges(bestMv.cells.data(), bestMv.vals.data(), bestMv.cnt);\n        best.consider(st);\n    }\n}\n\nvoid conflictSearch(State& st, Timer& timer, double endTime, Best& best) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 5 == 0) buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) {\n            if (st.cover[sid] == 0) unc.push_back(sid);\n        }\n        if (unc.empty()) break;\n\n        int sid = unc[rng.randint((int)unc.size())];\n\n        int samples = min(26, (int)unc.size());\n        int bestKey = -1;\n        for (int t = 0; t < samples; t++) {\n            int x = unc[rng.randint((int)unc.size())];\n\n            int minM = 13;\n            const auto& hh = st.hist[x];\n            for (int m = 0; m <= Ls[x]; m++) {\n                if (hh[m] > 0) {\n                    minM = m;\n                    break;\n                }\n            }\n\n            int key = Ls[x] * 100 + W[x] * 35 - minM * 30 + rng.randint(120);\n            if (key > bestKey) {\n                bestKey = key;\n                sid = x;\n            }\n        }\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.12 + 1.15 * frac;\n\n        int d;\n        bool ok = tryInsertConflict(st, sid, masks, 9, 5, true, temp, d);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 8);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 150) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n                iter = 0;\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nvoid segmentSearch(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    if (segments.empty() || st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 4 == 0) buildLossMasks(st, masks);\n\n        struct Pick {\n            long long key;\n            int idx;\n            int gain;\n        };\n\n        vector<Pick> top;\n        top.reserve(10);\n\n        auto pushPick = [&](Pick p) {\n            if ((int)top.size() < 10) {\n                top.push_back(p);\n                return;\n            }\n            int wi = 0;\n            for (int i = 1; i < (int)top.size(); i++) {\n                if (top[i].key < top[wi].key) wi = i;\n            }\n            if (p.key > top[wi].key) top[wi] = p;\n        };\n\n        for (int i = 0; i < (int)segments.size(); i++) {\n            int gain = 0;\n            for (int sid : segments[i].contains) {\n                if (st.cover[sid] == 0) gain += W[sid];\n            }\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL\n                          + 1LL * segments[i].val * 120LL\n                          + 1LL * (int)segments[i].ch.size() * 30LL\n                          + (long long)(rng.next() & 4095);\n            pushPick({key, i, gain});\n        }\n\n        if (top.empty()) break;\n\n        int chooseLim = min(5, (int)top.size());\n        nth_element(top.begin(), top.begin() + chooseLim - 1, top.end(),\n                    [](const Pick& a, const Pick& b) { return a.key > b.key; });\n        int idx = top[rng.randint(chooseLim)].idx;\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.10 + 1.05 * frac;\n\n        int d;\n        bool ok = tryPlaceSequenceConflict(st, segments[idx].ch, masks, 11, 6, true, temp, d,\n                                           &segments[idx].mask);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 10);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n\n            if (st.obj < localBestObj - 14) {\n                st.build(localBestGrid);\n                noProgress = 0;\n            }\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 80) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nvoid forceWalk(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int stagnant = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && localBestObj < TOTAL) {\n        if (iter % 4 == 0) buildLossMasks(st, masks);\n\n        SmallMove mv;\n        bool found = false;\n\n        bool useSeg = (avgLen >= 5.2 && !segments.empty() && rng.randint(100) < 35);\n\n        if (useSeg) {\n            int bestIdx = -1;\n            long long bestKey = LLONG_MIN;\n\n            int trials = min(90, max(1, (int)segments.size()));\n            for (int t = 0; t < trials; t++) {\n                int idx;\n                if (t < 35 && t < (int)segments.size()) idx = t;\n                else idx = rng.randint((int)segments.size());\n\n                int gain = 0;\n                for (int sid : segments[idx].contains) {\n                    if (st.cover[sid] == 0) gain += W[sid];\n                }\n                if (gain <= 0) continue;\n\n                long long key = 1LL * gain * 100000LL + 1LL * segments[idx].val * 80LL\n                              + 1LL * (int)segments[idx].ch.size() * 30LL + (rng.next() & 4095);\n                if (key > bestKey) {\n                    bestKey = key;\n                    bestIdx = idx;\n                }\n            }\n\n            if (bestIdx >= 0) {\n                found = findBestSequenceConflictMove(st, segments[bestIdx].ch, masks, 8, 5, mv,\n                                                     &segments[bestIdx].mask);\n            }\n        }\n\n        if (!found) {\n            vector<int> unc;\n            unc.reserve(U);\n            for (int sid = 0; sid < U; sid++) if (st.cover[sid] == 0) unc.push_back(sid);\n            if (unc.empty()) break;\n\n            int sid = unc[rng.randint((int)unc.size())];\n            int samples = min(30, (int)unc.size());\n            int bestKey = INT_MIN;\n\n            for (int t = 0; t < samples; t++) {\n                int x = unc[rng.randint((int)unc.size())];\n                int minM = 13;\n                for (int m = 0; m <= Ls[x]; m++) {\n                    if (st.hist[x][m] > 0) {\n                        minM = m;\n                        break;\n                    }\n                }\n                int key = W[x] * 180 + Ls[x] * 90 - minM * 65 + rng.randint(160);\n                if (key > bestKey) {\n                    bestKey = key;\n                    sid = x;\n                }\n            }\n\n            found = findBestInsertConflictMove(st, sid, masks, 8, 5, mv);\n        }\n\n        iter++;\n\n        if (!found || mv.d == INT_MIN) {\n            stagnant++;\n            if (stagnant > 50 && st.obj < localBestObj) {\n                st.build(localBestGrid);\n                stagnant = 0;\n            }\n            continue;\n        }\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n\n        int tolerance = 10 + (TOTAL - localBestObj) / 7 + (int)(18 * frac);\n        tolerance = min(tolerance, 55);\n        int maxNeg = 3 + (int)(12 * frac);\n\n        bool accept = false;\n        if (mv.d >= 0) accept = true;\n        else if (mv.d >= -maxNeg) accept = true;\n        else if (st.obj + mv.d >= localBestObj - tolerance) accept = true;\n        else if (rng.randint(100) < 3) accept = true;\n\n        if (!accept) {\n            stagnant++;\n            if (stagnant > 80 && st.obj < localBestObj) {\n                st.build(localBestGrid);\n                stagnant = 0;\n            }\n            continue;\n        }\n\n        st.applyChanges(mv.cells.data(), mv.vals.data(), mv.cnt);\n        best.consider(st);\n\n        if (st.obj > localBestObj) {\n            localBestObj = st.obj;\n            localBestGrid = st.grid;\n            stagnant = 0;\n            if (st.obj == TOTAL) break;\n        } else {\n            stagnant++;\n        }\n\n        if (st.obj < localBestObj - tolerance || stagnant > 120) {\n            st.build(localBestGrid);\n            stagnant = 0;\n        }\n    }\n\n    st.build(localBestGrid);\n    best.consider(st);\n}\n\nint repairPass(State& st, Timer& timer, double endTime, int K, int maxChange,\n               bool allowZero, double temp, Best& best) {\n    vector<int> ids;\n    ids.reserve(U);\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] == 0) ids.push_back(sid);\n    }\n    if (ids.empty()) return 0;\n\n    shuffleVec(ids);\n    stable_sort(ids.begin(), ids.end(), [](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int before = st.obj;\n    int applied = 0;\n\n    for (int sid : ids) {\n        if (timer.elapsed() > endTime) break;\n        if (st.cover[sid] > 0) continue;\n\n        int d;\n        if (tryInsert(st, sid, K, maxChange, allowZero, temp, d)) {\n            applied++;\n            if (d > 0 || st.obj == TOTAL) best.consider(st);\n            if (st.obj == TOTAL) break;\n        }\n    }\n\n    best.consider(st);\n    return st.obj - before + applied / 1000000;\n}\n\nvoid fillDots(State& st, Timer& timer, double endTime, Best& best) {\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] != DOT) continue;\n\n        int bestD = INT_MIN;\n        int bestCh = 0;\n        oneCell[0] = cell;\n\n        for (int ch = 0; ch < 8; ch++) {\n            oneVal[0] = (uint8_t)ch;\n            int d = st.evalChanges(oneCell, oneVal, 1);\n            if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n                bestD = d;\n                bestCh = ch;\n            }\n        }\n\n        oneVal[0] = (uint8_t)bestCh;\n        st.applyChanges(oneCell, oneVal, 1);\n        best.consider(st);\n\n        if (st.obj == TOTAL) return;\n    }\n\n    best.consider(st);\n}\n\nint cellHillSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int totalImp = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int imp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            int bestD = 0;\n            int bestCh = old;\n\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                int d = st.evalChanges(oneCell, oneVal, 1);\n                if (d > bestD || (d == bestD && d > 0 && rng.randint(2) == 0)) {\n                    bestD = d;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestD > 0) {\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                imp += bestD;\n                best.consider(st);\n                if (st.obj == TOTAL) return totalImp + imp;\n            }\n        }\n\n        totalImp += imp;\n        if (imp == 0) break;\n    }\n\n    best.consider(st);\n    return totalImp;\n}\n\nvoid voteRefine(State& st, Timer& timer, double endTime, Best& best, int iters) {\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    static int votes[CELLS][8];\n\n    for (int it = 0; it < iters && timer.elapsed() < endTime; it++) {\n        memset(votes, 0, sizeof(votes));\n\n        for (int cell = 0; cell < CELLS; cell++) {\n            int old = st.grid[cell];\n            if (0 <= old && old < 8) votes[cell][old] += 1;\n        }\n\n        for (int sid = 0; sid < U; sid++) {\n            if ((sid & 31) == 0 && timer.elapsed() > endTime) break;\n\n            int base = sid * POS;\n            int bestM = 100;\n            int bestPos = 0;\n            int seen = 0;\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = st.mism[base + pos];\n                if (m < bestM) {\n                    bestM = m;\n                    bestPos = pos;\n                    seen = 1;\n                } else if (m == bestM) {\n                    seen++;\n                    if (rng.randint(seen) == 0) bestPos = pos;\n                }\n            }\n\n            int wt = W[sid] * max(1, Ls[sid] - bestM);\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[bestPos][p];\n                votes[cell][S[sid][p]] += wt;\n            }\n        }\n\n        vector<uint8_t> ng = st.grid;\n\n        for (int cell = 0; cell < CELLS; cell++) {\n            int bestCh = ng[cell];\n            int bestV = -1;\n            for (int ch = 0; ch < 8; ch++) {\n                int v = votes[cell][ch];\n                if (v > bestV || (v == bestV && rng.randint(2) == 0)) {\n                    bestV = v;\n                    bestCh = ch;\n                }\n            }\n            if (bestV > 0) ng[cell] = (uint8_t)bestCh;\n        }\n\n        st.build(ng);\n        best.consider(st);\n\n        if (st.obj > localBestObj) {\n            localBestObj = st.obj;\n            localBestGrid = st.grid;\n        }\n    }\n\n    st.build(localBestGrid);\n    best.consider(st);\n}\n\nbool hasDots(const vector<uint8_t>& g) {\n    for (auto x : g) if (x == DOT) return true;\n    return false;\n}\n\nvoid localSearch(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    best.consider(st);\n    if (st.obj == TOTAL) return;\n\n    int maxChFull = (avgLen >= 8.0 ? 5 : 6);\n\n    if (hasDots(st.grid)) {\n        for (int pass = 0; pass < 2 && timer.elapsed() < endTime; pass++) {\n            int before = st.obj;\n            repairPass(st, timer, endTime, 3, maxLenInput, false, -1.0, best);\n            if (st.obj == TOTAL) return;\n            if (st.obj == before) break;\n        }\n    }\n\n    if (st.obj == TOTAL) return;\n\n    if (hasDots(st.grid)) {\n        fillDots(st, timer, endTime, best);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (avgLen >= 5.5 && timer.elapsed() + 0.07 < endTime) {\n        double vtEnd = min(endTime, timer.elapsed() + 0.10);\n        voteRefine(st, timer, vtEnd, best, 2);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() + 0.05 < endTime && st.obj < TOTAL) {\n        softCellSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n    }\n\n    for (int cyc = 0; cyc < 2 && timer.elapsed() < endTime; cyc++) {\n        int before = st.obj;\n        repairPass(st, timer, endTime, 5, maxChFull, false, -1.0, best);\n        if (st.obj == TOTAL) return;\n\n        cellHillSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n\n        if (st.obj <= before && cyc > 0) break;\n    }\n\n    if (timer.elapsed() + 0.06 < endTime && st.obj < TOTAL) {\n        greedyImproveConflict(st, timer, min(endTime, timer.elapsed() + 0.12), best, 4, 80);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (avgLen >= 5.5 && timer.elapsed() + 0.10 < endTime && st.obj < TOTAL) {\n        greedyImproveSegments(st, timer, min(endTime, timer.elapsed() + 0.10), best, segments, 2, 7);\n        if (st.obj == TOTAL) return;\n\n        double rem = endTime - timer.elapsed();\n        double segEnd = min(endTime, timer.elapsed() + rem * 0.42);\n        segmentSearch(st, timer, segEnd, best, segments);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() < endTime && st.obj < TOTAL) {\n        conflictSearch(st, timer, endTime, best);\n    }\n\n    best.consider(st);\n}\n\nvoid dotMaximize(Best& best, State& st, Timer& timer, double endTime) {\n    if (best.obj < TOTAL) return;\n\n    st.build(best.grid);\n    if (st.obj < TOTAL) return;\n\n    vector<pair<int,int>> order;\n    order.reserve(CELLS);\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (st.grid[cell] == DOT) continue;\n\n        int impact = 0;\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            if (st.grid[cell] == req && st.mism[pid] == 0) {\n                int sid = pid / POS;\n                impact += (st.cover[sid] <= 1 ? 1000 * W[sid] : 1);\n            }\n        }\n        impact = impact * 1024 + rng.randint(1024);\n        order.push_back({impact, cell});\n    }\n\n    sort(order.begin(), order.end());\n\n    int oneCell[1];\n    uint8_t oneVal[1] = {(uint8_t)DOT};\n\n    for (auto [_, cell] : order) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] == DOT) continue;\n\n        oneCell[0] = cell;\n        int d = st.evalChanges(oneCell, oneVal, 1);\n        if (st.obj + d == TOTAL) {\n            st.applyChanges(oneCell, oneVal, 1);\n        }\n    }\n\n    best.consider(st);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin;\n    cin >> Nin >> M_input;\n\n    vector<string> input(M_input);\n    uint64_t h = 1469598103934665603ULL;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M_input * 2);\n\n    int totalLen = 0;\n    for (int i = 0; i < M_input; i++) {\n        cin >> input[i];\n        mp[input[i]]++;\n        totalLen += (int)input[i].size();\n        maxLenInput = max(maxLenInput, (int)input[i].size());\n        for (char c : input[i]) {\n            h ^= (uint64_t)c;\n            h *= 1099511628211ULL;\n        }\n    }\n\n    rng = XorShift(88172645463325252ULL ^ h);\n\n    vector<pair<string,int>> pairs;\n    pairs.reserve(mp.size());\n    for (auto& kv : mp) pairs.push_back(kv);\n    sort(pairs.begin(), pairs.end());\n\n    U = (int)pairs.size();\n    TOTAL = M_input;\n    avgLen = (double)totalLen / M_input;\n\n    uniqStr.reserve(U);\n    S.reserve(U);\n    Ls.reserve(U);\n    W.reserve(U);\n\n    for (auto& kv : pairs) {\n        uniqStr.push_back(kv.first);\n        S.push_back(strToVec(kv.first));\n        Ls.push_back((int)kv.first.size());\n        W.push_back(kv.second);\n    }\n\n    Timer timer;\n\n    initNearVal();\n    initPosCells();\n    buildIncidences();\n    buildStringContainMasks();\n\n    vector<Segment> segments = generateSegments();\n\n    State st;\n    st.init();\n\n    Best best;\n\n    vector<int> modes;\n    if (avgLen <= 5.2) {\n        modes = {5, 4, 0, 1};\n    } else if (avgLen <= 6.2) {\n        modes = {5, 1, 4, 0};\n    } else {\n        modes = {1, 5, 0, 3};\n    }\n\n    const double SEARCH_END = 2.62;\n    const double FINAL_END = 2.88;\n\n    for (int r = 0; r < (int)modes.size() && timer.elapsed() < SEARCH_END; r++) {\n        int mode = modes[r];\n        vector<uint8_t> grid;\n\n        double cEnd = SEARCH_END;\n        if (mode == 4) cEnd = min(SEARCH_END, timer.elapsed() + (avgLen <= 5.2 ? 0.23 : 0.17));\n        else if (mode == 5) cEnd = min(SEARCH_END, timer.elapsed() + (avgLen <= 5.2 ? 0.23 : 0.19));\n        else if (mode == 3) cEnd = min(SEARCH_END, timer.elapsed() + 0.08);\n\n        if (mode == 3) {\n            grid = constructRowPack(timer, cEnd);\n        } else if (mode == 4) {\n            grid = constructCoverRows(segments, timer, cEnd);\n        } else if (mode == 5) {\n            grid = constructCoverPlace(segments, timer, cEnd);\n        } else {\n            grid = constructGreedy(mode, segments, timer, cEnd);\n        }\n\n        st.build(grid);\n\n        double rem = SEARCH_END - timer.elapsed();\n        int left = (int)modes.size() - r;\n        double slice = max(0.05, rem / max(1, left));\n        double endTime = min(SEARCH_END, timer.elapsed() + slice);\n\n        localSearch(st, timer, endTime, best, segments);\n\n        if (best.obj == TOTAL) break;\n    }\n\n    if (best.grid.empty()) {\n        vector<uint8_t> g(CELLS);\n        for (int i = 0; i < CELLS; i++) g[i] = rng.randint(8);\n        st.build(g);\n        best.consider(st);\n    }\n\n    if (best.obj == TOTAL) {\n        dotMaximize(best, st, timer, FINAL_END);\n    } else {\n        st.build(best.grid);\n\n        if (hasDots(st.grid)) {\n            fillDots(st, timer, FINAL_END, best);\n        }\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            voteRefine(st, timer, min(FINAL_END, timer.elapsed() + 0.12), best, 2);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            greedyImproveSegments(st, timer, min(FINAL_END, timer.elapsed() + 0.12), best, segments, 3, 8);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            double rem = FINAL_END - timer.elapsed();\n            segmentSearch(st, timer, min(FINAL_END, timer.elapsed() + rem * 0.35), best, segments);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.05 < FINAL_END) {\n            softCellSweep(st, timer, FINAL_END, best, 1);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.06 < FINAL_END) {\n            greedyImproveConflict(st, timer, min(FINAL_END, timer.elapsed() + 0.16), best, 6, 110);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            forceWalk(st, timer, min(FINAL_END, timer.elapsed() + 0.20), best, segments);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() < FINAL_END) {\n            conflictSearch(st, timer, FINAL_END, best);\n        }\n\n        if (best.obj == TOTAL) {\n            dotMaximize(best, st, timer, FINAL_END);\n        } else {\n            st.build(best.grid);\n            if (hasDots(st.grid)) fillDots(st, timer, FINAL_END, best);\n\n            if (st.obj < TOTAL) {\n                cellHillSweep(st, timer, FINAL_END, best, 3);\n            }\n\n            if (best.obj == TOTAL) {\n                dotMaximize(best, st, timer, FINAL_END);\n            }\n        }\n    }\n\n    if (best.obj < TOTAL) {\n        for (auto& x : best.grid) {\n            if (x == DOT) x = rng.randint(8);\n        }\n    }\n\n    for (int r = 0; r < SZ; r++) {\n        string line;\n        line.reserve(SZ);\n        for (int c = 0; c < SZ; c++) {\n            uint8_t x = best.grid[r * SZ + c];\n            if (x == DOT) line.push_back('.');\n            else line.push_back(char('A' + x));\n        }\n        cout << line << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Dinic {\n    struct Edge {\n        int to, rev;\n        long long cap;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic(int n = 0) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, long long cap) {\n        Edge a{to, (int)g[to].size(), cap};\n        Edge b{fr, (int)g[fr].size(), 0};\n        g[fr].push_back(a);\n        g[to].push_back(b);\n    }\n\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\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return level[t] >= 0;\n    }\n\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n\n        for (int &i = it[v]; i < (int)g[v].size(); i++) {\n            Edge &e = g[v][i];\n\n            if (e.cap <= 0 || level[v] + 1 != level[e.to]) continue;\n\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if (ret > 0) {\n                e.cap -= ret;\n                g[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n\n        return 0;\n    }\n\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        const long long INF = (1LL << 60);\n\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n\n            while (true) {\n                long long f = dfs(s, t, INF);\n                if (!f) break;\n                flow += f;\n            }\n        }\n\n        return flow;\n    }\n\n    vector<int> reachable_from(int s) {\n        vector<int> vis(n, 0);\n        queue<int> q;\n        vis[s] = 1;\n        q.push(s);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return vis;\n    }\n};\n\nstruct Solver {\n    static constexpr int INF16 = 65535;\n\n    Timer timer;\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0, S = 0;\n    vector<vector<int>> id;\n    vector<int> rr, cc, wt;\n    vector<array<int, 4>> nbr;\n\n    vector<uint16_t> distMat, parMat;\n\n    vector<int> hid, vid;\n    vector<vector<int>> hCells, vCells;\n    vector<int> visVal;\n    vector<int> segMinH, segMinV;\n\n    vector<int> bestSafeSeq;\n    vector<int> bestFinalSeq;\n    vector<vector<int>> bestFinalEdges;\n    long long bestSafeCost = (1LL << 60);\n    long long bestFinalCost = (1LL << 60);\n\n    inline int D(int a, int b) const {\n        return distMat[(size_t)a * R + b];\n    }\n\n    inline int Sym(int a, int b) const {\n        return D(a, b) + wt[a];\n    }\n\n    char moveChar(int a, int b) const {\n        if (rr[b] == rr[a] - 1) return 'U';\n        if (rr[b] == rr[a] + 1) return 'D';\n        if (cc[b] == cc[a] - 1) return 'L';\n        return 'R';\n    }\n\n    void readInput() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void buildRoadGraph() {\n        id.assign(N, vector<int>(N, -1));\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    rr.push_back(i);\n                    cc.push_back(j);\n                    wt.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n\n        S = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        int di[4] = {-1, 1, 0, 0};\n        int dj[4] = {0, 0, -1, 1};\n\n        for (int v = 0; v < R; v++) {\n            int i = rr[v], j = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n\n                if (0 <= ni && ni < N && 0 <= nj && nj < N && id[ni][nj] >= 0) {\n                    nbr[v][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void buildSegments() {\n        hid.assign(R, -1);\n        vid.assign(R, -1);\n\n        for (int i = 0; i < N; i++) {\n            int j = 0;\n            while (j < N) {\n                if (id[i][j] < 0) {\n                    j++;\n                    continue;\n                }\n\n                int h = (int)hCells.size();\n                hCells.push_back({});\n\n                while (j < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    hid[v] = h;\n                    hCells.back().push_back(v);\n                    j++;\n                }\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            int i = 0;\n            while (i < N) {\n                if (id[i][j] < 0) {\n                    i++;\n                    continue;\n                }\n\n                int vseg = (int)vCells.size();\n                vCells.push_back({});\n\n                while (i < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    vid[v] = vseg;\n                    vCells.back().push_back(v);\n                    i++;\n                }\n            }\n        }\n\n        visVal.assign(R, 0);\n        for (int v = 0; v < R; v++) {\n            visVal[v] = (int)hCells[hid[v]].size() + (int)vCells[vid[v]].size() - 1;\n        }\n    }\n\n    void computeAPSP() {\n        distMat.assign((size_t)R * R, INF16);\n        parMat.assign((size_t)R * R, 0);\n\n        vector<uint16_t> dist(R), par(R);\n        vector<int> score(R);\n        vector<unsigned char> used(R);\n        vector<vector<int>> buckets(10);\n        for (auto &b : buckets) b.reserve(max(1, R / 2));\n\n        for (int s = 0; s < R; s++) {\n            fill(dist.begin(), dist.end(), (uint16_t)INF16);\n            fill(par.begin(), par.end(), 0);\n            fill(score.begin(), score.end(), -1);\n            fill(used.begin(), used.end(), 0);\n            for (auto &b : buckets) b.clear();\n\n            dist[s] = 0;\n            par[s] = s;\n            score[s] = visVal[s];\n            buckets[0].push_back(s);\n\n            int cur = 0, done = 0;\n\n            while (done < R) {\n                auto &bk = buckets[cur % 10];\n\n                if (bk.empty()) {\n                    cur++;\n                    continue;\n                }\n\n                int v = bk.back();\n                bk.pop_back();\n\n                if (used[v] || dist[v] != cur) continue;\n\n                used[v] = 1;\n                done++;\n\n                for (int k = 0; k < 4; k++) {\n                    int to = nbr[v][k];\n                    if (to < 0 || used[to]) continue;\n\n                    int nd = cur + wt[to];\n                    int ns = score[v] + visVal[to];\n\n                    if (nd < dist[to] || (nd == dist[to] && ns > score[to])) {\n                        dist[to] = (uint16_t)nd;\n                        par[to] = (uint16_t)v;\n                        score[to] = ns;\n                        buckets[nd % 10].push_back(to);\n                    }\n                }\n            }\n\n            memcpy(distMat.data() + (size_t)s * R, dist.data(), sizeof(uint16_t) * R);\n            memcpy(parMat.data() + (size_t)s * R, par.data(), sizeof(uint16_t) * R);\n        }\n    }\n\n    void computeSegmentApprox() {\n        segMinH.assign(hCells.size(), 1e9);\n        segMinV.assign(vCells.size(), 1e9);\n\n        for (int v = 0; v < R; v++) {\n            int rt = D(S, v) + D(v, S);\n            segMinH[hid[v]] = min(segMinH[hid[v]], rt);\n            segMinV[vid[v]] = min(segMinV[vid[v]], rt);\n        }\n    }\n\n    void getPathCellsUnordered(int a, int b, vector<int> &out) const {\n        out.clear();\n        if (a == b) return;\n\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            int p = parMat[(size_t)a * R + cur];\n            cur = p;\n\n            if (++cnt > R + 5) {\n                out.clear();\n                return;\n            }\n        }\n    }\n\n    void getPathCellsOrdered(int a, int b, vector<int> &out) const {\n        getPathCellsUnordered(a, b, out);\n        reverse(out.begin(), out.end());\n    }\n\n    long long routeCost(const vector<int> &seq) const {\n        if (seq.empty()) return (1LL << 60);\n\n        long long ret = 0;\n        int m = (int)seq.size();\n\n        for (int i = 0; i < m; i++) {\n            ret += D(seq[i], seq[(i + 1) % m]);\n        }\n\n        return ret;\n    }\n\n    struct Cover {\n        const Solver *sol = nullptr;\n        vector<int> cntH, cntV;\n        int bad = 0;\n\n        void init(const Solver *s) {\n            sol = s;\n            cntH.assign(sol->hCells.size(), 0);\n            cntV.assign(sol->vCells.size(), 0);\n            bad = sol->R;\n        }\n\n        void addH(int h, int delta) {\n            int old = cntH[h];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad++;\n                }\n            }\n\n            cntH[h] = neu;\n        }\n\n        void addV(int v, int delta) {\n            int old = cntV[v];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad++;\n                }\n            }\n\n            cntV[v] = neu;\n        }\n\n        void addCell(int p, int delta) {\n            addH(sol->hid[p], delta);\n            addV(sol->vid[p], delta);\n        }\n    };\n\n    void applyPath(Cover &cov, const vector<int> &path, int delta) const {\n        for (int p : path) cov.addCell(p, delta);\n    }\n\n    bool checkpointFull(const vector<int> &seq) const {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n\n        return cov.bad == 0;\n    }\n\n    void buildStaticEdges(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        int m = (int)seq.size();\n        edgeCells.assign(m, {});\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, edgeCells[i]);\n        }\n    }\n\n    void ensureEdgeCells(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        if ((int)edgeCells.size() != (int)seq.size()) {\n            buildStaticEdges(seq, edgeCells);\n        }\n    }\n\n    void buildCoverFromEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells, Cover &cov) const {\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            for (int p : edgeCells[i]) cov.addCell(p, +1);\n        }\n    }\n\n    bool actualFullEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (seq.empty()) return false;\n\n        Cover cov;\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                for (int p : edgeCells[i]) cov.addCell(p, +1);\n            }\n        } else {\n            vector<int> path;\n            for (int i = 0; i < m; i++) {\n                int a = seq[i], b = seq[(i + 1) % m];\n                getPathCellsUnordered(a, b, path);\n                for (int p : path) cov.addCell(p, +1);\n            }\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool actualFull(const vector<int> &seq) const {\n        static const vector<vector<int>> emptyEdges;\n        return actualFullEdges(seq, emptyEdges);\n    }\n\n    bool validEdgePaths(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (edgeCells.empty()) return true;\n        int m = (int)seq.size();\n        if ((int)edgeCells.size() != m) return false;\n\n        for (int i = 0; i < m; i++) {\n            int cur = seq[i];\n            int cost = 0;\n\n            for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                int p = edgeCells[i][k];\n                int md = abs(rr[cur] - rr[p]) + abs(cc[cur] - cc[p]);\n                if (md != 1) return false;\n                cost += wt[p];\n                cur = p;\n            }\n\n            if (cur != seq[(i + 1) % m]) return false;\n            if (cost != D(seq[i], seq[(i + 1) % m])) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> constructCellCover(double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<unsigned char> covered(R, 0);\n        vector<int> remH(hCells.size()), remV(vCells.size());\n\n        for (int h = 0; h < (int)hCells.size(); h++) remH[h] = (int)hCells[h].size();\n        for (int v = 0; v < (int)vCells.size(); v++) remV[v] = (int)vCells[v].size();\n\n        int uncovered = R;\n\n        auto mark = [&](int q) {\n            if (!covered[q]) {\n                covered[q] = 1;\n                uncovered--;\n                remH[hid[q]]--;\n                remV[vid[q]]--;\n            }\n        };\n\n        auto addCover = [&](int p) {\n            for (int q : hCells[hid[p]]) mark(q);\n            for (int q : vCells[vid[p]]) mark(q);\n        };\n\n        addCover(S);\n\n        vector<double> gp(R + 1, 1.0);\n        for (int g = 1; g <= R; g++) gp[g] = pow((double)g, alpha);\n\n        while (uncovered > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = remH[hid[p]] + remV[vid[p]] - (covered[p] ? 0 : 1);\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int p = 0; p < R; p++) {\n                    if (!covered[p]) {\n                        bestP = p;\n                        bestPos = 0;\n                        break;\n                    }\n                }\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            addCover(bestP);\n        }\n\n        return seq;\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCoverWeights(const vector<long long> &wH,\n                                                                const vector<long long> &wV) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        long long sumW = 0;\n        for (long long x : wH) sumW += x;\n        for (long long x : wV) sumW += x;\n\n        int SRC = 0;\n        int offH = 1;\n        int offV = offH + nH;\n        int SNK = offV + nV;\n\n        Dinic din(SNK + 1);\n\n        for (int h = 0; h < nH; h++) din.add_edge(SRC, offH + h, wH[h]);\n        for (int v = 0; v < nV; v++) din.add_edge(offV + v, SNK, wV[v]);\n\n        long long INF = sumW + 1;\n\n        for (int p = 0; p < R; p++) {\n            din.add_edge(offH + hid[p], offV + vid[p], INF);\n        }\n\n        din.max_flow(SRC, SNK);\n        vector<int> reach = din.reachable_from(SRC);\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int h = 0; h < nH; h++) selH[h] = !reach[offH + h];\n        for (int v = 0; v < nV; v++) selV[v] = reach[offV + v];\n\n        for (int p = 0; p < R; p++) {\n            if (!selH[hid[p]] && !selV[vid[p]]) selH[hid[p]] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCover(int type) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<long long> wH(nH), wV(nV);\n\n        auto calcW = [&](int minRT, int len, int tp, bool isH) -> long long {\n            len = max(1, len);\n\n            if (tp == 0) return 1;\n            if (tp == 1) return 100 + minRT / 40;\n            if (tp == 2) return 1 + minRT / 20;\n            if (tp == 3) return 1 + minRT / len;\n            if (tp == 4) return 1 + (10LL * minRT) / max(1, len * len);\n            if (tp == 5) return (len <= 1 ? 10000LL + minRT : 1LL + minRT / max(1, 30 * len));\n            if (tp == 6) return max(1LL, 2000LL / len) + minRT / 100;\n            if (tp == 7) {\n                long long base = 1 + minRT / max(1, 18 * len);\n                return isH ? base * 9 : base * 11;\n            }\n\n            return 1 + minRT / max(1, (int)(8.0 * sqrt((double)len)));\n        };\n\n        for (int h = 0; h < nH; h++) {\n            wH[h] = calcW(segMinH[h], (int)hCells[h].size(), type, true);\n        }\n\n        for (int v = 0; v < nV; v++) {\n            wV[v] = calcW(segMinV[v], (int)vCells[v].size(), type, false);\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    pair<vector<char>, vector<char>> preferenceCover(int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int lh = (int)hCells[h].size();\n            int lv = (int)vCells[v].size();\n\n            bool chooseH = true;\n\n            if (mode == 0) {\n                if (lh != lv) chooseH = lh > lv;\n                else chooseH = segMinH[h] <= segMinV[v];\n            } else if (mode == 1) {\n                long long sh = 1000LL * segMinH[h] / max(1, lh);\n                long long sv = 1000LL * segMinV[v] / max(1, lv);\n                chooseH = sh <= sv;\n            } else {\n                long long sh = 100000LL * segMinH[h] / max(1, lh * lh);\n                long long sv = 100000LL * segMinV[v] / max(1, lv * lv);\n                chooseH = sh <= sv;\n            }\n\n            if (chooseH) selH[h] = 1;\n            else selV[v] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> insertionWeightedVertexCover(const vector<int> &base, int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        const int INF = 1e9;\n        vector<int> insH(nH, INF), insV(nV, INF);\n\n        int m = (int)base.size();\n\n        for (int p = 0; p < R; p++) {\n            int best = INF;\n\n            for (int i = 0; i < m; i++) {\n                int a = base[i], b = base[(i + 1) % m];\n                int extra = D(a, p) + D(p, b) - D(a, b);\n                if (extra < best) best = extra;\n            }\n\n            insH[hid[p]] = min(insH[hid[p]], best);\n            insV[vid[p]] = min(insV[vid[p]], best);\n        }\n\n        vector<long long> wH(nH), wV(nV);\n\n        for (int h = 0; h < nH; h++) {\n            int len = max(1, (int)hCells[h].size());\n            int c = insH[h] == INF ? segMinH[h] : insH[h];\n\n            if (mode == 0) wH[h] = 1 + c / len;\n            else wH[h] = 1 + (10LL * c) / max(1, len * len) + segMinH[h] / 250;\n        }\n\n        for (int v = 0; v < nV; v++) {\n            int len = max(1, (int)vCells[v].size());\n            int c = insV[v] == INF ? segMinV[v] : insV[v];\n\n            if (mode == 0) wV[v] = 1 + c / len;\n            else wV[v] = 1 + (10LL * c) / max(1, len * len) + segMinV[v] / 250;\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    vector<int> constructSegmentCover(const vector<char> &selH, const vector<char> &selV,\n                                      double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<char> touchH(hCells.size(), 0), touchV(vCells.size(), 0);\n\n        int remain = 0;\n        for (char x : selH) if (x) remain++;\n        for (char x : selV) if (x) remain++;\n\n        auto touch = [&](int p) {\n            int h = hid[p], v = vid[p];\n\n            if (selH[h] && !touchH[h]) {\n                touchH[h] = 1;\n                remain--;\n            }\n\n            if (selV[v] && !touchV[v]) {\n                touchV[v] = 1;\n                remain--;\n            }\n        };\n\n        touch(S);\n\n        double gp[3] = {1.0, 1.0, pow(2.0, alpha)};\n\n        while (remain > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = 0;\n                if (selH[hid[p]] && !touchH[hid[p]]) gain++;\n                if (selV[vid[p]] && !touchV[vid[p]]) gain++;\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int h = 0; h < (int)selH.size() && bestP < 0; h++) {\n                    if (selH[h] && !touchH[h]) bestP = hCells[h][0];\n                }\n\n                for (int v = 0; v < (int)selV.size() && bestP < 0; v++) {\n                    if (selV[v] && !touchV[v]) bestP = vCells[v][0];\n                }\n\n                bestPos = 0;\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            touch(bestP);\n        }\n\n        return seq;\n    }\n\n    bool twoOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n\n        for (int i = 0; i < m - 1; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            reverse(seq.begin() + bi + 1, seq.begin() + bk + 1);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool orOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        int bestDelta = 0, bi = -1, bj = -1;\n\n        for (int i = 1; i < m; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int removeCost = Sym(prev, x) + Sym(x, next) - Sym(prev, next);\n\n            for (int j = 0; j < m; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j], b = seq[(j + 1) % m];\n                int addCost = Sym(a, x) + Sym(x, b) - Sym(a, b);\n                int delta = addCost - removeCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            int x = seq[bi];\n            seq.erase(seq.begin() + bi);\n\n            int pos;\n            if (bj > bi) pos = bj;\n            else pos = bj + 1;\n\n            seq.insert(seq.begin() + pos, x);\n            return true;\n        }\n\n        return false;\n    }\n\n    void optimizeOrder(vector<int> &seq, double limit) {\n        while (timer.elapsed() < limit) {\n            bool improved = false;\n\n            if (twoOptOnce(seq)) improved = true;\n            if (timer.elapsed() >= limit) break;\n            if (orOptOnce(seq)) improved = true;\n\n            if (!improved) break;\n        }\n    }\n\n    void safeRemove(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n\n            for (int i = 1; i < m; i++) {\n                int x = seq[i];\n\n                cov.addCell(x, -1);\n\n                if (cov.bad == 0) {\n                    int prev = seq[i - 1];\n                    int next = seq[(i + 1) % m];\n                    int save = D(prev, x) + D(x, next) - D(prev, next);\n\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestIdx = i;\n                    }\n                }\n\n                cov.addCell(x, +1);\n            }\n\n            if (bestIdx < 0) break;\n\n            cov.addCell(seq[bestIdx], -1);\n            seq.erase(seq.begin() + bestIdx);\n        }\n    }\n\n    void improveReplace(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                token++;\n                if (token == INT_MAX) {\n                    fill(seen.begin(), seen.end(), 0);\n                    token = 1;\n                }\n\n                cov.addCell(old, -1);\n\n                auto evalCand = [&](int p) {\n                    if (seen[p] == token) return;\n                    seen[p] = token;\n\n                    if (p == old) return;\n\n                    int newCost = D(prev, p) + D(p, next);\n                    int delta = newCost - oldCost;\n\n                    if (delta >= bestDelta) return;\n\n                    cov.addCell(p, +1);\n\n                    if (cov.bad == 0) {\n                        bestDelta = delta;\n                        bestIdx = i;\n                        bestP = p;\n                    }\n\n                    cov.addCell(p, -1);\n                };\n\n                for (int p : hCells[hid[old]]) evalCand(p);\n                for (int p : vCells[vid[old]]) evalCand(p);\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    void improveReplaceCritical(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                cov.addCell(old, -1);\n\n                if (cov.bad > 0) {\n                    int fb = -1;\n                    for (int q = 0; q < R; q++) {\n                        if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                            fb = q;\n                            break;\n                        }\n                    }\n\n                    if (fb >= 0) {\n                        token++;\n                        if (token == INT_MAX) {\n                            fill(seen.begin(), seen.end(), 0);\n                            token = 1;\n                        }\n\n                        auto evalCand = [&](int p) {\n                            if (seen[p] == token) return;\n                            seen[p] = token;\n                            if (p == old) return;\n\n                            int newCost = D(prev, p) + D(p, next);\n                            int delta = newCost - oldCost;\n                            if (delta >= bestDelta) return;\n\n                            cov.addCell(p, +1);\n                            if (cov.bad == 0) {\n                                bestDelta = delta;\n                                bestIdx = i;\n                                bestP = p;\n                            }\n                            cov.addCell(p, -1);\n                        };\n\n                        for (int p : hCells[hid[fb]]) evalCand(p);\n                        for (int p : vCells[vid[fb]]) evalCand(p);\n                    }\n                }\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    vector<int> dynamicShortestPath(int a, int b, const Cover &cov) const {\n        vector<int> fallback;\n        getPathCellsUnordered(a, b, fallback);\n\n        if (a == b) return {};\n\n        int target = D(a, b);\n        if (target >= INF16) return fallback;\n\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<int> badH(nH, 0), badV(nV, 0);\n\n        if (cov.bad > 0) {\n            for (int q = 0; q < R; q++) {\n                if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                    badH[hid[q]]++;\n                    badV[vid[q]]++;\n                }\n            }\n        }\n\n        vector<int> reward(R, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int g = 0;\n\n            if (cov.cntH[h] == 0) g += badH[h];\n            if (cov.cntV[v] == 0) g += badV[v];\n            if (cov.cntH[h] == 0 && cov.cntV[v] == 0) g--;\n\n            reward[p] = g * 10000 + min(visVal[p], 9999);\n        }\n\n        vector<int> nodes;\n        nodes.reserve(R);\n\n        for (int p = 0; p < R; p++) {\n            if (D(a, p) + D(p, b) == target) nodes.push_back(p);\n        }\n\n        sort(nodes.begin(), nodes.end(), [&](int x, int y) {\n            int dx = D(a, x), dy = D(a, y);\n            if (dx != dy) return dx < dy;\n            return x < y;\n        });\n\n        const long long NEG = -(1LL << 60);\n        vector<long long> dp(R, NEG);\n        vector<int> parent(R, -1);\n\n        dp[a] = 0;\n        parent[a] = a;\n\n        for (int v : nodes) {\n            if (dp[v] == NEG) continue;\n\n            int dv = D(a, v);\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n                if (to < 0) continue;\n\n                if (dv + wt[to] != D(a, to)) continue;\n                if (D(a, to) + D(to, b) != target) continue;\n\n                long long ndp = dp[v] + reward[to];\n\n                if (ndp > dp[to]) {\n                    dp[to] = ndp;\n                    parent[to] = v;\n                }\n            }\n        }\n\n        if (parent[b] < 0) return fallback;\n\n        vector<int> out;\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            cur = parent[cur];\n\n            if (cur < 0 || ++cnt > R + 5) return fallback;\n        }\n\n        return out;\n    }\n\n    bool rerouteEdgesImprove(vector<int> &seq, vector<vector<int>> &edgeCells, double limit) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int m = (int)seq.size();\n        vector<int> ord(m);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            int da = D(seq[a], seq[(a + 1) % m]);\n            int db = D(seq[b], seq[(b + 1) % m]);\n            return da > db;\n        });\n\n        bool any = false;\n\n        for (int pass = 0; pass < 2 && timer.elapsed() < limit; pass++) {\n            bool changed = false;\n\n            for (int idx = 0; idx < m && timer.elapsed() < limit; idx++) {\n                int i = ord[idx];\n\n                vector<int> oldPath = edgeCells[i];\n\n                applyPath(cov, oldPath, -1);\n\n                vector<int> np = dynamicShortestPath(seq[i], seq[(i + 1) % m], cov);\n                applyPath(cov, np, +1);\n\n                if (cov.bad == 0) {\n                    if (np != oldPath) {\n                        edgeCells[i] = np;\n                        changed = true;\n                        any = true;\n                    }\n                } else {\n                    applyPath(cov, np, -1);\n                    applyPath(cov, oldPath, +1);\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool pathRemove(vector<int> &seq, vector<vector<int>> &edgeCells, double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n            vector<int> bestNewPath;\n\n            for (int i = 1; i < m; i++) {\n                int prev = seq[i - 1];\n                int x = seq[i];\n                int next = seq[(i + 1) % m];\n\n                int save = D(prev, x) + D(x, next) - D(prev, next);\n                if (save < bestSave) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n\n                vector<int> np;\n                getPathCellsUnordered(prev, next, np);\n\n                applyPath(cov, np, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand = np;\n\n                applyPath(cov, np, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    vector<int> dp = dynamicShortestPath(prev, next, cov);\n\n                    applyPath(cov, dp, +1);\n\n                    if (cov.bad == 0) {\n                        ok = true;\n                        cand = dp;\n                    }\n\n                    applyPath(cov, dp, -1);\n                }\n\n                if (ok && save > bestSave) {\n                    bestSave = save;\n                    bestIdx = i;\n                    bestNewPath = cand;\n                }\n\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            applyPath(cov, edgeCells[bestIdx - 1], -1);\n            applyPath(cov, edgeCells[bestIdx], -1);\n            applyPath(cov, bestNewPath, +1);\n\n            seq.erase(seq.begin() + bestIdx);\n            edgeCells[bestIdx - 1] = bestNewPath;\n            edgeCells.erase(edgeCells.begin() + bestIdx);\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool pathBlockRemove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                         double limit, int maxLen, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 2) break;\n\n            int bestL = -1, bestR = -1;\n            int bestSave = 0;\n            vector<int> bestPath;\n\n            for (int len = 2; len <= maxLen; len++) {\n                if (len >= m) break;\n\n                for (int l = 1; l + len - 1 < m; l++) {\n                    int r = l + len - 1;\n                    int prev = seq[l - 1];\n                    int next = seq[(r + 1) % m];\n\n                    int oldCost = 0;\n                    for (int e = l - 1; e <= r; e++) {\n                        oldCost += D(seq[e], seq[(e + 1) % m]);\n                    }\n\n                    int save = oldCost - D(prev, next);\n                    if (save <= bestSave) continue;\n\n                    for (int e = l - 1; e <= r; e++) applyPath(cov, edgeCells[e], -1);\n\n                    vector<int> np;\n                    getPathCellsUnordered(prev, next, np);\n                    applyPath(cov, np, +1);\n\n                    bool ok = cov.bad == 0;\n                    vector<int> cand = np;\n\n                    applyPath(cov, np, -1);\n\n                    if (!ok && useDynamic && timer.elapsed() < limit) {\n                        vector<int> dp = dynamicShortestPath(prev, next, cov);\n                        applyPath(cov, dp, +1);\n\n                        if (cov.bad == 0) {\n                            ok = true;\n                            cand = dp;\n                        }\n\n                        applyPath(cov, dp, -1);\n                    }\n\n                    if (ok && save > bestSave) {\n                        bestSave = save;\n                        bestL = l;\n                        bestR = r;\n                        bestPath = cand;\n                    }\n\n                    for (int e = r; e >= l - 1; e--) applyPath(cov, edgeCells[e], +1);\n\n                    if (timer.elapsed() >= limit) break;\n                }\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestL < 0) break;\n\n            for (int e = bestL - 1; e <= bestR; e++) applyPath(cov, edgeCells[e], -1);\n            applyPath(cov, bestPath, +1);\n\n            seq.erase(seq.begin() + bestL, seq.begin() + bestR + 1);\n            edgeCells[bestL - 1] = bestPath;\n            edgeCells.erase(edgeCells.begin() + bestL, edgeCells.begin() + bestR + 1);\n        }\n\n        return cov.bad == 0;\n    }\n\n    vector<int> reverseEdgePath(const vector<int> &oldPath, int oldSource) const {\n        vector<int> ret;\n        if (oldPath.empty()) return ret;\n\n        ret.reserve(oldPath.size());\n        ret.push_back(oldSource);\n\n        for (int i = (int)oldPath.size() - 1; i >= 1; i--) {\n            ret.push_back(oldPath[i]);\n        }\n\n        return ret;\n    }\n\n    bool actualTwoOptOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                          Cover &cov, double limit, bool useDynamic) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n        vector<int> bestP1, bestP2;\n        vector<vector<int>> bestMid;\n\n        for (int i = 0; i < m - 1 && timer.elapsed() < limit; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m && timer.elapsed() < limit; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta >= bestDelta) continue;\n\n                for (int e = i; e <= k; e++) applyPath(cov, edgeCells[e], -1);\n\n                vector<vector<int>> mid;\n                mid.reserve(max(0, k - i - 1));\n\n                for (int ne = i + 1; ne <= k - 1; ne++) {\n                    int oldIdx = i + k - ne;\n                    mid.push_back(reverseEdgePath(edgeCells[oldIdx], seq[oldIdx]));\n                    applyPath(cov, mid.back(), +1);\n                }\n\n                vector<int> p1, p2;\n                getPathCellsUnordered(a, c, p1);\n                getPathCellsUnordered(b, d, p2);\n\n                applyPath(cov, p1, +1);\n                applyPath(cov, p2, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand1 = p1, cand2 = p2;\n\n                applyPath(cov, p2, -1);\n                applyPath(cov, p1, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    cand1 = dynamicShortestPath(a, c, cov);\n                    applyPath(cov, cand1, +1);\n\n                    cand2 = dynamicShortestPath(b, d, cov);\n                    applyPath(cov, cand2, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, cand2, -1);\n                    applyPath(cov, cand1, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                    bestP1 = cand1;\n                    bestP2 = cand2;\n                    bestMid = mid;\n                }\n\n                for (auto &v : mid) applyPath(cov, v, -1);\n                for (int e = k; e >= i; e--) applyPath(cov, edgeCells[e], +1);\n            }\n        }\n\n        if (bi < 0) return false;\n\n        for (int e = bi; e <= bk; e++) applyPath(cov, edgeCells[e], -1);\n        applyPath(cov, bestP1, +1);\n        for (auto &v : bestMid) applyPath(cov, v, +1);\n        applyPath(cov, bestP2, +1);\n\n        vector<int> newSeq = seq;\n        reverse(newSeq.begin() + bi + 1, newSeq.begin() + bk + 1);\n\n        vector<vector<int>> newEdges = edgeCells;\n        newEdges[bi] = bestP1;\n        for (int t = 0; t < (int)bestMid.size(); t++) {\n            newEdges[bi + 1 + t] = bestMid[t];\n        }\n        newEdges[bk] = bestP2;\n\n        seq.swap(newSeq);\n        edgeCells.swap(newEdges);\n\n        return true;\n    }\n\n    bool actualTwoOptImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                             double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        bool any = false;\n\n        while (timer.elapsed() < limit) {\n            bool ok = actualTwoOptOnce(seq, edgeCells, cov, limit, useDynamic);\n            if (!ok) break;\n            any = true;\n        }\n\n        return any && cov.bad == 0;\n    }\n\n    void applyOrOptMove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                        int i, int j,\n                        const vector<int> &pPrevNext,\n                        const vector<int> &pAX,\n                        const vector<int> &pXB) {\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n        int m = (int)oldSeq.size();\n\n        vector<int> ns;\n        vector<vector<int>> ne(m);\n\n        ns.reserve(m);\n\n        if (j < i) {\n            for (int k = 0; k <= j; k++) ns.push_back(oldSeq[k]);\n            ns.push_back(oldSeq[i]);\n            for (int k = j + 1; k <= i - 1; k++) ns.push_back(oldSeq[k]);\n            for (int k = i + 1; k < m; k++) ns.push_back(oldSeq[k]);\n\n            for (int k = 0; k < j; k++) ne[k] = oldEdges[k];\n            ne[j] = pAX;\n            ne[j + 1] = pXB;\n            for (int k = j + 2; k <= i - 1; k++) ne[k] = oldEdges[k - 1];\n            ne[i] = pPrevNext;\n            for (int k = i + 1; k < m; k++) ne[k] = oldEdges[k];\n        } else {\n            for (int k = 0; k <= i - 1; k++) ns.push_back(oldSeq[k]);\n            for (int k = i + 1; k <= j; k++) ns.push_back(oldSeq[k]);\n            ns.push_back(oldSeq[i]);\n            for (int k = j + 1; k < m; k++) ns.push_back(oldSeq[k]);\n\n            for (int k = 0; k <= i - 2; k++) ne[k] = oldEdges[k];\n            ne[i - 1] = pPrevNext;\n            for (int k = i; k <= j - 2; k++) ne[k] = oldEdges[k + 1];\n            ne[j - 1] = pAX;\n            ne[j] = pXB;\n            for (int k = j + 1; k < m; k++) ne[k] = oldEdges[k];\n        }\n\n        if ((int)ns.size() == m && (int)ne.size() == m) {\n            seq.swap(ns);\n            edgeCells.swap(ne);\n        }\n    }\n\n    bool actualOrOptOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                         double limit, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n        vector<int> bestPN, bestAX, bestXB;\n\n        for (int i = 1; i < m && timer.elapsed() < limit; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int oldCost = D(prev, x) + D(x, next);\n\n            for (int j = 0; j < m && timer.elapsed() < limit; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n\n                int delta = D(prev, next) + D(a, x) + D(x, b)\n                          - oldCost - D(a, b);\n\n                if (delta >= bestDelta) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n                applyPath(cov, edgeCells[j], -1);\n\n                vector<int> pn, ax, xb;\n                getPathCellsUnordered(prev, next, pn);\n                getPathCellsUnordered(a, x, ax);\n                getPathCellsUnordered(x, b, xb);\n\n                applyPath(cov, pn, +1);\n                applyPath(cov, ax, +1);\n                applyPath(cov, xb, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> candPN = pn, candAX = ax, candXB = xb;\n\n                applyPath(cov, xb, -1);\n                applyPath(cov, ax, -1);\n                applyPath(cov, pn, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    candPN = dynamicShortestPath(prev, next, cov);\n                    applyPath(cov, candPN, +1);\n                    candAX = dynamicShortestPath(a, x, cov);\n                    applyPath(cov, candAX, +1);\n                    candXB = dynamicShortestPath(x, b, cov);\n                    applyPath(cov, candXB, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, candXB, -1);\n                    applyPath(cov, candAX, -1);\n                    applyPath(cov, candPN, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                    bestPN = candPN;\n                    bestAX = candAX;\n                    bestXB = candXB;\n                }\n\n                applyPath(cov, edgeCells[j], +1);\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n            }\n        }\n\n        if (bestI < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        applyOrOptMove(seq, edgeCells, bestI, bestJ, bestPN, bestAX, bestXB);\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualOrOptImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                            double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualOrOptOnce(seq, edgeCells, limit, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool actualReplaceOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                           double limit, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 2) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestI = -1, bestP = -1;\n        vector<int> bestA, bestB;\n\n        for (int i = 1; i < m && timer.elapsed() < limit; i++) {\n            int old = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int oldCost = D(prev, old) + D(old, next);\n\n            applyPath(cov, edgeCells[i - 1], -1);\n            applyPath(cov, edgeCells[i], -1);\n\n            for (int p = 0; p < R && timer.elapsed() < limit; p++) {\n                if (p == old || p == prev || p == next) continue;\n\n                int delta = D(prev, p) + D(p, next) - oldCost;\n                if (delta >= bestDelta) continue;\n\n                vector<int> pa, pb;\n                getPathCellsUnordered(prev, p, pa);\n                getPathCellsUnordered(p, next, pb);\n\n                applyPath(cov, pa, +1);\n                applyPath(cov, pb, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> ca = pa, cb = pb;\n\n                applyPath(cov, pb, -1);\n                applyPath(cov, pa, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    ca = dynamicShortestPath(prev, p, cov);\n                    applyPath(cov, ca, +1);\n                    cb = dynamicShortestPath(p, next, cov);\n                    applyPath(cov, cb, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, cb, -1);\n                    applyPath(cov, ca, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestP = p;\n                    bestA = ca;\n                    bestB = cb;\n                }\n            }\n\n            applyPath(cov, edgeCells[i], +1);\n            applyPath(cov, edgeCells[i - 1], +1);\n        }\n\n        if (bestI < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        seq[bestI] = bestP;\n        edgeCells[bestI - 1] = bestA;\n        edgeCells[bestI] = bestB;\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualReplaceImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                              double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualReplaceOnce(seq, edgeCells, limit, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool actualBlockReplaceOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                                double limit, int maxLen, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestL = -1, bestR = -1, bestP = -1;\n        vector<int> bestA, bestB;\n\n        for (int len = 2; len <= maxLen && timer.elapsed() < limit; len++) {\n            if (len >= m) break;\n\n            for (int l = 1; l + len - 1 < m && timer.elapsed() < limit; l++) {\n                int r = l + len - 1;\n                int prev = seq[l - 1];\n                int next = seq[(r + 1) % m];\n\n                int oldCost = 0;\n                for (int e = l - 1; e <= r; e++) {\n                    oldCost += D(seq[e], seq[(e + 1) % m]);\n                }\n\n                for (int e = l - 1; e <= r; e++) applyPath(cov, edgeCells[e], -1);\n\n                for (int p = 0; p < R && timer.elapsed() < limit; p++) {\n                    if (p == prev || p == next) continue;\n\n                    int delta = D(prev, p) + D(p, next) - oldCost;\n                    if (delta >= bestDelta) continue;\n\n                    vector<int> pa, pb;\n                    getPathCellsUnordered(prev, p, pa);\n                    getPathCellsUnordered(p, next, pb);\n\n                    applyPath(cov, pa, +1);\n                    applyPath(cov, pb, +1);\n\n                    bool ok = cov.bad == 0;\n                    vector<int> ca = pa, cb = pb;\n\n                    applyPath(cov, pb, -1);\n                    applyPath(cov, pa, -1);\n\n                    if (!ok && useDynamic && timer.elapsed() < limit) {\n                        ca = dynamicShortestPath(prev, p, cov);\n                        applyPath(cov, ca, +1);\n                        cb = dynamicShortestPath(p, next, cov);\n                        applyPath(cov, cb, +1);\n\n                        if (cov.bad == 0) ok = true;\n\n                        applyPath(cov, cb, -1);\n                        applyPath(cov, ca, -1);\n                    }\n\n                    if (ok) {\n                        bestDelta = delta;\n                        bestL = l;\n                        bestR = r;\n                        bestP = p;\n                        bestA = ca;\n                        bestB = cb;\n                    }\n                }\n\n                for (int e = r; e >= l - 1; e--) applyPath(cov, edgeCells[e], +1);\n            }\n        }\n\n        if (bestL < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        seq.erase(seq.begin() + bestL, seq.begin() + bestR + 1);\n        seq.insert(seq.begin() + bestL, bestP);\n\n        edgeCells[bestL - 1] = bestA;\n        edgeCells.erase(edgeCells.begin() + bestL, edgeCells.begin() + bestR + 1);\n        edgeCells.insert(edgeCells.begin() + bestL, bestB);\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualBlockReplaceImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                                   double limit, int maxLen, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualBlockReplaceOnce(seq, edgeCells, limit, maxLen, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    int edgeCellTotal(const vector<vector<int>> &edgeCells) const {\n        int ret = 0;\n        for (auto &v : edgeCells) ret += (int)v.size();\n        return ret;\n    }\n\n    void updateFinalStatic(const vector<int> &seq) {\n        long long c = routeCost(seq);\n\n        if (c < bestFinalCost) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges.clear();\n        }\n    }\n\n    void updateFinalRoute(const vector<int> &seq, const vector<vector<int>> &edgeCells) {\n        long long c = routeCost(seq);\n\n        if (c > bestFinalCost) return;\n        if (!actualFullEdges(seq, edgeCells)) return;\n        if (!edgeCells.empty() && !validEdgePaths(seq, edgeCells)) return;\n\n        bool upd = false;\n\n        if (c < bestFinalCost) {\n            upd = true;\n        } else if (c == bestFinalCost && !edgeCells.empty()) {\n            if (bestFinalEdges.empty() || edgeCellTotal(edgeCells) > edgeCellTotal(bestFinalEdges)) {\n                upd = true;\n            }\n        }\n\n        if (upd) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges = edgeCells;\n        }\n    }\n\n    void updateSafe(const vector<int> &seq) {\n        if (!checkpointFull(seq)) return;\n\n        long long c = routeCost(seq);\n\n        if (c < bestSafeCost) {\n            bestSafeCost = c;\n            bestSafeSeq = seq;\n        }\n\n        updateFinalStatic(seq);\n    }\n\n    void processCandidate(vector<int> seq, bool heavy) {\n        if (seq.empty()) return;\n\n        double lim = min(2.50, timer.elapsed() + (heavy ? 0.22 : 0.08));\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n        if (timer.elapsed() < lim) safeRemove(seq, lim);\n\n        if (heavy && timer.elapsed() < lim) {\n            improveReplace(seq, lim);\n            improveReplaceCritical(seq, lim);\n            safeRemove(seq, lim);\n        }\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.62) {\n            vector<int> pseq = seq;\n            vector<vector<int>> pedges;\n\n            double plim = min(2.67, timer.elapsed() + (heavy ? 0.085 : 0.045));\n            bool dyn = heavy || timer.elapsed() < 1.80;\n\n            if (pathRemove(pseq, pedges, plim, dyn)) {\n                if (heavy && timer.elapsed() < plim) {\n                    pathBlockRemove(pseq, pedges, plim, 2, dyn);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    string buildOutput(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        string ans;\n        ans.reserve(200000);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                int cur = seq[i];\n\n                for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                    int p = edgeCells[i][k];\n                    ans.push_back(moveChar(cur, p));\n                    cur = p;\n                }\n            }\n\n            return ans;\n        }\n\n        vector<int> path;\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsOrdered(a, b, path);\n\n            int cur = a;\n\n            for (int p : path) {\n                ans.push_back(moveChar(cur, p));\n                cur = p;\n            }\n        }\n\n        return ans;\n    }\n\n    string dfsFallback() const {\n        vector<vector<int>> child(R);\n        vector<int> par(R, -1);\n        queue<int> q;\n\n        par[S] = S;\n        q.push(S);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n\n                if (to >= 0 && par[to] < 0) {\n                    par[to] = v;\n                    child[v].push_back(to);\n                    q.push(to);\n                }\n            }\n        }\n\n        string ans;\n        ans.reserve(max(0, 2 * (R - 1)));\n\n        function<void(int)> dfs = [&](int v) {\n            for (int to : child[v]) {\n                ans.push_back(moveChar(v, to));\n                dfs(to);\n                ans.push_back(moveChar(to, v));\n            }\n        };\n\n        dfs(S);\n        return ans;\n    }\n\n    void finalPolish(bool hard) {\n        if (bestSafeSeq.empty() || timer.elapsed() > 2.76) return;\n\n        vector<int> seq = bestSafeSeq;\n        double lim = 2.84;\n\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n        improveReplace(seq, lim);\n        improveReplaceCritical(seq, lim);\n        safeRemove(seq, lim);\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() >= 2.86) return;\n\n        vector<int> pseq = seq;\n        vector<vector<int>> pedges;\n\n        if (!hard) {\n            if (pathRemove(pseq, pedges, 2.89, true)) {\n                if (timer.elapsed() < 2.895) {\n                    pathBlockRemove(pseq, pedges, 2.908, 3, true);\n                }\n\n                if (timer.elapsed() < 2.908) {\n                    actualBlockReplaceImprove(pseq, pedges, 2.925, 2, false);\n                }\n\n                if (timer.elapsed() < 2.925) {\n                    actualTwoOptImprove(pseq, pedges, 2.938, true);\n                }\n\n                if (timer.elapsed() < 2.938) {\n                    actualOrOptImprove(pseq, pedges, 2.948, false);\n                }\n\n                if (timer.elapsed() < 2.948) {\n                    actualReplaceImprove(pseq, pedges, 2.955, false);\n                }\n\n                if (timer.elapsed() < 2.955) {\n                    pathRemove(pseq, pedges, 2.960, true);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        } else {\n            if (pathRemove(pseq, pedges, 2.890, true)) {\n                if (timer.elapsed() < 2.890) {\n                    pathBlockRemove(pseq, pedges, 2.905, 3, true);\n                }\n\n                if (timer.elapsed() < 2.905) {\n                    actualTwoOptImprove(pseq, pedges, 2.922, true);\n                }\n\n                if (timer.elapsed() < 2.922) {\n                    rerouteEdgesImprove(pseq, pedges, 2.932);\n                }\n\n                if (timer.elapsed() < 2.932) {\n                    pathRemove(pseq, pedges, 2.940, true);\n                }\n\n                if (timer.elapsed() < 2.940) {\n                    actualBlockReplaceImprove(pseq, pedges, 2.952, 2, false);\n                }\n\n                if (timer.elapsed() < 2.952) {\n                    actualOrOptImprove(pseq, pedges, 2.960, false);\n                }\n\n                if (timer.elapsed() < 2.960) {\n                    actualReplaceImprove(pseq, pedges, 2.965, false);\n                }\n\n                if (timer.elapsed() < 2.965) {\n                    pathRemove(pseq, pedges, 2.970, true);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    void finalActualPolish(bool hard) {\n        if (bestFinalSeq.empty()) return;\n\n        if (!hard && timer.elapsed() > 2.90) return;\n        if (hard && timer.elapsed() > 2.91) return;\n\n        vector<int> seq = bestFinalSeq;\n        vector<vector<int>> edges = bestFinalEdges;\n        ensureEdgeCells(seq, edges);\n\n        if (!actualFullEdges(seq, edges)) return;\n\n        if (!hard) {\n            if (timer.elapsed() < 2.915) {\n                pathBlockRemove(seq, edges, 2.925, 3, true);\n            }\n\n            if (timer.elapsed() < 2.925) {\n                actualBlockReplaceImprove(seq, edges, 2.940, 2, false);\n            }\n\n            if (timer.elapsed() < 2.940) {\n                actualOrOptImprove(seq, edges, 2.950, false);\n            }\n\n            if (timer.elapsed() < 2.950) {\n                actualReplaceImprove(seq, edges, 2.957, false);\n            }\n\n            if (timer.elapsed() < 2.957) {\n                pathRemove(seq, edges, 2.962, true);\n            }\n\n            updateFinalRoute(seq, edges);\n        } else {\n            if (timer.elapsed() < 2.915) {\n                pathBlockRemove(seq, edges, 2.925, 3, true);\n            }\n\n            if (timer.elapsed() < 2.925) {\n                actualTwoOptImprove(seq, edges, 2.938, true);\n            }\n\n            if (timer.elapsed() < 2.938) {\n                rerouteEdgesImprove(seq, edges, 2.946);\n            }\n\n            if (timer.elapsed() < 2.946) {\n                pathRemove(seq, edges, 2.952, true);\n            }\n\n            if (timer.elapsed() < 2.952) {\n                actualBlockReplaceImprove(seq, edges, 2.962, 2, false);\n            }\n\n            if (timer.elapsed() < 2.962) {\n                actualOrOptImprove(seq, edges, 2.968, false);\n            }\n\n            if (timer.elapsed() < 2.968) {\n                pathRemove(seq, edges, 2.972, true);\n            }\n\n            updateFinalRoute(seq, edges);\n        }\n    }\n\n    void finalRerouteOpportunity() {\n        if (bestFinalSeq.empty() || timer.elapsed() > 2.962) return;\n\n        vector<int> seq = bestFinalSeq;\n        vector<vector<int>> edges = bestFinalEdges;\n        ensureEdgeCells(seq, edges);\n\n        if (!actualFullEdges(seq, edges)) return;\n\n        if (timer.elapsed() < 2.966) {\n            rerouteEdgesImprove(seq, edges, 2.974);\n        }\n\n        if (timer.elapsed() < 2.974) {\n            pathRemove(seq, edges, 2.982, true);\n        }\n\n        updateFinalRoute(seq, edges);\n    }\n\n    void solve() {\n        readInput();\n        buildRoadGraph();\n        buildSegments();\n        computeAPSP();\n        computeSegmentApprox();\n\n        vector<pair<double, double>> cellParams = {\n            {1.25, 0.0},\n            {1.00, 0.0},\n            {1.50, 0.0},\n            {0.75, 0.0},\n            {1.25, 30.0},\n            {1.70, 80.0}\n        };\n\n        for (int i = 0; i < (int)cellParams.size(); i++) {\n            if (i > 0 && timer.elapsed() > 2.18) break;\n\n            auto [a, l] = cellParams[i];\n            vector<int> seq = constructCellCover(a, l);\n            processCandidate(seq, i == 0);\n        }\n\n        vector<int> vcTypes = {0, 2, 3, 1, 5, 4, 6, 7};\n\n        for (int tp : vcTypes) {\n            if (timer.elapsed() > 2.34) break;\n\n            auto [selH, selV] = weightedVertexCover(tp);\n\n            vector<int> seq = constructSegmentCover(selH, selV, 1.0, 25.0);\n            processCandidate(seq, false);\n\n            if (timer.elapsed() > 2.34) break;\n\n            if (tp == 0) {\n                vector<int> seq2 = constructSegmentCover(selH, selV, 1.0, 0.0);\n                processCandidate(seq2, false);\n            }\n        }\n\n        for (int mode = 0; mode < 3; mode++) {\n            if (timer.elapsed() > 2.40) break;\n\n            auto [selH, selV] = preferenceCover(mode);\n            vector<int> seq = constructSegmentCover(selH, selV, 1.2, 10.0);\n            processCandidate(seq, false);\n        }\n\n        if (!bestSafeSeq.empty()) {\n            for (int mode = 0; mode < 2; mode++) {\n                if (timer.elapsed() > 2.43) break;\n\n                auto [selH, selV] = insertionWeightedVertexCover(bestSafeSeq, mode);\n                vector<int> seq = constructSegmentCover(selH, selV, 1.0, 15.0);\n                processCandidate(seq, false);\n            }\n        }\n\n        long long refCost = bestFinalCost;\n        if (refCost >= (1LL << 55)) refCost = bestSafeCost;\n        bool hard = (refCost < (1LL << 55) && refCost > 54LL * N);\n\n        finalPolish(hard);\n        finalActualPolish(hard);\n        if (!hard) finalRerouteOpportunity();\n\n        if (!bestFinalSeq.empty() &&\n            actualFullEdges(bestFinalSeq, bestFinalEdges) &&\n            validEdgePaths(bestFinalSeq, bestFinalEdges)) {\n            cout << buildOutput(bestFinalSeq, bestFinalEdges) << '\\n';\n        } else if (!bestSafeSeq.empty() && actualFull(bestSafeSeq)) {\n            vector<vector<int>> emptyEdges;\n            cout << buildOutput(bestSafeSeq, emptyEdges) << '\\n';\n        } else {\n            cout << dfsFallback() << '\\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\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconst int MAXN = 1000;\nconst int MAXM = 20;\nconst int MAXK = 20;\nconst int PARTICLES = 128;\n\nint N, M, K, R;\nint reqv[MAXN][MAXK];\n\nvector<int> children_[MAXN];\n\nint statusTask[MAXN]; // 0: unstarted, 1: running, 2: done\nint remDep[MAXN];\nint readyDay[MAXN];\n\nint sumReq[MAXN];\nint descCnt[MAXN];\n\ndouble baseDur[MAXN];\ndouble predDur[MAXM][MAXN];\ndouble sumPred[MAXN];\ndouble upRank_[MAXN];\n\ndouble priorSkill[MAXK];\nint initSkill[MAXK];\nint upperSkill[MAXK];\n\nstatic bitset<MAXN> reachBits[MAXN];\n\nunsigned char particleSkill[PARTICLES][MAXK];\ndouble particlePrior[PARTICLES];\ndouble particleLoss[MAXM][PARTICLES];\n\nstruct Member {\n    int skill[MAXK];\n    vector<int> obsTask;\n    vector<int> obsDur;\n    int task = -1;\n    int startDay = 0;\n};\n\nMember members_[MAXM];\n\ninline double expectedTimeFromW(int w) {\n    if (w <= 0) return 1.0;\n    if (w == 1) return 13.0 / 7.0;\n    if (w == 2) return 17.0 / 7.0;\n    if (w == 3) return 22.0 / 7.0;\n    return (double)w;\n}\n\ninline int calcW(int task, const int skill[]) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        if (reqv[task][k] > skill[k]) {\n            w += reqv[task][k] - skill[k];\n        }\n    }\n    return w;\n}\n\ninline int calcWParticle(int task, int p) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        int s = (int)particleSkill[p][k];\n        if (reqv[task][k] > s) {\n            w += reqv[task][k] - s;\n        }\n    }\n    return w;\n}\n\ninline double durationWithSkill(int task, const int skill[]) {\n    return expectedTimeFromW(calcW(task, skill));\n}\n\ninline double obsLoss(int w, int t) {\n    double p = expectedTimeFromW(w);\n    double diff = p - t;\n    return diff * diff;\n}\n\nconst double PRIOR_W = 0.003;\n\ninline double priorLossComp(int k, int v) {\n    double diff = v - priorSkill[k];\n    return PRIOR_W * diff * diff;\n}\n\nvoid generateParticles() {\n    mt19937 rng(123456789);\n    normal_distribution<double> nd(0.0, 1.0);\n\n    for (int p = 0; p < PARTICLES; p++) {\n        double z[MAXK];\n        double norm = 0.0;\n\n        for (int k = 0; k < K; k++) {\n            z[k] = fabs(nd(rng));\n            norm += z[k] * z[k];\n        }\n\n        norm = sqrt(max(norm, 1e-12));\n\n        // Stratified norm q in [20, 60], matching the generator distribution.\n        double q = 20.0 + 40.0 * ((double)p + 0.5) / (double)PARTICLES;\n\n        particlePrior[p] = 0.0;\n\n        for (int k = 0; k < K; k++) {\n            int v = (int)llround(q * z[k] / norm);\n            v = max(0, min(60, v));\n            particleSkill[p][k] = (unsigned char)v;\n            particlePrior[p] += priorLossComp(k, v);\n        }\n    }\n\n    for (int j = 0; j < MAXM; j++) {\n        for (int p = 0; p < PARTICLES; p++) {\n            particleLoss[j][p] = 0.0;\n        }\n    }\n}\n\nvoid updateParticleLoss(int member, int task, int dur) {\n    for (int p = 0; p < PARTICLES; p++) {\n        int w = calcWParticle(task, p);\n        particleLoss[member][p] += obsLoss(w, dur);\n    }\n}\n\ndouble runCoordinateDescent(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return 0.0;\n\n    vector<int> w(O);\n    for (int i = 0; i < O; i++) {\n        w[i] = calcW(mem.obsTask[i], mem.skill);\n    }\n\n    double curPrior = 0.0;\n    for (int k = 0; k < K; k++) {\n        curPrior += priorLossComp(k, mem.skill[k]);\n    }\n\n    double curObj = curPrior;\n    for (int i = 0; i < O; i++) {\n        curObj += obsLoss(w[i], mem.obsDur[i]);\n    }\n\n    const int MAX_PASS = 4;\n\n    for (int pass = 0; pass < MAX_PASS; pass++) {\n        bool improved = false;\n\n        for (int k = 0; k < K; k++) {\n            int oldVal = mem.skill[k];\n            double priorExcept = curPrior - priorLossComp(k, oldVal);\n\n            int bestVal = oldVal;\n            double bestObj = curObj;\n\n            for (int v = 0; v <= upperSkill[k]; v++) {\n                if (v == oldVal) continue;\n\n                double obj = priorExcept + priorLossComp(k, v);\n\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > v) {\n                        newContrib = reqv[task][k] - v;\n                    }\n\n                    int nw = w[i] - oldContrib + newContrib;\n                    obj += obsLoss(nw, mem.obsDur[i]);\n\n                    if (obj >= bestObj) break;\n                }\n\n                if (obj + 1e-9 < bestObj) {\n                    bestObj = obj;\n                    bestVal = v;\n                }\n            }\n\n            if (bestVal != oldVal) {\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > bestVal) {\n                        newContrib = reqv[task][k] - bestVal;\n                    }\n\n                    w[i] += newContrib - oldContrib;\n                }\n\n                mem.skill[k] = bestVal;\n                curPrior = priorExcept + priorLossComp(k, bestVal);\n                curObj = bestObj;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return curObj;\n}\n\nvoid optimizeMember(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return;\n\n    // Original optimizer first.\n    double obj = runCoordinateDescent(j);\n\n    // Conservative multi-start fallback.\n    // Use it only after enough observations, and only if a sampled realistic skill\n    // vector is already clearly better than the current local optimum.\n    int threshold = max(6, K / 2);\n    if (O >= threshold) {\n        int bestP = -1;\n        double bestObj = 1e100;\n\n        for (int p = 0; p < PARTICLES; p++) {\n            double cand = particleLoss[j][p] + particlePrior[p];\n            if (cand < bestObj) {\n                bestObj = cand;\n                bestP = p;\n            }\n        }\n\n        if (bestP >= 0 && bestObj + 0.5 < obj) {\n            for (int k = 0; k < K; k++) {\n                mem.skill[k] = (int)particleSkill[bestP][k];\n            }\n            runCoordinateDescent(j);\n        }\n    }\n}\n\nvoid updateMemberPredictions(int j) {\n    Member &mem = members_[j];\n\n    double nobs = (double)mem.obsTask.size();\n    double trust = 0.0;\n    if (nobs > 0) trust = nobs / (nobs + 3.0);\n\n    for (int i = 0; i < N; i++) {\n        double pSkill = durationWithSkill(i, mem.skill);\n        double np = trust * pSkill + (1.0 - trust) * baseDur[i];\n\n        sumPred[i] += np - predDur[j][i];\n        predDur[j][i] = np;\n    }\n}\n\nvoid recomputeRanks() {\n    for (int i = N - 1; i >= 0; i--) {\n        if (statusTask[i] == 2) {\n            upRank_[i] = 0.0;\n            continue;\n        }\n\n        double mx = 0.0;\n        for (int v : children_[i]) {\n            if (statusTask[v] != 2) {\n                mx = max(mx, upRank_[v]);\n            }\n        }\n\n        double avg = sumPred[i] / M;\n        upRank_[i] = avg + 0.015 * sumReq[i] + mx;\n    }\n}\n\ndouble taskPriority(int task, int day) {\n    double pr = upRank_[task];\n\n    pr += 0.015 * descCnt[task];\n    pr += 0.25 * (double)children_[task].size();\n\n    int unlock = 0;\n    for (int v : children_[task]) {\n        if (statusTask[v] == 0 && remDep[v] == 1) unlock++;\n    }\n    pr += 2.0 * unlock;\n\n    if (readyDay[task] > 0) {\n        pr += 0.015 * max(0, day - readyDay[task]);\n    }\n\n    return pr;\n}\n\ndouble edgeScore(int member, int task, double prio) {\n    double avg = sumPred[task] / M;\n    double p = predDur[member][task];\n\n    return prio + 0.4 * avg - p;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n\n    int V;\n    vector<vector<Edge>> graph;\n\n    MinCostFlow(int n = 0) {\n        init(n);\n    }\n\n    void init(int n) {\n        V = n;\n        graph.assign(V, {});\n    }\n\n    void addEdge(int fr, int to, int cap, ll cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge r{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(r);\n    }\n\n    pair<int, ll> minCostFlow(int s, int t, int maxf) {\n        const ll INF = (1LL << 62);\n\n        int flow = 0;\n        ll cost = 0;\n\n        vector<ll> h(V, 0), dist(V);\n        vector<int> prevv(V), preve(V);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != cd) continue;\n\n                for (int i = 0; i < (int)graph[v].size(); i++) {\n                    Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n\n                    ll nd = dist[v] + e.cost + h[v] - h[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INF) break;\n\n            for (int v = 0; v < V; v++) {\n                if (dist[v] < INF) h[v] += dist[v];\n            }\n\n            int add = maxf - flow;\n            ll pathCost = 0;\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                add = min(add, e.cap);\n                pathCost += e.cost;\n            }\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= add;\n                graph[v][e.rev].cap += add;\n            }\n\n            flow += add;\n            cost += pathCost * add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> K >> R)) return 0;\n\n    for (int i = 0; i < N; i++) {\n        sumReq[i] = 0;\n        for (int k = 0; k < K; k++) {\n            cin >> reqv[i][k];\n            sumReq[i] += reqv[i][k];\n        }\n    }\n\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u;\n        --v;\n        children_[u].push_back(v);\n        remDep[v]++;\n    }\n\n    double pi = acos(-1.0);\n    double priorComp = 40.0 * sqrt(2.0 / (pi * K));\n\n    for (int k = 0; k < K; k++) {\n        priorSkill[k] = priorComp;\n        initSkill[k] = (int)round(priorComp);\n        initSkill[k] = max(0, min(60, initSkill[k]));\n        upperSkill[k] = 60;\n    }\n\n    generateParticles();\n\n    for (int j = 0; j < M; j++) {\n        for (int k = 0; k < K; k++) {\n            members_[j].skill[k] = initSkill[k];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        baseDur[i] = durationWithSkill(i, initSkill);\n        sumPred[i] = 0.0;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int i = 0; i < N; i++) {\n            predDur[j][i] = baseDur[i];\n            sumPred[i] += predDur[j][i];\n        }\n    }\n\n    for (int i = N - 1; i >= 0; i--) {\n        for (int v : children_[i]) {\n            reachBits[i] |= reachBits[v];\n            reachBits[i].set(v);\n        }\n        descCnt[i] = (int)reachBits[i].count();\n    }\n\n    for (int i = 0; i < N; i++) {\n        statusTask[i] = 0;\n        readyDay[i] = (remDep[i] == 0 ? 1 : -1);\n    }\n\n    static double prioArr[MAXN];\n\n    for (int day = 1;; day++) {\n        recomputeRanks();\n\n        vector<int> idle;\n        for (int j = 0; j < M; j++) {\n            if (members_[j].task < 0) idle.push_back(j);\n        }\n\n        vector<int> readyTasks;\n        for (int i = 0; i < N; i++) {\n            if (statusTask[i] == 0 && remDep[i] == 0) {\n                readyTasks.push_back(i);\n            }\n        }\n\n        vector<pair<int, int>> assignments;\n\n        if (!idle.empty() && !readyTasks.empty()) {\n            for (int task : readyTasks) {\n                prioArr[task] = taskPriority(task, day);\n            }\n\n            vector<int> sortedReady = readyTasks;\n            sort(sortedReady.begin(), sortedReady.end(), [&](int a, int b) {\n                if (prioArr[a] != prioArr[b]) return prioArr[a] > prioArr[b];\n                return a < b;\n            });\n\n            vector<int> candidates;\n            vector<char> inCand(N, 0);\n\n            auto addCandidate = [&](int task) {\n                if (!inCand[task]) {\n                    inCand[task] = 1;\n                    candidates.push_back(task);\n                }\n            };\n\n            int topC = min((int)sortedReady.size(), max(200, (int)idle.size() * 10));\n            for (int i = 0; i < topC; i++) {\n                addCandidate(sortedReady[i]);\n            }\n\n            const int BEST_PER_MEMBER = 10;\n\n            for (int member : idle) {\n                priority_queue<\n                    pair<double, int>,\n                    vector<pair<double, int>>,\n                    greater<pair<double, int>>\n                > pq;\n\n                for (int task : readyTasks) {\n                    double sc = edgeScore(member, task, prioArr[task]);\n                    if ((int)pq.size() < BEST_PER_MEMBER) {\n                        pq.push({sc, task});\n                    } else if (sc > pq.top().first) {\n                        pq.pop();\n                        pq.push({sc, task});\n                    }\n                }\n\n                while (!pq.empty()) {\n                    addCandidate(pq.top().second);\n                    pq.pop();\n                }\n            }\n\n            int I = (int)idle.size();\n            int C = (int)candidates.size();\n            int F = min(I, min(C, (int)readyTasks.size()));\n\n            if (F > 0) {\n                int S = 0;\n                int memberBase = 1;\n                int taskBase = memberBase + I;\n                int T = taskBase + C;\n\n                MinCostFlow mcf(T + 1);\n\n                for (int i = 0; i < I; i++) {\n                    mcf.addEdge(S, memberBase + i, 1, 0);\n                }\n\n                for (int c = 0; c < C; c++) {\n                    mcf.addEdge(taskBase + c, T, 1, 0);\n                }\n\n                const ll SCALE = 1000;\n                const ll OFFSET = 1000000000000000LL;\n\n                for (int i = 0; i < I; i++) {\n                    int member = idle[i];\n                    for (int c = 0; c < C; c++) {\n                        int task = candidates[c];\n                        double sc = edgeScore(member, task, prioArr[task]);\n                        ll isc = llround(sc * SCALE);\n                        ll cost = OFFSET - isc;\n                        if (cost < 0) cost = 0;\n                        mcf.addEdge(memberBase + i, taskBase + c, 1, cost);\n                    }\n                }\n\n                mcf.minCostFlow(S, T, F);\n\n                for (int i = 0; i < I; i++) {\n                    int node = memberBase + i;\n\n                    for (auto &e : mcf.graph[node]) {\n                        if (e.to >= taskBase && e.to < taskBase + C && e.cap == 0) {\n                            int member = idle[i];\n                            int task = candidates[e.to - taskBase];\n\n                            if (members_[member].task < 0 &&\n                                statusTask[task] == 0 &&\n                                remDep[task] == 0) {\n                                assignments.push_back({member, task});\n                            }\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        for (auto [member, task] : assignments) {\n            members_[member].task = task;\n            members_[member].startDay = day;\n            statusTask[task] = 1;\n        }\n\n        cout << assignments.size();\n        for (auto [member, task] : assignments) {\n            cout << ' ' << member + 1 << ' ' << task + 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int nFinished;\n        if (!(cin >> nFinished)) return 0;\n        if (nFinished == -1) return 0;\n\n        for (int x = 0; x < nFinished; x++) {\n            int f;\n            cin >> f;\n            --f;\n\n            int task = members_[f].task;\n            if (task < 0) continue;\n\n            int dur = day - members_[f].startDay + 1;\n\n            statusTask[task] = 2;\n            members_[f].task = -1;\n\n            members_[f].obsTask.push_back(task);\n            members_[f].obsDur.push_back(dur);\n\n            updateParticleLoss(f, task, dur);\n            optimizeMember(f);\n            updateMemberPredictions(f);\n\n            for (int v : children_[task]) {\n                remDep[v]--;\n                if (remDep[v] == 0 && statusTask[v] == 0) {\n                    readyDay[v] = day + 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NORD = 1000;\nstatic constexpr int OFF = 1000;\nstatic constexpr int NID = 2001;\nstatic constexpr int INF = 1e9;\n\nint X[NID], Y[NID];\nint orderCentral[NORD + 1];\nvector<unsigned short> distMat;\n\ninline int distId(int a, int b) {\n    return distMat[a * NID + b];\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int m) {\n        return (int)(next() % (uint64_t)m);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct InsertRes {\n    int delta;\n    int p;\n    int q;\n};\n\nstruct Solution {\n    vector<int> route;\n    bitset<NORD + 1> selected;\n    int len = INF;\n};\n\nint routeCost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distId(route[i], route[i + 1]);\n    }\n    return s;\n}\n\nint selectedCount(const Solution& sol) {\n    return (int)sol.selected.count();\n}\n\nvector<int> selectedList(const Solution& sol) {\n    vector<int> v;\n    v.reserve(50);\n    for (int i = 1; i <= NORD; i++) {\n        if (sol.selected.test(i)) v.push_back(i);\n    }\n    return v;\n}\n\nInsertRes bestInsertion(const vector<int>& route, int oid) {\n    static constexpr int MAXG = 205;\n\n    int G = (int)route.size() - 1;\n    int P = oid;\n    int D = OFF + oid;\n    int pd = distId(P, D);\n\n    int addP[MAXG], addD[MAXG], consec[MAXG];\n    int suf[MAXG + 1], sufIdx[MAXG + 1];\n\n    for (int g = 0; g < G; g++) {\n        int A = route[g];\n        int B = route[g + 1];\n        int base = distId(A, B);\n\n        int dAP = distId(A, P);\n        int dPB = distId(P, B);\n        int dAD = distId(A, D);\n        int dDB = distId(D, B);\n\n        addP[g] = dAP + dPB - base;\n        addD[g] = dAD + dDB - base;\n        consec[g] = dAP + pd + dDB - base;\n    }\n\n    suf[G] = INF;\n    sufIdx[G] = -1;\n    for (int g = G - 1; g >= 0; g--) {\n        if (addD[g] <= suf[g + 1]) {\n            suf[g] = addD[g];\n            sufIdx[g] = g;\n        } else {\n            suf[g] = suf[g + 1];\n            sufIdx[g] = sufIdx[g + 1];\n        }\n    }\n\n    InsertRes best{INF, 0, 0};\n\n    for (int p = 0; p < G; p++) {\n        if (consec[p] < best.delta) {\n            best = {consec[p], p, p};\n        }\n        if (p + 1 < G) {\n            int cost = addP[p] + suf[p + 1];\n            if (cost < best.delta) {\n                best = {cost, p, sufIdx[p + 1]};\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid insertOrder(vector<int>& route, int oid, const InsertRes& res) {\n    int P = oid;\n    int D = OFF + oid;\n\n    if (res.q == res.p) {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.p + 2, D);\n    } else {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.q + 2, D);\n    }\n}\n\nSolution buildGreedy(int seed) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    auto add = [&](int oid, const InsertRes& res) {\n        insertOrder(sol.route, oid, res);\n        sol.selected.set(oid);\n        sol.len += res.delta;\n        cnt++;\n    };\n\n    if (seed > 0) {\n        InsertRes res = bestInsertion(sol.route, seed);\n        add(seed, res);\n    }\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        add(bestOid, best);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildFromPool(const vector<int>& pool) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid : pool) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        if (bestOid == -1) {\n            for (int oid = 1; oid <= NORD; oid++) {\n                if (sol.selected.test(oid)) continue;\n\n                InsertRes res = bestInsertion(sol.route, oid);\n                int tie = orderCentral[oid];\n\n                if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                    best = res;\n                    bestOid = oid;\n                    bestTie = tie;\n                }\n            }\n        }\n\n        insertOrder(sol.route, bestOid, best);\n        sol.selected.set(bestOid);\n        sol.len += best.delta;\n        cnt++;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildRandomizedGreedy(const vector<int>& pool, XorShift& rng, int topR, int bias) {\n    struct Choice {\n        int rank;\n        int oid;\n        InsertRes res;\n    };\n\n    topR = min(topR, 16);\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    for (int cnt = 0; cnt < 50; cnt++) {\n        Choice top[16];\n        int ts = 0;\n\n        auto consider = [&](int oid) {\n            if (sol.selected.test(oid)) return;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rank = res.delta + bias * orderCentral[oid] / 100;\n\n            Choice c{rank, oid, res};\n\n            if (ts < topR) {\n                top[ts++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < ts; i++) {\n                    if (top[i].rank > top[worst].rank) worst = i;\n                }\n                if (c.rank < top[worst].rank) top[worst] = c;\n            }\n        };\n\n        for (int oid : pool) consider(oid);\n\n        if (ts == 0) {\n            for (int oid = 1; oid <= NORD; oid++) consider(oid);\n        }\n\n        sort(top, top + ts, [](const Choice& a, const Choice& b) {\n            if (a.rank != b.rank) return a.rank < b.rank;\n            return a.oid < b.oid;\n        });\n\n        int pick = 0;\n        if (ts > 1) {\n            int r = rng.nextInt(100);\n            if (r < 55) pick = 0;\n            else if (r < 75) pick = min(1, ts - 1);\n            else if (r < 90) pick = min(2, ts - 1);\n            else pick = rng.nextInt(ts);\n        }\n\n        Choice c = top[pick];\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nvector<Solution> buildBeam(const vector<int>& pool, int W, int K, int bias) {\n    struct State {\n        vector<int> route;\n        bitset<NORD + 1> selected;\n        int len;\n    };\n\n    struct Choice {\n        int rank;\n        int len;\n        int oid;\n        InsertRes res;\n    };\n\n    K = min(K, 16);\n\n    vector<State> beam;\n    State init;\n    init.route = {0, 0};\n    init.selected.reset();\n    init.len = 0;\n    beam.push_back(init);\n\n    for (int step = 0; step < 50; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int oid) {\n                if (st.selected.test(oid)) return;\n\n                InsertRes res = bestInsertion(st.route, oid);\n                int nl = st.len + res.delta;\n                int rank = nl + bias * orderCentral[oid] / 100;\n\n                Choice c{rank, nl, oid, res};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int oid : pool) consider(oid);\n\n            if (ts == 0) {\n                for (int oid = 1; oid <= NORD; oid++) consider(oid);\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                if (a.rank != b.rank) return a.rank < b.rank;\n                return a.oid < b.oid;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                insertOrder(ch.route, top[i].oid, top[i].res);\n                ch.selected.set(top[i].oid);\n                ch.len = top[i].len;\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            return a.len < b.len;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    vector<Solution> res;\n    for (auto& st : beam) {\n        if ((int)st.selected.count() != 50) continue;\n\n        Solution sol;\n        sol.route = std::move(st.route);\n        sol.selected = st.selected;\n        sol.len = routeCost(sol.route);\n        res.push_back(std::move(sol));\n    }\n\n    sort(res.begin(), res.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    return res;\n}\n\nvector<int> removeOrderRoute(const vector<int>& route, int oid) {\n    vector<int> nr;\n    nr.reserve(route.size() - 2);\n\n    int P = oid;\n    int D = OFF + oid;\n\n    for (int id : route) {\n        if (id != P && id != D) nr.push_back(id);\n    }\n    return nr;\n}\n\nbool twoOptDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int delPos[NORD + 1];\n        for (int i = 0; i <= NORD; i++) delPos[i] = -1;\n\n        for (int i = 0; i < n; i++) {\n            int id = sol.route[i];\n            if (id > OFF) delPos[id - OFF] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        bool timeout = false;\n\n        for (int l = 1; l <= n - 3; l++) {\n            if ((l & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int minDelivery = INF;\n\n            for (int r = l; r <= n - 2; r++) {\n                int node = sol.route[r];\n\n                if (1 <= node && node <= NORD) {\n                    minDelivery = min(minDelivery, delPos[node]);\n                }\n\n                if (r == l) continue;\n\n                // Invalid iff interval contains pickup and delivery of the same order.\n                if (minDelivery <= r) continue;\n\n                int A = sol.route[l - 1];\n                int B = sol.route[l];\n                int C = sol.route[r];\n                int D = sol.route[r + 1];\n\n                int delta = distId(A, C) + distId(B, D) -\n                            distId(A, B) - distId(C, D);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta < 0) {\n            reverse(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSegmentMoveFast(const vector<int>& route, const int pos[], int l, int r, int k) {\n    int oids[8];\n    int cnt = 0;\n\n    for (int i = l; i <= r; i++) {\n        int id = route[i];\n        int oid = (id <= OFF ? id : id - OFF);\n\n        bool exists = false;\n        for (int j = 0; j < cnt; j++) {\n            if (oids[j] == oid) {\n                exists = true;\n                break;\n            }\n        }\n\n        if (!exists) oids[cnt++] = oid;\n    }\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        bool inP = (l <= pp && pp <= r);\n        bool inD = (l <= dd && dd <= r);\n\n        if (inP && !inD) {\n            if (!(k < dd)) return false;\n        } else if (!inP && inD) {\n            if (!(k >= pp)) return false;\n        }\n    }\n\n    return true;\n}\n\nbool orOptDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        int bestK = -1;\n\n        int checks = 0;\n        bool timeout = false;\n\n        for (int len = 1; len <= maxSegLen; len++) {\n            for (int l = 1; l + len - 1 <= n - 2; l++) {\n                int r = l + len - 1;\n\n                int oldLR = distId(sol.route[l - 1], sol.route[l]) +\n                            distId(sol.route[r], sol.route[r + 1]);\n\n                for (int k = 0; k <= n - 2; k++) {\n                    if (++checks % 8192 == 0 && timer.elapsed() >= deadline) {\n                        timeout = true;\n                        break;\n                    }\n\n                    if (k >= l - 1 && k <= r) continue;\n\n                    int delta =\n                        distId(sol.route[l - 1], sol.route[r + 1]) +\n                        distId(sol.route[k], sol.route[l]) +\n                        distId(sol.route[r], sol.route[k + 1]) -\n                        oldLR -\n                        distId(sol.route[k], sol.route[k + 1]);\n\n                    if (delta >= bestDelta) continue;\n\n                    if (!validSegmentMoveFast(sol.route, pos, l, r, k)) continue;\n\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                    bestK = k;\n                }\n\n                if (timeout) break;\n            }\n            if (timeout) break;\n        }\n\n        if (bestDelta < 0) {\n            int segLen = bestR - bestL + 1;\n            vector<int> seg(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n\n            if (bestK < bestL) {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                sol.route.insert(sol.route.begin() + bestK + 1, seg.begin(), seg.end());\n            } else {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                int ins = bestK - segLen + 1;\n                sol.route.insert(sol.route.begin() + ins, seg.begin(), seg.end());\n            }\n\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSwapFast(const vector<int>& route, const int pos[], int i, int j) {\n    int a = route[i];\n    int b = route[j];\n\n    int oids[2];\n    int cnt = 0;\n\n    auto addOid = [&](int id) {\n        int oid = (id <= OFF ? id : id - OFF);\n        for (int z = 0; z < cnt; z++) {\n            if (oids[z] == oid) return;\n        }\n        oids[cnt++] = oid;\n    };\n\n    addOid(a);\n    addOid(b);\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        if (pp == i) pp = j;\n        else if (pp == j) pp = i;\n\n        if (dd == i) dd = j;\n        else if (dd == j) dd = i;\n\n        if (pp >= dd) return false;\n    }\n\n    return true;\n}\n\nbool swapDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) pos[sol.route[i]] = i;\n\n        int bestDelta = 0;\n        int bestI = -1;\n        int bestJ = -1;\n\n        bool timeout = false;\n\n        for (int i = 1; i <= n - 3; i++) {\n            if ((i & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            for (int j = i + 1; j <= n - 2; j++) {\n                int u = sol.route[i];\n                int v = sol.route[j];\n\n                int delta;\n\n                if (i + 1 == j) {\n                    int A = sol.route[i - 1];\n                    int B = sol.route[j + 1];\n\n                    delta = distId(A, v) + distId(v, u) + distId(u, B)\n                          - distId(A, u) - distId(u, v) - distId(v, B);\n                } else {\n                    int Ai = sol.route[i - 1];\n                    int Bi = sol.route[i + 1];\n                    int Aj = sol.route[j - 1];\n                    int Bj = sol.route[j + 1];\n\n                    delta = distId(Ai, v) + distId(v, Bi) +\n                            distId(Aj, u) + distId(u, Bj) -\n                            distId(Ai, u) - distId(u, Bi) -\n                            distId(Aj, v) - distId(v, Bj);\n                }\n\n                if (delta >= bestDelta) continue;\n                if (!validSwapFast(sol.route, pos, i, j)) continue;\n\n                bestDelta = delta;\n                bestI = i;\n                bestJ = j;\n            }\n        }\n\n        if (bestDelta < 0) {\n            swap(sol.route[bestI], sol.route[bestJ]);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool routeDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen = 3, bool doSwap = false) {\n    bool any = false;\n\n    for (int rep = 0; rep < 5 && timer.elapsed() < deadline; rep++) {\n        bool moved = false;\n\n        if (twoOptDescent(sol, timer, deadline)) moved = true;\n\n        if (timer.elapsed() >= deadline) break;\n\n        if (orOptDescent(sol, timer, deadline, maxSegLen)) moved = true;\n\n        if (doSwap && timer.elapsed() < deadline) {\n            if (swapDescent(sol, timer, deadline)) moved = true;\n        }\n\n        if (!moved) break;\n        any = true;\n    }\n\n    sol.len = routeCost(sol.route);\n    return any;\n}\n\nbool findAndApplyBestPairMove(Solution& sol, Timer& timer, double deadline) {\n    int cur = sol.len;\n    vector<int> sel = selectedList(sol);\n\n    int bestNewLen = cur;\n    int bestRem = -1;\n    int bestIns = -1;\n\n    bool stop = false;\n\n    for (int idx = 0; idx < (int)sel.size(); idx++) {\n        if (timer.elapsed() >= deadline) break;\n\n        int rem = sel[idx];\n        vector<int> tmp = removeOrderRoute(sol.route, rem);\n        int lenTmp = routeCost(tmp);\n\n        {\n            InsertRes res = bestInsertion(tmp, rem);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = rem;\n            }\n        }\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if ((oid & 63) == 0 && timer.elapsed() >= deadline) {\n                stop = true;\n                break;\n            }\n\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(tmp, oid);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = oid;\n            }\n        }\n\n        if (stop) break;\n    }\n\n    if (bestRem == -1) return false;\n\n    vector<int> tmp = removeOrderRoute(sol.route, bestRem);\n\n    if (bestIns != bestRem) {\n        sol.selected.reset(bestRem);\n        sol.selected.set(bestIns);\n    }\n\n    InsertRes res = bestInsertion(tmp, bestIns);\n    insertOrder(tmp, bestIns, res);\n\n    sol.route.swap(tmp);\n    sol.len = routeCost(sol.route);\n\n    return sol.len < cur;\n}\n\nvoid localImprove(Solution& sol, Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 3, false);\n\n        if (timer.elapsed() >= deadline) break;\n\n        bool moved = findAndApplyBestPairMove(sol, timer, deadline);\n        if (!moved) break;\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nSolution rebuildFixedOrder(const Solution& base, vector<int> orders) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    for (int oid : orders) {\n        InsertRes res = bestInsertion(sol.route, oid);\n        insertOrder(sol.route, oid, res);\n        sol.len += res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildFixedGreedy(const Solution& base) {\n    vector<int> orders = selectedList(base);\n    int m = (int)orders.size();\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    vector<char> used(m, 0);\n\n    for (int cnt = 0; cnt < m; cnt++) {\n        int bestIdx = -1;\n        InsertRes best{INF, 0, 0};\n\n        for (int i = 0; i < m; i++) {\n            if (used[i]) continue;\n\n            InsertRes res = bestInsertion(sol.route, orders[i]);\n            if (res.delta < best.delta) {\n                best = res;\n                bestIdx = i;\n            }\n        }\n\n        used[bestIdx] = 1;\n        insertOrder(sol.route, orders[bestIdx], best);\n        sol.len += best.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildSequentialBeam(const Solution& base, int W, int K) {\n    vector<int> orders = selectedList(base);\n    int M = (int)orders.size();\n    if (M != 50) return base;\n\n    struct State {\n        uint64_t picked;\n        uint64_t delivered;\n        int last;\n        int cost;\n        int eval;\n        vector<int> route;\n    };\n\n    struct Choice {\n        int rank;\n        int node;\n        int idx;\n        int type;\n        int add;\n    };\n\n    uint64_t fullMask = (1ULL << M) - 1ULL;\n\n    vector<State> beam;\n    State init;\n    init.picked = 0;\n    init.delivered = 0;\n    init.last = 0;\n    init.cost = 0;\n    init.eval = 0;\n    init.route = {0};\n    beam.push_back(init);\n\n    for (int step = 0; step < 2 * M; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int node, int idx, int type) {\n                int add = distId(st.last, node);\n                int rank = add + distId(node, 0) / 6;\n\n                Choice c{rank, node, idx, type, add};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int j = 0; j < M; j++) {\n                uint64_t bit = 1ULL << j;\n\n                if (!(st.picked & bit)) {\n                    consider(orders[j], j, 0);\n                } else if (!(st.delivered & bit)) {\n                    consider(OFF + orders[j], j, 1);\n                }\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                return a.rank < b.rank;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                uint64_t bit = 1ULL << top[i].idx;\n\n                if (top[i].type == 0) ch.picked |= bit;\n                else ch.delivered |= bit;\n\n                ch.last = top[i].node;\n                ch.cost += top[i].add;\n                ch.eval = ch.cost + distId(ch.last, 0);\n                ch.route.push_back(top[i].node);\n\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    int best = -1;\n    int bestCost = INF;\n\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (beam[i].delivered != fullMask) continue;\n\n        int c = beam[i].cost + distId(beam[i].last, 0);\n        if (c < bestCost) {\n            bestCost = c;\n            best = i;\n        }\n    }\n\n    if (best == -1) return base;\n\n    Solution sol;\n    sol.selected = base.selected;\n    sol.route = std::move(beam[best].route);\n    sol.route.push_back(0);\n    sol.len = routeCost(sol.route);\n\n    return sol;\n}\n\nvoid tryRebuilds(Solution& sol, XorShift& rng, Timer& timer, double deadline) {\n    if (timer.elapsed() >= deadline) return;\n\n    {\n        Solution g = rebuildFixedGreedy(sol);\n        routeDescent(g, timer, min(deadline, timer.elapsed() + 0.030), 2, false);\n        if (g.len < sol.len) sol = std::move(g);\n    }\n\n    if (timer.elapsed() < deadline) {\n        Solution b = rebuildSequentialBeam(sol, 60, 6);\n        routeDescent(b, timer, min(deadline, timer.elapsed() + 0.035), 2, false);\n        if (b.len < sol.len) sol = std::move(b);\n    }\n\n    for (int it = 0; it < 2 && timer.elapsed() < deadline; it++) {\n        vector<int> orders = selectedList(sol);\n\n        for (int i = (int)orders.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(orders[i], orders[j]);\n        }\n\n        Solution r = rebuildFixedOrder(sol, orders);\n        routeDescent(r, timer, min(deadline, timer.elapsed() + 0.025), 2, false);\n\n        if (r.len < sol.len) sol = std::move(r);\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nstruct Cand {\n    int rankCost;\n    int oid;\n    InsertRes res;\n};\n\nSolution ruinRecreate(const Solution& base, int k, XorShift& rng, Timer& timer, double deadline) {\n    Solution sol = base;\n    vector<int> sel = selectedList(base);\n    k = min(k, (int)sel.size());\n\n    vector<char> rem(NORD + 1, 0);\n    vector<int> toRemove;\n\n    int strategy = rng.nextInt(4);\n\n    if (strategy == 0) {\n        vector<pair<int, int>> savings;\n        savings.reserve(sel.size());\n\n        for (int oid : sel) {\n            vector<int> tmp = removeOrderRoute(base.route, oid);\n            int l = routeCost(tmp);\n            savings.push_back({base.len - l, oid});\n        }\n\n        sort(savings.begin(), savings.end(), [](const auto& a, const auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int topLimit = min(25, (int)savings.size());\n\n        while ((int)toRemove.size() < k) {\n            int idx;\n            if (rng.nextInt(100) < 75) idx = rng.nextInt(topLimit);\n            else idx = rng.nextInt((int)savings.size());\n\n            int oid = savings[idx].second;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 1) {\n        while ((int)toRemove.size() < k) {\n            int oid = sel[rng.nextInt((int)sel.size())];\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 2) {\n        int pos[NID];\n        for (int i = 0; i < (int)base.route.size(); i++) {\n            pos[base.route[i]] = i;\n        }\n\n        int seed = sel[rng.nextInt((int)sel.size())];\n        int sp = pos[seed];\n        int sd = pos[OFF + seed];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int pp = pos[oid];\n            int dd = pos[OFF + oid];\n\n            int sc = min({\n                abs(pp - sp),\n                abs(pp - sd),\n                abs(dd - sp),\n                abs(dd - sd)\n            });\n\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else {\n        int seed = sel[rng.nextInt((int)sel.size())];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int sc1 = distId(seed, oid) + distId(OFF + seed, OFF + oid);\n            int sc2 = distId(seed, OFF + oid) + distId(OFF + seed, oid);\n            int sc = min(sc1, sc2);\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    }\n\n    for (int oid : toRemove) {\n        sol.selected.reset(oid);\n    }\n\n    vector<int> nr;\n    nr.reserve(base.route.size());\n\n    for (int id : base.route) {\n        if (id == 0) {\n            nr.push_back(id);\n        } else {\n            int oid = (id <= OFF ? id : id - OFF);\n            if (!rem[oid]) nr.push_back(id);\n        }\n    }\n\n    sol.route.swap(nr);\n    sol.len = routeCost(sol.route);\n\n    int removedPenalty = 8 + rng.nextInt(45);\n\n    for (int t = 0; t < k; t++) {\n        static constexpr int R = 7;\n        Cand top[R];\n        int topSize = 0;\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rankCost = res.delta + (rem[oid] ? removedPenalty : 0) + rng.nextInt(7);\n\n            Cand c{rankCost, oid, res};\n\n            if (topSize < R) {\n                top[topSize++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < R; i++) {\n                    if (top[i].rankCost > top[worst].rankCost) worst = i;\n                }\n                if (c.rankCost < top[worst].rankCost) top[worst] = c;\n            }\n        }\n\n        sort(top, top + topSize, [](const Cand& a, const Cand& b) {\n            return a.rankCost < b.rankCost;\n        });\n\n        int pick = 0;\n        if (topSize > 1) {\n            int roll = rng.nextInt(100);\n            if (roll < 62) pick = 0;\n            else if (roll < 82) pick = min(1, topSize - 1);\n            else if (roll < 93) pick = min(2, topSize - 1);\n            else pick = rng.nextInt(topSize);\n        }\n\n        Cand c = top[pick];\n\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    if (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 2, false);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nbool validate(const Solution& sol) {\n    if (selectedCount(sol) != 50) return false;\n    if (sol.route.empty()) return false;\n    if (sol.route.front() != 0 || sol.route.back() != 0) return false;\n\n    vector<int> pp(NORD + 1, -1), dd(NORD + 1, -1);\n\n    for (int i = 0; i < (int)sol.route.size(); i++) {\n        int id = sol.route[i];\n\n        if (id == 0) continue;\n\n        if (1 <= id && id <= NORD) {\n            pp[id] = i;\n        } else if (OFF < id && id <= OFF + NORD) {\n            dd[id - OFF] = i;\n        } else {\n            return false;\n        }\n    }\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (!sol.selected.test(oid)) continue;\n        if (pp[oid] == -1 || dd[oid] == -1) return false;\n        if (pp[oid] >= dd[oid]) return false;\n    }\n\n    return true;\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    for (int i = 1; i <= NORD; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n\n        X[i] = a;\n        Y[i] = b;\n        X[OFF + i] = c;\n        Y[OFF + i] = d;\n    }\n\n    distMat.assign(NID * NID, 0);\n\n    for (int i = 0; i < NID; i++) {\n        for (int j = 0; j <= i; j++) {\n            int v = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n            distMat[i * NID + j] = distMat[j * NID + i] = (unsigned short)v;\n        }\n    }\n\n    vector<pair<int, int>> firstCost;\n    firstCost.reserve(NORD);\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        int dP = distId(0, oid);\n        int dD = distId(0, OFF + oid);\n        int pd = distId(oid, OFF + oid);\n\n        orderCentral[oid] = dP + dD;\n        firstCost.push_back({dP + pd + dD, oid});\n    }\n\n    sort(firstCost.begin(), firstCost.end());\n\n    Timer timer;\n    XorShift rng(1234567891234567ull);\n\n    vector<int> allIds(NORD);\n    iota(allIds.begin(), allIds.end(), 1);\n\n    vector<Solution> candidates;\n\n    auto addCandidate = [&](Solution sol) {\n        if (selectedCount(sol) == 50) {\n            sol.len = routeCost(sol.route);\n            candidates.push_back(std::move(sol));\n        }\n    };\n\n    addCandidate(buildGreedy(firstCost[0].second));\n\n    const double INIT_DEAD = 0.52;\n\n    for (int idx = 1; idx < 10 && timer.elapsed() < 0.22; idx++) {\n        addCandidate(buildGreedy(firstCost[idx].second));\n    }\n\n    if (timer.elapsed() < 0.32) {\n        auto sols = buildBeam(allIds, 8, 4, 0);\n        for (int i = 0; i < (int)sols.size() && i < 4; i++) {\n            addCandidate(std::move(sols[i]));\n        }\n    }\n\n    vector<vector<int>> sortedModes;\n\n    for (int mode = 0; mode < 8; mode++) {\n        vector<pair<int, int>> score;\n        score.reserve(NORD);\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            int dP = distId(0, oid);\n            int dD = distId(0, OFF + oid);\n            int pd = distId(oid, OFF + oid);\n\n            int linf = max({\n                abs(X[oid] - 400),\n                abs(Y[oid] - 400),\n                abs(X[OFF + oid] - 400),\n                abs(Y[OFF + oid] - 400)\n            });\n\n            int mid = abs(X[oid] + X[OFF + oid] - 800) +\n                      abs(Y[oid] + Y[OFF + oid] - 800);\n\n            int dxSpan = abs(X[oid] - X[OFF + oid]);\n            int dySpan = abs(Y[oid] - Y[OFF + oid]);\n\n            int sc;\n\n            if (mode == 0) {\n                sc = dP + dD;\n            } else if (mode == 1) {\n                sc = max(dP, dD) * 2000 + dP + dD;\n            } else if (mode == 2) {\n                sc = dP + dD + pd;\n            } else if (mode == 3) {\n                sc = linf * 2000 + dP + dD;\n            } else if (mode == 4) {\n                sc = max(dP, dD) * 3 + min(dP, dD);\n            } else if (mode == 5) {\n                sc = dP + dD + mid;\n            } else if (mode == 6) {\n                sc = linf * 3000 + pd;\n            } else {\n                sc = dP + dD + max(dxSpan, dySpan);\n            }\n\n            score.push_back({sc, oid});\n        }\n\n        sort(score.begin(), score.end());\n\n        vector<int> ord;\n        ord.reserve(NORD);\n        for (auto [sc, oid] : score) ord.push_back(oid);\n        sortedModes.push_back(std::move(ord));\n    }\n\n    vector<int> poolSizes = {55, 70, 90, 130, 200, 300};\n\n    for (int mode = 0; mode < (int)sortedModes.size(); mode++) {\n        for (int ps : poolSizes) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            ps = min(ps, (int)sortedModes[mode].size());\n            vector<int> pool(sortedModes[mode].begin(), sortedModes[mode].begin() + ps);\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    // Shifted compact-cluster pools.\n    vector<int> centers = {250, 300, 350, 400, 450, 500, 550};\n\n    for (int cx : centers) {\n        for (int cy : centers) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                int lp = abs(X[oid] - cx) + abs(Y[oid] - cy);\n                int ld = abs(X[OFF + oid] - cx) + abs(Y[OFF + oid] - cy);\n\n                int infp = max(abs(X[oid] - cx), abs(Y[oid] - cy));\n                int infd = max(abs(X[OFF + oid] - cx), abs(Y[OFF + oid] - cy));\n\n                int centerPenalty = abs(cx - 400) + abs(cy - 400);\n                int sc = max(infp, infd) * 3000 + max(lp, ld) * 3 + centerPenalty * 20;\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            int ps = 110;\n            vector<int> pool;\n            pool.reserve(ps);\n            for (int i = 0; i < ps; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    // Directional sector / half-plane pools.\n    for (int sx : {-1, 1}) {\n        for (int sy : {-1, 1}) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                auto outsidePoint = [&](int id) {\n                    int px = sx * (X[id] - 400);\n                    int py = sy * (Y[id] - 400);\n                    return max(0, -px) + max(0, -py);\n                };\n\n                int out = outsidePoint(oid) + outsidePoint(OFF + oid);\n                int far = max(distId(0, oid), distId(0, OFF + oid));\n                int sc = out * 10000 + far * 10 + orderCentral[oid];\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            vector<int> pool;\n            for (int i = 0; i < 130; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    for (int axis = 0; axis < 2; axis++) {\n        for (int sgn : {-1, 1}) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                auto outsidePoint = [&](int id) {\n                    int v = (axis == 0 ? X[id] - 400 : Y[id] - 400);\n                    return max(0, -sgn * v);\n                };\n\n                int out = outsidePoint(oid) + outsidePoint(OFF + oid);\n                int far = max(distId(0, oid), distId(0, OFF + oid));\n                int sc = out * 10000 + far * 10 + orderCentral[oid];\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            vector<int> pool;\n            for (int i = 0; i < 170; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    while (timer.elapsed() < INIT_DEAD && (int)candidates.size() < 65) {\n        if (rng.nextInt(2) == 0) {\n            addCandidate(buildRandomizedGreedy(allIds, rng, 8, 0));\n        } else {\n            int mi = rng.nextInt((int)sortedModes.size());\n            int ps = min(300, (int)sortedModes[mi].size());\n            vector<int> pool(sortedModes[mi].begin(), sortedModes[mi].begin() + ps);\n            addCandidate(buildRandomizedGreedy(pool, rng, 8, 2));\n        }\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    if (candidates.empty()) {\n        candidates.push_back(buildGreedy(firstCost[0].second));\n    }\n\n    const double QUICK_DEAD = 0.72;\n\n    for (int i = 0; i < (int)candidates.size() && i < 14 && timer.elapsed() < QUICK_DEAD; i++) {\n        double sub = min(QUICK_DEAD, timer.elapsed() + 0.020);\n        routeDescent(candidates[i], timer, sub, 2, false);\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    Solution bestOverall = candidates[0];\n\n    const double LOCAL_DEAD = 1.40;\n\n    int starts = min(5, (int)candidates.size());\n\n    for (int i = 0; i < starts && timer.elapsed() < LOCAL_DEAD; i++) {\n        Solution sol = candidates[i];\n\n        double sub = min(LOCAL_DEAD, timer.elapsed() + 0.15);\n        localImprove(sol, timer, sub);\n\n        if (sol.len < bestOverall.len) {\n            bestOverall = std::move(sol);\n        }\n    }\n\n    const double REBUILD_DEAD = 1.48;\n\n    if (timer.elapsed() < REBUILD_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, REBUILD_DEAD);\n        localImprove(bestOverall, timer, REBUILD_DEAD);\n    }\n\n    Solution current = bestOverall;\n\n    const double LNS_DEAD = 1.84;\n\n    while (timer.elapsed() < LNS_DEAD) {\n        if (LNS_DEAD - timer.elapsed() < 0.045) break;\n\n        int roll = rng.nextInt(100);\n        int k;\n\n        if (roll < 58) {\n            k = 3 + rng.nextInt(5);       // 3..7\n        } else if (roll < 90) {\n            k = 8 + rng.nextInt(6);       // 8..13\n        } else {\n            k = 14 + rng.nextInt(7);      // 14..20\n        }\n\n        const Solution& base = (rng.nextInt(5) == 0 ? current : bestOverall);\n\n        Solution cand = ruinRecreate(base, k, rng, timer, LNS_DEAD);\n\n        if (cand.len < bestOverall.len) {\n            bestOverall = std::move(cand);\n\n            double sub = min(LNS_DEAD, timer.elapsed() + 0.08);\n            localImprove(bestOverall, timer, sub);\n\n            if (timer.elapsed() < LNS_DEAD) {\n                tryRebuilds(bestOverall, rng, timer, min(LNS_DEAD, timer.elapsed() + 0.04));\n            }\n\n            current = bestOverall;\n        } else {\n            int diff = cand.len - current.len;\n            double progress = min(1.0, timer.elapsed() / LNS_DEAD);\n            double temp = 45.0 * (1.0 - progress) + 3.0;\n\n            if (diff < 0 || rng.nextDouble() < exp(-(double)diff / temp)) {\n                current = std::move(cand);\n            }\n\n            if (current.len > bestOverall.len + 350) {\n                current = bestOverall;\n            }\n        }\n    }\n\n    const double FINAL_DEAD = 1.90;\n\n    if (timer.elapsed() < FINAL_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, min(FINAL_DEAD, timer.elapsed() + 0.045));\n    }\n\n    routeDescent(bestOverall, timer, FINAL_DEAD, 4, true);\n\n    bestOverall.len = routeCost(bestOverall.route);\n\n    if (!validate(bestOverall)) {\n        bestOverall = buildGreedy(firstCost[0].second);\n    }\n\n    cout << 50;\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (bestOverall.selected.test(oid)) {\n            cout << ' ' << oid;\n        }\n    }\n    cout << '\\n';\n\n    cout << bestOverall.route.size();\n    for (int id : bestOverall.route) {\n        cout << ' ' << X[id] << ' ' << Y[id];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nstatic constexpr int FIRST_SAMPLES = 64;\nstatic constexpr int MAX_SAMPLES = 256;\nstatic constexpr int BLOCK_SIZE = 64;\n\nstatic constexpr int INF = 1e9;\n\nstatic constexpr double BASE_ADAPT_PART = 0.88;\nstatic constexpr double Q_BLEND = 0.12;\n\nstatic constexpr int YMAX = 20000;\n\nstruct DSU {\n    int p[N];\n    int comps;\n\n    void init() {\n        comps = N;\n        for (int i = 0; i < N; i++) p[i] = -1;\n    }\n\n    inline int find(int x) {\n        while (p[x] >= 0) {\n            int y = p[x];\n            if (p[y] >= 0) p[x] = p[y];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n\n    inline bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (p[a] > p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        comps--;\n        return true;\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next() % uint64_t(r - l + 1));\n    }\n};\n\nint X[N], Y[N];\nint U[M], V[M], D[M];\n\nstatic int sampleW[MAX_SAMPLES][M];\nstatic int orderSample[MAX_SAMPLES][M];\nstatic int orderD[M];\n\nstatic double onlineY[YMAX + 1];\n\nstatic inline double online_y_from_offline_mean(double yoff) {\n    if (yoff <= 0.0) return 0.0;\n    if (yoff >= 0.5) return 0.5;\n\n    double k = 1.0 / yoff - 1.0;\n    if (k <= 1.0) return 0.5;\n\n    if (k >= YMAX) {\n        return 2.0 / (k + 3.0);\n    }\n\n    int a = int(floor(k));\n    double f = k - a;\n\n    if (a < 1) return 0.5;\n    if (a + 1 > YMAX) return 2.0 / (k + 3.0);\n\n    return onlineY[a] * (1.0 - f) + onlineY[a + 1] * f;\n}\n\nstatic inline double sample_quantile(const int* vals, int cnt, double p) {\n    static int tmp[MAX_SAMPLES];\n\n    for (int i = 0; i < cnt; i++) tmp[i] = vals[i];\n    sort(tmp, tmp + cnt);\n\n    if (cnt == 1) return tmp[0];\n\n    p = clamp(p, 0.0, 1.0);\n    double pos = p * double(cnt - 1);\n    int a = int(floor(pos));\n    double f = pos - a;\n\n    if (a >= cnt - 1) return tmp[cnt - 1];\n\n    return tmp[a] * (1.0 - f) + tmp[a + 1] * f;\n}\n\nint bottleneck_baseD(int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderD[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return D[e];\n        }\n    }\n\n    return INF;\n}\n\nint bottleneck_sample(int s, int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    const int* ord = orderSample[s];\n    const int* w = sampleW[s];\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = ord[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return w[e];\n        }\n    }\n\n    return INF;\n}\n\ndouble make_threshold(\n    double mc,\n    double lo,\n    int idx,\n    int acceptedEdges,\n    const int* vals,\n    int cnt\n) {\n    double hi = 3.0 * lo;\n    double range = hi - lo;\n    double det = 2.0 * lo;\n\n    if (mc < lo) mc = lo;\n    if (mc > hi) mc = hi;\n\n    double z = (mc - lo) / range;\n    z = clamp(z, 0.0, 1.0);\n\n    double target = double(idx + 1) * double(N - 1) / double(M);\n    double deficit = target - acceptedEdges;\n\n    double threshold;\n\n    if (z < 0.5) {\n        double adapt = BASE_ADAPT_PART;\n\n        // If we are behind the expected acceptance schedule, be slightly less\n        // aggressive. If we are ahead, be slightly more selective.\n        if (deficit > 4.0) {\n            adapt -= min(0.16, 0.012 * (deficit - 4.0));\n        } else if (deficit < -8.0) {\n            adapt += min(0.09, 0.008 * (-deficit - 8.0));\n        }\n\n        adapt = clamp(adapt, 0.70, 0.97);\n\n        double yon = online_y_from_offline_mean(z);\n\n        // Old linear correction in normalized coordinates:\n        // old threshold = mc + 0.22 * (det - mc)\n        // normalized: 0.11 + 0.78*z.\n        double linear = 0.11 + 0.78 * z;\n        if (linear > 0.5) linear = 0.5;\n\n        double tnorm = adapt * yon + (1.0 - adapt) * linear;\n        threshold = lo + range * tnorm;\n\n        // Distribution-shape correction.\n        // For min of k uniform variables, the optimal online threshold is\n        // approximately a high quantile of the offline-min distribution.\n        if (cnt >= 16) {\n            double p;\n\n            if (z <= 1e-12 || yon <= 1e-12) {\n                p = 0.865;\n            } else {\n                double kEff = 1.0 / z - 1.0;\n                if (kEff < 1.0) kEff = 1.0;\n\n                double remBase = max(1e-15, 1.0 - yon);\n                double logRemain = kEff * log(remBase);\n\n                if (logRemain < -50.0) p = 1.0;\n                else p = 1.0 - exp(logRemain);\n\n                p = clamp(p, 0.50, 0.875);\n            }\n\n            double q = sample_quantile(vals, cnt, p);\n\n            double qw = Q_BLEND;\n            if (deficit > 4.0) qw *= 0.55;\n            if (deficit < -8.0) qw = min(0.22, qw * 1.25);\n\n            threshold = threshold * (1.0 - qw) + q * qw;\n        }\n    } else {\n        // Scarce-alternative situation.  The sampled offline marginal is\n        // already high; lowering it tends to reject too much.\n        threshold = mc;\n    }\n\n    // Safety correction against falling too far behind.\n    if (deficit > 8.0) {\n        double mult = 1.0 + 0.0035 * (deficit - 8.0);\n        if (mult > 1.07) mult = 1.07;\n        threshold *= mult;\n    }\n\n    if (threshold < lo) threshold = lo;\n    if (threshold > hi) threshold = hi;\n\n    return threshold;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    onlineY[1] = 0.5;\n    for (int i = 2; i <= YMAX; i++) {\n        onlineY[i] = onlineY[i - 1] - 0.5 * onlineY[i - 1] * onlineY[i - 1];\n    }\n\n    uint64_t seed = 0x123456789abcdefULL;\n\n    auto mix_seed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n        mix_seed(uint64_t(X[i] + 1009));\n        mix_seed(uint64_t(Y[i] + 9176));\n    }\n\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n\n        long long dx = X[U[i]] - X[V[i]];\n        long long dy = Y[U[i]] - Y[V[i]];\n        D[i] = int(sqrt(double(dx * dx + dy * dy)) + 0.5);\n\n        mix_seed(uint64_t(U[i] + 1));\n        mix_seed(uint64_t(V[i] + 1));\n        mix_seed(uint64_t(D[i] + 1));\n    }\n\n    SplitMix64 rng(seed);\n\n    vector<int> perm(BLOCK_SIZE);\n    iota(perm.begin(), perm.end(), 0);\n\n    for (int e = 0; e < M; e++) {\n        int R = 2 * D[e] + 1;\n\n        for (int block = 0; block < MAX_SAMPLES / BLOCK_SIZE; block++) {\n            iota(perm.begin(), perm.end(), 0);\n\n            for (int i = BLOCK_SIZE - 1; i > 0; i--) {\n                int j = rng.randint(0, i);\n                swap(perm[i], perm[j]);\n            }\n\n            for (int s = 0; s < BLOCK_SIZE; s++) {\n                long long numerator = 1LL * (2 * perm[s] + 1) * R;\n                int k = int(numerator / (2LL * BLOCK_SIZE));\n\n                if (k < 0) k = 0;\n                if (k >= R) k = R - 1;\n\n                sampleW[block * BLOCK_SIZE + s][e] = D[e] + k;\n            }\n        }\n    }\n\n    vector<int> ids(M);\n\n    for (int s = 0; s < MAX_SAMPLES; s++) {\n        iota(ids.begin(), ids.end(), 0);\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (sampleW[s][a] != sampleW[s][b]) return sampleW[s][a] < sampleW[s][b];\n            return a < b;\n        });\n\n        for (int i = 0; i < M; i++) orderSample[s][i] = ids[i];\n    }\n\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < M; i++) orderD[i] = ids[i];\n\n    DSU accepted;\n    accepted.init();\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        cin >> l;\n\n        int ans = 0;\n\n        if (!accepted.same(U[i], V[i])) {\n            int base = bottleneck_baseD(i, U[i], V[i], accepted);\n\n            if (base >= INF) {\n                ans = 1;\n            } else {\n                int loInt = base;\n                int hiInt = 3 * base;\n\n                if (l <= loInt) {\n                    ans = 1;\n                } else if (l > hiInt) {\n                    ans = 0;\n                } else {\n                    int vals[MAX_SAMPLES];\n\n                    long long sum = 0;\n                    long long sumsq = 0;\n\n                    for (int s = 0; s < FIRST_SAMPLES; s++) {\n                        int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                        if (b >= INF) b = hiInt;\n\n                        vals[s] = b;\n                        sum += b;\n                        sumsq += 1LL * b * b;\n                    }\n\n                    double mc = double(sum) / FIRST_SAMPLES;\n                    int acceptedEdges = N - accepted.comps;\n\n                    double threshold = make_threshold(\n                        mc,\n                        double(loInt),\n                        i,\n                        acceptedEdges,\n                        vals,\n                        FIRST_SAMPLES\n                    );\n\n                    double var = double(sumsq) / FIRST_SAMPLES - mc * mc;\n                    if (var < 0.0) var = 0.0;\n\n                    double se = sqrt(var / FIRST_SAMPLES);\n\n                    // Use extra samples only when the observed edge length is\n                    // close enough to the threshold to matter.\n                    double margin = max(4.0, 2.4 * se + 0.012 * double(loInt));\n\n                    if (fabs(double(l) - threshold) <= margin) {\n                        for (int s = FIRST_SAMPLES; s < MAX_SAMPLES; s++) {\n                            int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                            if (b >= INF) b = hiInt;\n\n                            vals[s] = b;\n                            sum += b;\n                        }\n\n                        mc = double(sum) / MAX_SAMPLES;\n\n                        threshold = make_threshold(\n                            mc,\n                            double(loInt),\n                            i,\n                            acceptedEdges,\n                            vals,\n                            MAX_SAMPLES\n                        );\n                    }\n\n                    if (double(l) <= threshold) ans = 1;\n                }\n            }\n\n            if (ans) accepted.unite(U[i], V[i]);\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int G = 30;\nconst int INF = 1e9;\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar DIR_CH[4] = {'U', 'D', 'L', 'R'};\n\nint dirId(char ch) {\n    ch = toupper(ch);\n    if (ch == 'U') return 0;\n    if (ch == 'D') return 1;\n    if (ch == 'L') return 2;\n    return 3;\n}\n\nbool inside(int r, int c) {\n    return 0 <= r && r < G && 0 <= c && c < G;\n}\n\nstruct Pet {\n    int r, c, t;\n};\n\npair<int,int> toPhysCoord(int r, int c, int ori) {\n    if (ori == 0) return {r, c};             // corridor = bottom\n    if (ori == 1) return {G - 1 - r, c};     // corridor = top\n    if (ori == 2) return {c, r};             // corridor = right\n    return {c, G - 1 - r};                   // corridor = left\n}\n\npair<int,int> toLogCoord(int pr, int pc, int ori) {\n    if (ori == 0) return {pr, pc};\n    if (ori == 1) return {G - 1 - pr, pc};\n    if (ori == 2) return {pc, pr};\n    return {G - 1 - pc, pr};\n}\n\nint chooseOrientation(const vector<Pet>& petsPhys, const vector<pair<int,int>>& humansPhys) {\n    double best = 1e100;\n    int bestOri = 0;\n\n    for (int ori = 0; ori < 4; ori++) {\n        double cost = 0.0;\n\n        for (auto p : petsPhys) {\n            auto [r, c] = toLogCoord(p.r, p.c, ori);\n            int distCorr = G - 1 - r;\n\n            double w = 1.0;\n            if (p.t == 4) w = 3.0;      // dog\n            else if (p.t == 3) w = 1.5;\n            else if (p.t == 5) w = 1.4;\n            else if (p.t == 2) w = 1.2;\n\n            int near = max(0, 12 - distCorr);\n            cost += w * near * near;\n            if (r >= 28) cost += 100.0 * w;\n        }\n\n        for (auto h : humansPhys) {\n            auto [r, c] = toLogCoord(h.first, h.second, ori);\n            int bestStand = 100;\n            for (int s = 2; s <= 26; s += 4) {\n                bestStand = min(bestStand, abs(c - s));\n            }\n            cost += 0.5 * (G - 1 - r) + 0.2 * bestStand;\n        }\n\n        if (cost < best) {\n            best = cost;\n            bestOri = ori;\n        }\n    }\n\n    return bestOri;\n}\n\nstruct Task {\n    int stand;\n    vector<int> walls;\n    int assigned = -1; // -1: free, >=0: human id, -2: finished\n};\n\nstruct HState {\n    int task = -1;\n    int phase = 0;\n    int wait = 0;\n    int home = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, ori;\n    int turnNo = 0;\n\n    vector<Pet> pets;\n    vector<pair<int,int>> humans;\n\n    bool blocked[G][G]{};\n    bool petOcc[G][G]{};\n    bool humanOcc[G][G]{};\n    bool resBuild[G][G]{};\n    bool resMove[G][G]{};\n\n    vector<Task> tasks;\n    vector<HState> hs;\n\n    char logToPhys[256]{};\n    char physToLog[256]{};\n\n    static constexpr int FREE = 0;\n    static constexpr int GO = 1;\n    static constexpr int UP = 2;\n    static constexpr int DOWN = 3;\n    static constexpr int RET = 4;\n\n    static constexpr int ASSIGN_LIMIT = 190;\n    static constexpr int BUILD_LIMIT = 265;\n    static constexpr int WAIT_UNTIL = 230;\n    static constexpr int WAIT_LIMIT = 2;\n\n    Solver(int n,\n           const vector<Pet>& petsPhys,\n           int m,\n           const vector<pair<int,int>>& humansPhys,\n           int orientation)\n        : N(n), M(m), ori(orientation)\n    {\n        initDirectionMaps();\n\n        pets.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto [r, c] = toLogCoord(petsPhys[i].r, petsPhys[i].c, ori);\n            pets[i] = {r, c, petsPhys[i].t};\n        }\n\n        humans.resize(M);\n        for (int i = 0; i < M; i++) {\n            humans[i] = toLogCoord(humansPhys[i].first, humansPhys[i].second, ori);\n        }\n\n        initTasks();\n\n        hs.resize(M);\n        for (int i = 0; i < M; i++) {\n            hs[i].home = (i + 1) * G / (M + 1);\n        }\n    }\n\n    void initDirectionMaps() {\n        memset(logToPhys, 0, sizeof(logToPhys));\n        memset(physToLog, 0, sizeof(physToLog));\n\n        int br = 15, bc = 15;\n        for (char ch : string(\"UDLR\")) {\n            int d = dirId(ch);\n            auto p1 = toPhysCoord(br, bc, ori);\n            auto p2 = toPhysCoord(br + DR[d], bc + DC[d], ori);\n            int rr = p2.first - p1.first;\n            int cc = p2.second - p1.second;\n\n            char pc = '?';\n            if (rr == -1 && cc == 0) pc = 'U';\n            if (rr == 1 && cc == 0) pc = 'D';\n            if (rr == 0 && cc == -1) pc = 'L';\n            if (rr == 0 && cc == 1) pc = 'R';\n\n            logToPhys[(int)ch] = pc;\n            physToLog[(int)pc] = ch;\n        }\n    }\n\n    void initTasks() {\n        // Logical wall columns: 1,3,5,...,27.\n        // Each task uses an even stand column and builds both adjacent walls.\n        for (int s = 2; s <= 26; s += 4) {\n            Task t;\n            t.stand = s;\n            t.walls = {s - 1, s + 1};\n            tasks.push_back(t);\n        }\n    }\n\n    void buildOcc() {\n        memset(petOcc, 0, sizeof(petOcc));\n        memset(humanOcc, 0, sizeof(humanOcc));\n\n        for (auto &p : pets) {\n            if (inside(p.r, p.c)) petOcc[p.r][p.c] = true;\n        }\n        for (auto &h : humans) {\n            if (inside(h.first, h.second)) humanOcc[h.first][h.second] = true;\n        }\n    }\n\n    void resetReservations() {\n        memset(resBuild, 0, sizeof(resBuild));\n        memset(resMove, 0, sizeof(resMove));\n    }\n\n    bool canBuild(int i, char lowerDir) {\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (petOcc[r][c]) return false;\n        if (humanOcc[r][c]) return false;\n        if (resMove[r][c]) return false;\n\n        for (int k = 0; k < 4; k++) {\n            int nr = r + DR[k], nc = c + DC[k];\n            if (inside(nr, nc) && petOcc[nr][nc]) return false;\n        }\n\n        return true;\n    }\n\n    bool canMove(int i, char upperDir) {\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (blocked[r][c]) return false;\n        if (resBuild[r][c]) return false;\n        return true;\n    }\n\n    bool issueBuild(int i, char lowerDir, vector<char>& act) {\n        lowerDir = tolower(lowerDir);\n        if (!canBuild(i, lowerDir)) return false;\n\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = lowerDir;\n        resBuild[r][c] = true;\n        return true;\n    }\n\n    bool issueMove(int i, char upperDir, vector<char>& act) {\n        upperDir = toupper(upperDir);\n        if (!canMove(i, upperDir)) return false;\n\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = upperDir;\n        resMove[r][c] = true;\n        return true;\n    }\n\n    bool taskComplete(int tid) {\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) return false;\n            }\n        }\n        return true;\n    }\n\n    int countRemainingBuilds(int tid) {\n        int cnt = 0;\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int shortestDist(pair<int,int> st, pair<int,int> goal) {\n        if (!inside(goal.first, goal.second)) return INF;\n        if (blocked[goal.first][goal.second]) return INF;\n\n        int dist[G][G];\n        for (int r = 0; r < G; r++) for (int c = 0; c < G; c++) dist[r][c] = -1;\n\n        queue<pair<int,int>> q;\n        dist[st.first][st.second] = 0;\n        q.push(st);\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            if (r == goal.first && c == goal.second) return dist[r][c];\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (dist[nr][nc] != -1) continue;\n\n                dist[nr][nc] = dist[r][c] + 1;\n                q.push({nr, nc});\n            }\n        }\n\n        return INF;\n    }\n\n    char bfsMove(int i, const vector<pair<int,int>>& goals) {\n        bool goal[G][G]{};\n        int goalCnt = 0;\n\n        for (auto [r, c] : goals) {\n            if (!inside(r, c)) continue;\n            if (blocked[r][c]) continue;\n            if (resBuild[r][c]) continue;\n            if (!goal[r][c]) {\n                goal[r][c] = true;\n                goalCnt++;\n            }\n        }\n\n        if (goalCnt == 0) return '.';\n\n        int sr = humans[i].first;\n        int sc = humans[i].second;\n\n        if (goal[sr][sc]) return '.';\n\n        bool vis[G][G]{};\n        char first[G][G]{};\n\n        queue<pair<int,int>> q;\n        vis[sr][sc] = true;\n        q.push({sr, sc});\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (resBuild[nr][nc]) continue;\n                if (vis[nr][nc]) continue;\n\n                vis[nr][nc] = true;\n                first[nr][nc] = (r == sr && c == sc ? DIR_CH[d] : first[r][c]);\n\n                if (goal[nr][nc]) return first[nr][nc];\n\n                q.push({nr, nc});\n            }\n        }\n\n        return '.';\n    }\n\n    int taskPriority(int tid) {\n        int s = tasks[tid].stand;\n        int pr = 0;\n\n        for (auto &p : pets) {\n            int w = 1;\n            if (p.t == 4) w = 6;\n            else if (p.t == 5) w = 3;\n            else if (p.t == 3) w = 3;\n            else if (p.t == 2) w = 2;\n\n            if (p.r <= 28) {\n                int dc = abs(p.c - s);\n                if (dc <= 2) pr += w * (3 - dc);\n                else if (dc <= 4) pr += 1;\n            } else {\n                if (abs(p.c - s) <= 2) pr += 1;\n            }\n        }\n\n        return pr;\n    }\n\n    void normalizeStates() {\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task == -1) continue;\n\n            int tid = hs[i].task;\n            bool comp = taskComplete(tid);\n\n            if (comp) hs[i].phase = RET;\n            if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n            if (humans[i].first == 29 && hs[i].phase == RET) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n            }\n        }\n    }\n\n    void assignTasks() {\n        if (turnNo > ASSIGN_LIMIT) return;\n\n        while (true) {\n            int bestI = -1, bestT = -1;\n            double bestVal = -1e100;\n\n            for (int i = 0; i < M; i++) {\n                if (hs[i].task != -1) continue;\n\n                for (int tid = 0; tid < (int)tasks.size(); tid++) {\n                    if (tasks[tid].assigned != -1) continue;\n                    if (taskComplete(tid)) continue;\n\n                    int stand = tasks[tid].stand;\n                    if (blocked[28][stand]) continue;\n\n                    int dist = shortestDist(humans[i], {29, stand});\n                    if (dist >= INF) continue;\n\n                    int rem = countRemainingBuilds(tid);\n                    int estimate = dist + rem + 58;\n                    if (turnNo + estimate > BUILD_LIMIT + 8) continue;\n\n                    double val = 50.0 * taskPriority(tid) - dist;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestI = i;\n                        bestT = tid;\n                    }\n                }\n            }\n\n            if (bestI == -1) break;\n\n            hs[bestI].task = bestT;\n            hs[bestI].phase = GO;\n            hs[bestI].wait = 0;\n            tasks[bestT].assigned = bestI;\n        }\n    }\n\n    array<bool, G> computeDoorTargets() {\n        array<bool, G> need;\n        need.fill(false);\n\n        struct Comp {\n            int area = 0;\n            int pets = 0;\n            bool protect = false;\n            vector<int> doors;\n        };\n\n        int compId[G][G];\n        for (int r = 0; r < G; r++) {\n            for (int c = 0; c < G; c++) compId[r][c] = -1;\n        }\n\n        vector<Comp> comps;\n\n        for (int sr = 0; sr <= 28; sr++) {\n            for (int sc = 0; sc < G; sc++) {\n                if (blocked[sr][sc]) continue;\n                if (compId[sr][sc] != -1) continue;\n\n                int id = (int)comps.size();\n                comps.push_back(Comp());\n\n                queue<pair<int,int>> q;\n                compId[sr][sc] = id;\n                q.push({sr, sc});\n\n                while (!q.empty()) {\n                    auto [r, c] = q.front();\n                    q.pop();\n\n                    comps[id].area++;\n\n                    if (r == 28 && !blocked[29][c]) {\n                        comps[id].doors.push_back(c);\n                    }\n\n                    for (int d = 0; d < 4; d++) {\n                        int nr = r + DR[d], nc = c + DC[d];\n                        if (!inside(nr, nc)) continue;\n                        if (nr == 29) continue; // bottom corridor excluded\n                        if (blocked[nr][nc]) continue;\n                        if (compId[nr][nc] != -1) continue;\n\n                        compId[nr][nc] = id;\n                        q.push({nr, nc});\n                    }\n                }\n            }\n        }\n\n        int corridorPets = 0;\n\n        for (auto &p : pets) {\n            if (p.r == 29) {\n                corridorPets++;\n            } else if (0 <= p.r && p.r <= 28) {\n                int id = compId[p.r][p.c];\n                if (id >= 0) comps[id].pets++;\n            }\n        }\n\n        for (auto &h : humans) {\n            if (h.first <= 28) {\n                int id = compId[h.first][h.second];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        // Protect components currently needed by active builders.\n        for (int i = 0; i < M; i++) {\n            int tid = hs[i].task;\n            if (tid == -1) continue;\n            if (hs[i].phase == RET) continue;\n            if (taskComplete(tid)) continue;\n\n            int s = tasks[tid].stand;\n            if (!blocked[28][s]) {\n                int id = compId[28][s];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        int baseArea = 0;\n        for (int c = 0; c < G; c++) {\n            if (!blocked[29][c]) baseArea++;\n        }\n\n        int basePets = corridorPets;\n        (void)basePets; // constant for subset choice\n\n        struct Item {\n            int comp;\n            int area;\n            int pets;\n        };\n\n        vector<Item> items;\n\n        for (int id = 0; id < (int)comps.size(); id++) {\n            auto &cp = comps[id];\n\n            if (cp.doors.empty()) continue; // already isolated from corridor\n\n            if (cp.protect || cp.pets == 0) {\n                baseArea += cp.area;\n                basePets += cp.pets;\n            } else {\n                items.push_back({id, cp.area, cp.pets});\n            }\n        }\n\n        int K = (int)items.size();\n        int maxP = N;\n\n        vector<vector<int>> dp(K + 1, vector<int>(maxP + 1, -INF));\n        vector<vector<int>> pre(K + 1, vector<int>(maxP + 1, -1));\n        vector<vector<char>> take(K + 1, vector<char>(maxP + 1, 0));\n\n        dp[0][0] = baseArea;\n\n        for (int k = 0; k < K; k++) {\n            int a = items[k].area;\n            int p = items[k].pets;\n\n            for (int q = 0; q <= maxP; q++) {\n                if (dp[k][q] < 0) continue;\n\n                // Close this component.\n                if (dp[k][q] > dp[k + 1][q]) {\n                    dp[k + 1][q] = dp[k][q];\n                    pre[k + 1][q] = q;\n                    take[k + 1][q] = 0;\n                }\n\n                // Leave it open.\n                if (q + p <= maxP && dp[k][q] + a > dp[k + 1][q + p]) {\n                    dp[k + 1][q + p] = dp[k][q] + a;\n                    pre[k + 1][q + p] = q;\n                    take[k + 1][q + p] = 1;\n                }\n            }\n        }\n\n        int bestQ = 0;\n        double bestScore = -1.0;\n\n        for (int q = 0; q <= maxP; q++) {\n            if (dp[K][q] < 0) continue;\n            double val = ldexp((double)dp[K][q], -q);\n            if (val > bestScore) {\n                bestScore = val;\n                bestQ = q;\n            }\n        }\n\n        vector<bool> include(K, false);\n        int q = bestQ;\n        for (int k = K; k >= 1; k--) {\n            include[k - 1] = take[k][q];\n            q = pre[k][q];\n            if (q < 0) break;\n        }\n\n        for (int k = 0; k < K; k++) {\n            if (include[k]) continue;\n\n            int id = items[k].comp;\n            for (int c : comps[id].doors) {\n                if (!blocked[28][c]) need[c] = true;\n            }\n        }\n\n        return need;\n    }\n\n    int tryBuildCurrentRow(int i, int tid, vector<char>& act) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (!(0 <= r && r <= 28)) return 0;\n        if (c != stand) return 0;\n\n        bool anyUnbuilt = false;\n\n        for (int wc : tasks[tid].walls) {\n            if (blocked[r][wc]) continue;\n\n            anyUnbuilt = true;\n            char low = (wc < stand ? 'l' : 'r');\n\n            if (!resBuild[r][wc] && canBuild(i, low)) {\n                issueBuild(i, low, act);\n                return 1;\n            }\n        }\n\n        return anyUnbuilt ? -1 : 0;\n    }\n\n    void moveToGoals(int i, const vector<pair<int,int>>& goals, vector<char>& act) {\n        char mv = bfsMove(i, goals);\n        if (mv != '.') issueMove(i, mv, act);\n    }\n\n    void actBuilder(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int tid = hs[i].task;\n\n        if (tid == -1) {\n            actFree(i, act, needDoor);\n            return;\n        }\n\n        bool comp = taskComplete(tid);\n        if (comp) hs[i].phase = RET;\n        if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (hs[i].phase == RET) {\n            if (r == 29) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n                actFree(i, act, needDoor);\n                return;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col = 0; col < G; col++) {\n                if (!blocked[29][col]) goals.push_back({29, col});\n            }\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        if (hs[i].phase == GO) {\n            if (!(r == 29 && c == stand)) {\n                moveToGoals(i, {{29, stand}}, act);\n                return;\n            }\n            hs[i].phase = UP;\n        }\n\n        if (c != stand) {\n            hs[i].phase = GO;\n            moveToGoals(i, {{29, stand}}, act);\n            return;\n        }\n\n        if (hs[i].phase == UP) {\n            if (r == 29) {\n                hs[i].wait = 0;\n                issueMove(i, 'U', act);\n                return;\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r > 0) {\n                issueMove(i, 'U', act);\n                return;\n            } else {\n                hs[i].phase = DOWN;\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n\n        if (hs[i].phase == DOWN) {\n            if (r == 29) {\n                if (taskComplete(tid)) {\n                    hs[i].phase = RET;\n                    actBuilder(i, act, needDoor);\n                    return;\n                } else {\n                    hs[i].phase = UP;\n                    issueMove(i, 'U', act);\n                    return;\n                }\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r < 28) {\n                issueMove(i, 'D', act);\n                return;\n            } else {\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n    }\n\n    void actFree(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n\n        if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c]) {\n            if (canBuild(i, 'u')) {\n                issueBuild(i, 'u', act);\n                return;\n            }\n        }\n\n        vector<int> cols;\n        for (int col = 0; col < G; col++) {\n            if (needDoor[col] && !blocked[28][col] && !resBuild[28][col]) {\n                cols.push_back(col);\n            }\n        }\n\n        if (!cols.empty()) {\n            bool curIllegal = false;\n            if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c] && !canBuild(i, 'u')) {\n                curIllegal = true;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col : cols) {\n                if (curIllegal && col == c && cols.size() >= 2) continue;\n                goals.push_back({29, col});\n            }\n\n            if (goals.empty()) goals.push_back({29, c});\n\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        moveToGoals(i, {{29, hs[i].home}}, act);\n    }\n\n    string decideActions() {\n        buildOcc();\n        resetReservations();\n\n        normalizeStates();\n        assignTasks();\n\n        auto needDoor = computeDoorTargets();\n\n        vector<char> act(M, '.');\n\n        vector<int> order;\n        for (int i = 0; i < M; i++) if (hs[i].task != -1) order.push_back(i);\n        for (int i = 0; i < M; i++) if (hs[i].task == -1) order.push_back(i);\n\n        for (int i : order) {\n            if (hs[i].task != -1) actBuilder(i, act, needDoor);\n            else actFree(i, act, needDoor);\n        }\n\n        string s;\n        s.reserve(M);\n        for (int i = 0; i < M; i++) s.push_back(act[i]);\n        return s;\n    }\n\n    char convertAction(char ch) {\n        if (ch == '.') return '.';\n\n        bool low = islower((unsigned char)ch);\n        char up = toupper(ch);\n        char p = logToPhys[(int)up];\n\n        if (low) p = tolower(p);\n        return p;\n    }\n\n    string toPhysicalOutput(const string& logAct) {\n        string out;\n        out.reserve(logAct.size());\n\n        for (char ch : logAct) {\n            out.push_back(convertAction(ch));\n        }\n\n        return out;\n    }\n\n    void applyActions(const string& logAct) {\n        auto oldHumans = humans;\n        auto newHumans = humans;\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('a' <= a && a <= 'z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) blocked[r][c] = true;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('A' <= a && a <= 'Z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) newHumans[i] = {r, c};\n            }\n        }\n\n        humans = newHumans;\n    }\n\n    bool readPetMovesAndUpdate() {\n        for (int i = 0; i < N; i++) {\n            string s;\n            if (!(cin >> s)) return false;\n\n            if (s == \".\") continue;\n\n            for (char pc : s) {\n                if (pc == '.') continue;\n\n                char lc = physToLog[(int)pc];\n                int d = dirId(lc);\n\n                pets[i].r += DR[d];\n                pets[i].c += DC[d];\n            }\n        }\n\n        return true;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<Pet> petsPhys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> petsPhys[i].r >> petsPhys[i].c >> petsPhys[i].t;\n        petsPhys[i].r--;\n        petsPhys[i].c--;\n    }\n\n    int M;\n    cin >> M;\n\n    vector<pair<int,int>> humansPhys(M);\n    for (int i = 0; i < M; i++) {\n        cin >> humansPhys[i].first >> humansPhys[i].second;\n        humansPhys[i].first--;\n        humansPhys[i].second--;\n    }\n\n    int ori = chooseOrientation(petsPhys, humansPhys);\n    Solver solver(N, petsPhys, M, humansPhys, ori);\n\n    for (int turn = 0; turn < 300; turn++) {\n        solver.turnNo = turn;\n\n        string logAct = solver.decideActions();\n        string out = solver.toPhysicalOutput(logAct);\n\n        cout << out << endl;\n        cout.flush();\n\n        solver.applyActions(logAct);\n\n        if (!solver.readPetMovesAndUpdate()) return 0;\n    }\n\n    return 0;\n}","ahc009":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 20;\nstatic constexpr int W = 20;\nstatic constexpr int N = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr int MAXD = 400;\n\nint si_, sj_, ti_, tj_;\nint SID, TID;\ndouble pForget, qRemember;\n\nstring hwall[H], vwall[H - 1];\n\nint goTo[4][N]; // U D L R\nint distT[N], distS[N];\n\ndouble pot[MAXL + 1][MAXD + 1];\ndouble adaptVal[MAXL + 1][N];\n\ndouble pref[MAXL + 1][N];\ndouble suff[MAXL + 1][N];\ndouble prefScore[MAXL + 1];\n\nchrono::steady_clock::time_point startTime;\n\nconst double HARD_LIMIT = 1.88;\nconst double EPS = 1e-10;\nconst string DIRS = \"UDLR\";\n\nenum FillMode {\n    F_LAST = 0,\n    F_GREEDY = 1\n};\n\ninline int id(int i, int j) {\n    return i * W + j;\n}\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n}\n\nvoid buildGo() {\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x = id(i, j);\n            goTo[0][x] = (i > 0 && vwall[i - 1][j] == '0') ? id(i - 1, j) : x;\n            goTo[1][x] = (i + 1 < H && vwall[i][j] == '0') ? id(i + 1, j) : x;\n            goTo[2][x] = (j > 0 && hwall[i][j - 1] == '0') ? id(i, j - 1) : x;\n            goTo[3][x] = (j + 1 < W && hwall[i][j] == '0') ? id(i, j + 1) : x;\n        }\n    }\n}\n\nvoid bfsDistFrom(int st, int* dist) {\n    fill(dist, dist + N, -1);\n    queue<int> que;\n    dist[st] = 0;\n    que.push(st);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            if (dist[y] == -1) {\n                dist[y] = dist[x] + 1;\n                que.push(y);\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (dist[i] < 0) dist[i] = MAXD;\n    }\n}\n\nvoid buildPotential() {\n    for (int d = 0; d <= MAXD; d++) pot[MAXL][d] = 0.0;\n    pot[MAXL][0] = 401 - MAXL;\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        pot[l][0] = 401 - l;\n\n        for (int d = 1; d <= MAXD; d++) {\n            pot[l][d] = qRemember * pot[l + 1][d - 1] + pForget * pot[l + 1][d];\n        }\n    }\n}\n\nvoid buildAdaptiveValue() {\n    fill(adaptVal[MAXL], adaptVal[MAXL] + N, 0.0);\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        double reward = 400 - l;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                adaptVal[l][v] = 0.0;\n                continue;\n            }\n\n            double best = 0.0;\n\n            for (int a = 0; a < 4; a++) {\n                int u = goTo[a][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * adaptVal[l + 1][v];\n                } else if (u == v) {\n                    val = adaptVal[l + 1][v];\n                } else {\n                    val = pForget * adaptVal[l + 1][v] + qRemember * adaptVal[l + 1][u];\n                }\n\n                best = max(best, val);\n            }\n\n            adaptVal[l][v] = best;\n        }\n    }\n}\n\ndouble evaluate(const vector<int>& seq) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    double score = 0.0;\n    int L = (int)seq.size();\n\n    for (int k = 0; k < L; k++) {\n        fill(ndp, ndp + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = dp[v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                ndp[v] += m * pForget;\n            } else if (u == v) {\n                ndp[v] += m;\n            } else {\n                ndp[v] += m * pForget;\n                ndp[u] += m * qRemember;\n            }\n        }\n\n        score += reward * hit;\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return score;\n}\n\nvoid applyActionDist(const double* dp, double* ndp, int a) {\n    fill(ndp, ndp + N, 0.0);\n\n    for (int v = 0; v < N; v++) {\n        double m = dp[v];\n        if (m == 0.0) continue;\n\n        int u = goTo[a][v];\n\n        if (u == TID) {\n            ndp[v] += m * pForget;\n        } else if (u == v) {\n            ndp[v] += m;\n        } else {\n            ndp[v] += m * pForget;\n            ndp[u] += m * qRemember;\n        }\n    }\n}\n\nvoid computePrefixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(pref[0], pref[0] + N, 0.0);\n    pref[0][SID] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int k = 0; k < L; k++) {\n        fill(pref[k + 1], pref[k + 1] + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = pref[k][v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                pref[k + 1][v] += m * pForget;\n            } else if (u == v) {\n                pref[k + 1][v] += m;\n            } else {\n                pref[k + 1][v] += m * pForget;\n                pref[k + 1][u] += m * qRemember;\n            }\n        }\n\n        prefScore[k + 1] = prefScore[k] + reward * hit;\n    }\n}\n\nvoid computeSuffixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(suff[L], suff[L] + N, 0.0);\n\n    for (int k = L - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                suff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                suff[k][v] = qRemember * reward + pForget * suff[k + 1][v];\n            } else if (u == v) {\n                suff[k][v] = suff[k + 1][v];\n            } else {\n                suff[k][v] = pForget * suff[k + 1][v] + qRemember * suff[k + 1][u];\n            }\n        }\n    }\n}\n\nvoid computePrefixSuffix(const vector<int>& seq) {\n    computePrefixOnly(seq);\n    computeSuffixOnly(seq);\n}\n\ninline double heuristicFuture(int mode, int pos, int state) {\n    if (mode == 0) return adaptVal[pos][state];\n    if (mode == 1) return pot[pos][distT[state]];\n    return 0.55 * adaptVal[pos][state] + 0.45 * pot[pos][distT[state]];\n}\n\nvoid completeGreedy(vector<int>& seq) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n    if ((int)seq.size() == MAXL) return;\n\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    int len = (int)seq.size();\n\n    for (int k = 0; k < len; k++) {\n        applyActionDist(dp, ndp, seq[k]);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    for (int k = len; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * adaptVal[k + 1][v]);\n                } else if (u == v) {\n                    val += m * adaptVal[k + 1][v];\n                } else {\n                    val += m * (pForget * adaptVal[k + 1][v] + qRemember * adaptVal[k + 1][u]);\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n}\n\nvector<int> greedySequenceMode(int mode) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    vector<int> seq;\n    seq.reserve(MAXL);\n\n    for (int k = 0; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * heuristicFuture(mode, k + 1, v));\n                } else if (u == v) {\n                    val += m * heuristicFuture(mode, k + 1, v);\n                } else {\n                    val += m * (pForget * heuristicFuture(mode, k + 1, v) + qRemember * heuristicFuture(mode, k + 1, u));\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return seq;\n}\n\nstruct Candidate {\n    vector<int> seq;\n    double score;\n};\n\nvoid fillLast(vector<int>& seq) {\n    if (seq.empty()) seq.push_back(1);\n    while ((int)seq.size() < MAXL) seq.push_back(seq.back());\n}\n\nvoid addCandidate(vector<Candidate>& cands, vector<int> seq, int mode = F_GREEDY) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n\n    if ((int)seq.size() < MAXL) {\n        if (mode == F_GREEDY) completeGreedy(seq);\n        else fillLast(seq);\n    }\n\n    for (const auto& c : cands) {\n        if (c.seq == seq) return;\n    }\n\n    double sc = evaluate(seq);\n    cands.push_back({move(seq), sc});\n}\n\nvoid pruneCands(vector<Candidate>& cands, int limit) {\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        return a.score > b.score;\n    });\n\n    if ((int)cands.size() > limit) cands.resize(limit);\n}\n\nint repCost(int d, double z) {\n    if (d <= 0) return 0;\n\n    double val = d / qRemember + z * sqrt(max(0.0, d * pForget)) / qRemember;\n    int r = (int)ceil(val - 1e-9);\n\n    r = max(r, d);\n    r = max(r, 1);\n\n    return r;\n}\n\nint cappedRep(int d, double z) {\n    if (d <= 0) return 0;\n    return min(18, repCost(d, z));\n}\n\nvoid appendRun(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt && (int)s.size() < MAXL; i++) {\n        s.push_back(a);\n    }\n}\n\nvoid appendRunRaw(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt; i++) s.push_back(a);\n}\n\nvector<int> bfsPath(int start, int goal, const array<int, 4>& order) {\n    if (start == goal) return {};\n\n    vector<int> par(N, -1), parA(N, -1);\n    queue<int> que;\n\n    par[start] = start;\n    que.push(start);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        if (x == goal) break;\n\n        for (int a : order) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            if (par[y] == -1) {\n                par[y] = x;\n                parA[y] = a;\n                que.push(y);\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != start) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> randomPathTo(int goal, int seed, int noise, int biasAway) {\n    mt19937 rng(seed);\n\n    int wgt[4][N];\n\n    for (int a = 0; a < 4; a++) {\n        for (int v = 0; v < N; v++) {\n            if (goTo[a][v] == v) {\n                wgt[a][v] = INT_MAX / 4;\n            } else {\n                int pen = (a == 0 || a == 2) ? biasAway : 0;\n                wgt[a][v] = 1000 + pen + (int)(rng() % max(1, noise));\n            }\n        }\n    }\n\n    const int INF = 1 << 29;\n    vector<int> dist(N, INF), par(N, -1), parA(N, -1);\n    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n    dist[SID] = 0;\n    pq.push({0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd != dist[x]) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            int nd = cd + wgt[a][x];\n            if (nd < dist[y]) {\n                dist[y] = nd;\n                par[y] = x;\n                parA[y] = a;\n                pq.push({nd, y});\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != SID) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> makeCyclePath(const vector<int>& path) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    s.reserve(MAXL);\n    for (int i = 0; i < MAXL; i++) {\n        s.push_back(path[i % path.size()]);\n    }\n\n    return s;\n}\n\nvector<int> repeatEachPathOriginal(const vector<int>& path, int rep) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    for (int a : path) {\n        for (int r = 0; r < rep && (int)s.size() < MAXL; r++) {\n            s.push_back(a);\n        }\n\n        if ((int)s.size() >= MAXL) break;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(path[ptr % path.size()]);\n        ptr++;\n    }\n\n    return s;\n}\n\nvector<int> syncRunPath(const vector<int>& path, double z, int extraUnsynced = 0) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    int cell = SID;\n\n    for (int i = 0; i < (int)path.size();) {\n        int a = path[i];\n        int j = i;\n\n        while (j < (int)path.size() && path[j] == a) j++;\n\n        int d = j - i;\n        int end = cell;\n\n        for (int k = 0; k < d; k++) {\n            end = goTo[a][end];\n        }\n\n        bool synced = (end == TID || goTo[a][end] == end);\n        int r = synced ? repCost(d, z) : d + extraUnsynced;\n        r = max(r, d);\n\n        appendRun(s, a, r);\n\n        cell = end;\n\n        if ((int)s.size() >= MAXL) break;\n\n        i = j;\n    }\n\n    return s;\n}\n\npair<int, int> slideResult(int cell, int a) {\n    int c = cell;\n    int d = 0;\n\n    while (true) {\n        int u = goTo[a][c];\n        if (u == c) break;\n\n        c = u;\n        d++;\n\n        if (c == TID) break;\n    }\n\n    return {c, d};\n}\n\nvector<int> slidePathToGoal(int goal, double z) {\n    if (goal == SID) return {};\n\n    const double INF = 1e100;\n\n    vector<double> dc(N, INF);\n    vector<int> pre(N, -1), preA(N, -1), preD(N, 0);\n\n    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n\n    dc[SID] = 0.0;\n    pq.push({0.0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd > dc[x] + 1e-9) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            auto [to, d] = slideResult(x, a);\n            if (d == 0) continue;\n\n            double nd = cd + repCost(d, z);\n\n            if (nd < dc[to]) {\n                dc[to] = nd;\n                pre[to] = x;\n                preA[to] = a;\n                preD[to] = d;\n                pq.push({nd, to});\n            }\n        }\n    }\n\n    if (pre[goal] == -1) return {};\n\n    vector<pair<int, int>> segs;\n\n    int x = goal;\n    while (x != SID) {\n        segs.push_back({preA[x], preD[x]});\n        x = pre[x];\n    }\n\n    reverse(segs.begin(), segs.end());\n\n    vector<int> seq;\n\n    for (auto [a, d] : segs) {\n        appendRun(seq, a, repCost(d, z));\n        if ((int)seq.size() >= MAXL) break;\n    }\n\n    return seq;\n}\n\nvector<int> slideCandidate(double z) {\n    return slidePathToGoal(TID, z);\n}\n\nvoid addPathCandidatesOriginal(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, F_LAST);\n    addCandidate(cands, makeCyclePath(path), F_LAST);\n\n    for (int rep : {2, 3, 4}) {\n        addCandidate(cands, repeatEachPathOriginal(path, rep), F_LAST);\n    }\n}\n\nvoid addLightPathCandidates(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, F_GREEDY);\n    addCandidate(cands, makeCyclePath(path), F_LAST);\n    addCandidate(cands, syncRunPath(path, 0.9, 0), F_GREEDY);\n\n    int r = max(2, (int)ceil(1.0 / qRemember));\n    addCandidate(cands, repeatEachPathOriginal(path, r), F_GREEDY);\n}\n\nvector<int> patternFromRuns(const vector<pair<int, int>>& runs) {\n    vector<int> pat;\n\n    for (auto [a, c] : runs) {\n        if (c <= 0) continue;\n        appendRunRaw(pat, a, c);\n    }\n\n    return pat;\n}\n\nvoid addPatternCandidate(vector<Candidate>& cands, const vector<int>& prefix, const vector<int>& pattern) {\n    vector<int> s = prefix;\n\n    if ((int)s.size() > MAXL) s.resize(MAXL);\n\n    if (pattern.empty()) {\n        addCandidate(cands, s, F_GREEDY);\n        return;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(pattern[ptr]);\n        ptr++;\n        if (ptr == (int)pattern.size()) ptr = 0;\n    }\n\n    addCandidate(cands, s, F_LAST);\n}\n\nvoid addLineCandidates(vector<Candidate>& cands, int goal, int toward, int back, int offset) {\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<vector<int>> prefixes;\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPath(SID, goal, ord);\n        if (goal != SID && path.empty()) continue;\n\n        prefixes.push_back(path);\n\n        vector<int> sp = syncRunPath(path, 0.8, 0);\n        prefixes.push_back(sp);\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    if (offset == 0) {\n        for (auto& pre : prefixes) {\n            addCandidate(cands, pre, F_GREEDY);\n        }\n        return;\n    }\n\n    vector<int> counts = {\n        offset,\n        max(offset, (int)ceil(offset / qRemember)),\n        cappedRep(offset, 0.7),\n        min(18, max(offset, 5))\n    };\n\n    sort(counts.begin(), counts.end());\n    counts.erase(unique(counts.begin(), counts.end()), counts.end());\n\n    for (auto& pre : prefixes) {\n        for (int c : counts) {\n            vector<int> pat = patternFromRuns({{toward, c}, {back, c}});\n            addPatternCandidate(cands, pre, pat);\n        }\n    }\n}\n\nvoid addSweepCandidates(vector<Candidate>& cands) {\n    vector<vector<int>> patterns;\n\n    vector<int> cs = {\n        4,\n        max(4, (int)round(4.0 / qRemember)),\n        min(14, repCost(4, 0.7)),\n        min(18, repCost(4, 1.4))\n    };\n\n    sort(cs.begin(), cs.end());\n    cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n    for (int c : cs) {\n        patterns.push_back(patternFromRuns({{0, c}, {2, c}, {1, c}, {3, c}}));\n        patterns.push_back(patternFromRuns({{2, c}, {0, c}, {3, c}, {1, c}}));\n    }\n\n    int up = 19 - ti_;\n    int left = 19 - tj_;\n\n    for (double z : {0.0, 0.8, 1.5}) {\n        int ru = cappedRep(up, z);\n        int rl = cappedRep(left, z);\n\n        if (ru + rl > 0) {\n            patterns.push_back(patternFromRuns({{0, ru}, {2, rl}, {1, ru}, {3, rl}}));\n            patterns.push_back(patternFromRuns({{2, rl}, {0, ru}, {3, rl}, {1, ru}}));\n        }\n    }\n\n    vector<vector<int>> prefixes;\n\n    for (double z : {0.0, 1.0}) {\n        int big = min(75, repCost(19, z));\n\n        vector<int> s1;\n        appendRun(s1, 1, big);\n        appendRun(s1, 3, big);\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        appendRun(s2, 3, big);\n        appendRun(s2, 1, big);\n        prefixes.push_back(s2);\n    }\n\n    for (int chunk : {max(5, (int)round(7.0 / qRemember)), max(8, (int)round(11.0 / qRemember))}) {\n        vector<int> s1;\n        while ((int)s1.size() < 115) {\n            appendRun(s1, 1, chunk);\n            appendRun(s1, 3, chunk);\n        }\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        while ((int)s2.size() < 115) {\n            appendRun(s2, 3, chunk);\n            appendRun(s2, 1, chunk);\n        }\n        prefixes.push_back(s2);\n    }\n\n    array<int, 4> drOrder{1, 3, 0, 2};\n    vector<int> cornerPath = bfsPath(SID, id(19, 19), drOrder);\n\n    if (!cornerPath.empty()) {\n        prefixes.push_back(cornerPath);\n        prefixes.push_back(syncRunPath(cornerPath, 0.8, 0));\n        prefixes.push_back(syncRunPath(cornerPath, 1.6, 0));\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    int used = 0;\n\n    for (auto& pre : prefixes) {\n        for (auto& pat : patterns) {\n            addPatternCandidate(cands, pre, pat);\n            used++;\n            if (used >= 60) break;\n        }\n        if (used >= 60) break;\n    }\n\n    addLineCandidates(cands, id(ti_, 19), 2, 3, 19 - tj_);\n    addLineCandidates(cands, id(19, tj_), 0, 1, 19 - ti_);\n}\n\nvoid addNearTargetCandidates(vector<Candidate>& cands) {\n    vector<int> cells;\n\n    for (int v = 0; v < N; v++) {\n        if (v == TID) continue;\n        if (distT[v] <= 4) cells.push_back(v);\n    }\n\n    sort(cells.begin(), cells.end(), [&](int a, int b) {\n        int ca = distS[a] + 5 * distT[a];\n        int cb = distS[b] + 5 * distT[b];\n        return ca < cb;\n    });\n\n    if ((int)cells.size() > 10) cells.resize(10);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    for (int v : cells) {\n        for (auto ord : orders) {\n            vector<int> path = bfsPath(SID, v, ord);\n            if (v != SID && path.empty()) continue;\n\n            addCandidate(cands, path, F_GREEDY);\n\n            vector<int> sp = syncRunPath(path, 0.8, 0);\n            addCandidate(cands, sp, F_GREEDY);\n        }\n    }\n}\n\nstruct RayInfo {\n    int cell;\n    int action;\n    int d;\n    int rank;\n};\n\nvoid addTargetRayCandidates(vector<Candidate>& cands) {\n    vector<RayInfo> rays;\n\n    for (int a = 0; a < 4; a++) {\n        for (int c = 0; c < N; c++) {\n            if (c == TID) continue;\n\n            int x = c;\n\n            for (int d = 1; d <= 25; d++) {\n                int y = goTo[a][x];\n                if (y == x) break;\n\n                x = y;\n\n                if (x == TID) {\n                    int rank = distS[c] + repCost(d, 1.0);\n                    rays.push_back({c, a, d, rank});\n                    break;\n                }\n            }\n        }\n    }\n\n    sort(rays.begin(), rays.end(), [](const RayInfo& a, const RayInfo& b) {\n        if (a.rank != b.rank) return a.rank < b.rank;\n        return a.d < b.d;\n    });\n\n    if ((int)rays.size() > 16) rays.resize(16);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<double> zs = {0.0, 1.0};\n    if (pForget >= 0.25) zs.push_back(1.8);\n\n    for (const auto& r : rays) {\n        for (auto ord : orders) {\n            vector<int> path = bfsPath(SID, r.cell, ord);\n            if (r.cell != SID && path.empty()) continue;\n\n            vector<vector<int>> prefixes;\n            prefixes.push_back(path);\n            prefixes.push_back(syncRunPath(path, 0.8, 0));\n\n            sort(prefixes.begin(), prefixes.end());\n            prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n            for (auto pre : prefixes) {\n                for (double z : zs) {\n                    vector<int> s = pre;\n                    appendRun(s, r.action, repCost(r.d, z));\n                    addCandidate(cands, s, F_GREEDY);\n                }\n            }\n        }\n\n        for (double pz : {0.5, 1.2}) {\n            vector<int> pre = slidePathToGoal(r.cell, pz);\n            if (r.cell != SID && pre.empty()) continue;\n\n            for (double z : zs) {\n                vector<int> s = pre;\n                appendRun(s, r.action, repCost(r.d, z));\n                addCandidate(cands, s, F_GREEDY);\n            }\n        }\n    }\n}\n\nstruct BeamNode {\n    float prob[N];\n    double score;\n    double est;\n    unsigned char seq[MAXL];\n\n    BeamNode() {}\n};\n\n// mode 0: original distance potential\n// mode 1: mixed adaptive + distance potential\nvector<vector<int>> beamSearchMode(int topCount, int initialWidth, int mode) {\n    int width = initialWidth;\n\n    vector<BeamNode> cur, nxt, selected;\n    vector<int> idx;\n\n    cur.reserve(initialWidth);\n    nxt.reserve(initialWidth * 4);\n    selected.reserve(initialWidth);\n    idx.reserve(initialWidth * 4);\n\n    BeamNode root;\n    fill(root.prob, root.prob + N, 0.0f);\n    root.prob[SID] = 1.0f;\n    root.score = 0.0;\n\n    if (mode == 0) {\n        root.est = pot[0][distT[SID]];\n    } else {\n        root.est = 0.75 * adaptVal[0][SID] + 0.25 * pot[0][distT[SID]];\n    }\n\n    cur.push_back(root);\n\n    for (int l = 0; l < MAXL; l++) {\n        if ((l % 5) == 0) {\n            double e = elapsedSec();\n\n            if (e > 1.55) width = min(width, 35);\n            else if (e > 1.42) width = min(width, 70);\n            else if (e > 1.28) width = min(width, 120);\n            else if (e > 1.12 && mode != 0) width = min(width, 120);\n        }\n\n        nxt.clear();\n\n        for (const BeamNode& par : cur) {\n            for (int a = 0; a < 4; a++) {\n                BeamNode& ch = nxt.emplace_back();\n\n                fill(ch.prob, ch.prob + N, 0.0f);\n\n                if (l > 0) memcpy(ch.seq, par.seq, l * sizeof(unsigned char));\n                ch.seq[l] = (unsigned char)a;\n\n                double hit = 0.0;\n                double future = 0.0;\n                const double* drow = pot[l + 1];\n                const double* vrow = adaptVal[l + 1];\n\n                for (int v = 0; v < N; v++) {\n                    float mf = par.prob[v];\n                    if (mf == 0.0f) continue;\n\n                    double m = mf;\n                    int u = goTo[a][v];\n\n                    auto addFuture = [&](int state, double mass) {\n                        if (mode == 0) {\n                            future += mass * drow[distT[state]];\n                        } else {\n                            future += mass * (0.75 * vrow[state] + 0.25 * drow[distT[state]]);\n                        }\n                    };\n\n                    if (u == TID) {\n                        double stay = m * pForget;\n                        hit += m * qRemember;\n                        ch.prob[v] += (float)stay;\n                        addFuture(v, stay);\n                    } else if (u == v) {\n                        ch.prob[v] += mf;\n                        addFuture(v, m);\n                    } else {\n                        double stay = m * pForget;\n                        double mv = m * qRemember;\n\n                        ch.prob[v] += (float)stay;\n                        ch.prob[u] += (float)mv;\n\n                        addFuture(v, stay);\n                        addFuture(u, mv);\n                    }\n                }\n\n                ch.score = par.score + (400 - l) * hit;\n                ch.est = ch.score + future;\n            }\n        }\n\n        int n = (int)nxt.size();\n\n        if (n > width) {\n            idx.resize(n);\n            iota(idx.begin(), idx.end(), 0);\n\n            auto cmp = [&](int x, int y) {\n                if (nxt[x].est != nxt[y].est) return nxt[x].est > nxt[y].est;\n                return nxt[x].score > nxt[y].score;\n            };\n\n            nth_element(idx.begin(), idx.begin() + width, idx.end(), cmp);\n\n            selected.clear();\n\n            for (int i = 0; i < width; i++) {\n                selected.push_back(nxt[idx[i]]);\n            }\n\n            cur.swap(selected);\n        } else {\n            cur.swap(nxt);\n        }\n    }\n\n    vector<vector<int>> res;\n    int n = (int)cur.size();\n\n    idx.resize(n);\n    iota(idx.begin(), idx.end(), 0);\n\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        return cur[x].score > cur[y].score;\n    });\n\n    int take = min(topCount, n);\n\n    for (int r = 0; r < take; r++) {\n        vector<int> s(MAXL);\n        const BeamNode& node = cur[idx[r]];\n\n        for (int k = 0; k < MAXL; k++) {\n            s[k] = node.seq[k];\n        }\n\n        res.push_back(move(s));\n    }\n\n    return res;\n}\n\nvector<int> bestCrossoverSeq(const vector<int>& A, const vector<int>& B) {\n    computeSuffixOnly(B);\n    computePrefixOnly(A);\n\n    double best = -1.0;\n    int bestK = 0;\n\n    for (int k = 0; k <= MAXL; k++) {\n        double total = prefScore[k];\n\n        for (int v = 0; v < N; v++) {\n            total += pref[k][v] * suff[k][v];\n        }\n\n        if (total > best) {\n            best = total;\n            bestK = k;\n        }\n    }\n\n    vector<int> s;\n    s.reserve(MAXL);\n\n    for (int i = 0; i < bestK; i++) s.push_back(A[i]);\n    for (int i = bestK; i < MAXL; i++) s.push_back(B[i]);\n\n    return s;\n}\n\nvoid addCrossovers(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>((int)cands.size(), 14));\n\n    int m = min<int>(8, cands.size());\n    vector<vector<int>> top;\n\n    for (int i = 0; i < m; i++) top.push_back(cands[i].seq);\n\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < m; j++) {\n            if (i == j) continue;\n\n            if (elapsedSec() > 1.60) return;\n\n            vector<int> s = bestCrossoverSeq(top[i], top[j]);\n            addCandidate(cands, s, F_LAST);\n        }\n    }\n}\n\nvoid addGreedyTailCandidates(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>((int)cands.size(), 12));\n\n    vector<vector<int>> top;\n    int m = min<int>(6, cands.size());\n\n    for (int i = 0; i < m; i++) top.push_back(cands[i].seq);\n\n    vector<int> cuts = {0, 25, 50, 75, 100, 125, 150, 175};\n\n    for (auto& base : top) {\n        for (int k : cuts) {\n            if (elapsedSec() > 1.55) return;\n\n            vector<int> s(base.begin(), base.begin() + k);\n            addCandidate(cands, s, F_GREEDY);\n        }\n    }\n}\n\nbool tryWindow(vector<int>& seq, int win, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    int masks = 1 << (2 * win);\n\n    static double buf1[N], buf2[N];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 3) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        for (int mask = 0; mask < masks; mask++) {\n            if (mask == curMask) continue;\n\n            memcpy(buf1, pref[k], sizeof(double) * N);\n\n            double* dp = buf1;\n            double* ndp = buf2;\n            double sc = prefScore[k];\n\n            int mm = mask;\n\n            for (int r = 0; r < win; r++) {\n                int a = mm & 3;\n                mm >>= 2;\n\n                fill(ndp, ndp + N, 0.0);\n\n                double hit = 0.0;\n                double reward = 400 - (k + r);\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        ndp[v] += m * pForget;\n                    } else if (u == v) {\n                        ndp[v] += m;\n                    } else {\n                        ndp[v] += m * pForget;\n                        ndp[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp, ndp);\n            }\n\n            double total = sc;\n            const double* sw = suff[k + win];\n\n            for (int v = 0; v < N; v++) {\n                total += dp[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = mask;\n            }\n        }\n    }\n\n    if (bestK != -1) {\n        int mm = bestMask;\n\n        for (int r = 0; r < win; r++) {\n            seq[bestK + r] = mm & 3;\n            mm >>= 2;\n        }\n\n        newScore = best;\n        return true;\n    }\n\n    return false;\n}\n\nbool tryShiftDP(vector<int>& seq, double currentScore, double& newScore) {\n    int L = (int)seq.size();\n    if (L != MAXL) return false;\n\n    static double insSuff[MAXL + 1][N];\n    static double delSuff[4][MAXL + 1][N];\n\n    fill(insSuff[L - 1], insSuff[L - 1] + N, 0.0);\n\n    for (int k = L - 2; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 399 - k;\n        const double* nxt = insSuff[k + 1];\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                insSuff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                insSuff[k][v] = qRemember * reward + pForget * nxt[v];\n            } else if (u == v) {\n                insSuff[k][v] = nxt[v];\n            } else {\n                insSuff[k][v] = pForget * nxt[v] + qRemember * nxt[u];\n            }\n        }\n    }\n\n    double finalReward = 400 - (L - 1);\n\n    for (int c = 0; c < 4; c++) {\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                delSuff[c][L][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[c][v];\n            delSuff[c][L][v] = (u == TID ? qRemember * finalReward : 0.0);\n        }\n\n        for (int k = L - 1; k >= 1; k--) {\n            int a = seq[k];\n            double reward = 401 - k;\n            const double* nxt = delSuff[c][k + 1];\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    delSuff[c][k][v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    delSuff[c][k][v] = qRemember * reward + pForget * nxt[v];\n                } else if (u == v) {\n                    delSuff[c][k][v] = nxt[v];\n                } else {\n                    delSuff[c][k][v] = pForget * nxt[v] + qRemember * nxt[u];\n                }\n            }\n        }\n    }\n\n    double best = currentScore;\n    int bestType = -1;\n    int bestI = -1;\n    int bestC = -1;\n\n    // Insert command at i and drop last.\n    for (int i = 0; i < L; i++) {\n        const double* row = pref[i];\n        double base = prefScore[i];\n        double reward = 400 - i;\n        const double* tail = insSuff[i];\n\n        for (int c = 0; c < 4; c++) {\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                double m = row[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[c][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * tail[v];\n                } else if (u == v) {\n                    val = tail[v];\n                } else {\n                    val = pForget * tail[v] + qRemember * tail[u];\n                }\n\n                total += m * val;\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 0;\n                bestI = i;\n                bestC = c;\n            }\n        }\n    }\n\n    // Delete command at i and append c.\n    for (int i = 0; i < L; i++) {\n        const double* row = pref[i];\n        double base = prefScore[i];\n\n        for (int c = 0; c < 4; c++) {\n            const double* tail = delSuff[c][i + 1];\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                total += row[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 1;\n                bestI = i;\n                bestC = c;\n            }\n        }\n    }\n\n    if (bestType == -1) return false;\n\n    vector<int> ns(L);\n\n    if (bestType == 0) {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n        ns[bestI] = bestC;\n        for (int k = bestI + 1; k < L; k++) ns[k] = seq[k - 1];\n    } else {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n        for (int k = bestI; k < L - 1; k++) ns[k] = seq[k + 1];\n        ns[L - 1] = bestC;\n    }\n\n    seq.swap(ns);\n    newScore = best;\n    return true;\n}\n\n// Exact arbitrary block insert/delete shift, used only as a late spare-time move.\nbool tryShiftAnyBlock(vector<int>& seq, int b, double currentScore, double& newScore, double deadline) {\n    int L = (int)seq.size();\n    if (L != MAXL || b < 2 || b > 3) return false;\n\n    int masks = 1 << (2 * b);\n\n    static double insSuff[MAXL + 1][N];\n    static double delSuff[64][MAXL + 1][N];\n    static double dp1[N], dp2[N];\n    static double tmp1[N], tmp2[N];\n\n    // Insert block of length b at i, drop last b chars.\n    fill(insSuff[L - b], insSuff[L - b] + N, 0.0);\n\n    for (int k = L - b - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - (k + b);\n        const double* nxt = insSuff[k + 1];\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                insSuff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                insSuff[k][v] = qRemember * reward + pForget * nxt[v];\n            } else if (u == v) {\n                insSuff[k][v] = nxt[v];\n            } else {\n                insSuff[k][v] = pForget * nxt[v] + qRemember * nxt[u];\n            }\n        }\n    }\n\n    // Delete block of length b, append arbitrary block mask.\n    for (int mask = 0; mask < masks; mask++) {\n        fill(tmp1, tmp1 + N, 0.0);\n\n        for (int r = b - 1; r >= 0; r--) {\n            int a = (mask >> (2 * r)) & 3;\n            double reward = 400 - (L - b + r);\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    tmp2[v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    tmp2[v] = qRemember * reward + pForget * tmp1[v];\n                } else if (u == v) {\n                    tmp2[v] = tmp1[v];\n                } else {\n                    tmp2[v] = pForget * tmp1[v] + qRemember * tmp1[u];\n                }\n            }\n\n            memcpy(tmp1, tmp2, sizeof(double) * N);\n        }\n\n        memcpy(delSuff[mask][L], tmp1, sizeof(double) * N);\n\n        for (int k = L - 1; k >= b; k--) {\n            int a = seq[k];\n            double reward = 400 - (k - b);\n            const double* nxt = delSuff[mask][k + 1];\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    delSuff[mask][k][v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    delSuff[mask][k][v] = qRemember * reward + pForget * nxt[v];\n                } else if (u == v) {\n                    delSuff[mask][k][v] = nxt[v];\n                } else {\n                    delSuff[mask][k][v] = pForget * nxt[v] + qRemember * nxt[u];\n                }\n            }\n        }\n    }\n\n    double best = currentScore;\n    int bestType = -1;\n    int bestI = -1;\n    int bestMask = 0;\n\n    // Insert arbitrary block.\n    for (int i = 0; i <= L - b; i++) {\n        if ((i & 7) == 0 && elapsedSec() > deadline - 0.006) goto finish_search;\n\n        const double* row = pref[i];\n        double base = prefScore[i];\n        const double* tail = insSuff[i];\n\n        for (int mask = 0; mask < masks; mask++) {\n            memcpy(dp1, row, sizeof(double) * N);\n            double sc = base;\n\n            for (int r = 0; r < b; r++) {\n                int a = (mask >> (2 * r)) & 3;\n\n                fill(dp2, dp2 + N, 0.0);\n\n                double reward = 400 - (i + r);\n                double hit = 0.0;\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp1[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        dp2[v] += m * pForget;\n                    } else if (u == v) {\n                        dp2[v] += m;\n                    } else {\n                        dp2[v] += m * pForget;\n                        dp2[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp1, dp2);\n            }\n\n            double total = sc;\n\n            for (int v = 0; v < N; v++) {\n                total += dp1[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 0;\n                bestI = i;\n                bestMask = mask;\n            }\n        }\n    }\n\n    // Delete arbitrary block, append arbitrary block.\n    for (int i = 0; i <= L - b; i++) {\n        if ((i & 7) == 0 && elapsedSec() > deadline - 0.006) goto finish_search;\n\n        const double* row = pref[i];\n        double base = prefScore[i];\n\n        for (int mask = 0; mask < masks; mask++) {\n            const double* tail = delSuff[mask][i + b];\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                total += row[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 1;\n                bestI = i;\n                bestMask = mask;\n            }\n        }\n    }\n\nfinish_search:\n\n    if (bestType == -1) return false;\n\n    vector<int> ns(L);\n\n    if (bestType == 0) {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n\n        for (int r = 0; r < b; r++) {\n            ns[bestI + r] = (bestMask >> (2 * r)) & 3;\n        }\n\n        for (int k = bestI + b; k < L; k++) {\n            ns[k] = seq[k - b];\n        }\n    } else {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n\n        for (int k = bestI; k < L - b; k++) {\n            ns[k] = seq[k + b];\n        }\n\n        for (int r = 0; r < b; r++) {\n            ns[L - b + r] = (bestMask >> (2 * r)) & 3;\n        }\n    }\n\n    seq.swap(ns);\n    newScore = best;\n    return true;\n}\n\nstruct BlockNode {\n    double prob[N];\n    double sc;\n    double key;\n    int mask;\n};\n\nbool tryWindowBeam(vector<int>& seq, int win, int beamW, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    if (win <= 0 || win > 10) return false;\n\n    beamW = min(beamW, 30);\n\n    static BlockNode cur[32], nxt[128], sel[32];\n    static int idx[128];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 1) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        int curN = 1;\n        memcpy(cur[0].prob, pref[k], sizeof(double) * N);\n        cur[0].sc = 0.0;\n        cur[0].key = 0.0;\n        cur[0].mask = 0;\n\n        for (int r = 0; r < win; r++) {\n            int nn = 0;\n            int pos = k + r;\n            double reward = 400 - pos;\n            const double* vrow = adaptVal[pos + 1];\n            const double* drow = pot[pos + 1];\n\n            for (int bi = 0; bi < curN; bi++) {\n                const BlockNode& par = cur[bi];\n\n                for (int a = 0; a < 4; a++) {\n                    BlockNode& ch = nxt[nn++];\n                    fill(ch.prob, ch.prob + N, 0.0);\n\n                    double hit = 0.0;\n                    double future = 0.0;\n\n                    for (int v = 0; v < N; v++) {\n                        double m = par.prob[v];\n                        if (m == 0.0) continue;\n\n                        int u = goTo[a][v];\n\n                        if (u == TID) {\n                            double stay = m * pForget;\n                            hit += m * qRemember;\n                            ch.prob[v] += stay;\n                            future += stay * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                        } else if (u == v) {\n                            ch.prob[v] += m;\n                            future += m * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                        } else {\n                            double stay = m * pForget;\n                            double mv = m * qRemember;\n                            ch.prob[v] += stay;\n                            ch.prob[u] += mv;\n                            future += stay * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                            future += mv * (0.65 * vrow[u] + 0.35 * drow[distT[u]]);\n                        }\n                    }\n\n                    ch.sc = par.sc + reward * hit;\n                    ch.key = ch.sc + future;\n                    ch.mask = par.mask | (a << (2 * r));\n                }\n            }\n\n            if (nn > beamW) {\n                iota(idx, idx + nn, 0);\n                nth_element(idx, idx + beamW, idx + nn, [&](int x, int y) {\n                    return nxt[x].key > nxt[y].key;\n                });\n\n                for (int i = 0; i < beamW; i++) {\n                    sel[i] = nxt[idx[i]];\n                }\n\n                curN = beamW;\n                for (int i = 0; i < curN; i++) {\n                    cur[i] = sel[i];\n                }\n            } else {\n                curN = nn;\n                for (int i = 0; i < curN; i++) {\n                    cur[i] = nxt[i];\n                }\n            }\n        }\n\n        const double* sw = suff[k + win];\n\n        for (int bi = 0; bi < curN; bi++) {\n            if (cur[bi].mask == curMask) continue;\n\n            double total = prefScore[k] + cur[bi].sc;\n\n            for (int v = 0; v < N; v++) {\n                total += cur[bi].prob[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = cur[bi].mask;\n            }\n        }\n    }\n\n    if (bestK == -1) return false;\n\n    int mm = bestMask;\n    for (int r = 0; r < win; r++) {\n        seq[bestK + r] = mm & 3;\n        mm >>= 2;\n    }\n\n    newScore = best;\n    return true;\n}\n\ndouble improve(vector<int>& seq, double deadline, int maxWindow, bool useShift, bool useLarge, bool useAnyBlock = false) {\n    int L = (int)seq.size();\n    double curScore = evaluate(seq);\n\n    while (elapsedSec() < deadline) {\n        computePrefixSuffix(seq);\n        curScore = prefScore[L];\n\n        double bestScore = curScore;\n        int bestK = -1;\n        int bestC = -1;\n\n        for (int k = 0; k < L; k++) {\n            const double* row = pref[k];\n            const double* sw = suff[k + 1];\n            double base = prefScore[k];\n            double reward = 400 - k;\n\n            for (int c = 0; c < 4; c++) {\n                if (c == seq[k]) continue;\n\n                double total = base;\n\n                for (int v = 0; v < N; v++) {\n                    double m = row[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[c][v];\n                    double val;\n\n                    if (u == TID) {\n                        val = qRemember * reward + pForget * sw[v];\n                    } else if (u == v) {\n                        val = sw[v];\n                    } else {\n                        val = pForget * sw[v] + qRemember * sw[u];\n                    }\n\n                    total += m * val;\n                }\n\n                if (total > bestScore + EPS) {\n                    bestScore = total;\n                    bestK = k;\n                    bestC = c;\n                }\n            }\n        }\n\n        if (bestK != -1) {\n            seq[bestK] = bestC;\n            curScore = bestScore;\n            continue;\n        }\n\n        bool changed = false;\n\n        for (int w = 2; w <= maxWindow; w++) {\n            if (elapsedSec() > deadline - 0.01) break;\n\n            double ns;\n            if (tryWindow(seq, w, curScore, deadline, ns)) {\n                curScore = ns;\n                changed = true;\n                break;\n            }\n        }\n\n        if (changed) continue;\n\n        if (useShift && elapsedSec() < deadline - 0.005) {\n            double ns;\n            if (tryShiftDP(seq, curScore, ns)) {\n                curScore = ns;\n                continue;\n            }\n        }\n\n        if (useLarge && elapsedSec() < deadline - 0.05) {\n            double ns;\n            int bw = (pForget >= 0.35 ? 14 : 12);\n\n            if (tryWindowBeam(seq, 7, bw, curScore, deadline, ns)) {\n                curScore = ns;\n                continue;\n            }\n\n            if (elapsedSec() < deadline - 0.06 && tryWindowBeam(seq, 10, 8, curScore, deadline, ns)) {\n                curScore = ns;\n                continue;\n            }\n        }\n\n        // Late exact timing move. Placed after all normal moves, so it does not steal\n        // time from the stronger main local search unless that search has converged.\n        if (useAnyBlock && elapsedSec() < deadline - 0.055) {\n            double ns;\n\n            if (tryShiftAnyBlock(seq, 2, curScore, ns, deadline)) {\n                curScore = ns;\n                continue;\n            }\n\n            if (pForget >= 0.30 && elapsedSec() < deadline - 0.12) {\n                if (tryShiftAnyBlock(seq, 3, curScore, ns, deadline)) {\n                    curScore = ns;\n                    continue;\n                }\n            }\n        }\n\n        break;\n    }\n\n    return evaluate(seq);\n}\n\nvector<int> recompleteFromCut(const vector<int>& seq, int cut) {\n    cut = min(cut, (int)seq.size());\n    vector<int> s(seq.begin(), seq.begin() + cut);\n    completeGreedy(s);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si_ >> sj_ >> ti_ >> tj_ >> pForget;\n    qRemember = 1.0 - pForget;\n\n    for (int i = 0; i < H; i++) cin >> hwall[i];\n    for (int i = 0; i < H - 1; i++) cin >> vwall[i];\n\n    SID = id(si_, sj_);\n    TID = id(ti_, tj_);\n\n    startTime = chrono::steady_clock::now();\n\n    buildGo();\n    bfsDistFrom(TID, distT);\n    bfsDistFrom(SID, distS);\n    buildPotential();\n    buildAdaptiveValue();\n\n    vector<Candidate> cands;\n\n    addCandidate(cands, vector<int>{}, F_GREEDY);\n\n    for (int mode = 0; mode < 3; mode++) {\n        addCandidate(cands, greedySequenceMode(mode), F_LAST);\n    }\n\n    array<int, 4> originalOrder{0, 1, 2, 3};\n    vector<int> spOriginal = bfsPath(SID, TID, originalOrder);\n    addPathCandidatesOriginal(cands, spOriginal);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2},\n        array<int, 4>{1, 3, 2, 0},\n        array<int, 4>{3, 1, 2, 0},\n        array<int, 4>{0, 1, 3, 2},\n        array<int, 4>{2, 3, 1, 0}\n    };\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPath(SID, TID, ord);\n        addLightPathCandidates(cands, path);\n    }\n\n    for (int r = 0; r < 4; r++) {\n        int noise = 350 + 100 * r;\n        int bias = (r % 2 == 0 ? 120 : 0);\n        addLightPathCandidates(cands, randomPathTo(TID, 10000 + r * 97, noise, bias));\n    }\n\n    addNearTargetCandidates(cands);\n    addTargetRayCandidates(cands);\n    addSweepCandidates(cands);\n\n    for (double z : {0.0, 0.5, 1.0, 1.5, 2.2}) {\n        vector<int> s = slideCandidate(z);\n        if (!s.empty()) {\n            addCandidate(cands, s, F_LAST);\n            addCandidate(cands, s, F_GREEDY);\n        }\n    }\n\n    pruneCands(cands, 90);\n\n    vector<vector<int>> distBeamSeqs;\n    distBeamSeqs = beamSearchMode(8, 430, 0);\n\n    for (auto& s : distBeamSeqs) {\n        addCandidate(cands, s, F_LAST);\n    }\n\n    if (elapsedSec() < 1.20) {\n        vector<vector<int>> adapBeamSeqs = beamSearchMode(5, 170, 1);\n        for (auto& s : adapBeamSeqs) {\n            addCandidate(cands, s, F_LAST);\n        }\n    }\n\n    pruneCands(cands, 100);\n\n    if (elapsedSec() < 1.45) {\n        addGreedyTailCandidates(cands);\n    }\n\n    if (elapsedSec() < 1.50) {\n        addCrossovers(cands);\n    }\n\n    if (cands.empty()) {\n        addCandidate(cands, vector<int>{}, F_GREEDY);\n    }\n\n    pruneCands(cands, 100);\n\n    vector<int> bestSeq = cands[0].seq;\n    double bestScore = cands[0].score;\n\n    vector<vector<int>> localStarts;\n\n    auto addStart = [&](const vector<int>& s) {\n        if ((int)s.size() != MAXL) return;\n\n        for (auto& t : localStarts) {\n            if (t == s) return;\n        }\n\n        localStarts.push_back(s);\n    };\n\n    addStart(cands[0].seq);\n\n    if (!distBeamSeqs.empty()) {\n        addStart(distBeamSeqs[0]);\n        if ((int)distBeamSeqs.size() >= 2) addStart(distBeamSeqs[1]);\n    }\n\n    int topStarts = min<int>(8, cands.size());\n    for (int i = 1; i < topStarts; i++) {\n        addStart(cands[i].seq);\n    }\n\n    for (int i = 0; i < (int)localStarts.size(); i++) {\n        if (elapsedSec() > HARD_LIMIT - 0.22) break;\n\n        vector<int> seq = localStarts[i];\n\n        double budget;\n        if (i == 0) budget = 0.22;\n        else if (i <= 2) budget = 0.20;\n        else budget = 0.10;\n\n        double dl = min(HARD_LIMIT - 0.12, elapsedSec() + budget);\n        if (dl <= elapsedSec() + 0.01) break;\n\n        int mw = (i <= 2 ? 3 : 2);\n        bool useShift = (i <= 3);\n        double sc = improve(seq, dl, mw, useShift, false, false);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    // Main final local search: same stable core as the previous best version.\n    if (elapsedSec() < HARD_LIMIT - 0.04) {\n        vector<int> seq = bestSeq;\n        double sc = improve(seq, HARD_LIMIT, 4, true, true, false);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    // Spare-time exact timing refinement. This is deliberately after the main\n    // search to avoid the regression seen from doing these moves too early.\n    if (elapsedSec() < HARD_LIMIT - 0.055) {\n        vector<int> seq = bestSeq;\n        double sc = improve(seq, HARD_LIMIT, 2, true, false, true);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    // Spare-time greedy suffix recompletion from the final locally optimized route.\n    if (elapsedSec() < HARD_LIMIT - 0.08) {\n        vector<int> cuts = {40, 60, 80, 100, 120, 140, 160};\n\n        for (int cut : cuts) {\n            if (elapsedSec() > HARD_LIMIT - 0.055) break;\n\n            vector<int> s = recompleteFromCut(bestSeq, cut);\n            double sc = evaluate(s);\n\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = move(s);\n            }\n        }\n\n        if (elapsedSec() < HARD_LIMIT - 0.035) {\n            vector<int> seq = bestSeq;\n            double sc = improve(seq, HARD_LIMIT, 2, true, false, true);\n\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = move(seq);\n            }\n        }\n    }\n\n    if ((int)bestSeq.size() > MAXL) bestSeq.resize(MAXL);\n    if ((int)bestSeq.size() < MAXL) completeGreedy(bestSeq);\n\n    string out;\n    out.reserve(MAXL);\n\n    for (int a : bestSeq) {\n        out.push_back(DIRS[a]);\n    }\n\n    cout << out << '\\n';\n\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int N = 30;\nconstexpr int CELLS = N * N;\nconstexpr int PORTS = CELLS * 4;\nconstexpr int MAXLEN = 1800;\nconstexpr int MAXCOMP = 4005;\nconstexpr int BITWORDS = (CELLS + 63) / 64;\n\nusing StateArr = array<unsigned char, CELLS>;\n\nint pairDir[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\nint maskState[8];\nint segCnt[8];\nint segA[8][2], segB[8][2];\n\nint adjPort[PORTS];\nint neighCell[CELLS][4];\n\nint baseTile[CELLS];\nint optCnt[CELLS];\nint optState[CELLS][4];\n\nint moveCnt[PORTS];\nint moveNextState[PORTS][2];\nvector<int> validMoveStates;\n\nint di[4] = {0, -1, 0, 1};\nint dj[4] = {-1, 0, 1, 0};\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = seed ? seed : 88172645463325252ULL;\n        for (int i = 0; i < 20; i++) next();\n    }\n    inline uint64_t next() {\n        x ^= x << 13;\n        x ^= x >> 7;\n        x ^= x << 17;\n        return x;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct BIT {\n    int bit[MAXLEN + 2];\n    int total;\n\n    void reset() {\n        memset(bit, 0, sizeof(bit));\n        total = 0;\n    }\n\n    void add(int idx, int delta) {\n        if (idx <= 0) return;\n        total += delta;\n        for (int i = idx; i <= MAXLEN; i += i & -i) bit[i] += delta;\n    }\n\n    int kth(int k) const {\n        int idx = 0;\n        for (int pw = 2048; pw; pw >>= 1) {\n            int ni = idx + pw;\n            if (ni <= MAXLEN && bit[ni] < k) {\n                idx = ni;\n                k -= bit[ni];\n            }\n        }\n        return idx + 1;\n    }\n};\n\nstruct Stats {\n    int l1 = 0, l2 = 0;\n    int c1 = 0, c2 = 0;\n    int loops = 0;\n    int broken = 0;\n    long long score = 0;\n    long long loopSq = 0;\n};\n\nstruct Manager {\n    unsigned char st[CELLS];\n\n    int comp[PORTS];\n    vector<int> ports[MAXCOMP];\n    bool alive[MAXCOMP];\n    int compLen[MAXCOMP];\n    int compBroken[MAXCOMP];\n\n    int nextId = 0;\n    vector<int> freeIds;\n\n    BIT compBIT, loopBIT;\n    long long loopSq = 0;\n    int brokenTotal = 0;\n\n    int stackBuf[PORTS];\n\n    Manager() {\n        freeIds.reserve(MAXCOMP);\n        memset(alive, 0, sizeof(alive));\n    }\n\n    inline bool active(int p) const {\n        return pairDir[st[p >> 2]][p & 3] >= 0;\n    }\n\n    inline int internalPort(int p) const {\n        return (p & ~3) | pairDir[st[p >> 2]][p & 3];\n    }\n\n    int allocId() {\n        int id;\n        if (!freeIds.empty()) {\n            id = freeIds.back();\n            freeIds.pop_back();\n        } else {\n            id = nextId++;\n        }\n        alive[id] = true;\n        ports[id].clear();\n        return id;\n    }\n\n    void addStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, 1);\n        brokenTotal += br;\n\n        if (br == 0) {\n            loopBIT.add(len, 1);\n            loopSq += 1LL * len * len;\n        }\n    }\n\n    void removeStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, -1);\n        brokenTotal -= br;\n\n        if (br == 0) {\n            loopBIT.add(len, -1);\n            loopSq -= 1LL * len * len;\n        }\n    }\n\n    void removeComp(int id) {\n        if (id < 0 || !alive[id]) return;\n\n        removeStats(id);\n\n        for (int p : ports[id]) comp[p] = -1;\n        ports[id].clear();\n        alive[id] = false;\n        freeIds.push_back(id);\n    }\n\n    void addComponent(int start) {\n        int id = allocId();\n\n        int top = 0;\n        stackBuf[top++] = start;\n        comp[start] = id;\n        ports[id].push_back(start);\n\n        int broken = 0;\n\n        while (top) {\n            int p = stackBuf[--top];\n\n            int q = internalPort(p);\n            if (comp[q] == -1) {\n                comp[q] = id;\n                ports[id].push_back(q);\n                stackBuf[top++] = q;\n            }\n\n            int e = adjPort[p];\n            if (e != -1 && active(e)) {\n                if (comp[e] == -1) {\n                    comp[e] = id;\n                    ports[id].push_back(e);\n                    stackBuf[top++] = e;\n                }\n            } else {\n                broken++;\n            }\n        }\n\n        compLen[id] = (int)ports[id].size() / 2;\n        compBroken[id] = broken;\n        addStats(id);\n    }\n\n    void build(const StateArr &arr) {\n        for (int i = 0; i < nextId; i++) {\n            ports[i].clear();\n            alive[i] = false;\n        }\n\n        nextId = 0;\n        freeIds.clear();\n\n        compBIT.reset();\n        loopBIT.reset();\n        loopSq = 0;\n        brokenTotal = 0;\n\n        for (int i = 0; i < CELLS; i++) st[i] = arr[i];\n        fill(comp, comp + PORTS, -1);\n\n        for (int p = 0; p < PORTS; p++) {\n            if (active(p) && comp[p] == -1) addComponent(p);\n        }\n    }\n\n    void updateCell(int cell, int newState) {\n        if (st[cell] == newState) return;\n\n        int ids[20];\n        int cnt = 0;\n\n        auto addId = [&](int id) {\n            if (id < 0 || !alive[id]) return;\n            for (int k = 0; k < cnt; k++) {\n                if (ids[k] == id) return;\n            }\n            ids[cnt++] = id;\n        };\n\n        int base = cell * 4;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            addId(comp[p]);\n            int e = adjPort[p];\n            if (e != -1) addId(comp[e]);\n        }\n\n        for (int k = 0; k < cnt; k++) removeComp(ids[k]);\n\n        st[cell] = (unsigned char)newState;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            if (active(p) && comp[p] == -1) addComponent(p);\n\n            int e = adjPort[p];\n            if (e != -1 && active(e) && comp[e] == -1) addComponent(e);\n        }\n    }\n\n    Stats getStats() const {\n        Stats s;\n\n        s.loops = loopBIT.total;\n\n        if (loopBIT.total >= 1) s.l1 = loopBIT.kth(loopBIT.total);\n        if (loopBIT.total >= 2) s.l2 = loopBIT.kth(loopBIT.total - 1);\n\n        if (compBIT.total >= 1) s.c1 = compBIT.kth(compBIT.total);\n        if (compBIT.total >= 2) s.c2 = compBIT.kth(compBIT.total - 1);\n\n        s.score = 1LL * s.l1 * s.l2;\n        s.loopSq = loopSq;\n        s.broken = brokenTotal;\n\n        return s;\n    }\n\n    void exportState(StateArr &out) const {\n        for (int i = 0; i < CELLS; i++) out[i] = st[i];\n    }\n};\n\nvoid initGlobals() {\n    for (int t = 0; t < 8; t++) {\n        maskState[t] = 0;\n        segCnt[t] = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (pairDir[t][d] != -1) maskState[t] |= 1 << d;\n        }\n\n        for (int d = 0; d < 4; d++) {\n            int e = pairDir[t][d];\n            if (e != -1 && d < e) {\n                int k = segCnt[t]++;\n                segA[t][k] = d;\n                segB[t][k] = e;\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                    neighCell[id][d] = -1;\n                    adjPort[id * 4 + d] = -1;\n                } else {\n                    int nb = ni * N + nj;\n                    neighCell[id][d] = nb;\n                    adjPort[id * 4 + d] = nb * 4 + (d ^ 2);\n                }\n            }\n        }\n    }\n}\n\nvoid buildMoveTransitions() {\n    validMoveStates.clear();\n\n    for (int s = 0; s < PORTS; s++) {\n        moveCnt[s] = 0;\n\n        int c = s >> 2;\n        int d = s & 3;\n\n        if (neighCell[c][d] == -1) continue;\n\n        if (baseTile[c] >= 6) {\n            int out = d ^ 2;\n            int nb = neighCell[c][out];\n            if (nb != -1) {\n                moveNextState[s][moveCnt[s]++] = nb * 4 + (out ^ 2);\n            }\n        } else {\n            int out1 = (d + 1) & 3;\n            int out2 = (d + 3) & 3;\n\n            int nb1 = neighCell[c][out1];\n            if (nb1 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb1 * 4 + (out1 ^ 2);\n            }\n\n            int nb2 = neighCell[c][out2];\n            if (nb2 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb2 * 4 + (out2 ^ 2);\n            }\n        }\n\n        if (moveCnt[s] > 0) validMoveStates.push_back(s);\n    }\n}\n\nint stateForPair(int base, int a, int b) {\n    if (a > b) swap(a, b);\n\n    if (base < 4) {\n        if (a == 0 && b == 1) return 0;\n        if (a == 0 && b == 3) return 1;\n        if (a == 2 && b == 3) return 2;\n        if (a == 1 && b == 2) return 3;\n        return -1;\n    } else if (base < 6) {\n        if ((a == 0 && b == 1) || (a == 2 && b == 3)) return 4;\n        if ((a == 0 && b == 3) || (a == 1 && b == 2)) return 5;\n        return -1;\n    } else {\n        if (a == 0 && b == 2) return 6;\n        if (a == 1 && b == 3) return 7;\n        return -1;\n    }\n}\n\nint localQuality(const unsigned char *arr, int id, int candState) {\n    bool nbAct[4];\n\n    for (int d = 0; d < 4; d++) {\n        int nb = neighCell[id][d];\n        nbAct[d] = false;\n\n        if (nb != -1) {\n            int ns = arr[nb];\n            nbAct[d] = (maskState[ns] >> (d ^ 2)) & 1;\n        }\n    }\n\n    int cm = maskState[candState];\n    int q = 0;\n\n    for (int d = 0; d < 4; d++) {\n        bool ca = (cm >> d) & 1;\n        bool na = nbAct[d];\n\n        if (ca && na) q += 6;\n        else if (ca || na) q -= 4;\n    }\n\n    for (int k = 0; k < segCnt[candState]; k++) {\n        int a = segA[candState][k];\n        int b = segB[candState][k];\n\n        int c = (nbAct[a] ? 1 : 0) + (nbAct[b] ? 1 : 0);\n\n        if (c == 2) q += 20;\n        else if (c == 1) q -= 3;\n        else q -= 8;\n    }\n\n    return q;\n}\n\nvoid greedyImprove(StateArr &cand, RNG &rng, int sweeps, const char *fixed = nullptr) {\n    int steps = sweeps * CELLS;\n\n    for (int it = 0; it < steps; it++) {\n        int id = rng.nextInt(CELLS);\n        if (fixed && fixed[id]) continue;\n\n        int bestSt = cand[id];\n        int bestQ = -1000000000;\n        int ties = 0;\n\n        for (int k = 0; k < optCnt[id]; k++) {\n            int s = optState[id][k];\n            int q = localQuality(cand.data(), id, s);\n\n            if (q > bestQ) {\n                bestQ = q;\n                bestSt = s;\n                ties = 1;\n            } else if (q == bestQ) {\n                ties++;\n                if (rng.nextInt(ties) == 0) bestSt = s;\n            }\n        }\n\n        cand[id] = (unsigned char)bestSt;\n    }\n}\n\nlong long startValue(const Stats &s) {\n    long long compProd = 1LL * s.c1 * s.c2;\n    return s.score * 1500LL + s.loopSq * 25LL + compProd * 6LL - 120LL * s.broken;\n}\n\nlong long energyValue(const Stats &s, double progress) {\n    long long compProd = 1LL * s.c1 * s.c2;\n\n    if (progress < 0.60) {\n        return s.score * 500LL\n             + s.loopSq * 30LL\n             + compProd * 8LL\n             + 1LL * s.l1 * s.l1 * 10LL\n             + 1LL * s.l2 * s.l2 * 10LL\n             - 110LL * s.broken;\n    } else {\n        return s.score * 2500LL\n             + s.loopSq * 5LL\n             + 1LL * s.l1 * s.l1 * 3LL\n             + 1LL * s.l2 * s.l2 * 3LL\n             + compProd / 3LL\n             - 4LL * s.broken;\n    }\n}\n\nlong long finalValue(const Stats &s) {\n    return s.score * 1000000LL\n         + 1LL * s.l1 * 2000LL\n         + 1LL * s.l2 * 1000LL\n         + s.loopSq\n         - 10LL * s.broken;\n}\n\nbool betterStats(const Stats &s, long long bestScore, int bestL1, int bestL2) {\n    if (s.score != bestScore) return s.score > bestScore;\n    return s.l1 + s.l2 > bestL1 + bestL2;\n}\n\nvoid updateBestWithState(\n    const StateArr &arr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        bestState = arr;\n    }\n}\n\nvoid updateBestWithManager(\n    const Manager &mgr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        mgr.exportState(bestState);\n    }\n}\n\nstruct Cycle {\n    int len = 0;\n    uint64_t hash = 0;\n    array<uint64_t, BITWORDS> bits{};\n    array<unsigned char, CELLS> pmask{};\n    array<unsigned char, CELLS> cstate{};\n    vector<int> cells;\n    vector<unsigned char> states;\n    vector<unsigned char> masks;\n};\n\nbool incompatibleCycle(const Cycle &a, const Cycle &b) {\n    for (int w = 0; w < BITWORDS; w++) {\n        uint64_t x = a.bits[w] & b.bits[w];\n\n        while (x) {\n            int bit = __builtin_ctzll(x);\n            int c = w * 64 + bit;\n            x &= x - 1;\n\n            if (c >= CELLS) continue;\n\n            if (!(baseTile[c] >= 4 && baseTile[c] < 6)) return true;\n            if (a.cstate[c] != b.cstate[c]) return true;\n            if (a.pmask[c] & b.pmask[c]) return true;\n        }\n    }\n\n    return false;\n}\n\nstruct CycleSampler {\n    static constexpr int MIN_LEN = 16;\n    static constexpr int KEEP = 1300;\n\n    vector<Cycle> cycles;\n\n    int stateSeen[PORTS];\n    int statePos[PORTS];\n\n    int cellSeen[CELLS];\n    int cellCnt[CELLS];\n\n    int tmpSeen[CELLS];\n    unsigned char tmpState[CELLS];\n    unsigned char tmpMask[CELLS];\n\n    int stamp = 1;\n    int tmpStamp = 1;\n    int minStored = MIN_LEN;\n\n    vector<int> path;\n    vector<int> tmpCells;\n\n    CycleSampler() {\n        memset(stateSeen, 0, sizeof(stateSeen));\n        memset(cellSeen, 0, sizeof(cellSeen));\n        memset(tmpSeen, 0, sizeof(tmpSeen));\n        cycles.reserve(KEEP);\n        path.reserve(PORTS);\n        tmpCells.reserve(MAXLEN);\n    }\n\n    void markState(int s) {\n        int pos = (int)path.size();\n        path.push_back(s);\n\n        stateSeen[s] = stamp;\n        statePos[s] = pos;\n\n        int c = s >> 2;\n        if (cellSeen[c] != stamp) {\n            cellSeen[c] = stamp;\n            cellCnt[c] = 0;\n        }\n        cellCnt[c]++;\n    }\n\n    bool canVisitState(int s) const {\n        if (stateSeen[s] == stamp) return false;\n\n        int c = s >> 2;\n\n        if (cellSeen[c] != stamp) return true;\n\n        return baseTile[c] >= 4 && baseTile[c] < 6 && cellCnt[c] < 2;\n    }\n\n    void recomputeMin() {\n        if ((int)cycles.size() < KEEP) {\n            minStored = MIN_LEN;\n            return;\n        }\n\n        minStored = 1000000;\n        for (const auto &c : cycles) minStored = min(minStored, c.len);\n    }\n\n    uint64_t calcHash(const Cycle &cy) {\n        uint64_t h = 1469598103934665603ULL ^ (uint64_t)cy.len;\n\n        for (uint64_t x : cy.bits) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n\n        for (int i = 0; i < (int)cy.cells.size(); i++) {\n            uint64_t v = (uint64_t)cy.cells[i] * 1315423911ULL\n                       + (uint64_t)cy.states[i] * 911382323ULL\n                       + (uint64_t)cy.masks[i] * 972663749ULL;\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n\n        return h;\n    }\n\n    void storeCycle(Cycle &&cy) {\n        for (const auto &ex : cycles) {\n            if (ex.len != cy.len || ex.hash != cy.hash) continue;\n            if (ex.cells == cy.cells && ex.states == cy.states && ex.masks == cy.masks) {\n                return;\n            }\n        }\n\n        if ((int)cycles.size() < KEEP) {\n            cycles.push_back(std::move(cy));\n            if ((int)cycles.size() == KEEP) recomputeMin();\n            return;\n        }\n\n        int mi = 0;\n        for (int i = 1; i < KEEP; i++) {\n            if (cycles[i].len < cycles[mi].len) mi = i;\n        }\n\n        if (cy.len > cycles[mi].len) {\n            cycles[mi] = std::move(cy);\n            recomputeMin();\n        }\n    }\n\n    void addCycle(int idx) {\n        int end = (int)path.size();\n        int len = end - idx;\n\n        if (len < MIN_LEN || len > MAXLEN) return;\n        if ((int)cycles.size() >= KEEP && len < minStored) return;\n\n        tmpStamp++;\n        if (tmpStamp == INT_MAX) {\n            memset(tmpSeen, 0, sizeof(tmpSeen));\n            tmpStamp = 1;\n        }\n\n        tmpCells.clear();\n\n        for (int p = idx; p < end; p++) {\n            int s = path[p];\n            int nxt = (p + 1 < end ? path[p + 1] : path[idx]);\n\n            int c = s >> 2;\n            int in = s & 3;\n            int out = (nxt & 3) ^ 2;\n\n            int st = stateForPair(baseTile[c], in, out);\n            if (st < 0) return;\n\n            unsigned char pm = (unsigned char)((1 << in) | (1 << out));\n\n            if (tmpSeen[c] != tmpStamp) {\n                tmpSeen[c] = tmpStamp;\n                tmpState[c] = (unsigned char)st;\n                tmpMask[c] = pm;\n                tmpCells.push_back(c);\n            } else {\n                if (!(baseTile[c] >= 4 && baseTile[c] < 6)) return;\n                if (tmpState[c] != st) return;\n                if (tmpMask[c] & pm) return;\n                tmpMask[c] |= pm;\n            }\n        }\n\n        Cycle cy;\n        cy.len = len;\n        cy.bits.fill(0);\n        cy.pmask.fill(0);\n        cy.cstate.fill((unsigned char)255);\n\n        sort(tmpCells.begin(), tmpCells.end());\n\n        cy.cells.reserve(tmpCells.size());\n        cy.states.reserve(tmpCells.size());\n        cy.masks.reserve(tmpCells.size());\n\n        for (int c : tmpCells) {\n            cy.bits[c >> 6] |= 1ULL << (c & 63);\n            cy.pmask[c] = tmpMask[c];\n            cy.cstate[c] = tmpState[c];\n\n            cy.cells.push_back(c);\n            cy.states.push_back(tmpState[c]);\n            cy.masks.push_back(tmpMask[c]);\n        }\n\n        cy.hash = calcHash(cy);\n        storeCycle(std::move(cy));\n    }\n\n    int onwardDegree(int ns) {\n        int deg = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) deg++;\n            } else if (canVisitState(nn)) {\n                deg++;\n            }\n        }\n\n        return deg;\n    }\n\n    int onwardScore(int ns, RNG &rng) {\n        int sc = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) sc += 20 + min(50, len / 8);\n            } else if (canVisitState(nn)) {\n                sc += 3;\n            }\n        }\n\n        int c = ns >> 2;\n        int i = c / N;\n        int j = c % N;\n        int border = min(min(i, N - 1 - i), min(j, N - 1 - j));\n        sc += border / 4;\n\n        return sc + rng.nextInt(4);\n    }\n\n    void sample(Timer &timer, double endTime, RNG &rng) {\n        if (validMoveStates.empty()) return;\n\n        while (timer.elapsed() < endTime) {\n            stamp++;\n\n            if (stamp == INT_MAX) {\n                memset(stateSeen, 0, sizeof(stateSeen));\n                memset(cellSeen, 0, sizeof(cellSeen));\n                stamp = 1;\n            }\n\n            path.clear();\n\n            int start = validMoveStates[rng.nextInt((int)validMoveStates.size())];\n            markState(start);\n\n            int mode = rng.nextInt(3);\n            int inner = 0;\n\n            while ((int)path.size() < MAXLEN) {\n                int cur = path.back();\n                int cnt = moveCnt[cur];\n\n                if (cnt == 0) break;\n\n                int cont[2];\n                int cc = 0;\n\n                for (int k = 0; k < cnt; k++) {\n                    int ns = moveNextState[cur][k];\n\n                    if (stateSeen[ns] == stamp) {\n                        int idx = statePos[ns];\n                        int len = (int)path.size() - idx;\n                        if (len >= MIN_LEN) addCycle(idx);\n                    } else if (canVisitState(ns)) {\n                        cont[cc++] = ns;\n                    }\n                }\n\n                if (cc == 0) break;\n\n                int chosen;\n\n                if (cc == 1) {\n                    chosen = cont[0];\n                } else if (mode == 2) {\n                    chosen = cont[rng.nextInt(2)];\n                } else if (mode == 1) {\n                    int d0 = onwardDegree(cont[0]);\n                    int d1 = onwardDegree(cont[1]);\n\n                    if (d0 == 0 && d1 > 0) {\n                        chosen = cont[1];\n                    } else if (d1 == 0 && d0 > 0) {\n                        chosen = cont[0];\n                    } else if (d0 == d1) {\n                        chosen = cont[rng.nextInt(2)];\n                    } else if (d0 < d1) {\n                        chosen = (rng.nextInt(4) ? cont[0] : cont[1]);\n                    } else {\n                        chosen = (rng.nextInt(4) ? cont[1] : cont[0]);\n                    }\n                } else {\n                    int s0 = onwardScore(cont[0], rng);\n                    int s1 = onwardScore(cont[1], rng);\n\n                    if (s0 == s1) {\n                        chosen = cont[rng.nextInt(2)];\n                    } else if (s0 > s1) {\n                        chosen = (rng.nextInt(5) ? cont[0] : cont[1]);\n                    } else {\n                        chosen = (rng.nextInt(5) ? cont[1] : cont[0]);\n                    }\n                }\n\n                markState(chosen);\n\n                inner++;\n                if ((inner & 255) == 0 && timer.elapsed() >= endTime) break;\n            }\n        }\n    }\n};\n\nvoid runSA(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    double startTime = timer.elapsed();\n    if (endTime - startTime < 0.01) return;\n\n    Stats initS = mgr.getStats();\n    updateBestWithManager(mgr, initS, bestState, bestScore, bestL1, bestL2);\n\n    int iter = 0;\n    double now = startTime;\n    double progress = 0.0;\n    double temp = 6e6;\n\n    while (true) {\n        if ((iter & 127) == 0) {\n            now = timer.elapsed();\n            if (now >= endTime) break;\n\n            progress = (now - startTime) / (endTime - startTime);\n            progress = min(1.0, max(0.0, progress));\n            temp = 6e6 * pow(2000.0 / 6e6, progress);\n        }\n\n        int ids[4];\n        int oldSt[4];\n        int newSt[4];\n        int m = 1;\n\n        int rr = rng.nextInt(100);\n\n        if (progress < 0.65 && rr < 6) {\n            m = 4;\n            int i = rng.nextInt(N - 1);\n            int j = rng.nextInt(N - 1);\n\n            ids[0] = i * N + j;\n            ids[1] = i * N + j + 1;\n            ids[2] = (i + 1) * N + j;\n            ids[3] = (i + 1) * N + j + 1;\n        } else if (progress < 0.85 && rr < 22) {\n            m = 2;\n            ids[0] = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int nb = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[ids[0]][d] != -1) {\n                    nb = neighCell[ids[0]][d];\n                    break;\n                }\n            }\n\n            ids[1] = nb;\n        } else {\n            m = 1;\n            ids[0] = rng.nextInt(CELLS);\n        }\n\n        bool changed = false;\n\n        for (int x = 0; x < m; x++) {\n            int id = ids[x];\n            int cur = mgr.st[id];\n            oldSt[x] = cur;\n\n            int ns = cur;\n\n            int smartProb = (m == 1 ? 25 : 45);\n\n            if (rng.nextInt(100) < smartProb) {\n                int bestQ = -1000000000;\n                int ties = 0;\n\n                for (int k = 0; k < optCnt[id]; k++) {\n                    int s = optState[id][k];\n                    if (s == cur) continue;\n\n                    int q = localQuality(mgr.st, id, s);\n\n                    if (q > bestQ) {\n                        bestQ = q;\n                        ns = s;\n                        ties = 1;\n                    } else if (q == bestQ) {\n                        ties++;\n                        if (rng.nextInt(ties) == 0) ns = s;\n                    }\n                }\n            } else {\n                do {\n                    ns = optState[id][rng.nextInt(optCnt[id])];\n                } while (ns == cur);\n            }\n\n            newSt[x] = ns;\n            if (ns != cur) changed = true;\n        }\n\n        if (!changed) {\n            iter++;\n            continue;\n        }\n\n        Stats oldS = mgr.getStats();\n        long long oldE = energyValue(oldS, progress);\n\n        for (int x = 0; x < m; x++) mgr.updateCell(ids[x], newSt[x]);\n\n        Stats newS = mgr.getStats();\n        long long newE = energyValue(newS, progress);\n\n        updateBestWithManager(mgr, newS, bestState, bestScore, bestL1, bestL2);\n\n        long long diff = newE - oldE;\n\n        bool accept = false;\n\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            double x = (double)diff / temp;\n            if (x > -30.0 && rng.nextDouble() < exp(x)) accept = true;\n        }\n\n        if (!accept) {\n            for (int x = m - 1; x >= 0; x--) mgr.updateCell(ids[x], oldSt[x]);\n        }\n\n        iter++;\n    }\n}\n\nvoid runHillClimb(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    mgr.build(bestState);\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 7) == 0) {\n            if (timer.elapsed() >= endTime) break;\n        }\n\n        bool pairMove = rng.nextInt(100) < 35;\n\n        if (!pairMove) {\n            int id = rng.nextInt(CELLS);\n            int cur = mgr.st[id];\n\n            Stats baseS = mgr.getStats();\n            long long bestVal = finalValue(baseS);\n            int bestSt = cur;\n\n            for (int k = 0; k < optCnt[id]; k++) {\n                int s = optState[id][k];\n                if (s == cur) continue;\n\n                mgr.updateCell(id, s);\n                Stats ns = mgr.getStats();\n                long long v = finalValue(ns);\n                mgr.updateCell(id, cur);\n\n                if (v > bestVal) {\n                    bestVal = v;\n                    bestSt = s;\n                }\n            }\n\n            if (bestSt != cur) {\n                mgr.updateCell(id, bestSt);\n                Stats s = mgr.getStats();\n                updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n            }\n        } else {\n            int id1 = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int id2 = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[id1][d] != -1) {\n                    id2 = neighCell[id1][d];\n                    break;\n                }\n            }\n\n            if (id2 == -1) {\n                iter++;\n                continue;\n            }\n\n            int old1 = mgr.st[id1];\n            int old2 = mgr.st[id2];\n\n            Stats baseS = mgr.getStats();\n            long long bestVal = finalValue(baseS);\n            int best1 = old1;\n            int best2 = old2;\n\n            for (int a = 0; a < optCnt[id1]; a++) {\n                int s1 = optState[id1][a];\n\n                for (int b = 0; b < optCnt[id2]; b++) {\n                    int s2 = optState[id2][b];\n\n                    if (s1 == old1 && s2 == old2) continue;\n\n                    mgr.updateCell(id1, s1);\n                    mgr.updateCell(id2, s2);\n\n                    Stats ns = mgr.getStats();\n                    long long v = finalValue(ns);\n\n                    mgr.updateCell(id2, old2);\n                    mgr.updateCell(id1, old1);\n\n                    if (v > bestVal) {\n                        bestVal = v;\n                        best1 = s1;\n                        best2 = s2;\n                    }\n                }\n            }\n\n            if (best1 != old1 || best2 != old2) {\n                mgr.updateCell(id1, best1);\n                mgr.updateCell(id2, best2);\n\n                Stats s = mgr.getStats();\n                updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n            }\n        }\n\n        iter++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initGlobals();\n\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        string row;\n        cin >> row;\n\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            int t = row[j] - '0';\n\n            baseTile[id] = t;\n            seed = seed * 1000003ULL + (uint64_t)(t + 17);\n        }\n    }\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n\n        if (b < 4) {\n            optCnt[id] = 4;\n            for (int k = 0; k < 4; k++) optState[id][k] = k;\n        } else if (b < 6) {\n            optCnt[id] = 2;\n            optState[id][0] = 4;\n            optState[id][1] = 5;\n        } else {\n            optCnt[id] = 2;\n            optState[id][0] = 6;\n            optState[id][1] = 7;\n        }\n    }\n\n    buildMoveTransitions();\n\n    Timer timer;\n    RNG rng(seed);\n\n    Manager mgr;\n\n    StateArr bestState{};\n    long long bestScore = -1;\n    int bestL1 = 0;\n    int bestL2 = 0;\n\n    vector<pair<long long, StateArr>> topStarts;\n\n    auto insertTop = [&](long long val, const StateArr &s) {\n        topStarts.push_back({val, s});\n\n        sort(topStarts.begin(), topStarts.end(),\n             [](const auto &a, const auto &b) {\n                 return a.first > b.first;\n             });\n\n        if ((int)topStarts.size() > 10) topStarts.pop_back();\n    };\n\n    auto evalCandidate = [&](const StateArr &cand) {\n        mgr.build(cand);\n        Stats s = mgr.getStats();\n\n        updateBestWithState(cand, s, bestState, bestScore, bestL1, bestL2);\n        insertTop(startValue(s), cand);\n    };\n\n    StateArr baseArr;\n    for (int id = 0; id < CELLS; id++) baseArr[id] = baseTile[id];\n    evalCandidate(baseArr);\n\n    CycleSampler sampler;\n    sampler.sample(timer, 0.30, rng);\n\n    auto &cycles = sampler.cycles;\n\n    sort(cycles.begin(), cycles.end(),\n         [](const Cycle &a, const Cycle &b) {\n             return a.len > b.len;\n         });\n\n    vector<tuple<long long, int, int>> topPairs;\n\n    auto insertPair = [&](long long prod, int a, int b) {\n        topPairs.emplace_back(prod, a, b);\n\n        sort(topPairs.begin(), topPairs.end(),\n             [](const auto &x, const auto &y) {\n                 return get<0>(x) > get<0>(y);\n             });\n\n        if ((int)topPairs.size() > 10) topPairs.pop_back();\n    };\n\n    int C = (int)cycles.size();\n    int I = min(C, 350);\n    int J = min(C, 1000);\n\n    for (int i = 0; i < I; i++) {\n        for (int j = i + 1; j < J; j++) {\n            long long prod = 1LL * cycles[i].len * cycles[j].len;\n\n            if ((int)topPairs.size() >= 10 && prod <= get<0>(topPairs.back())) {\n                break;\n            }\n\n            if (!incompatibleCycle(cycles[i], cycles[j])) {\n                insertPair(prod, i, j);\n            }\n        }\n    }\n\n    auto applyCycle = [&](const Cycle &cy, StateArr &cand, array<char, CELLS> &fixed) {\n        for (int c : cy.cells) {\n            cand[c] = cy.cstate[c];\n            fixed[c] = 1;\n        }\n    };\n\n    for (int p = 0; p < (int)topPairs.size(); p++) {\n        if (timer.elapsed() > 0.45) break;\n\n        int a = get<1>(topPairs[p]);\n        int b = get<2>(topPairs[p]);\n\n        for (int var = 0; var < 2; var++) {\n            if (timer.elapsed() > 0.48) break;\n\n            StateArr cand;\n            array<char, CELLS> fixed{};\n            fixed.fill(0);\n\n            if (var == 0) {\n                for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n            } else {\n                for (int id = 0; id < CELLS; id++) {\n                    cand[id] = optState[id][rng.nextInt(optCnt[id])];\n                }\n            }\n\n            applyCycle(cycles[a], cand, fixed);\n            applyCycle(cycles[b], cand, fixed);\n\n            greedyImprove(cand, rng, 7 + var, fixed.data());\n            evalCandidate(cand);\n        }\n    }\n\n    for (int sidx = 0; sidx < min(5, C); sidx++) {\n        if (timer.elapsed() > 0.49) break;\n\n        StateArr cand;\n        array<char, CELLS> fixed{};\n        fixed.fill(0);\n\n        for (int id = 0; id < CELLS; id++) {\n            cand[id] = optState[id][rng.nextInt(optCnt[id])];\n        }\n\n        applyCycle(cycles[sidx], cand, fixed);\n        greedyImprove(cand, rng, 7, fixed.data());\n        evalCandidate(cand);\n    }\n\n    constexpr int CAND_LIMIT = 55;\n    constexpr double START_END = 0.52;\n\n    for (int c = 0; c < CAND_LIMIT; c++) {\n        if (c > 4 && timer.elapsed() > START_END) break;\n\n        StateArr cand;\n\n        if (c == 0) {\n            for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n        } else {\n            for (int id = 0; id < CELLS; id++) {\n                cand[id] = optState[id][rng.nextInt(optCnt[id])];\n            }\n        }\n\n        int sweeps = 7 + (c % 4);\n        greedyImprove(cand, rng, sweeps);\n\n        evalCandidate(cand);\n    }\n\n    vector<StateArr> starts;\n\n    auto addUniqueStart = [&](const StateArr &s) {\n        for (const auto &t : starts) {\n            if (t == s) return;\n        }\n        starts.push_back(s);\n    };\n\n    addUniqueStart(bestState);\n\n    for (auto &p : topStarts) addUniqueStart(p.second);\n\n    if (starts.empty()) {\n        StateArr init;\n        for (int id = 0; id < CELLS; id++) init[id] = baseTile[id];\n        starts.push_back(init);\n        bestState = init;\n    }\n\n    double SA_END = 1.70;\n    double HILL_END = 1.92;\n\n    int runs = min(4, (int)starts.size());\n\n    for (int r = 0; r < runs; r++) {\n        double now = timer.elapsed();\n\n        if (now >= SA_END) break;\n\n        double endTime = now + (SA_END - now) / (runs - r);\n\n        mgr.build(starts[r]);\n        runSA(mgr, timer, endTime, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    if (timer.elapsed() < HILL_END) {\n        runHillClimb(mgr, timer, HILL_END, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    string ans;\n    ans.reserve(CELLS);\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n        int f = bestState[id];\n        int r;\n\n        if (b < 4) {\n            r = (f - b + 4) % 4;\n        } else {\n            r = (f == b ? 0 : 1);\n        }\n\n        ans.push_back(char('0' + r));\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#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\nint N, T, NN, M;\nvector<int> initBoard;\nint initBlank;\nint invCnt[16];\nint nbCell[105][4];\nint nearDistMask[16][105];\n\nconst int DR[4] = {-1, 1, 0, 0};\nconst int DC[4] = {0, 0, -1, 1};\nconst char DCH[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\nstruct Shape {\n    int h, w, ori;\n};\n\nint hexVal(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return c - 'a' + 10;\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\nint bitForDir(int d) {\n    if (d == 0) return 2;\n    if (d == 1) return 8;\n    if (d == 2) return 1;\n    return 4;\n}\n\nint manhattanCell(int a, int b) {\n    return abs(a / N - b / N) + abs(a % N - b % N);\n}\n\nint transToAct(int tid, int ori) {\n    int r = tid / N, c = tid % N;\n    if (ori == 0) return r * N + c;\n    if (ori == 1) return r * N + (N - 1 - c);\n    if (ori == 2) return (N - 1 - r) * N + c;\n    return (N - 1 - r) * N + (N - 1 - c);\n}\n\nint actToTrans(int aid, int ori) {\n    int r = aid / N, c = aid % N;\n    if (ori == 0) return r * N + c;\n    if (ori == 1) return r * N + (N - 1 - c);\n    if (ori == 2) return (N - 1 - r) * N + c;\n    return (N - 1 - r) * N + (N - 1 - c);\n}\n\nint mapDirTransToAct(int d, int ori) {\n    static int mp[4][4] = {\n        {0, 1, 2, 3},\n        {0, 1, 3, 2},\n        {1, 0, 2, 3},\n        {1, 0, 3, 2},\n    };\n    return mp[ori][d];\n}\n\nbool inRegionCell(int aid, const Shape& s) {\n    int tid = actToTrans(aid, s.ori);\n    int r = tid / N, c = tid % N;\n    return !(r >= N - s.h && c >= N - s.w);\n}\n\nint shapeArea(const Shape& s) {\n    return s.h * s.w;\n}\n\nint freeBlankCell(const Shape& s) {\n    return transToAct((N - 1) * N + (N - 1), s.ori);\n}\n\nvector<int> freeCellsOf(const Shape& s) {\n    vector<int> cells;\n    for (int r = N - s.h; r < N; r++) {\n        for (int c = N - s.w; c < N; c++) {\n            cells.push_back(transToAct(r * N + c, s.ori));\n        }\n    }\n    return cells;\n}\n\nstruct FastDSU {\n    int p[105], sz[105];\n\n    void init(int n) {\n        for (int i = 0; i < n; i++) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\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\n    void unite(int a, int b) {\n        a = find(a);\n        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 Eval {\n    int S;\n    int edges;\n    int maxComp;\n};\n\nEval evalBoard(const vector<int>& bd) {\n    FastDSU dsu;\n    dsu.init(NN);\n\n    pair<int, int> edges[220];\n    int ec = 0;\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            int v = bd[id];\n            if (v == 0) continue;\n\n            if (c + 1 < N) {\n                int j = id + 1;\n                if (bd[j] != 0 && (v & 4) && (bd[j] & 1)) {\n                    dsu.unite(id, j);\n                    edges[ec++] = {id, j};\n                }\n            }\n\n            if (r + 1 < N) {\n                int j = id + N;\n                if (bd[j] != 0 && (v & 8) && (bd[j] & 2)) {\n                    dsu.unite(id, j);\n                    edges[ec++] = {id, j};\n                }\n            }\n        }\n    }\n\n    int vcnt[105] = {};\n    int ecnt[105] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (bd[i] != 0) vcnt[dsu.find(i)]++;\n    }\n    for (int i = 0; i < ec; i++) {\n        ecnt[dsu.find(edges[i].first)]++;\n    }\n\n    int best = 0;\n    int mx = 0;\n\n    for (int i = 0; i < NN; i++) {\n        if (dsu.find(i) == i && vcnt[i] > 0) {\n            mx = max(mx, vcnt[i]);\n            if (ecnt[i] == vcnt[i] - 1) best = max(best, vcnt[i]);\n        }\n    }\n\n    return {best, ec, mx};\n}\n\nlong long scoreFromEval(const Eval& e, int K) {\n    if (e.S == M) {\n        return llround(500000.0 * (2.0 - (double)K / T));\n    } else {\n        return llround(500000.0 * (double)e.S / M);\n    }\n}\n\nbool applyDir(vector<int>& bd, int& blank, int d) {\n    int nb = nbCell[blank][d];\n    if (nb < 0) return false;\n    swap(bd[blank], bd[nb]);\n    blank = nb;\n    return true;\n}\n\nvector<int> simulateMoves(const string& moves) {\n    vector<int> bd = initBoard;\n    int blank = initBlank;\n\n    for (char ch : moves) {\n        int d = dirIndex(ch);\n        if (!applyDir(bd, blank, d)) break;\n    }\n\n    return bd;\n}\n\nstring simplifyMoves(const string& s) {\n    string res;\n\n    for (char ch : s) {\n        int d = dirIndex(ch);\n        if (!res.empty() && dirIndex(res.back()) == OPP[d]) {\n            res.pop_back();\n        } else {\n            res.push_back(ch);\n        }\n    }\n\n    return res;\n}\n\nstruct BestAns {\n    string moves;\n    long long score = -1;\n    int S = 0;\n};\n\nvoid updateBestKnownBoard(BestAns& best, const string& mv0, const vector<int>& bd) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nvoid updateBest(BestAns& best, const string& mv0) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n\n    vector<int> bd = simulateMoves(mv);\n    updateBestKnownBoard(best, mv, bd);\n}\n\nuint64_t hashRegionMask(const vector<int>& mask, const Shape& s) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)(s.h * 100 + s.w * 10 + s.ori);\n    h *= 1099511628211ULL;\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) {\n            h ^= (uint64_t)(mask[i] + 17);\n            h *= 1099511628211ULL;\n        }\n    }\n\n    return h;\n}\n\nint rectHungarian(const vector<int>& targets, const vector<int>& sources) {\n    int n = (int)targets.size();\n    int m = (int)sources.size();\n\n    if (n == 0) return 0;\n    if (n > m) return 1000000000;\n\n    const int INF = 1000000000;\n    vector<vector<int>> cost(n, vector<int>(m));\n\n    for (int i = 0; i < n; i++) {\n        int tr = targets[i] / N;\n        int tc = targets[i] % N;\n\n        for (int j = 0; j < m; j++) {\n            int sr = sources[j] / N;\n            int sc = sources[j] % N;\n            cost[i][j] = abs(tr - sr) + abs(tc - sc);\n        }\n    }\n\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\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n\n        do {\n            used[j0] = true;\n            int i0 = p[j0];\n            int delta = INF;\n            int j1 = 0;\n\n            for (int j = 1; j <= m; j++) {\n                if (used[j]) continue;\n\n                int cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\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\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);\n    }\n\n    return -v[0];\n}\n\nint partialMatchingCost(const vector<int>& target, const Shape& s) {\n    int total = 0;\n\n    for (int m = 1; m < 16; m++) {\n        vector<int> A;\n        vector<int> S;\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, s) && target[i] == m) A.push_back(i);\n            if (initBoard[i] == m) S.push_back(i);\n        }\n\n        if (A.size() > S.size()) return 1000000000;\n        total += rectHungarian(A, S);\n    }\n\n    return total;\n}\n\nint kindRank(int kind) {\n    if (kind == 1) return 0; // monotone exact\n    if (kind == 0) return 1; // adjusted/canonical\n    return 2;                // arbitrary tree\n}\n\nstruct Candidate {\n    vector<int> target;\n    Shape s;\n    int expectedS;\n    int estCost;\n    int kind;\n    uint64_t hash;\n};\n\nlong long candidateValue(const Candidate& c) {\n    return (long long)c.expectedS * 1000000LL\n         - (long long)(c.estCost + kindRank(c.kind) * 40) * 1000LL\n         - (long long)shapeArea(c.s) * 100LL;\n}\n\nvoid addPartialCandidate(vector<Candidate>& cands, const vector<int>& regionMask, const Shape& s, int kind) {\n    int cnt[16] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (!inRegionCell(i, s)) continue;\n        int m = regionMask[i];\n        if (m <= 0 || m >= 16) return;\n        cnt[m]++;\n    }\n\n    for (int m = 0; m < 16; m++) {\n        if (cnt[m] > invCnt[m]) return;\n    }\n\n    vector<int> freeCells = freeCellsOf(s);\n\n    vector<int> target(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) target[i] = regionMask[i];\n    }\n\n    int blankCell = freeBlankCell(s);\n    target[blankCell] = 0;\n\n    vector<int> remCnt(16);\n    int remSum = 0;\n\n    for (int m = 1; m < 16; m++) {\n        remCnt[m] = invCnt[m] - cnt[m];\n        remSum += remCnt[m];\n    }\n\n    if (remSum != (int)freeCells.size() - 1) return;\n\n    int ptr = 1;\n\n    for (int id : freeCells) {\n        if (id == blankCell) continue;\n\n        while (ptr < 16 && remCnt[ptr] == 0) ptr++;\n        if (ptr >= 16) return;\n\n        target[id] = ptr;\n        remCnt[ptr]--;\n    }\n\n    vector<int> ideal(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) ideal[i] = regionMask[i];\n    }\n\n    Eval e = evalBoard(ideal);\n    int est = partialMatchingCost(target, s);\n\n    if (est >= 1000000000) return;\n\n    uint64_t h = hashRegionMask(regionMask, s);\n\n    for (auto& c : cands) {\n        if (c.hash == h && c.s.h == s.h && c.s.w == s.w && c.s.ori == s.ori) {\n            if (kindRank(kind) < kindRank(c.kind)) c.kind = kind;\n            return;\n        }\n    }\n\n    Candidate nc{target, s, e.S, est, kind, h};\n\n    const int MAX_CANDS = 700;\n\n    if ((int)cands.size() < MAX_CANDS) {\n        cands.push_back(nc);\n    } else {\n        int worst = 0;\n\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (candidateValue(cands[i]) < candidateValue(cands[worst])) {\n                worst = i;\n            }\n        }\n\n        if (candidateValue(nc) > candidateValue(cands[worst])) {\n            cands[worst] = nc;\n        }\n    }\n}\n\nint outwardToFreeBits(int id, const Shape& s) {\n    int bits = 0;\n\n    for (int d = 0; d < 4; d++) {\n        int nb = nbCell[id][d];\n\n        if (nb >= 0 && !inRegionCell(nb, s)) {\n            bits |= bitForDir(d);\n        }\n    }\n\n    return bits;\n}\n\nvoid adjustAndAddCandidate(vector<Candidate>& cands, vector<int> regMask, const Shape& s) {\n    int cnt[16] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) cnt[regMask[i]]++;\n    }\n\n    vector<int> cur(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) cur[i] = regMask[i];\n    }\n\n    int guard = 0;\n\n    while (guard++ < 260) {\n        int over = -1;\n\n        for (int m = 1; m < 16; m++) {\n            if (cnt[m] > invCnt[m]) {\n                over = m;\n                break;\n            }\n        }\n\n        if (over == -1) break;\n\n        vector<int> deficits;\n\n        for (int m = 1; m < 16; m++) {\n            if (cnt[m] < invCnt[m]) deficits.push_back(m);\n        }\n\n        if (deficits.empty()) break;\n\n        int bestCell = -1;\n        int bestNew = -1;\n        long long bestVal = LLONG_MIN;\n\n        for (int id = 0; id < NN; id++) {\n            if (!inRegionCell(id, s) || cur[id] != over) continue;\n\n            int old = cur[id];\n\n            for (int nm : deficits) {\n                cur[id] = nm;\n                Eval e = evalBoard(cur);\n\n                int outPenalty = __builtin_popcount((unsigned)(nm & outwardToFreeBits(id, s)));\n\n                long long val =\n                    (long long)e.S * 1000000LL +\n                    (long long)e.maxComp * 5000LL +\n                    (long long)e.edges * 100LL -\n                    (long long)outPenalty * 250000LL -\n                    (long long)nearDistMask[nm][id] * 240LL -\n                    (long long)__builtin_popcount((unsigned)(nm ^ old)) * 60LL;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestCell = id;\n                    bestNew = nm;\n                }\n            }\n\n            cur[id] = old;\n        }\n\n        if (bestCell < 0) break;\n\n        int old = cur[bestCell];\n        cur[bestCell] = bestNew;\n        cnt[old]--;\n        cnt[bestNew]++;\n    }\n\n    for (int m = 0; m < 16; m++) {\n        if (cnt[m] > invCnt[m]) return;\n    }\n\n    addPartialCandidate(cands, cur, s, 0);\n}\n\nvector<int> canonicalTreeMask(const Shape& s) {\n    vector<int> mask(NN, 0);\n    int root = 0;\n\n    for (int tid = 0; tid < NN; tid++) {\n        int aid = transToAct(tid, s.ori);\n\n        if (!inRegionCell(aid, s) || tid == root) continue;\n\n        int r = tid / N;\n        int c = tid % N;\n        int parentTid = -1;\n        int childTransDir = -1;\n\n        if (r > 0 && inRegionCell(transToAct(tid - N, s.ori), s)) {\n            parentTid = tid - N;\n            childTransDir = 0;\n        } else if (c > 0 && inRegionCell(transToAct(tid - 1, s.ori), s)) {\n            parentTid = tid - 1;\n            childTransDir = 2;\n        }\n\n        if (parentTid < 0) continue;\n\n        int pid = transToAct(parentTid, s.ori);\n        int childActualDir = mapDirTransToAct(childTransDir, s.ori);\n        int parentActualDir = OPP[childActualDir];\n\n        mask[aid] |= bitForDir(childActualDir);\n        mask[pid] |= bitForDir(parentActualDir);\n    }\n\n    return mask;\n}\n\nstruct Edge {\n    int a, b;\n    int ba, bb;\n};\n\nconst int OVER_W = 120000;\nconst int DIST_W = 95;\nconst int POS_W = 12;\n\nstruct Change {\n    int vc = 0;\n    int verts[4];\n    int oldm[4];\n    int newm[4];\n    int dcnt[16];\n    int overD = 0;\n    int distD = 0;\n    int posD = 0;\n    int energyD = 0;\n};\n\nstruct RegionTreeState {\n    Shape s;\n    vector<char> inReg;\n    vector<int> verts;\n    vector<Edge> edges;\n    int E;\n\n    vector<char> inTree;\n    vector<vector<int>> adj;\n    vector<int> mask;\n\n    int cnt[16];\n    int overflow = 0;\n    int distCost = 0;\n    int posCost = 0;\n\n    vector<int> par;\n    vector<int> pare;\n    vector<int> qbuf;\n    vector<int> path;\n\n    RegionTreeState(const Shape& s_) : s(s_) {\n        inReg.assign(NN, 0);\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, s)) {\n                inReg[i] = 1;\n                verts.push_back(i);\n            }\n        }\n\n        for (int tid = 0; tid < NN; tid++) {\n            int aid = transToAct(tid, s.ori);\n            if (!inReg[aid]) continue;\n\n            int r = tid / N;\n            int c = tid % N;\n\n            if (c + 1 < N) {\n                int ntid = tid + 1;\n                int bid = transToAct(ntid, s.ori);\n\n                if (inReg[bid]) {\n                    int d = mapDirTransToAct(3, s.ori);\n                    edges.push_back({aid, bid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n\n            if (r + 1 < N) {\n                int ntid = tid + N;\n                int bid = transToAct(ntid, s.ori);\n\n                if (inReg[bid]) {\n                    int d = mapDirTransToAct(1, s.ori);\n                    edges.push_back({aid, bid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n        }\n\n        E = (int)edges.size();\n\n        inTree.assign(E, 0);\n        adj.assign(NN, {});\n        mask.assign(NN, 0);\n\n        par.resize(NN);\n        pare.resize(NN);\n        qbuf.reserve(NN);\n        path.reserve(NN);\n    }\n\n    int other(int eid, int v) const {\n        const Edge& e = edges[eid];\n        return e.a == v ? e.b : e.a;\n    }\n\n    void addInitialEdge(int eid) {\n        const Edge& e = edges[eid];\n\n        inTree[eid] = 1;\n        adj[e.a].push_back(eid);\n        adj[e.b].push_back(eid);\n        mask[e.a] |= e.ba;\n        mask[e.b] |= e.bb;\n    }\n\n    int calcOverflow() const {\n        int ov = 0;\n        for (int m = 0; m < 16; m++) ov += max(0, cnt[m] - invCnt[m]);\n        return ov;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(inTree.begin(), inTree.end(), 0);\n\n        for (auto& a : adj) a.clear();\n        fill(mask.begin(), mask.end(), 0);\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(E);\n\n        for (int i = 0; i < E; i++) {\n            const Edge& e = edges[i];\n            int w = 0;\n\n            if (mode > 0) {\n                if (initBoard[e.a] & e.ba) w += 4;\n                else w -= 1;\n\n                if (initBoard[e.b] & e.bb) w += 4;\n                else w -= 1;\n\n                if (nearDistMask[e.ba][e.a] == 0) w++;\n                if (nearDistMask[e.bb][e.b] == 0) w++;\n\n                if (mode == 2) w += (int)(rng() % 7) - 3;\n            }\n\n            long long noise = ((long long)rng() << 32) ^ rng();\n            long long key = noise - (long long)w * (mode == 1 ? 950000000LL : 260000000LL);\n            if (mode == 0) key = noise;\n            ord.push_back({key, i});\n        }\n\n        sort(ord.begin(), ord.end());\n\n        FastDSU dsu;\n        dsu.init(NN);\n\n        int selected = 0;\n\n        for (auto [key, id] : ord) {\n            (void)key;\n\n            const Edge& e = edges[id];\n\n            if (dsu.find(e.a) != dsu.find(e.b)) {\n                dsu.unite(e.a, e.b);\n                addInitialEdge(id);\n                selected++;\n\n                if (selected == (int)verts.size() - 1) break;\n            }\n        }\n\n        memset(cnt, 0, sizeof(cnt));\n\n        overflow = 0;\n        distCost = 0;\n        posCost = 0;\n\n        for (int v : verts) {\n            cnt[mask[v]]++;\n            distCost += nearDistMask[mask[v]][v];\n            posCost += __builtin_popcount((unsigned)(mask[v] ^ initBoard[v]));\n        }\n\n        overflow = calcOverflow();\n    }\n\n    void getPath(int s0, int t0) {\n        fill(par.begin(), par.end(), -1);\n        qbuf.clear();\n        path.clear();\n\n        int head = 0;\n        par[s0] = s0;\n        qbuf.push_back(s0);\n\n        while (head < (int)qbuf.size()) {\n            int v = qbuf[head++];\n\n            if (v == t0) break;\n\n            for (int eid : adj[v]) {\n                if (!inTree[eid]) continue;\n\n                int u = other(eid, v);\n\n                if (par[u] == -1) {\n                    par[u] = v;\n                    pare[u] = eid;\n                    qbuf.push_back(u);\n                }\n            }\n        }\n\n        if (par[t0] == -1) return;\n\n        int cur = t0;\n        while (cur != s0) {\n            path.push_back(pare[cur]);\n            cur = par[cur];\n        }\n    }\n\n    Change makeChange(int addId, int remId) const {\n        Change ch;\n        memset(ch.dcnt, 0, sizeof(ch.dcnt));\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < ch.vc; i++) {\n                if (ch.verts[i] == v) return i;\n            }\n\n            int idx = ch.vc++;\n            ch.verts[idx] = v;\n            ch.oldm[idx] = mask[v];\n            ch.newm[idx] = mask[v];\n            return idx;\n        };\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        int ia = getIdx(ea.a);\n        ch.newm[ia] |= ea.ba;\n\n        int ib = getIdx(ea.b);\n        ch.newm[ib] |= ea.bb;\n\n        int ra = getIdx(er.a);\n        ch.newm[ra] &= ~er.ba;\n\n        int rb = getIdx(er.b);\n        ch.newm[rb] &= ~er.bb;\n\n        for (int i = 0; i < ch.vc; i++) {\n            if (ch.oldm[i] == ch.newm[i]) continue;\n\n            int v = ch.verts[i];\n\n            ch.dcnt[ch.oldm[i]]--;\n            ch.dcnt[ch.newm[i]]++;\n\n            ch.distD += nearDistMask[ch.newm[i]][v] - nearDistMask[ch.oldm[i]][v];\n            ch.posD += __builtin_popcount((unsigned)(ch.newm[i] ^ initBoard[v]))\n                     - __builtin_popcount((unsigned)(ch.oldm[i] ^ initBoard[v]));\n        }\n\n        for (int m = 0; m < 16; m++) {\n            if (ch.dcnt[m]) {\n                ch.overD += max(0, cnt[m] + ch.dcnt[m] - invCnt[m])\n                          - max(0, cnt[m] - invCnt[m]);\n            }\n        }\n\n        ch.energyD = ch.overD * OVER_W + ch.distD * DIST_W + ch.posD * POS_W;\n        return ch;\n    }\n\n    void removeAdj(int v, int eid) {\n        auto& a = adj[v];\n\n        for (int i = 0; i < (int)a.size(); i++) {\n            if (a[i] == eid) {\n                a[i] = a.back();\n                a.pop_back();\n                return;\n            }\n        }\n    }\n\n    void applySwap(int addId, int remId, const Change& ch) {\n        for (int m = 0; m < 16; m++) cnt[m] += ch.dcnt[m];\n\n        overflow += ch.overD;\n        distCost += ch.distD;\n        posCost += ch.posD;\n\n        for (int i = 0; i < ch.vc; i++) {\n            mask[ch.verts[i]] = ch.newm[i];\n        }\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        inTree[addId] = 1;\n        inTree[remId] = 0;\n\n        adj[ea.a].push_back(addId);\n        adj[ea.b].push_back(addId);\n\n        removeAdj(er.a, remId);\n        removeAdj(er.b, remId);\n    }\n\n    void step(mt19937& rng, double temp) {\n        if (E <= (int)verts.size() - 1) return;\n\n        int addId = -1;\n\n        for (int tries = 0; tries < E * 3 + 10; tries++) {\n            int x = (int)(rng() % E);\n            if (!inTree[x]) {\n                addId = x;\n                break;\n            }\n        }\n\n        if (addId < 0) return;\n\n        const Edge& e = edges[addId];\n        getPath(e.a, e.b);\n\n        if (path.empty()) return;\n\n        int remId = -1;\n        Change bestCh;\n        int bestDelta = INT_MAX;\n\n        bool chooseBest = (rng() % 100) < 90;\n\n        if (chooseBest) {\n            for (int pe : path) {\n                Change ch = makeChange(addId, pe);\n\n                if (ch.energyD < bestDelta) {\n                    bestDelta = ch.energyD;\n                    bestCh = ch;\n                    remId = pe;\n                }\n            }\n        } else {\n            remId = path[rng() % path.size()];\n            bestCh = makeChange(addId, remId);\n            bestDelta = bestCh.energyD;\n        }\n\n        bool accept = false;\n\n        if (bestDelta <= 0) {\n            accept = true;\n        } else if (bestDelta < temp * 70.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-(double)bestDelta / temp);\n        }\n\n        if (accept) applySwap(addId, remId, bestCh);\n    }\n};\n\nvoid runPartialSearch(const Shape& s, double endTime, Timer& timer, mt19937& rng, vector<Candidate>& cands) {\n    int bestOver = INT_MAX;\n    int bestDist = INT_MAX;\n    vector<int> bestMask;\n\n    int restart = 0;\n\n    while (timer.elapsed() < endTime) {\n        RegionTreeState st(s);\n\n        int mode = restart % 3;\n        st.initRandom(mode, rng);\n\n        if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n            bestOver = st.overflow;\n            bestDist = st.distCost;\n            bestMask = st.mask;\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 2);\n\n        int maxIter = 21000 + N * 1400;\n        if (shapeArea(s) >= 20) maxIter = 16000 + N * 1000;\n\n        int bestZeroDist = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n\n            double p = (double)it / maxIter;\n            double temp = 90000.0 * pow(80.0 / 90000.0, p);\n\n            st.step(rng, temp);\n\n            if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n                bestOver = st.overflow;\n                bestDist = st.distCost;\n                bestMask = st.mask;\n            }\n\n            if (st.overflow == 0) {\n                if (st.distCost + 4 < bestZeroDist || (it & 4095) == 0) {\n                    addPartialCandidate(cands, st.mask, s, 2);\n                    bestZeroDist = min(bestZeroDist, st.distCost);\n                }\n            }\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 2);\n        restart++;\n    }\n\n    if (!bestMask.empty()) adjustAndAddCandidate(cands, bestMask, s);\n}\n\nstruct ParOpt {\n    int parent;\n    int cb;\n    int pb;\n};\n\nstruct MonoTreeState {\n    Shape s;\n    vector<int> nodes;\n    vector<vector<ParOpt>> opts;\n    vector<int> choice;\n    vector<int> flex;\n    vector<int> mask;\n    int cnt[16];\n    int overflow = 0;\n    int distCost = 0;\n    int posCost = 0;\n\n    MonoTreeState(const Shape& s_) : s(s_) {\n        mask.assign(NN, 0);\n\n        int rootTid = 0;\n\n        for (int tid = 0; tid < NN; tid++) {\n            int aid = transToAct(tid, s.ori);\n            if (!inRegionCell(aid, s) || tid == rootTid) continue;\n\n            int r = tid / N, c = tid % N;\n            vector<ParOpt> v;\n\n            if (r > 0) {\n                int ptid = tid - N;\n                int pid = transToAct(ptid, s.ori);\n                if (inRegionCell(pid, s)) {\n                    int d = mapDirTransToAct(0, s.ori);\n                    v.push_back({pid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n            if (c > 0) {\n                int ptid = tid - 1;\n                int pid = transToAct(ptid, s.ori);\n                if (inRegionCell(pid, s)) {\n                    int d = mapDirTransToAct(2, s.ori);\n                    v.push_back({pid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n\n            if (v.empty()) continue;\n\n            int idx = (int)nodes.size();\n            nodes.push_back(aid);\n            opts.push_back(v);\n            if (v.size() >= 2) flex.push_back(idx);\n        }\n\n        choice.assign(nodes.size(), 0);\n    }\n\n    int calcOverflow() const {\n        int ov = 0;\n        for (int m = 0; m < 16; m++) ov += max(0, cnt[m] - invCnt[m]);\n        return ov;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(mask.begin(), mask.end(), 0);\n\n        for (int i = 0; i < (int)nodes.size(); i++) {\n            int ch = nodes[i];\n\n            if (mode == 0 || opts[i].size() == 1) {\n                choice[i] = rng() % opts[i].size();\n            } else {\n                int best = 0;\n                int bestScore = -1000000;\n\n                for (int j = 0; j < (int)opts[i].size(); j++) {\n                    const ParOpt& o = opts[i][j];\n                    int sc = 0;\n                    sc += (initBoard[ch] & o.cb) ? 5 : -1;\n                    sc += (initBoard[o.parent] & o.pb) ? 5 : -1;\n                    sc -= nearDistMask[o.cb][ch];\n                    sc -= nearDistMask[o.pb][o.parent];\n                    if (mode == 2) sc += (int)(rng() % 7) - 3;\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        best = j;\n                    }\n                }\n\n                choice[i] = best;\n            }\n\n            const ParOpt& o = opts[i][choice[i]];\n            mask[ch] |= o.cb;\n            mask[o.parent] |= o.pb;\n        }\n\n        memset(cnt, 0, sizeof(cnt));\n        overflow = 0;\n        distCost = 0;\n        posCost = 0;\n\n        for (int v = 0; v < NN; v++) {\n            if (!inRegionCell(v, s)) continue;\n            cnt[mask[v]]++;\n            distCost += nearDistMask[mask[v]][v];\n            posCost += __builtin_popcount((unsigned)(mask[v] ^ initBoard[v]));\n        }\n\n        overflow = calcOverflow();\n    }\n\n    Change makeChangeNode(int idx, int newChoice) const {\n        Change chg;\n        memset(chg.dcnt, 0, sizeof(chg.dcnt));\n\n        int child = nodes[idx];\n        const ParOpt& old = opts[idx][choice[idx]];\n        const ParOpt& nw = opts[idx][newChoice];\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < chg.vc; i++) {\n                if (chg.verts[i] == v) return i;\n            }\n            int k = chg.vc++;\n            chg.verts[k] = v;\n            chg.oldm[k] = mask[v];\n            chg.newm[k] = mask[v];\n            return k;\n        };\n\n        int ic = getIdx(child);\n        chg.newm[ic] &= ~old.cb;\n        chg.newm[ic] |= nw.cb;\n\n        int io = getIdx(old.parent);\n        chg.newm[io] &= ~old.pb;\n\n        int in = getIdx(nw.parent);\n        chg.newm[in] |= nw.pb;\n\n        for (int i = 0; i < chg.vc; i++) {\n            if (chg.oldm[i] == chg.newm[i]) continue;\n\n            int v = chg.verts[i];\n\n            chg.dcnt[chg.oldm[i]]--;\n            chg.dcnt[chg.newm[i]]++;\n\n            chg.distD += nearDistMask[chg.newm[i]][v] - nearDistMask[chg.oldm[i]][v];\n            chg.posD += __builtin_popcount((unsigned)(chg.newm[i] ^ initBoard[v]))\n                      - __builtin_popcount((unsigned)(chg.oldm[i] ^ initBoard[v]));\n        }\n\n        for (int m = 0; m < 16; m++) {\n            if (chg.dcnt[m]) {\n                chg.overD += max(0, cnt[m] + chg.dcnt[m] - invCnt[m])\n                           - max(0, cnt[m] - invCnt[m]);\n            }\n        }\n\n        chg.energyD = chg.overD * OVER_W + chg.distD * DIST_W + chg.posD * POS_W;\n        return chg;\n    }\n\n    void applyNode(int idx, int newChoice, const Change& chg) {\n        for (int m = 0; m < 16; m++) cnt[m] += chg.dcnt[m];\n\n        overflow += chg.overD;\n        distCost += chg.distD;\n        posCost += chg.posD;\n\n        for (int i = 0; i < chg.vc; i++) {\n            mask[chg.verts[i]] = chg.newm[i];\n        }\n\n        choice[idx] = newChoice;\n    }\n\n    void step(mt19937& rng, double temp) {\n        if (flex.empty()) return;\n\n        int idx = flex[rng() % flex.size()];\n        int cur = choice[idx];\n        int nc = cur;\n\n        if (opts[idx].size() == 2) {\n            nc = 1 - cur;\n        } else {\n            while (nc == cur) nc = rng() % opts[idx].size();\n        }\n\n        Change chg = makeChangeNode(idx, nc);\n        int delta = chg.energyD;\n\n        bool accept = false;\n\n        if (delta <= 0) {\n            accept = true;\n        } else if (delta < temp * 70.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-(double)delta / temp);\n        }\n\n        if (accept) applyNode(idx, nc, chg);\n    }\n};\n\nvoid runMonoSearch(const Shape& s, double endTime, Timer& timer, mt19937& rng, vector<Candidate>& cands) {\n    int bestOver = INT_MAX;\n    int bestDist = INT_MAX;\n    vector<int> bestMask;\n\n    int restart = 0;\n\n    while (timer.elapsed() < endTime) {\n        MonoTreeState st(s);\n\n        int mode = restart % 3;\n        st.initRandom(mode, rng);\n\n        if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n            bestOver = st.overflow;\n            bestDist = st.distCost;\n            bestMask = st.mask;\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 1);\n\n        int maxIter = 32000 + N * 1200;\n        int bestZeroDist = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n\n            double p = (double)it / maxIter;\n            double temp = 90000.0 * pow(80.0 / 90000.0, p);\n\n            st.step(rng, temp);\n\n            if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n                bestOver = st.overflow;\n                bestDist = st.distCost;\n                bestMask = st.mask;\n            }\n\n            if (st.overflow == 0) {\n                if (st.distCost + 4 < bestZeroDist || (it & 4095) == 0) {\n                    addPartialCandidate(cands, st.mask, s, 1);\n                    bestZeroDist = min(bestZeroDist, st.distCost);\n                }\n            }\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 1);\n        restart++;\n    }\n\n    if (!bestMask.empty()) adjustAndAddCandidate(cands, bestMask, s);\n}\n\nstruct SolveResult {\n    string bestMoves;\n    int bestS;\n    bool completed;\n};\n\nstruct PathRes {\n    bool ok;\n    vector<int> path;\n};\n\nstruct SlidingSolver {\n    vector<int> board;\n    vector<int> target;\n    vector<char> fixed;\n    string ops;\n\n    int blank;\n    Shape s;\n    int variant;\n    int baseVar;\n    bool adaptive;\n    bool freeBeam;\n\n    Timer& timer;\n    double timeLimit;\n    int cap;\n\n    string localBestMoves;\n    long long localBestScore = -1;\n    int localBestS = 0;\n\n    vector<int> dirOrder;\n    vector<int> parent;\n    vector<unsigned char> pdir;\n    vector<int> que;\n\n    SlidingSolver(const vector<int>& tgt, const Shape& s_, int var, Timer& tm, double lim, int cp)\n        : board(initBoard),\n          target(tgt),\n          fixed(NN, 0),\n          blank(initBlank),\n          s(s_),\n          variant(var),\n          baseVar(var & 15),\n          adaptive((var & 16) != 0),\n          freeBeam((var & 32) != 0),\n          timer(tm),\n          timeLimit(lim),\n          cap(cp) {\n        static const int perms[8][4] = {\n            {0, 1, 2, 3},\n            {2, 3, 0, 1},\n            {1, 0, 3, 2},\n            {3, 2, 1, 0},\n            {0, 2, 1, 3},\n            {2, 0, 3, 1},\n            {1, 3, 0, 2},\n            {3, 1, 2, 0},\n        };\n\n        int pm = baseVar % 8;\n        dirOrder.assign(perms[pm], perms[pm] + 4);\n\n        parent.resize(NN * NN);\n        pdir.resize(NN * NN);\n        que.reserve(NN * NN);\n    }\n\n    void considerLocal() {\n        if ((int)ops.size() > T) return;\n\n        Eval e = evalBoard(board);\n        long long sc = scoreFromEval(e, (int)ops.size());\n\n        if (sc > localBestScore || (sc == localBestScore && ops.size() < localBestMoves.size())) {\n            localBestScore = sc;\n            localBestMoves = ops;\n            localBestS = e.S;\n        }\n    }\n\n    bool doDir(int d) {\n        int nb = nbCell[blank][d];\n        if (nb < 0) return false;\n\n        swap(board[blank], board[nb]);\n        blank = nb;\n        ops.push_back(DCH[d]);\n        return true;\n    }\n\n    PathRes findPathTo(int qcell) {\n        int desired = target[qcell];\n\n        if (desired == 0) return {false, {}};\n\n        vector<int> sources;\n        sources.reserve(NN);\n\n        for (int i = 0; i < NN; i++) {\n            if (!fixed[i] && i != blank && board[i] == desired) {\n                sources.push_back(i);\n            }\n        }\n\n        if (sources.empty()) return {false, {}};\n\n        sort(sources.begin(), sources.end(), [&](int a, int b) {\n            int ka = manhattanCell(a, qcell);\n            int kb = manhattanCell(b, qcell);\n            if (a == qcell) ka -= 100;\n            if (b == qcell) kb -= 100;\n            if (baseVar & 1) return ka < kb;\n            return ka > kb;\n        });\n\n        fill(parent.begin(), parent.end(), -1);\n        que.clear();\n\n        int goal = -1;\n\n        for (int i : sources) {\n            int id = i * NN + blank;\n\n            if (parent[id] == -1) {\n                parent[id] = -2;\n                que.push_back(id);\n\n                if (i == qcell) goal = id;\n            }\n        }\n\n        int head = 0;\n\n        while (goal == -1 && head < (int)que.size()) {\n            int id = que[head++];\n            int tile = id / NN;\n            int emp = id % NN;\n\n            for (int d : dirOrder) {\n                int nb = nbCell[emp][d];\n\n                if (nb < 0 || fixed[nb]) continue;\n\n                int ntile = tile;\n                int nemp = nb;\n\n                if (nb == tile) {\n                    ntile = emp;\n                    nemp = nb;\n                }\n\n                int nid = ntile * NN + nemp;\n\n                if (parent[nid] != -1) continue;\n\n                parent[nid] = id;\n                pdir[nid] = (unsigned char)d;\n\n                if (ntile == qcell) {\n                    goal = nid;\n                    break;\n                }\n\n                que.push_back(nid);\n            }\n        }\n\n        if (goal == -1) return {false, {}};\n\n        vector<int> path;\n\n        for (int cur = goal; parent[cur] != -2; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n\n        reverse(path.begin(), path.end());\n        return {true, path};\n    }\n\n    bool executePath(const vector<int>& path) {\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            if (!doDir(d)) return false;\n\n            if (((int)ops.size() & 7) == 0) {\n                considerLocal();\n                if (timer.elapsed() > timeLimit) return false;\n            }\n        }\n\n        return true;\n    }\n\n    bool placeTile(int qcell) {\n        PathRes res = findPathTo(qcell);\n        if (!res.ok) return false;\n        if (!executePath(res.path)) return false;\n        if (board[qcell] != target[qcell]) return false;\n        fixed[qcell] = 1;\n        return true;\n    }\n\n    bool readyAdaptiveCell(int aid) const {\n        int tid = actToTrans(aid, s.ori);\n        int r = tid / N;\n        int c = tid % N;\n\n        if (r > 0) {\n            int u = transToAct(tid - N, s.ori);\n            if (inRegionCell(u, s) && !fixed[u]) return false;\n        }\n\n        if (c > 0) {\n            int l = transToAct(tid - 1, s.ori);\n            if (inRegionCell(l, s) && !fixed[l]) return false;\n        }\n\n        return true;\n    }\n\n    void optimizeFreeBlock() {\n        int rem = cap - (int)ops.size();\n        if (rem <= 0 || timer.elapsed() > timeLimit) return;\n\n        vector<int> cells = freeCellsOf(s);\n        vector<int> idx(NN, -1);\n\n        for (int i = 0; i < (int)cells.size(); i++) idx[cells[i]] = i;\n\n        int L = (int)cells.size();\n        int startBlankK = (blank >= 0 ? idx[blank] : -1);\n        if (startBlankK < 0 || L > 36) return;\n\n        // Exact/small BFS for tiny free blocks. This often gains 1-2 vertices.\n        if (L <= 9) {\n            auto getVal = [&](uint64_t code, int k) -> int {\n                return (int)((code >> (4 * k)) & 15ULL);\n            };\n\n            auto swapBlank = [&](uint64_t code, int bk, int nk) -> uint64_t {\n                int v = getVal(code, nk);\n                uint64_t mb = 15ULL << (4 * bk);\n                uint64_t mn = 15ULL << (4 * nk);\n                code &= ~mb;\n                code &= ~mn;\n                code |= (uint64_t)v << (4 * bk);\n                return code;\n            };\n\n            array<array<int, 4>, 36> adjK;\n            for (auto& a : adjK) a.fill(-1);\n\n            for (int k = 0; k < L; k++) {\n                int cell = cells[k];\n                for (int d = 0; d < 4; d++) {\n                    int nb = nbCell[cell][d];\n                    if (nb >= 0 && idx[nb] >= 0) adjK[k][d] = idx[nb];\n                }\n            }\n\n            uint64_t start = 0;\n            for (int k = 0; k < L; k++) {\n                start |= (uint64_t)board[cells[k]] << (4 * k);\n            }\n\n            int stateCap = (L <= 6 ? 100000 : (L <= 8 ? 110000 : 130000));\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(stateCap * 2);\n            mp.max_load_factor(0.7);\n\n            vector<uint64_t> states;\n            vector<int> par;\n            vector<unsigned char> mv;\n            vector<unsigned char> blanks;\n            vector<unsigned short> dep;\n\n            states.reserve(stateCap);\n            par.reserve(stateCap);\n            mv.reserve(stateCap);\n            blanks.reserve(stateCap);\n            dep.reserve(stateCap);\n\n            mp[start] = 0;\n            states.push_back(start);\n            par.push_back(-1);\n            mv.push_back(0);\n            blanks.push_back((unsigned char)startBlankK);\n            dep.push_back(0);\n\n            int bestIdx = -1;\n            long long bestScore = localBestScore;\n            int bestS = localBestS;\n            int bestLen = (int)localBestMoves.size();\n\n            vector<int> tmp = board;\n\n            for (int head = 0; head < (int)states.size(); head++) {\n                if ((head & 1023) == 0 && timer.elapsed() > timeLimit) break;\n                if (dep[head] >= rem) continue;\n\n                int bk = blanks[head];\n\n                for (int d = 0; d < 4; d++) {\n                    int nk = adjK[bk][d];\n                    if (nk < 0) continue;\n\n                    uint64_t nc = swapBlank(states[head], bk, nk);\n                    if (mp.find(nc) != mp.end()) continue;\n                    if ((int)states.size() >= stateCap) continue;\n\n                    int ni = (int)states.size();\n                    mp[nc] = ni;\n                    states.push_back(nc);\n                    par.push_back(head);\n                    mv.push_back((unsigned char)d);\n                    blanks.push_back((unsigned char)nk);\n                    dep.push_back(dep[head] + 1);\n\n                    tmp = board;\n                    for (int k = 0; k < L; k++) tmp[cells[k]] = getVal(nc, k);\n\n                    Eval e = evalBoard(tmp);\n                    int mvLen = (int)ops.size() + dep[ni];\n                    long long sc = scoreFromEval(e, mvLen);\n\n                    if (sc > bestScore || (sc == bestScore && mvLen < bestLen)) {\n                        bestScore = sc;\n                        bestIdx = ni;\n                        bestS = e.S;\n                        bestLen = mvLen;\n                    }\n                }\n            }\n\n            if (bestIdx != -1) {\n                string add;\n                for (int cur = bestIdx; par[cur] != -1; cur = par[cur]) {\n                    add.push_back(DCH[mv[cur]]);\n                }\n                reverse(add.begin(), add.end());\n\n                localBestScore = bestScore;\n                localBestMoves = ops + add;\n                localBestS = bestS;\n            }\n\n            return;\n        }\n\n        struct Node {\n            array<unsigned char, 36> val;\n            int blankK;\n            int last;\n            string path;\n            int key;\n        };\n\n        auto hashNode = [&](const Node& nd) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int i = 0; i < L; i++) {\n                h ^= (uint64_t)(nd.val[i] + 1);\n                h *= 1099511628211ULL;\n            }\n            h ^= (uint64_t)(nd.blankK + 123);\n            h *= 1099511628211ULL;\n            return h;\n        };\n\n        Node st;\n        st.val.fill(0);\n        for (int i = 0; i < L; i++) st.val[i] = (unsigned char)board[cells[i]];\n        st.blankK = startBlankK;\n        st.last = -1;\n        st.path.clear();\n        st.key = 0;\n\n        vector<Node> beam;\n        beam.push_back(st);\n\n        int width;\n        if (L <= 6) width = 260;\n        else if (L <= 9) width = 220;\n        else if (L <= 16) width = 160;\n        else width = 95;\n\n        int depthLimit = min(rem, 45 + max(s.h, s.w) * 8);\n        vector<int> tmp = board;\n\n        for (int depth = 0; depth < depthLimit; depth++) {\n            if ((depth & 7) == 0 && timer.elapsed() > timeLimit) break;\n\n            vector<Node> nxt;\n            nxt.reserve(beam.size() * 3);\n\n            unordered_map<uint64_t, int> seen;\n            seen.reserve(beam.size() * 5 + 10);\n            seen.max_load_factor(0.7);\n\n            for (const Node& nd : beam) {\n                int globalBlank = cells[nd.blankK];\n\n                for (int d = 0; d < 4; d++) {\n                    if (nd.last != -1 && d == OPP[nd.last]) continue;\n\n                    int nb = nbCell[globalBlank][d];\n                    if (nb < 0 || idx[nb] < 0) continue;\n\n                    int nk = idx[nb];\n\n                    Node ch = nd;\n                    swap(ch.val[ch.blankK], ch.val[nk]);\n                    ch.blankK = nk;\n                    ch.last = d;\n                    ch.path.push_back(DCH[d]);\n\n                    tmp = board;\n                    for (int k = 0; k < L; k++) tmp[cells[k]] = ch.val[k];\n\n                    Eval e = evalBoard(tmp);\n                    int mvLen = (int)ops.size() + (int)ch.path.size();\n\n                    if (mvLen <= T) {\n                        long long sc = scoreFromEval(e, mvLen);\n                        if (sc > localBestScore ||\n                            (sc == localBestScore && ops.size() + ch.path.size() < localBestMoves.size())) {\n                            localBestScore = sc;\n                            localBestMoves = ops + ch.path;\n                            localBestS = e.S;\n                        }\n                    }\n\n                    ch.key =\n                        e.S * 1000000 +\n                        e.maxComp * 7000 +\n                        e.edges * 200 -\n                        depth * 5 -\n                        (int)ch.path.size() * 2;\n\n                    uint64_t h = hashNode(ch);\n                    auto it = seen.find(h);\n\n                    if (it == seen.end()) {\n                        seen[h] = (int)nxt.size();\n                        nxt.push_back(std::move(ch));\n                    } else {\n                        int pos = it->second;\n                        if (ch.key > nxt[pos].key) nxt[pos] = std::move(ch);\n                    }\n                }\n            }\n\n            if (nxt.empty()) break;\n\n            if ((int)nxt.size() > width) {\n                nth_element(nxt.begin(), nxt.begin() + width, nxt.end(),\n                            [](const Node& a, const Node& b) { return a.key > b.key; });\n                nxt.resize(width);\n            }\n\n            beam.swap(nxt);\n        }\n    }\n\n    SolveResult runAdaptive() {\n        considerLocal();\n\n        int total = 0;\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, s) && target[i] != 0) total++;\n        }\n\n        bool completed = true;\n\n        for (int placed = 0; placed < total; placed++) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                completed = false;\n                break;\n            }\n\n            int bestQ = -1;\n            int bestKey = INT_MAX;\n            vector<int> bestPath;\n\n            for (int q = 0; q < NN; q++) {\n                if (!inRegionCell(q, s) || fixed[q] || target[q] == 0) continue;\n                if (!readyAdaptiveCell(q)) continue;\n\n                PathRes res = findPathTo(q);\n                if (!res.ok) continue;\n\n                int key = (int)res.path.size() * 100;\n                if (board[q] == target[q]) key -= 80;\n                key += nearDistMask[target[q]][q] * 2;\n                key += manhattanCell(blank, q);\n\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestQ = q;\n                    bestPath = std::move(res.path);\n                }\n            }\n\n            if (bestQ < 0) {\n                completed = false;\n                break;\n            }\n\n            if (!executePath(bestPath)) {\n                completed = false;\n                break;\n            }\n\n            if (board[bestQ] != target[bestQ]) {\n                completed = false;\n                break;\n            }\n\n            fixed[bestQ] = 1;\n            considerLocal();\n        }\n\n        considerLocal();\n\n        if (completed && freeBeam && timer.elapsed() < timeLimit) optimizeFreeBlock();\n\n        considerLocal();\n        return {localBestMoves, localBestS, completed};\n    }\n\n    SolveResult runStatic() {\n        considerLocal();\n\n        int rowMode = baseVar % 3;\n        int colMode = (baseVar / 3) % 4;\n\n        vector<int> order;\n        order.reserve(NN);\n\n        for (int r = 0; r < N - s.h; r++) {\n            bool rev = false;\n            if (rowMode == 1) rev = true;\n            if (rowMode == 2 && (r & 1)) rev = true;\n\n            if (!rev) {\n                for (int c = 0; c < N; c++) order.push_back(transToAct(r * N + c, s.ori));\n            } else {\n                for (int c = N - 1; c >= 0; c--) order.push_back(transToAct(r * N + c, s.ori));\n            }\n        }\n\n        for (int c = 0; c < N - s.w; c++) {\n            vector<int> rows;\n            for (int r = N - s.h; r < N; r++) rows.push_back(r);\n\n            if (colMode == 1) {\n                reverse(rows.begin(), rows.end());\n            } else if (colMode == 2 && (c & 1)) {\n                reverse(rows.begin(), rows.end());\n            } else if (colMode == 3 && s.h > 1) {\n                rotate(rows.begin(), rows.begin() + (baseVar % s.h), rows.end());\n            }\n\n            for (int r : rows) order.push_back(transToAct(r * N + c, s.ori));\n        }\n\n        bool completed = true;\n\n        for (int q : order) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                completed = false;\n                break;\n            }\n\n            if (target[q] == 0) continue;\n\n            if (!placeTile(q)) {\n                completed = false;\n                break;\n            }\n\n            considerLocal();\n        }\n\n        considerLocal();\n\n        if (completed && freeBeam && timer.elapsed() < timeLimit) optimizeFreeBlock();\n\n        considerLocal();\n        return {localBestMoves, localBestS, completed};\n    }\n\n    SolveResult run() {\n        if (adaptive) return runAdaptive();\n        return runStatic();\n    }\n};\n\nSolveResult solveCandidate(const Candidate& cand, int variant, Timer& timer, double limit) {\n    SlidingSolver solver(cand.target, cand.s, variant, timer, limit, T);\n    return solver.run();\n}\n\nvoid greedyImprove(BestAns& best, double endTime, Timer& timer, mt19937& rng) {\n    while (timer.elapsed() < endTime) {\n        vector<int> bd = initBoard;\n        int blank = initBlank;\n        string mv;\n        int last = -1;\n\n        for (int step = 0; step < T && timer.elapsed() < endTime; step++) {\n            vector<int> opts;\n\n            for (int d = 0; d < 4; d++) {\n                if (nbCell[blank][d] >= 0 && (last == -1 || d != OPP[last])) {\n                    opts.push_back(d);\n                }\n            }\n\n            if (opts.empty()) {\n                for (int d = 0; d < 4; d++) {\n                    if (nbCell[blank][d] >= 0) opts.push_back(d);\n                }\n            }\n\n            int bestD = opts[0];\n            long long bestVal = LLONG_MIN;\n            Eval chosenEval{0, 0, 0};\n\n            for (int d : opts) {\n                int oldBlank = blank;\n                int nb = nbCell[blank][d];\n\n                swap(bd[blank], bd[nb]);\n                blank = nb;\n\n                Eval e = evalBoard(bd);\n\n                long long val =\n                    (long long)e.S * 1000000LL +\n                    (long long)e.maxComp * 8000LL +\n                    (long long)e.edges * 300LL +\n                    (long long)(rng() % 1000);\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestD = d;\n                    chosenEval = e;\n                }\n\n                swap(bd[oldBlank], bd[blank]);\n                blank = oldBlank;\n            }\n\n            applyDir(bd, blank, bestD);\n            mv.push_back(DCH[bestD]);\n            last = bestD;\n\n            if (chosenEval.S >= best.S || (step & 15) == 0) {\n                updateBestKnownBoard(best, mv, bd);\n            }\n        }\n\n        updateBestKnownBoard(best, mv, bd);\n    }\n}\n\nvoid addShape(vector<pair<int,int>>& v, int h, int w) {\n    if (h < 2 || w < 2 || h >= N || w >= N) return;\n    if (h * w > 36) return;\n    for (auto p : v) if (p.first == h && p.second == w) return;\n    v.push_back({h, w});\n}\n\nvector<pair<int,int>> preferredShapes() {\n    vector<pair<int,int>> v;\n\n    if (N == 6) {\n        addShape(v, 2, 2);\n        addShape(v, 2, 3);\n        addShape(v, 3, 2);\n        addShape(v, 3, 3);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n    } else if (N == 7) {\n        addShape(v, 2, 3);\n        addShape(v, 3, 2);\n        addShape(v, 3, 3);\n        addShape(v, 2, 2);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 4, 4);\n    } else if (N == 8) {\n        addShape(v, 2, 3);\n        addShape(v, 3, 2);\n        addShape(v, 3, 3);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 3, 4);\n        addShape(v, 4, 3);\n        addShape(v, 4, 4);\n    } else if (N == 9) {\n        addShape(v, 3, 4);\n        addShape(v, 4, 3);\n        addShape(v, 4, 4);\n        addShape(v, 3, 3);\n        addShape(v, 2, 5);\n        addShape(v, 5, 2);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 4, 5);\n        addShape(v, 5, 4);\n    } else {\n        addShape(v, 3, 4);\n        addShape(v, 4, 3);\n        addShape(v, 4, 4);\n        addShape(v, 3, 5);\n        addShape(v, 5, 3);\n        addShape(v, 2, 5);\n        addShape(v, 5, 2);\n        addShape(v, 3, 3);\n        addShape(v, 4, 5);\n        addShape(v, 5, 4);\n        addShape(v, 5, 5);\n        addShape(v, 6, 6);\n    }\n\n    return v;\n}\n\nvector<int> orientationOrder(int h, int w) {\n    vector<int> os = {0, 1, 2, 3};\n    sort(os.begin(), os.end(), [&](int a, int b) {\n        Shape sa{h, w, a};\n        Shape sb{h, w, b};\n        int da = manhattanCell(initBlank, freeBlankCell(sa));\n        int db = manhattanCell(initBlank, freeBlankCell(sb));\n        return da < db;\n    });\n    return os;\n}\n\nbool sameHW(const Candidate& c, pair<int,int> p) {\n    return c.s.h == p.first && c.s.w == p.second;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n\n    NN = N * N;\n    M = NN - 1;\n\n    initBoard.assign(NN, 0);\n    memset(invCnt, 0, sizeof(invCnt));\n\n    for (int r = 0; r < N; r++) {\n        string s;\n        cin >> s;\n\n        for (int c = 0; c < N; c++) {\n            int v = hexVal(s[c]);\n            int id = r * N + c;\n\n            initBoard[id] = v;\n\n            if (v == 0) initBlank = id;\n            else invCnt[v]++;\n        }\n    }\n\n    for (int id = 0; id < NN; id++) {\n        int r = id / N;\n        int c = id % N;\n\n        for (int d = 0; d < 4; d++) {\n            int nr = r + DR[d];\n            int nc = c + DC[d];\n\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                nbCell[id][d] = -1;\n            } else {\n                nbCell[id][d] = nr * N + nc;\n            }\n        }\n    }\n\n    for (int m = 0; m < 16; m++) {\n        for (int v = 0; v < NN; v++) {\n            nearDistMask[m][v] = 2 * N + 5;\n        }\n    }\n\n    for (int v = 0; v < NN; v++) nearDistMask[0][v] = 0;\n\n    for (int m = 1; m < 16; m++) {\n        vector<int> pos;\n\n        for (int i = 0; i < NN; i++) {\n            if (initBoard[i] == m) pos.push_back(i);\n        }\n\n        if (pos.empty()) continue;\n\n        for (int v = 0; v < NN; v++) {\n            int best = 2 * N + 5;\n            for (int p : pos) best = min(best, manhattanCell(v, p));\n            nearDistMask[m][v] = best;\n        }\n    }\n\n    Timer timer;\n\n    uint64_t seed = 88172645463393265ULL;\n    for (int x : initBoard) {\n        seed = seed * 1315423911ULL + x + 1;\n    }\n    seed ^= (uint64_t)N * 1000003ULL;\n\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n    BestAns best;\n    updateBest(best, \"\");\n\n    if (best.S == M) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<Candidate> cands;\n    vector<pair<int,int>> prefs = preferredShapes();\n\n    for (auto [h, w] : prefs) {\n        for (int ori = 0; ori < 4; ori++) {\n            Shape s{h, w, ori};\n            vector<int> can = canonicalTreeMask(s);\n            adjustAndAddCandidate(cands, can, s);\n        }\n    }\n\n    auto runMonoAll = [&](pair<int,int> hw, double until, double slice) {\n        int h = hw.first, w = hw.second;\n        vector<int> os = orientationOrder(h, w);\n        int ptr = 0;\n\n        while (timer.elapsed() < until) {\n            int ori = os[ptr % 4];\n            ptr++;\n            Shape s{h, w, ori};\n            double nxt = min(until, timer.elapsed() + slice);\n            runMonoSearch(s, nxt, timer, rng, cands);\n        }\n    };\n\n    auto runArbAll = [&](pair<int,int> hw, double until, double slice) {\n        int h = hw.first, w = hw.second;\n        vector<int> os = orientationOrder(h, w);\n        int ptr = 0;\n\n        while (timer.elapsed() < until) {\n            int ori = os[ptr % 4];\n            ptr++;\n            Shape s{h, w, ori};\n            double nxt = min(until, timer.elapsed() + slice);\n            runPartialSearch(s, nxt, timer, rng, cands);\n        }\n    };\n\n    if (!prefs.empty()) runMonoAll(prefs[0], 0.44, 0.055);\n    if ((int)prefs.size() >= 2) runMonoAll(prefs[1], 0.74, 0.055);\n    if ((int)prefs.size() >= 3) runMonoAll(prefs[2], 0.94, 0.050);\n\n    if (!prefs.empty()) runArbAll(prefs[0], 1.13, 0.075);\n    if ((int)prefs.size() >= 2) runArbAll(prefs[1], 1.31, 0.070);\n    if ((int)prefs.size() >= 3) runArbAll(prefs[2], 1.48, 0.070);\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.expectedS != b.expectedS) return a.expectedS > b.expectedS;\n        if (kindRank(a.kind) != kindRank(b.kind)) return kindRank(a.kind) < kindRank(b.kind);\n        int aa = a.estCost + kindRank(a.kind) * 40;\n        int bb = b.estCost + kindRank(b.kind) * 40;\n        if (aa != bb) return aa < bb;\n        if (shapeArea(a.s) != shapeArea(b.s)) return shapeArea(a.s) < shapeArea(b.s);\n        return a.s.ori < b.s.ori;\n    });\n\n    vector<int> orderIdx;\n    vector<char> used(cands.size(), 0);\n\n    for (int pi = 0; pi < (int)prefs.size(); pi++) {\n        int takeLimit = (pi == 0 ? 20 : 12);\n        int take = 0;\n\n        for (int i = 0; i < (int)cands.size() && take < takeLimit; i++) {\n            if (!used[i] && sameHW(cands[i], prefs[pi])) {\n                orderIdx.push_back(i);\n                used[i] = 1;\n                take++;\n            }\n        }\n    }\n\n    for (int i = 0; i < (int)cands.size(); i++) {\n        if (!used[i]) orderIdx.push_back(i);\n    }\n\n    int attemptRank = 0;\n\n    for (int idx : orderIdx) {\n        if (timer.elapsed() > 2.80) break;\n\n        const Candidate& cand = cands[idx];\n\n        if (attemptRank > 12 && cand.expectedS + 2 <= best.S) continue;\n\n        vector<int> vars;\n\n        if (attemptRank < 7) {\n            vars = {48, 49, 50, 51, 52, 53, 54, 55, 16, 17, 18, 19, 0, 1};\n        } else if (attemptRank < 22) {\n            vars = {48, 49, 16, 17, 0, 1, 50};\n        } else {\n            vars = {16, 0};\n        }\n\n        for (int v : vars) {\n            if (timer.elapsed() > 2.83) break;\n\n            SolveResult res = solveCandidate(cand, v, timer, 2.85);\n            updateBest(best, res.bestMoves);\n\n            if (res.completed && best.S >= cand.expectedS + min(2, shapeArea(cand.s) - 1)) break;\n            if (best.S == M) break;\n        }\n\n        attemptRank++;\n        if (best.S == M) break;\n    }\n\n    if (best.S < NN - 9 && timer.elapsed() < 2.86) {\n        greedyImprove(best, 2.87, timer, rng);\n    }\n\n    if ((int)best.moves.size() > T) best.moves.resize(T);\n\n    cout << best.moves << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint N, K_input, MAX_CUTS;\nint targetA[11];\nvector<int> Xs, Ys;\nint M_attendees;\n\nchrono::steady_clock::time_point START_TIME;\nconst double STOP_START_TIME = 2.50;\nconst double HARD_TIME_LIMIT = 2.88;\n\nconst ll SCORE_W = 1000000000000LL;\nconst ll OVER_W = 5000LL;\nconst ll OVERSQ_W = 20LL;\nconst ll SURPLUS_W = 10000LL;\n\ndouble elapsed_time() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t state = 1;\n    uint64_t next() {\n        uint64_t z = (state += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) {\n        if (l > r) swap(l, r);\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\nRNG rng;\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key& o) const {\n        return lo == o.lo && hi == o.hi;\n    }\n};\n\nstruct KeyHash {\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    size_t operator()(const Key& k) const {\n        return (size_t)(splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1));\n    }\n};\n\nstruct Proj {\n    ll s;\n    int idx;\n    bool operator<(const Proj& o) const {\n        if (s != o.s) return s < o.s;\n        return idx < o.idx;\n    }\n};\n\nstruct Line {\n    ll A, B, C;\n    shared_ptr<vector<Proj>> ord;\n};\n\nstruct LineOut {\n    ll A, B, C;\n};\n\nvector<LineOut> bestLines;\nint bestScore = -1;\nll bestValue = LLONG_MIN;\n\ninline bool getBit(const Key& k, int j) {\n    if (j < 64) return (k.lo >> j) & 1ULL;\n    return (k.hi >> (j - 64)) & 1ULL;\n}\n\ninline void flipBit(Key& k, int j) {\n    if (j < 64) k.lo ^= (1ULL << j);\n    else k.hi ^= (1ULL << (j - 64));\n}\n\ninline Key clearedBit(Key k, int j) {\n    if (j < 64) k.lo &= ~(1ULL << j);\n    else k.hi &= ~(1ULL << (j - 64));\n    return k;\n}\n\ninline int overPart(int c) {\n    return c > 10 ? c : 0;\n}\n\ninline ll overSqPart(int c) {\n    if (c <= 10) return 0;\n    ll e = c - 10;\n    return e * e;\n}\n\nshared_ptr<vector<Proj>> computeOrder(ll A, ll B) {\n    auto ord = make_shared<vector<Proj>>();\n    ord->reserve(N);\n    for (int i = 0; i < N; i++) {\n        ll s = A * (ll)Xs[i] + B * (ll)Ys[i];\n        ord->push_back({s, i});\n    }\n    sort(ord->begin(), ord->end());\n    return ord;\n}\n\nll thresholdAtRank(const vector<Proj>& ord, int rank) {\n    int n = (int)ord.size();\n    if (rank <= 0) return ord[0].s - 1;\n    if (rank >= n) return ord[n - 1].s + 1;\n\n    for (int d = 0; d <= n; d++) {\n        int b = rank - d;\n        if (0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n        b = rank + d;\n        if (d != 0 && 0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n    }\n    return (rank < n / 2 ? ord[0].s - 1 : ord[n - 1].s + 1);\n}\n\npair<ll,ll> primitive(ll A, ll B) {\n    if (A == 0 && B == 0) return {1, 0};\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) g = 1;\n    A /= g;\n    B /= g;\n    return {A, B};\n}\n\npair<ll,ll> normalFromAngle(long double theta) {\n    static const long double PI = acosl(-1.0L);\n    theta = fmodl(theta, PI);\n    if (theta < 0) theta += PI;\n\n    const long double S = 1000000.0L;\n    ll A = llround(cosl(theta) * S);\n    ll B = llround(sinl(theta) * S);\n    if (A == 0 && B == 0) A = 1;\n    return primitive(A, B);\n}\n\nlong long cellCountFormula(const vector<int>& c) {\n    long long cells = 1;\n    int sum = 0;\n    for (int x : c) sum += x;\n    cells += sum;\n    for (int i = 0; i < (int)c.size(); i++) {\n        for (int j = i + 1; j < (int)c.size(); j++) {\n            cells += 1LL * c[i] * c[j];\n        }\n    }\n    return cells;\n}\n\nvector<int> bestCounts(int G, int T) {\n    vector<int> best(G, 0), cur(G, 0);\n    long long bestCost = LLONG_MAX;\n\n    auto eval = [&]() {\n        int sum = 0, mn = 1e9, mx = -1;\n        for (int x : cur) {\n            sum += x;\n            mn = min(mn, x);\n            mx = max(mx, x);\n        }\n        if (sum > MAX_CUTS) return;\n        long long cells = cellCountFormula(cur);\n        long long diff = llabs(cells - T);\n        long long cost = diff * 100000LL + (cells < T ? 1000LL : 0LL)\n                       + (mx - mn) * 100LL + sum;\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = cur;\n        }\n    };\n\n    if (G == 2) {\n        for (int a = 0; a <= MAX_CUTS; a++) {\n            for (int b = 0; a + b <= MAX_CUTS; b++) {\n                cur[0] = a;\n                cur[1] = b;\n                eval();\n            }\n        }\n        return best;\n    }\n\n    if (G <= 4) {\n        long double denom = max(1, G * (G - 1));\n        int base = (int)round(sqrt((2.0L * T) / denom));\n        int R = (G == 4 ? 10 : 12);\n        int lo = max(0, base - R);\n        int hi = min(MAX_CUTS, base + R);\n\n        function<void(int,int)> dfs = [&](int pos, int sum) {\n            if (pos == G) {\n                eval();\n                return;\n            }\n            for (int v = lo; v <= hi; v++) {\n                if (sum + v <= MAX_CUTS) {\n                    cur[pos] = v;\n                    dfs(pos + 1, sum + v);\n                }\n            }\n        };\n        dfs(0, 0);\n    } else {\n        // Balanced counts are good, but slightly unbalanced counts give finer\n        // control of the number of arrangement cells.\n        for (int sum = 0; sum <= MAX_CUTS; sum++) {\n            for (int h = 0; h <= sum; h++) {\n                cur[0] = h;\n                int rem = sum - h;\n                int q = rem / (G - 1);\n                int r = rem % (G - 1);\n                for (int i = 1; i < G; i++) cur[i] = q + (i - 1 < r);\n                eval();\n            }\n        }\n    }\n\n    if (bestCost == LLONG_MAX) {\n        int v = min(MAX_CUTS / G, 1);\n        fill(best.begin(), best.end(), v);\n    }\n    return best;\n}\n\nvector<Line> makeGroup(int G, const vector<int>& counts, long double baseAngle, int initMode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n\n    for (int g = 0; g < G; g++) {\n        int m = counts[g];\n        if (m <= 0) continue;\n\n        auto [A, B] = normalFromAngle(baseAngle + PI * g / G);\n        auto ord = computeOrder(A, B);\n\n        vector<int> ranks;\n        ranks.reserve(m);\n\n        if (initMode == 0) {\n            for (int t = 1; t <= m; t++) {\n                ranks.push_back((int)((long long)t * N / (m + 1)));\n            }\n        } else if (initMode == 1) {\n            int low = N / 20;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            for (int t = 0; t < m; t++) ranks.push_back(rng.nextInt(low, high));\n            sort(ranks.begin(), ranks.end());\n        } else {\n            for (int t = 1; t <= m; t++) {\n                long double u = (long double)t + (rng.nextDouble() - 0.5L) * 0.9L;\n                int rank = (int)llround(u * N / (m + 1));\n                rank = max(0, min(N, rank));\n                ranks.push_back(rank);\n            }\n            sort(ranks.begin(), ranks.end());\n        }\n\n        for (int rank : ranks) {\n            Line L;\n            L.A = A;\n            L.B = B;\n            L.ord = ord;\n            L.C = thresholdAtRank(*L.ord, rank);\n            res.push_back(std::move(L));\n        }\n    }\n\n    if ((int)res.size() > MAX_CUTS) res.resize(MAX_CUTS);\n    return res;\n}\n\nint kForCells(int T) {\n    for (int k = 0; k <= MAX_CUTS; k++) {\n        if (1LL + 1LL * k * (k + 1) / 2 >= T) return k;\n    }\n    return MAX_CUTS;\n}\n\nvector<Line> makeGeneral(int k, int mode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n    res.reserve(k);\n\n    long double base = (k > 0 ? rng.nextDouble() * PI / k : 0);\n\n    for (int i = 0; i < k; i++) {\n        long double theta;\n        if (mode == 0) {\n            theta = base + ((long double)i + 0.5L + (rng.nextDouble() - 0.5L) * 0.8L) * PI / k;\n        } else {\n            theta = rng.nextDouble() * PI;\n        }\n\n        auto [A, B] = normalFromAngle(theta);\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n\n        int low = N / 20;\n        int high = N - low;\n        if (low > high) {\n            low = 0;\n            high = N;\n        }\n        int rank = rng.nextInt(low, high);\n        L.C = thresholdAtRank(*L.ord, rank);\n\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nstruct Config {\n    int k;\n    vector<Line> lines;\n    vector<Key> pat;\n    unordered_map<Key, int, KeyHash> mp;\n    int hist[11];\n    int overStraw = 0;\n    ll overSq = 0;\n\n    Config(vector<Line>&& ls) : k((int)ls.size()), lines(std::move(ls)), pat(N) {\n        memset(hist, 0, sizeof(hist));\n    }\n\n    inline void removeEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]--;\n        else if (c > 10) {\n            overStraw -= c;\n            overSq -= overSqPart(c);\n        }\n    }\n\n    inline void addEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]++;\n        else if (c > 10) {\n            overStraw += c;\n            overSq += overSqPart(c);\n        }\n    }\n\n    void build() {\n        mp.clear();\n        mp.reserve(N * 4 + 100);\n        mp.max_load_factor(0.7);\n        memset(hist, 0, sizeof(hist));\n        overStraw = 0;\n        overSq = 0;\n\n        for (int i = 0; i < N; i++) {\n            Key key{0, 0};\n            for (int j = 0; j < k; j++) {\n                ll s = lines[j].A * (ll)Xs[i] + lines[j].B * (ll)Ys[i];\n                if (s > lines[j].C) {\n                    if (j < 64) key.lo |= (1ULL << j);\n                    else key.hi |= (1ULL << (j - 64));\n                }\n            }\n            pat[i] = key;\n            mp[key]++;\n        }\n\n        for (auto& kv : mp) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) hist[c]++;\n            else if (c > 10) {\n                overStraw += c;\n                overSq += overSqPart(c);\n            }\n        }\n    }\n\n    void decKey(const Key& key) {\n        auto it = mp.find(key);\n        int old = it->second;\n        removeEffect(old);\n        int nw = old - 1;\n        addEffect(nw);\n        if (nw == 0) mp.erase(it);\n        else it->second = nw;\n    }\n\n    void incKey(const Key& key) {\n        auto it = mp.find(key);\n        if (it == mp.end()) {\n            addEffect(1);\n            mp.emplace(key, 1);\n        } else {\n            int old = it->second;\n            removeEffect(old);\n            int nw = old + 1;\n            addEffect(nw);\n            it->second = nw;\n        }\n    }\n\n    inline void flipPoint(int idx, int j) {\n        Key old = pat[idx];\n        Key nw = old;\n        flipBit(nw, j);\n        decKey(old);\n        incKey(nw);\n        pat[idx] = nw;\n    }\n\n    int score() const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], hist[d]);\n        return sc;\n    }\n\n    int surplus() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (hist[d] > targetA[d]) s += hist[d] - targetA[d];\n        }\n        return s;\n    }\n\n    int scoreOfHist(const int h[11]) const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], h[d]);\n        return sc;\n    }\n\n    int surplusOfHist(const int h[11]) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (h[d] > targetA[d]) s += h[d] - targetA[d];\n        }\n        return s;\n    }\n\n    ll value() const {\n        return (ll)score() * SCORE_W\n             - (ll)overStraw * OVER_W\n             - overSq * OVERSQ_W\n             - (ll)surplus() * SURPLUS_W;\n    }\n\n    ll tempValue(const int h[11], int over, ll osq) const {\n        int sc = scoreOfHist(h);\n        int surp = surplusOfHist(h);\n        return (ll)sc * SCORE_W\n             - (ll)over * OVER_W\n             - osq * OVERSQ_W\n             - (ll)surp * SURPLUS_W;\n    }\n\n    int rankForC(int j) const {\n        const auto& ord = *lines[j].ord;\n        int l = 0, r = N;\n        ll C = lines[j].C;\n        while (l < r) {\n            int m = (l + r) >> 1;\n            if (ord[m].s <= C) l = m + 1;\n            else r = m;\n        }\n        return l;\n    }\n\n    void sweepLine(int j) {\n        const auto& ord = *lines[j].ord;\n\n        ll origVal = value();\n        int bestIdx = rankForC(j);\n        ll bestC = lines[j].C;\n        ll bestVal = origVal;\n\n        for (int i = 0; i < N; i++) {\n            if (!getBit(pat[i], j)) flipPoint(i, j);\n        }\n\n        ll valAll = value();\n        if (valAll > bestVal) {\n            bestVal = valAll;\n            bestIdx = 0;\n            bestC = ord[0].s - 1;\n        }\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = ord[idx].s;\n            while (idx < N && ord[idx].s == v) {\n                flipPoint(ord[idx].idx, j);\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = ord[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = value();\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestIdx = idx;\n                    bestC = candC;\n                }\n            }\n        }\n\n        for (int t = bestIdx; t < N; t++) {\n            flipPoint(ord[t].idx, j);\n        }\n        lines[j].C = bestC;\n    }\n\n    void optimize(int passes) {\n        if (k == 0) return;\n        vector<int> order(k);\n        iota(order.begin(), order.end(), 0);\n\n        for (int p = 0; p < passes; p++) {\n            for (int i = k - 1; i > 0; i--) {\n                int j = rng.nextInt(0, i);\n                swap(order[i], order[j]);\n            }\n\n            ll before = value();\n\n            for (int t = 0; t < k; t++) {\n                sweepLine(order[t]);\n                if ((t & 7) == 0 && elapsed_time() > HARD_TIME_LIMIT) return;\n            }\n\n            if (value() <= before) break;\n        }\n    }\n\n    int cellBadScoreGeneric(int c, const int hUse[11]) const {\n        if (c <= 1) return 0;\n\n        int def[11];\n        for (int d = 1; d <= 10; d++) def[d] = max(0, targetA[d] - hUse[d]);\n\n        int loss = 0;\n        if (1 <= c && c <= 10 && hUse[c] <= targetA[c]) loss = 1;\n\n        int best = -loss;\n\n        auto evalSplit = [&](int t) {\n            if (t <= 0 || t >= c) return;\n            int u = c - t;\n            int cnt[11] = {};\n            if (1 <= t && t <= 10) cnt[t]++;\n            if (1 <= u && u <= 10) cnt[u]++;\n            int gain = -loss;\n            for (int d = 1; d <= 10; d++) gain += min(cnt[d], def[d]);\n            best = max(best, gain);\n        };\n\n        for (int t = 1; t <= min(c - 1, 10); t++) evalSplit(t);\n        for (int t = max(1, c - 10); t <= c - 1; t++) evalSplit(t);\n\n        if (best > 0) return 100 * best + min(c, 60);\n        if (c > 10) return 15 + min(c, 50);\n        if (hUse[c] > targetA[c]) return 8 + min(hUse[c] - targetA[c], 25);\n        return 0;\n    }\n\n    int cellBadScore(int c) const {\n        return cellBadScoreGeneric(c, hist);\n    }\n\n    int chooseSplitSmallRank(int c, const int hUse[11]) const {\n        if (c <= 1) return 1;\n\n        vector<int> cand;\n        auto addCand = [&](int t) {\n            if (1 <= t && t < c) cand.push_back(t);\n        };\n\n        if (c <= 28) {\n            for (int t = 1; t < c; t++) addCand(t);\n        } else {\n            for (int t = 1; t <= 10; t++) addCand(t);\n            for (int t = c - 10; t < c; t++) addCand(t);\n            addCand(c / 2);\n            addCand((c + 1) / 2);\n            addCand(c / 3);\n            addCand(2 * c / 3);\n        }\n\n        for (int d = 1; d <= 10; d++) {\n            if (targetA[d] > hUse[d]) {\n                addCand(d);\n                addCand(c - d);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int beforeH[11];\n        memcpy(beforeH, hUse, sizeof(int) * 11);\n        int beforeScore = scoreOfHist(beforeH);\n        int beforeSur = surplusOfHist(beforeH);\n        int beforeOver = overPart(c);\n        ll beforeSq = overSqPart(c);\n\n        ll bestVal = LLONG_MIN;\n        int bestT = cand.empty() ? c / 2 : cand[0];\n\n        for (int t : cand) {\n            int u = c - t;\n            int afterH[11];\n            memcpy(afterH, hUse, sizeof(int) * 11);\n\n            if (1 <= c && c <= 10) afterH[c]--;\n            if (1 <= t && t <= 10) afterH[t]++;\n            if (1 <= u && u <= 10) afterH[u]++;\n\n            int afterScore = scoreOfHist(afterH);\n            int afterSur = surplusOfHist(afterH);\n            int afterOver = overPart(t) + overPart(u);\n            ll afterSq = overSqPart(t) + overSqPart(u);\n\n            ll delta = (ll)(afterScore - beforeScore) * SCORE_W\n                     - (ll)(afterOver - beforeOver) * OVER_W\n                     - (afterSq - beforeSq) * OVERSQ_W\n                     - (ll)(afterSur - beforeSur) * SURPLUS_W;\n\n            if (delta > bestVal) {\n                bestVal = delta;\n                bestT = t;\n            }\n        }\n\n        int r = min(bestT, c - bestT);\n        r = max(1, min(c - 1, r));\n        return r;\n    }\n\n    long double thetaFromPoints(const vector<int>& pts) const {\n        static const long double PI = acosl(-1.0L);\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        int bestA = pts[0], bestB = pts[1];\n        ll bestD = -1;\n        int samples = min(45, max(8, (int)pts.size() * 2));\n\n        for (int s = 0; s < samples; s++) {\n            int a = pts[rng.nextInt(0, (int)pts.size() - 1)];\n            int b = pts[rng.nextInt(0, (int)pts.size() - 1)];\n            if (a == b) continue;\n            ll dx = (ll)Xs[a] - Xs[b];\n            ll dy = (ll)Ys[a] - Ys[b];\n            ll dist = dx * dx + dy * dy;\n            if (dist > bestD) {\n                bestD = dist;\n                bestA = a;\n                bestB = b;\n            }\n        }\n\n        long double dx = (long double)Xs[bestA] - Xs[bestB];\n        long double dy = (long double)Ys[bestA] - Ys[bestB];\n        if (dx == 0 && dy == 0) return rng.nextDouble() * PI;\n\n        long double th = atan2l(dy, dx);\n        th += (rng.nextDouble() - 0.5L) * 0.32L;\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    long double thetaBySplitGap(const vector<int>& pts, int smallRank) const {\n        static const long double PI = acosl(-1.0L);\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        vector<int> sample;\n        if ((int)pts.size() <= 240) {\n            sample = pts;\n        } else {\n            sample.reserve(240);\n            for (int i = 0; i < 240; i++) sample.push_back(pts[rng.nextInt(0, (int)pts.size() - 1)]);\n        }\n\n        int m = (int)sample.size();\n        int r = (int)llround((long double)smallRank * m / max(1, (int)pts.size()));\n        r = max(1, min(m - 1, r));\n\n        vector<long double> angles;\n        angles.reserve(16);\n\n        angles.push_back(thetaFromPoints(sample));\n\n        for (int s = 0; s < 6; s++) {\n            int a = sample[rng.nextInt(0, m - 1)];\n            int b = sample[rng.nextInt(0, m - 1)];\n            if (a != b) {\n                long double dx = (long double)Xs[a] - Xs[b];\n                long double dy = (long double)Ys[a] - Ys[b];\n                if (dx != 0 || dy != 0) {\n                    long double th = atan2l(dy, dx);\n                    th = fmodl(th, PI);\n                    if (th < 0) th += PI;\n                    angles.push_back(th);\n                }\n            }\n        }\n\n        for (int s = 0; s < 5; s++) angles.push_back(rng.nextDouble() * PI);\n\n        long double bestGap = -1;\n        long double bestTheta = angles[0];\n\n        vector<long double> proj;\n        proj.reserve(m);\n\n        for (long double th : angles) {\n            long double cs = cosl(th), sn = sinl(th);\n            proj.clear();\n            for (int idx : sample) {\n                proj.push_back(cs * (long double)Xs[idx] + sn * (long double)Ys[idx]);\n            }\n            sort(proj.begin(), proj.end());\n            long double gap = proj[r] - proj[r - 1];\n            if (gap > bestGap) {\n                bestGap = gap;\n                bestTheta = th;\n            }\n        }\n\n        bestTheta += (rng.nextDouble() - 0.5L) * 0.10L;\n        bestTheta = fmodl(bestTheta, PI);\n        if (bestTheta < 0) bestTheta += PI;\n        return bestTheta;\n    }\n\n    long double targetedTheta() const {\n        static const long double PI = acosl(-1.0L);\n\n        Key chosen{0, 0};\n        bool has = false;\n        int chosenC = 0;\n        double total = 0.0;\n\n        for (const auto& kv : mp) {\n            int w = cellBadScore(kv.second);\n            if (w <= 0) continue;\n            double dw = (double)w;\n            total += dw;\n            if (rng.nextDouble() * total < dw) {\n                chosen = kv.first;\n                chosenC = kv.second;\n                has = true;\n            }\n        }\n\n        if (!has) {\n            for (int attempt = 0; attempt < 10; attempt++) {\n                int i = rng.nextInt(0, N - 1);\n                auto it = mp.find(pat[i]);\n                if (it != mp.end() && it->second >= 2) {\n                    chosen = pat[i];\n                    chosenC = it->second;\n                    has = true;\n                    break;\n                }\n            }\n        }\n\n        if (!has) return rng.nextDouble() * PI;\n\n        vector<int> pts;\n        pts.reserve(min(chosenC, 256));\n        for (int i = 0; i < N; i++) {\n            if (pat[i] == chosen) pts.push_back(i);\n        }\n\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        if (rng.nextDouble() < 0.70) {\n            int r = chooseSplitSmallRank((int)pts.size(), hist);\n            return thetaBySplitGap(pts, r);\n        } else {\n            return thetaFromPoints(pts);\n        }\n    }\n\n    long double targetedThetaWithoutLine(int j) const {\n        static const long double PI = acosl(-1.0L);\n        if (j < 0 || j >= k) return targetedTheta();\n\n        unordered_map<Key, int, KeyHash> cnt;\n        cnt.reserve(N * 2 + 10);\n        cnt.max_load_factor(0.7);\n\n        for (int i = 0; i < N; i++) {\n            cnt[clearedBit(pat[i], j)]++;\n        }\n\n        int h2[11] = {};\n        for (auto& kv : cnt) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) h2[c]++;\n        }\n\n        Key chosen{0, 0};\n        bool has = false;\n        int chosenC = 0;\n        double total = 0.0;\n\n        for (const auto& kv : cnt) {\n            int w = cellBadScoreGeneric(kv.second, h2);\n            if (w <= 0) continue;\n            double dw = (double)w;\n            total += dw;\n            if (rng.nextDouble() * total < dw) {\n                chosen = kv.first;\n                chosenC = kv.second;\n                has = true;\n            }\n        }\n\n        if (!has) {\n            for (int attempt = 0; attempt < 10; attempt++) {\n                int i = rng.nextInt(0, N - 1);\n                Key ck = clearedBit(pat[i], j);\n                auto it = cnt.find(ck);\n                if (it != cnt.end() && it->second >= 2) {\n                    chosen = ck;\n                    chosenC = it->second;\n                    has = true;\n                    break;\n                }\n            }\n        }\n\n        if (!has) return rng.nextDouble() * PI;\n\n        vector<int> pts;\n        pts.reserve(min(chosenC, 256));\n        for (int i = 0; i < N; i++) {\n            if (clearedBit(pat[i], j) == chosen) pts.push_back(i);\n        }\n\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        if (rng.nextDouble() < 0.75) {\n            int r = chooseSplitSmallRank((int)pts.size(), h2);\n            return thetaBySplitGap(pts, r);\n        } else {\n            return thetaFromPoints(pts);\n        }\n    }\n\n    bool trySetLineThetaFast(int j, long double theta, bool isAdd) {\n        if (elapsed_time() > HARD_TIME_LIMIT - 0.02) return false;\n        if (isAdd && k >= MAX_CUTS) return false;\n        if (!isAdd && (j < 0 || j >= k)) return false;\n\n        auto [A, B] = normalFromAngle(theta);\n        if (!isAdd && A == lines[j].A && B == lines[j].B) return false;\n\n        auto ord = computeOrder(A, B);\n        ll oldVal = value();\n\n        int bit = isAdd ? k : j;\n\n        unordered_map<Key, int, KeyHash> id;\n        id.reserve(N * 2 + 10);\n        id.max_load_factor(0.7);\n\n        vector<int> baseId(N);\n        vector<int> totalCnt;\n        totalCnt.reserve(mp.size() + 8);\n\n        for (int i = 0; i < N; i++) {\n            Key key = pat[i];\n            if (!isAdd) key = clearedBit(key, bit);\n\n            auto it = id.find(key);\n            if (it == id.end()) {\n                int nid = (int)totalCnt.size();\n                id.emplace(key, nid);\n                baseId[i] = nid;\n                totalCnt.push_back(1);\n            } else {\n                baseId[i] = it->second;\n                totalCnt[it->second]++;\n            }\n        }\n\n        int h2[11] = {};\n        int over2 = 0;\n        ll overSq2 = 0;\n\n        auto addCnt = [&](int c) {\n            if (1 <= c && c <= 10) h2[c]++;\n            else if (c > 10) {\n                over2 += c;\n                overSq2 += overSqPart(c);\n            }\n        };\n        auto remCnt = [&](int c) {\n            if (1 <= c && c <= 10) h2[c]--;\n            else if (c > 10) {\n                over2 -= c;\n                overSq2 -= overSqPart(c);\n            }\n        };\n\n        for (int c : totalCnt) addCnt(c);\n\n        vector<int> leftCnt(totalCnt.size(), 0);\n\n        ll bestVal = tempValue(h2, over2, overSq2);\n        ll bestC = (*ord)[0].s - 1;\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = (*ord)[idx].s;\n\n            while (idx < N && (*ord)[idx].s == v) {\n                int p = (*ord)[idx].idx;\n                int cid = baseId[p];\n                int l = leftCnt[cid];\n                int r = totalCnt[cid] - l;\n\n                remCnt(l);\n                remCnt(r);\n\n                leftCnt[cid]++;\n                l++;\n                r--;\n\n                addCnt(l);\n                addCnt(r);\n\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = (*ord)[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = tempValue(h2, over2, overSq2);\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestC = candC;\n                }\n            }\n        }\n\n        if (bestVal <= oldVal) return false;\n\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.C = bestC;\n        L.ord = ord;\n\n        if (isAdd) {\n            lines.push_back(std::move(L));\n            k++;\n        } else {\n            lines[j] = std::move(L);\n        }\n\n        build();\n        return true;\n    }\n\n    bool tryReplaceLineTheta(int j, long double theta) {\n        return trySetLineThetaFast(j, theta, false);\n    }\n\n    bool tryAddLineTheta(long double theta) {\n        return trySetLineThetaFast(k, theta, true);\n    }\n\n    int addLineSearch(int trials, int maxAccept) {\n        static const long double PI = acosl(-1.0L);\n        int acc = 0;\n        for (int t = 0; t < trials && acc < maxAccept && k < MAX_CUTS; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n            long double theta;\n            if (rng.nextDouble() < 0.82) theta = targetedTheta();\n            else theta = rng.nextDouble() * PI;\n\n            if (tryAddLineTheta(theta)) acc++;\n        }\n        return acc;\n    }\n\n    int chooseReplaceLine() const {\n        if (k <= 0) return -1;\n        if (rng.nextDouble() < 0.28) {\n            vector<int> cand;\n            cand.reserve(k);\n            for (int i = 0; i < k; i++) {\n                int r = rankForC(i);\n                if (r == 0 || r == N) cand.push_back(i);\n            }\n            if (!cand.empty()) return cand[rng.nextInt(0, (int)cand.size() - 1)];\n        }\n        return rng.nextInt(0, k - 1);\n    }\n\n    long double lineTheta(int j) const {\n        static const long double PI = acosl(-1.0L);\n        long double th = atan2l((long double)lines[j].B, (long double)lines[j].A);\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    int angleOptimize(int trials) {\n        static const long double PI = acosl(-1.0L);\n        if (k == 0) return 0;\n        int acc = 0;\n\n        for (int t = 0; t < trials; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n\n            int j = chooseReplaceLine();\n            if (j < 0) break;\n\n            long double theta;\n            double r = rng.nextDouble();\n\n            if (r < 0.24) {\n                theta = targetedThetaWithoutLine(j);\n            } else if (r < 0.48) {\n                long double scale = 0.04L + 0.32L * rng.nextDouble();\n                theta = lineTheta(j) + (rng.nextDouble() * 2.0L - 1.0L) * scale;\n            } else if (r < 0.85) {\n                theta = targetedTheta();\n            } else {\n                theta = rng.nextDouble() * PI;\n            }\n\n            if (tryReplaceLineTheta(j, theta)) acc++;\n        }\n\n        return acc;\n    }\n};\n\nvoid updateBest(const Config& cfg) {\n    int sc = cfg.score();\n    ll val = cfg.value();\n    if (sc > bestScore || (sc == bestScore && val > bestValue)) {\n        bestScore = sc;\n        bestValue = val;\n        bestLines.clear();\n        for (const auto& L : cfg.lines) {\n            bestLines.push_back({L.A, L.B, L.C});\n        }\n    }\n}\n\nvoid runCandidate(vector<Line> lines, int passes) {\n    if ((int)lines.size() > MAX_CUTS) lines.resize(MAX_CUTS);\n    if (elapsed_time() > STOP_START_TIME) return;\n\n    Config cfg(std::move(lines));\n    cfg.build();\n    cfg.optimize(passes);\n    updateBest(cfg);\n}\n\nvector<Line> rebuildLinesFromOut(const vector<LineOut>& outs) {\n    vector<Line> res;\n    res.reserve(outs.size());\n    for (auto O : outs) {\n        Line L;\n        L.A = O.A;\n        L.B = O.B;\n        L.C = O.C;\n        L.ord = computeOrder(L.A, L.B);\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nvoid finalPolish() {\n    if (bestLines.empty()) return;\n    if (elapsed_time() > HARD_TIME_LIMIT - 0.08) return;\n\n    auto ls = rebuildLinesFromOut(bestLines);\n    Config cfg(std::move(ls));\n    cfg.build();\n\n    cfg.optimize(5);\n    updateBest(cfg);\n\n    int loops = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.06 && cfg.score() < M_attendees) {\n        cfg.addLineSearch(22, 4);\n        cfg.angleOptimize(26);\n        cfg.optimize(1);\n        updateBest(cfg);\n        loops++;\n        if (loops > 45) break;\n    }\n\n    int shakeAttempts = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.04 && shakeAttempts < 8) {\n        vector<Line> sl = cfg.lines;\n        if (sl.empty()) break;\n\n        int changes = max(1, (int)sl.size() / 6);\n        for (int c = 0; c < changes; c++) {\n            int j = rng.nextInt(0, (int)sl.size() - 1);\n            int low = N / 25;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            int rank = rng.nextInt(low, high);\n            sl[j].C = thresholdAtRank(*sl[j].ord, rank);\n        }\n\n        Config tmp(std::move(sl));\n        tmp.build();\n        tmp.optimize(2);\n        tmp.addLineSearch(8, 2);\n        tmp.angleOptimize(10);\n        tmp.optimize(1);\n        updateBest(tmp);\n\n        if (tmp.value() > cfg.value()) {\n            cfg = std::move(tmp);\n        }\n\n        shakeAttempts++;\n    }\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = 1;\n        y = 0;\n        return a;\n    }\n    ll x1, y1;\n    ll g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<ll,4> fallbackLine() {\n    return {1000000000LL, 1000000000LL, 999999999LL, 1000000000LL};\n}\n\narray<ll,4> endpoints(LineOut L) {\n    ll A = L.A, B = L.B, C = L.C;\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) return fallbackLine();\n    if (C % g != 0) return fallbackLine();\n    A /= g;\n    B /= g;\n    C /= g;\n\n    auto inside = [](ll v) {\n        return -1000000000LL <= v && v <= 1000000000LL;\n    };\n\n    if (B == 0) {\n        if (A == 0 || C % A != 0) return fallbackLine();\n        ll x = C / A;\n        if (!inside(x)) return fallbackLine();\n        return {x, 0, x, 1};\n    }\n    if (A == 0) {\n        if (B == 0 || C % B != 0) return fallbackLine();\n        ll y = C / B;\n        if (!inside(y)) return fallbackLine();\n        return {0, y, 1, y};\n    }\n\n    ll xg, yg;\n    extgcd(llabs(A), llabs(B), xg, yg);\n\n    __int128 x0 = (__int128)xg * (A >= 0 ? 1 : -1) * C;\n    __int128 y0 = (__int128)yg * (B >= 0 ? 1 : -1) * C;\n\n    ll dx = B;\n    ll dy = -A;\n\n    long double dot = (long double)x0 * (long double)dx + (long double)y0 * (long double)dy;\n    long double den = (long double)dx * dx + (long double)dy * dy;\n    ll t0 = llround(-dot / den);\n\n    __int128 bestNorm = -1;\n    __int128 bx = x0, by = y0;\n\n    for (ll dt = -6; dt <= 6; dt++) {\n        ll t = t0 + dt;\n        __int128 x = x0 + (__int128)dx * t;\n        __int128 y = y0 + (__int128)dy * t;\n        __int128 norm = x * x + y * y;\n        if (bestNorm < 0 || norm < bestNorm) {\n            bestNorm = norm;\n            bx = x;\n            by = y;\n        }\n    }\n\n    __int128 qx = bx + dx;\n    __int128 qy = by + dy;\n\n    if (bx < -1000000000LL || bx > 1000000000LL ||\n        by < -1000000000LL || by > 1000000000LL ||\n        qx < -1000000000LL || qx > 1000000000LL ||\n        qy < -1000000000LL || qy > 1000000000LL) {\n        return fallbackLine();\n    }\n\n    ll px = (ll)bx, py = (ll)by;\n    ll rx = (ll)qx, ry = (ll)qy;\n    if (px == rx && py == ry) return fallbackLine();\n    return {px, py, rx, ry};\n}\n\nLineOut canonical(LineOut L) {\n    ll g = std::gcd(llabs(L.A), llabs(L.B));\n    if (g > 0 && L.C % g == 0) {\n        L.A /= g;\n        L.B /= g;\n        L.C /= g;\n    }\n    if (L.A < 0 || (L.A == 0 && L.B < 0)) {\n        L.A = -L.A;\n        L.B = -L.B;\n        L.C = -L.C;\n    }\n    return L;\n}\n\ndouble clampd(double x, double l, double r) {\n    return max(l, min(r, x));\n}\n\ndouble poissonFactorEstimate() {\n    int maxCells = min(5051, max(50, (int)ceil(M_attendees * 4.0)));\n    int minCells = max(20, (int)floor(M_attendees * 0.40));\n\n    double bestVal = -1e100;\n    int bestT = max(1, M_attendees);\n\n    for (int T = minCells; T <= maxCells; T++) {\n        double lambda = (double)N / T;\n        double p = exp(-lambda);\n        double approx = 0.0;\n        for (int d = 1; d <= 10; d++) {\n            p *= lambda / d;\n            double bd = T * p;\n            approx += min((double)targetA[d], bd);\n        }\n\n        double factor = (double)T / max(1, M_attendees);\n        double penalty = 0.04 * abs(factor - 1.25);\n        double val = approx - penalty;\n        if (val > bestVal) {\n            bestVal = val;\n            bestT = T;\n        }\n    }\n\n    return (double)bestT / max(1, M_attendees);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K_input;\n    MAX_CUTS = min(K_input, 100);\n\n    M_attendees = 0;\n    for (int d = 1; d <= 10; d++) {\n        cin >> targetA[d];\n        M_attendees += targetA[d];\n    }\n\n    Xs.resize(N);\n    Ys.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xs[i] >> Ys[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    auto mixSeed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed(N);\n    mixSeed(K_input);\n    for (int d = 1; d <= 10; d++) mixSeed(targetA[d]);\n    for (int i = 0; i < N; i++) {\n        mixSeed((uint64_t)(Xs[i] + 20000) * 40009ULL + (uint64_t)(Ys[i] + 20000));\n    }\n    rng.state = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    double avgD = (double)N / max(1, M_attendees);\n    double smallRatio = (targetA[1] + targetA[2] + targetA[3]) / (double)M_attendees;\n    double largeRatio = (targetA[8] + targetA[9] + targetA[10]) / (double)M_attendees;\n\n    double centerFactor = 1.25 + 0.95 * (smallRatio - largeRatio) + 0.10 * (5.5 - avgD);\n    centerFactor = clampd(centerFactor, 0.70, 2.05);\n\n    double poissonFactor = poissonFactorEstimate();\n    poissonFactor = clampd(poissonFactor, 0.55, 3.20);\n\n    auto normFactor = [&](double f) {\n        return clampd(f, 0.45, 4.00);\n    };\n\n    auto tryGroup = [&](int G, double factor, int initMode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        auto counts = bestCounts(G, T);\n        long double PI = acosl(-1.0L);\n        long double base = rng.nextDouble() * PI / G;\n        auto lines = makeGroup(G, counts, base, initMode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    auto tryGeneral = [&](double factor, int mode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        int k = kForCells(T);\n        auto lines = makeGeneral(k, mode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    tryGroup(2, centerFactor, 0, 4);\n    tryGroup(3, centerFactor, 0, 4);\n    tryGroup(4, centerFactor, 0, 3);\n    tryGroup(5, centerFactor, 0, 3);\n    tryGeneral(centerFactor, 0, 3);\n\n    tryGroup(2, centerFactor * 1.28, 2, 3);\n    tryGroup(3, centerFactor * 0.88, 2, 3);\n    tryGroup(4, centerFactor * 1.18, 2, 3);\n    tryGroup(6, centerFactor * 1.05, 0, 3);\n    tryGeneral(centerFactor * 1.28, 1, 3);\n\n    tryGroup(2, poissonFactor, 0, 3);\n    tryGroup(3, poissonFactor * 1.05, 2, 3);\n    tryGroup(7, (centerFactor + poissonFactor) * 0.5, 0, 2);\n    tryGeneral(poissonFactor, 0, 2);\n\n    int iter = 0;\n    while (elapsed_time() < STOP_START_TIME) {\n        int typ = iter % 8;\n\n        double baseF;\n        double rbase = rng.nextDouble();\n        if (rbase < 0.45) baseF = centerFactor;\n        else if (rbase < 0.80) baseF = poissonFactor;\n        else baseF = 0.5 * (centerFactor + poissonFactor);\n\n        double mult;\n        if (rng.nextDouble() < 0.16) mult = 0.50 + 2.15 * rng.nextDouble();\n        else mult = 0.68 + 1.05 * rng.nextDouble();\n\n        double factor = normFactor(baseF * mult);\n        int initMode = rng.nextInt(0, 2);\n\n        if (typ == 0) tryGroup(2, factor, initMode, 2);\n        else if (typ == 1) tryGroup(3, factor, initMode, 2);\n        else if (typ == 2) tryGroup(4, factor, initMode, 2);\n        else if (typ == 3) tryGroup(5, factor, initMode, 2);\n        else if (typ == 4) tryGroup(6, factor, initMode, 2);\n        else if (typ == 5) tryGroup(7, factor, initMode, 2);\n        else tryGeneral(factor, rng.nextInt(0, 1), 2);\n\n        iter++;\n    }\n\n    finalPolish();\n\n    vector<LineOut> outputLines;\n    vector<LineOut> seen;\n    for (auto L : bestLines) {\n        LineOut C = canonical(L);\n        bool dup = false;\n        for (auto S : seen) {\n            if (S.A == C.A && S.B == C.B && S.C == C.C) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) {\n            seen.push_back(C);\n            outputLines.push_back(L);\n        }\n        if ((int)outputLines.size() == MAX_CUTS) break;\n    }\n\n    cout << outputLines.size() << '\\n';\n    for (auto L : outputLines) {\n        auto e = endpoints(L);\n        cout << e[0] << ' ' << e[1] << ' ' << e[2] << ' ' << e[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#pragma GCC optimize(\"O3,unroll-loops\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAXN = 61;\nconst int MAXC = MAXN * MAXN;\nconst int MAXTOP = 128;\n\nint N, M, C;\nint PX[MAXC], PY[MAXC];\nint WT[MAXC];\nint maxWeight = 0;\nunsigned char initDot[MAXC];\ndouble priorityVal[MAXC];\nlong long initialSum = 0;\n\nint initMinX, initMaxX, initMinY, initMaxY;\nvector<int> initialDots;\n\nuint64_t RM[MAXN][MAXN];\n\nconst int DX[8] = {1, 0, -1, 0, 1, -1, -1, 1};\nconst int DY[8] = {0, 1, 0, -1, 1, 1, -1, -1};\nconst int OPP[8] = {2, 3, 0, 1, 6, 7, 4, 5};\n\n// E,N / N,W / W,S / S,E and NE,NW / NW,SW / SW,SE / SE,NE\nconst int PA[8] = {0, 1, 2, 3, 4, 5, 6, 7};\nconst int PB[8] = {1, 2, 3, 0, 5, 6, 7, 4};\n\nint startPts[8][2 * MAXN];\nint startCnt[8];\nint STEP_DIR[8];\n\ninline int pid(int x, int y) {\n    return x * N + y;\n}\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y < N;\n}\n\ninline uint64_t rangeMask(int l, int r) {\n    return RM[l][r];\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 RNG {\n    uint64_t x;\n\n    RNG(uint64_t seed = 1) {\n        x = splitmix64(seed);\n        if (x == 0) x = 88172645463325252ULL;\n    }\n\n    inline uint64_t next() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    inline double nextSigned() {\n        return nextDouble() * 2.0 - 1.0;\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n\n    Timer() {\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\nstruct Op {\n    int p1, p2, p3, p4;\n};\n\nstruct Candidate {\n    int p1, p2, p3, p4;\n    int lenSum;\n    int area;\n    int ord;\n};\n\nstruct Node {\n    double key;\n    int ord;\n    Candidate cand;\n};\n\ninline bool nodeWorse(const Node& a, const Node& b) {\n    if (a.key != b.key) return a.key < b.key;\n    return a.ord > b.ord;\n}\n\ninline void heapSiftUp(Node h[], int i) {\n    while (i > 0) {\n        int p = (i - 1) >> 1;\n        if (!nodeWorse(h[i], h[p])) break;\n        swap(h[p], h[i]);\n        i = p;\n    }\n}\n\ninline void heapSiftDown(Node h[], int n, int i = 0) {\n    while (true) {\n        int l = i * 2 + 1;\n        int r = l + 1;\n        int m = i;\n\n        if (l < n && nodeWorse(h[l], h[m])) m = l;\n        if (r < n && nodeWorse(h[r], h[m])) m = r;\n\n        if (m == i) break;\n\n        swap(h[i], h[m]);\n        i = m;\n    }\n}\n\ninline void heapPushTop(Node h[], int& n, int K, const Node& nd) {\n    if (n < K) {\n        h[n] = nd;\n        heapSiftUp(h, n);\n        ++n;\n    } else if (nodeWorse(h[0], nd)) {\n        h[0] = nd;\n        heapSiftDown(h, n, 0);\n    }\n}\n\nstruct Params {\n    double wcoef;\n    double perim;\n    double area;\n    double outAvg;\n    double outOpp;\n    double frontier;\n    int topK;\n    double rankPower;\n    double noise;\n};\n\nstruct State {\n    unsigned char dot[MAXC];\n    int nearestDot[8][MAXC];\n\n    // H[y]: horizontal segment bit x: (x,y)-(x+1,y)\n    // V[x]: vertical segment bit y: (x,y)-(x,y+1)\n    // DPm[x-y+N-1]: diagonal + segment bit x: (x,y)-(x+1,y+1)\n    // DMm[x+y]: diagonal - segment bit x: (x,y)-(x+1,y-1)\n    uint64_t H[MAXN], V[MAXN], DPm[2 * MAXN], DMm[2 * MAXN];\n\n    vector<int> dots;\n    vector<Op> ops;\n\n    long long sumW = 0;\n    bool dirtyNearest = true;\n\n    int minX, maxX, minY, maxY;\n\n    void reset() {\n        memcpy(dot, initDot, C * sizeof(unsigned char));\n\n        fill(H, H + MAXN, 0ULL);\n        fill(V, V + MAXN, 0ULL);\n        fill(DPm, DPm + 2 * MAXN, 0ULL);\n        fill(DMm, DMm + 2 * MAXN, 0ULL);\n\n        dots.clear();\n        dots.insert(dots.end(), initialDots.begin(), initialDots.end());\n\n        ops.clear();\n        sumW = initialSum;\n        dirtyNearest = true;\n\n        minX = initMinX;\n        maxX = initMaxX;\n        minY = initMinY;\n        maxY = initMaxY;\n    }\n\n    void buildNearest() {\n        for (int d = 0; d < 8; ++d) {\n            int dx = DX[d];\n            int dy = DY[d];\n            int step = STEP_DIR[d];\n\n            for (int si = 0; si < startCnt[d]; ++si) {\n                int p = startPts[d][si];\n                int x = PX[p];\n                int y = PY[p];\n                int cur = -1;\n\n                while (inside(x, y)) {\n                    nearestDot[d][p] = cur;\n\n                    if (dot[p]) cur = p;\n\n                    x -= dx;\n                    y -= dy;\n                    p -= step;\n                }\n            }\n        }\n\n        dirtyNearest = false;\n    }\n\n    void updateNearestAfterAdd(int p) {\n        for (int d = 0; d < 8; ++d) {\n            int x = PX[p] - DX[d];\n            int y = PY[p] - DY[d];\n            int q = p - STEP_DIR[d];\n\n            while (inside(x, y)) {\n                nearestDot[d][q] = p;\n\n                if (dot[q]) break;\n\n                x -= DX[d];\n                y -= DY[d];\n                q -= STEP_DIR[d];\n            }\n        }\n    }\n\n    bool sideFree(int a, int b) const {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            return (V[x1] & rangeMask(y1, y2)) == 0;\n        }\n\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            return (H[y1] & rangeMask(x1, x2)) == 0;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (abs(dx) != abs(dy)) return false;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 - y1 + N - 1;\n            return (DPm[line] & rangeMask(x1, x2)) == 0;\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 + y1;\n            return (DMm[line] & rangeMask(x1, x2)) == 0;\n        }\n    }\n\n    void markSide(int a, int b) {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            V[x1] |= rangeMask(y1, y2);\n            return;\n        }\n\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            H[y1] |= rangeMask(x1, x2);\n            return;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 - y1 + N - 1;\n            DPm[line] |= rangeMask(x1, x2);\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 + y1;\n            DMm[line] |= rangeMask(x1, x2);\n        }\n    }\n\n    void applyOp(const Op& op, bool updateNearest) {\n        markSide(op.p1, op.p2);\n        markSide(op.p2, op.p3);\n        markSide(op.p3, op.p4);\n        markSide(op.p4, op.p1);\n\n        dot[op.p1] = 1;\n        dots.push_back(op.p1);\n\n        sumW += WT[op.p1];\n        ops.push_back(op);\n\n        int x = PX[op.p1];\n        int y = PY[op.p1];\n\n        if (x < minX) minX = x;\n        if (x > maxX) maxX = x;\n        if (y < minY) minY = y;\n        if (y > maxY) maxY = y;\n\n        if (updateNearest && !dirtyNearest) {\n            updateNearestAfterAdd(op.p1);\n        } else {\n            dirtyNearest = true;\n        }\n    }\n\n    inline bool canReplay(const Op& op) const {\n        return !dot[op.p1] && dot[op.p2] && dot[op.p3] && dot[op.p4];\n    }\n\n    bool chooseCandidate(const Params& par, RNG& rng, Candidate& res) {\n        if (dirtyNearest) buildNearest();\n\n        int K = par.topK;\n        if (K < 1) K = 1;\n        if (K > MAXTOP) K = MAXTOP;\n\n        bool found = false;\n        double bestKey = -1e100;\n        int bestLen = INT_MAX;\n        int bestOrd = INT_MAX;\n        Candidate bestCand{};\n\n        Node heap[MAXTOP];\n        int hsz = 0;\n\n        // Exact enumeration from already-dotted opposite corner p3.\n        for (int p3 : dots) {\n            int x3 = PX[p3];\n            int y3 = PY[p3];\n\n            for (int t = 0; t < 8; ++t) {\n                int d1 = PA[t];\n                int d2 = PB[t];\n\n                int p2 = nearestDot[OPP[d2]][p3];\n                if (p2 < 0) continue;\n\n                int p4 = nearestDot[OPP[d1]][p3];\n                if (p4 < 0) continue;\n\n                int x1 = PX[p2] + PX[p4] - x3;\n                int y1 = PY[p2] + PY[p4] - y3;\n\n                if ((unsigned)x1 >= (unsigned)N || (unsigned)y1 >= (unsigned)N) continue;\n\n                int p1 = pid(x1, y1);\n                if (dot[p1]) continue;\n\n                if (nearestDot[d1][p1] != p2) continue;\n                if (nearestDot[d2][p1] != p4) continue;\n\n                if (!sideFree(p1, p2)) continue;\n                if (!sideFree(p2, p3)) continue;\n                if (!sideFree(p3, p4)) continue;\n                if (!sideFree(p4, p1)) continue;\n\n                int len1 = max(abs(PX[p2] - x1), abs(PY[p2] - y1));\n                int len2 = max(abs(PX[p4] - x1), abs(PY[p4] - y1));\n                int lenSum = len1 + len2;\n                int area = len1 * len2;\n\n                int ext = 0;\n\n                if (x1 < minX) ext += minX - x1;\n                else if (x1 > maxX) ext += x1 - maxX;\n\n                if (y1 < minY) ext += minY - y1;\n                else if (y1 > maxY) ext += y1 - maxY;\n\n                double avgOther = (WT[p2] + WT[p3] + WT[p4]) / 3.0;\n\n                double key =\n                    priorityVal[p1]\n                    + par.outAvg * (WT[p1] - avgOther)\n                    + par.outOpp * (WT[p1] - WT[p3])\n                    + par.frontier * ext\n                    - par.perim * lenSum\n                    - par.area * area;\n\n                int ord = p1 * 8 + t;\n                Candidate cand{p1, p2, p3, p4, lenSum, area, ord};\n\n                if (K == 1) {\n                    if (!found || key > bestKey ||\n                        (key == bestKey &&\n                         (lenSum < bestLen || (lenSum == bestLen && ord < bestOrd)))) {\n                        found = true;\n                        bestKey = key;\n                        bestLen = lenSum;\n                        bestOrd = ord;\n                        bestCand = cand;\n                    }\n                } else {\n                    Node nd{key, ord, cand};\n                    heapPushTop(heap, hsz, K, nd);\n                }\n            }\n        }\n\n        if (K == 1) {\n            if (!found) return false;\n            res = bestCand;\n            return true;\n        } else {\n            if (hsz == 0) return false;\n\n            sort(heap, heap + hsz, [](const Node& a, const Node& b) {\n                if (a.key != b.key) return a.key > b.key;\n                return a.ord < b.ord;\n            });\n\n            int idx = 0;\n\n            if (hsz > 1) {\n                if (par.rankPower <= 0.0) {\n                    idx = rng.nextInt(hsz);\n                } else {\n                    double z = pow(rng.nextDouble(), par.rankPower);\n                    idx = (int)(z * hsz);\n                    if (idx >= hsz) idx = hsz - 1;\n                }\n            }\n\n            res = heap[idx].cand;\n            return true;\n        }\n    }\n};\n\nParams randomParam(RNG& rng) {\n    static const double wcoefs[] = {\n        0.0, 0.15, 0.35, 0.65, 0.9, 1.0, 1.0, 1.25, 1.6, 2.1\n    };\n\n    static const double perims[] = {\n        -1.4, -0.8, -0.4, -0.1, 0.0, 0.4, 0.9, 1.6, 2.7, 4.2, 6.5, 9.0\n    };\n\n    static const double areas[] = {\n        -0.025, -0.010, -0.003, 0.0, 0.0, 0.006, 0.016, 0.035, 0.070\n    };\n\n    Params p;\n\n    p.wcoef = wcoefs[rng.nextInt((int)(sizeof(wcoefs) / sizeof(wcoefs[0])))];\n\n    p.perim = perims[rng.nextInt((int)(sizeof(perims) / sizeof(perims[0])))]\n              + (rng.nextDouble() - 0.5) * 0.45;\n\n    p.area = areas[rng.nextInt((int)(sizeof(areas) / sizeof(areas[0])))];\n\n    p.outAvg = 0.0;\n    p.outOpp = 0.0;\n\n    if (rng.nextInt(100) < 60) p.outAvg = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 50) p.outOpp = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 10) p.outOpp += rng.nextDouble() * 1.8;\n\n    p.frontier = 0.0;\n\n    if (rng.nextInt(100) < 45) p.frontier = rng.nextDouble() * 35.0;\n\n    // Sparse instances often need larger jumps.\n    // Dense instances often benefit from shorter scaffolding moves.\n    if (M < 2 * N && rng.nextInt(100) < 35) {\n        p.perim -= 1.0 + rng.nextDouble() * 2.0;\n        p.area -= rng.nextDouble() * 0.025;\n        p.frontier += rng.nextDouble() * 25.0;\n    }\n\n    if (M > N * N / 18 && rng.nextInt(100) < 35) {\n        p.perim += rng.nextDouble() * 4.0;\n        p.area += rng.nextDouble() * 0.040;\n        p.wcoef *= 0.7;\n    }\n\n    int r = rng.nextInt(100);\n\n    if (r < 18) {\n        p.topK = 1;\n    } else if (r < 72) {\n        p.topK = 3 + rng.nextInt(25);\n    } else {\n        p.topK = 30 + rng.nextInt(90);\n    }\n\n    if (p.topK > MAXTOP) p.topK = MAXTOP;\n\n    if (p.topK == 1) {\n        p.rankPower = 1.0;\n    } else {\n        int q = rng.nextInt(100);\n\n        if (q < 18) p.rankPower = 1.0;\n        else if (q < 84) p.rankPower = 1.5 + rng.nextDouble() * 3.2;\n        else p.rankPower = 0.45 + rng.nextDouble() * 0.65;\n    }\n\n    if (rng.nextInt(100) < 50) p.noise = rng.nextDouble() * 0.14;\n    else p.noise = rng.nextDouble() * 0.38;\n\n    if (rng.nextInt(100) < 5) p.noise = rng.nextDouble() * 0.75;\n\n    return p;\n}\n\nvoid preparePriority(const Params& par, RNG& rng) {\n    double amp = par.noise * maxWeight;\n\n    for (int i = 0; i < C; ++i) {\n        priorityVal[i] = par.wcoef * WT[i];\n\n        if (amp > 1e-12) {\n            priorityVal[i] += amp * rng.nextSigned();\n        }\n    }\n}\n\nvoid runGreedy(\n    State& st,\n    const Params& par,\n    RNG& rng,\n    const Timer& timer,\n    double TL\n) {\n    Candidate cand;\n\n    while (timer.elapsed() < TL) {\n        if (!st.chooseCandidate(par, rng, cand)) break;\n\n        Op op{cand.p1, cand.p2, cand.p3, cand.p4};\n        st.applyOp(op, true);\n    }\n}\n\nvoid replayDestroyed(State& st, const vector<Op>& base, RNG& rng) {\n    st.reset();\n\n    int K = (int)base.size();\n    if (K == 0) return;\n\n    int mode = rng.nextInt(100);\n\n    int cut = K;\n    int l = 0, r = 0;\n    int cx = 0, cy = 0, rad2 = 0, rx = 0, ry = 0;\n    bool circle = true;\n    double pdrop = 0.0, extra = 0.0;\n    bool dropLow = true;\n\n    if (mode < 20) {\n        int lim = min(K, 50 + rng.nextInt(950));\n        int drop = 1 + rng.nextInt(lim);\n        cut = K - drop;\n    } else if (mode < 45) {\n        pdrop = 0.01 + pow(rng.nextDouble(), 2.0) * 0.30;\n\n        if (rng.nextInt(100) < 10) {\n            pdrop = 0.30 + rng.nextDouble() * 0.35;\n        }\n    } else if (mode < 65) {\n        double frac = 0.02 + 0.55 * rng.nextDouble() * rng.nextDouble();\n        int maxLen = max(1, min(K, 1 + (int)(K * frac)));\n        int len = 1 + rng.nextInt(maxLen);\n\n        l = rng.nextInt(K - len + 1);\n        r = l + len;\n    } else if (mode < 85) {\n        const Op& op = base[rng.nextInt(K)];\n\n        cx = PX[op.p1];\n        cy = PY[op.p1];\n\n        circle = rng.nextInt(2) == 0;\n\n        if (circle) {\n            int rad = 2 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            rad2 = rad * rad;\n        } else {\n            rx = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            ry = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n        }\n    } else {\n        pdrop = 0.01 + rng.nextDouble() * 0.08;\n        extra = 0.05 + rng.nextDouble() * 0.32;\n        dropLow = rng.nextInt(2) == 0;\n    }\n\n    for (int i = 0; i < K; ++i) {\n        const Op& op = base[i];\n        bool keep = true;\n\n        if (mode < 20) {\n            keep = i < cut;\n        } else if (mode < 45) {\n            keep = rng.nextDouble() >= pdrop;\n        } else if (mode < 65) {\n            keep = !(l <= i && i < r);\n        } else if (mode < 85) {\n            int x = PX[op.p1];\n            int y = PY[op.p1];\n\n            bool inRegion;\n\n            if (circle) {\n                int dx = x - cx;\n                int dy = y - cy;\n                inRegion = dx * dx + dy * dy <= rad2;\n            } else {\n                inRegion = abs(x - cx) <= rx && abs(y - cy) <= ry;\n            }\n\n            keep = !inRegion;\n        } else {\n            double norm = (double)WT[op.p1] / maxWeight;\n            double pd = pdrop + extra * (dropLow ? (1.0 - norm) : norm);\n\n            if (pd > 0.80) pd = 0.80;\n\n            keep = rng.nextDouble() >= pd;\n        }\n\n        if (keep && st.canReplay(op)) {\n            st.applyOp(op, false);\n        }\n    }\n}\n\nstruct Solution {\n    long long sum;\n    vector<Op> ops;\n};\n\nvoid considerSolution(\n    const State& st,\n    vector<Solution>& pool,\n    vector<Op>& bestOps,\n    long long& bestSum\n) {\n    if (st.sumW > bestSum) {\n        bestSum = st.sumW;\n        bestOps = st.ops;\n    }\n\n    const int POOL_SIZE = 10;\n\n    if ((int)pool.size() >= POOL_SIZE && st.sumW <= pool.back().sum) return;\n\n    for (const auto& s : pool) {\n        if (s.sum == st.sumW && s.ops.size() == st.ops.size()) return;\n    }\n\n    Solution sol;\n    sol.sum = st.sumW;\n    sol.ops = st.ops;\n\n    pool.push_back(move(sol));\n\n    sort(pool.begin(), pool.end(), [](const Solution& a, const Solution& b) {\n        if (a.sum != b.sum) return a.sum > b.sum;\n        return a.ops.size() > b.ops.size();\n    });\n\n    if ((int)pool.size() > POOL_SIZE) pool.pop_back();\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    C = N * N;\n\n    for (int l = 0; l < MAXN; ++l) {\n        for (int r = 0; r < MAXN; ++r) {\n            if (r > l) RM[l][r] = ((1ULL << (r - l)) - 1ULL) << l;\n            else RM[l][r] = 0ULL;\n        }\n    }\n\n    fill(initDot, initDot + MAXC, 0);\n\n    int c = N / 2;\n\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y < N; ++y) {\n            int p = pid(x, y);\n            PX[p] = x;\n            PY[p] = y;\n\n            int dx = x - c;\n            int dy = y - c;\n\n            WT[p] = dx * dx + dy * dy + 1;\n            maxWeight = max(maxWeight, WT[p]);\n        }\n    }\n\n    for (int d = 0; d < 8; ++d) {\n        STEP_DIR[d] = DX[d] * N + DY[d];\n        startCnt[d] = 0;\n\n        for (int x = 0; x < N; ++x) {\n            for (int y = 0; y < N; ++y) {\n                if (!inside(x + DX[d], y + DY[d])) {\n                    startPts[d][startCnt[d]++] = pid(x, y);\n                }\n            }\n        }\n    }\n\n    initMinX = N;\n    initMaxX = -1;\n    initMinY = N;\n    initMaxY = -1;\n\n    uint64_t seed = splitmix64(((uint64_t)N << 32) ^ (uint64_t)M);\n\n    initialDots.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        int x, y;\n        cin >> x >> y;\n\n        int p = pid(x, y);\n        initDot[p] = 1;\n        initialDots.push_back(p);\n\n        initMinX = min(initMinX, x);\n        initMaxX = max(initMaxX, x);\n        initMinY = min(initMinY, y);\n        initMaxY = max(initMaxY, y);\n\n        seed ^= splitmix64(((uint64_t)(i + 1) << 40) ^ ((uint64_t)x << 20) ^ (uint64_t)y);\n    }\n\n    sort(initialDots.begin(), initialDots.end());\n\n    initialSum = 0;\n\n    for (int p = 0; p < C; ++p) {\n        if (initDot[p]) initialSum += WT[p];\n    }\n\n    RNG rng(seed);\n\n    vector<Params> presets = {\n        {1.0,  0.0,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  0.6,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  2.8,  0.015, 0.8, 0.2,  0.0,  1, 1.0, 0.00},\n        {1.0, -0.4, -0.004, 0.4, 0.0,  0.0,  8, 2.0, 0.00},\n        {1.0,  0.5,  0.000, 1.0, 0.0,  0.0, 16, 1.7, 0.00},\n        {1.0,  4.5,  0.050, 0.0, 0.0,  0.0, 24, 2.5, 0.00},\n        {0.0,  6.0,  0.040, 0.0, 0.0,  0.0,  8, 2.2, 0.01},\n        {0.25, 3.5,  0.020, 0.2, 0.0,  0.0, 12, 2.0, 0.02},\n        {0.8,  0.0,  0.000, 0.0, 0.8, 25.0, 20, 2.2, 0.04}\n    };\n\n    State st;\n    st.ops.reserve(C);\n    st.dots.reserve(C);\n\n    vector<Op> bestOps;\n    bestOps.reserve(C);\n\n    long long bestSum = initialSum;\n\n    vector<Solution> pool;\n    pool.reserve(12);\n\n    Timer timer;\n\n    const double TL = 4.86;\n\n    int trial = 0;\n\n    while (timer.elapsed() < TL) {\n        Params par;\n        bool useLNS = false;\n\n        if (trial < (int)presets.size()) {\n            par = presets[trial];\n        } else {\n            par = randomParam(rng);\n\n            if (!pool.empty() && rng.nextInt(100) < 78) {\n                useLNS = true;\n            }\n        }\n\n        preparePriority(par, rng);\n\n        if (useLNS) {\n            int ps = (int)pool.size();\n            double u = rng.nextDouble();\n            int idx = (int)(u * u * ps);\n\n            if (idx >= ps) idx = ps - 1;\n\n            replayDestroyed(st, pool[idx].ops, rng);\n        } else {\n            st.reset();\n        }\n\n        runGreedy(st, par, rng, timer, TL);\n        considerSolution(st, pool, bestOps, bestSum);\n\n        ++trial;\n    }\n\n    cout << bestOps.size() << '\\n';\n\n    for (const auto& op : bestOps) {\n        cout << PX[op.p1] << ' ' << PY[op.p1] << ' '\n             << PX[op.p2] << ' ' << PY[op.p2] << ' '\n             << PX[op.p3] << ' ' << PY[op.p3] << ' '\n             << PX[op.p4] << ' ' << PY[op.p4] << '\\n';\n    }\n\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint flav[100];\nint totalCnt[4];\nint remAfter[100][4];\n\nint neighs[100][4], degs_[100];\nint rightCell[100], downCell[100];\nuint8_t manhDist[100][100];\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Board {\n    uint8_t a[100];\n    int n;\n\n    Board() { clear(); }\n\n    void clear() {\n        memset(a, 0, sizeof(a));\n        n = 0;\n    }\n\n    void placeRank(int rk, int fl) {\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) {\n                if (rk == 0) {\n                    a[i] = (uint8_t)fl;\n                    n++;\n                    return;\n                }\n                rk--;\n            }\n        }\n    }\n\n    void placeCell(int pos, int fl) {\n        a[pos] = (uint8_t)fl;\n        n++;\n    }\n\n    int getEmpties(int emp[]) const {\n        int m = 0;\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) emp[m++] = i;\n        }\n        return m;\n    }\n\n    void tilt(int dir) {\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; c++) {\n                int w = 0;\n                for (int r = 0; r < 10; r++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w++ * 10 + c] = v;\n                }\n                for (int r = w; r < 10; r++) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; c++) {\n                int w = 9;\n                for (int r = 9; r >= 0; r--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w-- * 10 + c] = v;\n                }\n                for (int r = w; r >= 0; r--) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; r++) {\n                int w = 0;\n                for (int c = 0; c < 10; c++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w++] = v;\n                }\n                for (int c = w; c < 10; c++) a[r * 10 + c] = 0;\n            }\n        } else { // R\n            for (int r = 0; r < 10; r++) {\n                int w = 9;\n                for (int c = 9; c >= 0; c--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w--] = v;\n                }\n                for (int c = w; c >= 0; c--) a[r * 10 + c] = 0;\n            }\n        }\n    }\n};\n\nstruct Layout {\n    uint8_t target[100];\n    uint8_t dist[4][100];\n};\n\nvector<Layout> layouts;\nunordered_set<string> seenLayouts;\n\nvoid initTables() {\n    for (int i = 0; i < 100; i++) {\n        degs_[i] = 0;\n        rightCell[i] = downCell[i] = -1;\n    }\n\n    for (int r = 0; r < 10; r++) {\n        for (int c = 0; c < 10; c++) {\n            int id = r * 10 + c;\n            if (r > 0) neighs[id][degs_[id]++] = (r - 1) * 10 + c;\n            if (r < 9) neighs[id][degs_[id]++] = (r + 1) * 10 + c;\n            if (c > 0) neighs[id][degs_[id]++] = r * 10 + c - 1;\n            if (c < 9) neighs[id][degs_[id]++] = r * 10 + c + 1;\n\n            if (c < 9) rightCell[id] = id + 1;\n            if (r < 9) downCell[id] = id + 10;\n        }\n    }\n\n    for (int i = 0; i < 100; i++) {\n        int r1 = i / 10, c1 = i % 10;\n        for (int j = 0; j < 100; j++) {\n            int r2 = j / 10, c2 = j % 10;\n            manhDist[i][j] = (uint8_t)(abs(r1 - r2) + abs(c1 - c2));\n        }\n    }\n}\n\nll finalScoreNum(const Board& b) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    ll res = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        res += 1LL * sz * sz;\n    }\n\n    return res;\n}\n\nll evalBoard(const Board& b, int step, const Layout& L) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    int maxComp[4] = {};\n    int sumSq = 0;\n    int comps = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        comps++;\n        int head = 0, tail = 0;\n        int sz = 0;\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        sumSq += sz * sz;\n        maxComp[fl] = max(maxComp[fl], sz);\n    }\n\n    int adj = 0;\n    int distCost = 0;\n    int match = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int v = b.a[i];\n        if (!v) continue;\n\n        int r = rightCell[i];\n        if (r != -1 && b.a[r] == v) adj++;\n\n        int d = downCell[i];\n        if (d != -1 && b.a[d] == v) adj++;\n\n        distCost += L.dist[v][i];\n        if (L.target[i] == v) match++;\n    }\n\n    // Optimistic future-aware component potential:\n    // If all future candies of a flavor join its largest current component,\n    // contribution is sumSq + 2 * maxComponent * remaining + constant.\n    ll compPot = sumSq;\n    for (int f = 1; f <= 3; f++) {\n        compPot += 2LL * maxComp[f] * remAfter[step][f];\n    }\n\n    int future = 99 - step;\n\n    ll val = 0;\n    val += compPot * 1000LL;\n    val += adj * 200LL;\n    val -= comps * 50LL;\n    val += match * (30LL + future);\n    val -= distCost * (20LL + 3LL * future);\n\n    return val;\n}\n\nint greedyDir(const Board& b, int step, const Layout& L) {\n    int offset = ((step + 1) * 17 + flav[step] * 31) & 3;\n\n    int bestD = 0;\n    ll bestV = LLONG_MIN;\n\n    for (int k = 0; k < 4; k++) {\n        int d = (offset + k) & 3;\n        Board nb = b;\n        nb.tilt(d);\n        ll v = evalBoard(nb, step, L);\n        if (v > bestV) {\n            bestV = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nvoid computeLayoutDist(Layout& L) {\n    for (int f = 0; f < 4; f++) {\n        for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n    }\n\n    for (int f = 1; f <= 3; f++) {\n        vector<int> cells;\n        for (int i = 0; i < 100; i++) {\n            if (L.target[i] == f) cells.push_back(i);\n        }\n\n        if (cells.empty()) {\n            for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n            continue;\n        }\n\n        for (int i = 0; i < 100; i++) {\n            int best = 100;\n            for (int p : cells) {\n                best = min(best, (int)manhDist[i][p]);\n            }\n            L.dist[f][i] = (uint8_t)best;\n        }\n    }\n}\n\nvoid addLayout(const array<uint8_t, 100>& tar) {\n    string key;\n    key.resize(100);\n    for (int i = 0; i < 100; i++) key[i] = char('0' + tar[i]);\n\n    if (!seenLayouts.insert(key).second) return;\n\n    Layout L;\n    memset(&L, 0, sizeof(L));\n    for (int i = 0; i < 100; i++) L.target[i] = tar[i];\n    computeLayoutDist(L);\n    layouts.push_back(L);\n}\n\npair<int, int> transformCoord(int r, int c, int s) {\n    if (s == 0) return {r, c};\n    if (s == 1) return {r, 9 - c};\n    if (s == 2) return {9 - r, c};\n    if (s == 3) return {9 - r, 9 - c};\n    if (s == 4) return {c, r};\n    if (s == 5) return {c, 9 - r};\n    if (s == 6) return {9 - c, r};\n    return {9 - c, 9 - r};\n}\n\nstruct PQNode {\n    int dist;\n    int tie;\n    int f;\n    int pos;\n};\n\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        if (a.dist != b.dist) return a.dist > b.dist;\n        if (a.tie != b.tie) return a.tie > b.tie;\n        return a.f > b.f;\n    }\n};\n\nint tieValue(int pos, int f, int seed) {\n    return (pos * 37 + f * 101 + seed * 17) & 1023;\n}\n\narray<uint8_t, 100> makeCornerLayout(const int seeds[4]) {\n    array<uint8_t, 100> tar;\n    tar.fill(0);\n\n    int cap[4];\n    for (int f = 1; f <= 3; f++) cap[f] = totalCnt[f];\n\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq;\n\n    for (int f = 1; f <= 3; f++) {\n        if (cap[f] > 0) {\n            int p = seeds[f];\n            pq.push({0, tieValue(p, f, seeds[f]), f, p});\n        }\n    }\n\n    int assigned = 0;\n\n    while (assigned < 100 && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n\n        int f = cur.f;\n        int p = cur.pos;\n\n        if (cap[f] <= 0 || tar[p] != 0) continue;\n\n        tar[p] = (uint8_t)f;\n        cap[f]--;\n        assigned++;\n\n        if (cap[f] > 0) {\n            for (int k = 0; k < degs_[p]; k++) {\n                int to = neighs[p][k];\n                if (tar[to] == 0) {\n                    pq.push({cur.dist + 1, tieValue(to, f, seeds[f]), f, to});\n                }\n            }\n        }\n    }\n\n    // Fallback, rarely used.\n    if (assigned < 100) {\n        for (int p = 0; p < 100; p++) {\n            if (tar[p] != 0) continue;\n\n            int bestF = -1;\n            int bestCost = 1e9;\n\n            for (int f = 1; f <= 3; f++) {\n                if (cap[f] <= 0) continue;\n\n                int cost = manhDist[p][seeds[f]];\n                bool adj = false;\n                for (int k = 0; k < degs_[p]; k++) {\n                    if (tar[neighs[p][k]] == f) adj = true;\n                }\n                if (adj) cost -= 20;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestF = f;\n                }\n            }\n\n            if (bestF == -1) {\n                for (int f = 1; f <= 3; f++) {\n                    if (cap[f] > 0) {\n                        bestF = f;\n                        break;\n                    }\n                }\n            }\n\n            tar[p] = (uint8_t)bestF;\n            cap[bestF]--;\n            assigned++;\n        }\n    }\n\n    return tar;\n}\n\nvoid generateLayouts() {\n    layouts.clear();\n    seenLayouts.clear();\n    layouts.reserve(128);\n    seenLayouts.reserve(256);\n\n    // Neutral layout: target term disabled.\n    {\n        Layout neutral;\n        memset(&neutral, 0, sizeof(neutral));\n        layouts.push_back(neutral);\n        seenLayouts.insert(string(100, '0'));\n    }\n\n    // Snake/band layouts.\n    vector<int> basePath;\n    basePath.reserve(100);\n\n    for (int r = 0; r < 10; r++) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < 10; c++) basePath.push_back(r * 10 + c);\n        } else {\n            for (int c = 9; c >= 0; c--) basePath.push_back(r * 10 + c);\n        }\n    }\n\n    for (int sym = 0; sym < 8; sym++) {\n        vector<int> path;\n        path.reserve(100);\n        bool used[100] = {};\n        bool ok = true;\n\n        for (int id : basePath) {\n            int r = id / 10, c = id % 10;\n            auto [nr, nc] = transformCoord(r, c, sym);\n            int p = nr * 10 + nc;\n            if (used[p]) ok = false;\n            used[p] = true;\n            path.push_back(p);\n        }\n\n        if (!ok) continue;\n\n        array<int, 3> perm = {1, 2, 3};\n        do {\n            array<uint8_t, 100> tar;\n            tar.fill(0);\n\n            int idx = 0;\n            for (int k = 0; k < 3; k++) {\n                int f = perm[k];\n                for (int cnt = 0; cnt < totalCnt[f]; cnt++) {\n                    tar[path[idx++]] = (uint8_t)f;\n                }\n            }\n\n            addLayout(tar);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    // Three-corner growing layouts.\n    int corners[4] = {0, 9, 90, 99};\n    for (int a = 0; a < 4; a++) {\n        for (int b = 0; b < 4; b++) if (b != a) {\n            for (int c = 0; c < 4; c++) if (c != a && c != b) {\n                int seeds[4] = {};\n                seeds[1] = corners[a];\n                seeds[2] = corners[b];\n                seeds[3] = corners[c];\n\n                auto tar = makeCornerLayout(seeds);\n                addLayout(tar);\n            }\n        }\n    }\n}\n\nint chooseLayout() {\n    constexpr int K = 3;\n\n    uint64_t seed = 0x123456789abcdefULL;\n    for (int i = 0; i < 100; i++) {\n        seed = seed * 1000003ULL + flav[i] * 97ULL + i;\n    }\n\n    RNG rng(seed);\n    uint8_t ranks[K][100];\n\n    for (int k = 0; k < K; k++) {\n        for (int s = 0; s < 100; s++) {\n            ranks[k][s] = (uint8_t)rng.nextInt(100 - s);\n        }\n    }\n\n    int bestIdx = 0;\n    ll bestScore = LLONG_MIN;\n\n    for (int li = 0; li < (int)layouts.size(); li++) {\n        ll total = 0;\n\n        for (int k = 0; k < K; k++) {\n            Board b;\n\n            for (int s = 0; s < 100; s++) {\n                b.placeRank(ranks[k][s], flav[s]);\n\n                if (s == 99) break;\n\n                int d = greedyDir(b, s, layouts[li]);\n                b.tilt(d);\n            }\n\n            total += finalScoreNum(b);\n        }\n\n        if (total > bestScore) {\n            bestScore = total;\n            bestIdx = li;\n        }\n    }\n\n    return bestIdx;\n}\n\ndouble exactValue(const Board& b, int step);\n\ndouble exactDirValue(const Board& b, int step, int dir) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    Board bb = b;\n    bb.tilt(dir);\n\n    int emp[100];\n    int m = bb.getEmpties(emp);\n\n    if (m == 0) return (double)finalScoreNum(bb);\n\n    double sum = 0.0;\n\n    for (int i = 0; i < m; i++) {\n        Board nb = bb;\n        nb.placeCell(emp[i], flav[step + 1]);\n        sum += exactValue(nb, step + 1);\n    }\n\n    return sum / m;\n}\n\ndouble exactValue(const Board& b, int step) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        best = max(best, exactDirValue(b, step, d));\n    }\n\n    return best;\n}\n\nint exactBestDir(const Board& b, int step) {\n    int bestD = 0;\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        double v = exactDirValue(b, step, d);\n        if (v > best) {\n            best = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nstruct BeamNode {\n    Board b;\n    ll val;\n};\n\nvoid addBeamCandidate(BeamNode next[], int& cnt, int BW, const Board& b, ll val) {\n    if (cnt < BW) {\n        next[cnt].b = b;\n        next[cnt].val = val;\n        cnt++;\n        return;\n    }\n\n    int worst = 0;\n    for (int i = 1; i < BW; i++) {\n        if (next[i].val < next[worst].val) worst = i;\n    }\n\n    if (val > next[worst].val) {\n        next[worst].b = b;\n        next[worst].val = val;\n    }\n}\n\nll simulateBeam(const Board& start, int step, const uint8_t ranks[], const Layout& L, int BW) {\n    BeamNode beam[2], nxt[2];\n\n    int bc = 1;\n    beam[0].b = start;\n    beam[0].val = 0;\n\n    for (int s = step + 1; s < 100; s++) {\n        int nc = 0;\n        ll bestFinal = -1;\n\n        for (int i = 0; i < bc; i++) {\n            Board placed = beam[i].b;\n            placed.placeRank(ranks[s], flav[s]);\n\n            if (s == 99) {\n                bestFinal = max(bestFinal, finalScoreNum(placed));\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    Board nb = placed;\n                    nb.tilt(d);\n                    ll v = evalBoard(nb, s, L);\n                    addBeamCandidate(nxt, nc, BW, nb, v);\n                }\n            }\n        }\n\n        if (s == 99) return bestFinal;\n\n        bc = nc;\n        for (int i = 0; i < bc; i++) beam[i] = nxt[i];\n    }\n\n    return finalScoreNum(start);\n}\n\nint decideMove(const Board& b, int step, const Layout& L, RNG& rng) {\n    if (step >= 99) return 0;\n\n    int rem = 99 - step;\n    double el = elapsedSec();\n\n    // Exact expectimax for the last few moves.\n    if (rem <= 5 && el < 1.72) {\n        return exactBestDir(b, step);\n    }\n\n    if (el > 1.84) {\n        return greedyDir(b, step, L);\n    }\n\n    Board first[4];\n    for (int d = 0; d < 4; d++) {\n        first[d] = b;\n        first[d].tilt(d);\n    }\n\n    int BW = (rem <= 25 ? 2 : 1);\n    int work = (BW == 1 ? 520 : 360);\n    int R = max(4, min(60, work / max(1, rem)));\n\n    if (el > 1.70) R = max(2, R / 3);\n    else if (el > 1.50) R = max(3, R / 2);\n\n    ll scores[4] = {};\n    uint8_t ranks[100];\n\n    int done = 0;\n\n    for (int it = 0; it < R; it++) {\n        if (it > 0 && (it & 3) == 0 && elapsedSec() > 1.86) break;\n\n        for (int s = step + 1; s < 100; s++) {\n            ranks[s] = (uint8_t)rng.nextInt(100 - s);\n        }\n\n        for (int d = 0; d < 4; d++) {\n            scores[d] += simulateBeam(first[d], step, ranks, L, BW);\n        }\n\n        done++;\n    }\n\n    if (done == 0) {\n        return greedyDir(b, step, L);\n    }\n\n    int bestD = 0;\n    ll bestScore = LLONG_MIN;\n    ll bestHeur = LLONG_MIN;\n\n    for (int d = 0; d < 4; d++) {\n        ll h = evalBoard(first[d], step, L);\n\n        if (scores[d] > bestScore || (scores[d] == bestScore && h > bestHeur)) {\n            bestScore = scores[d];\n            bestHeur = h;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    initTables();\n\n    for (int i = 0; i < 100; i++) {\n        if (!(cin >> flav[i])) return 0;\n        totalCnt[flav[i]]++;\n    }\n\n    int suf[4] = {};\n    for (int i = 99; i >= 0; i--) {\n        for (int f = 1; f <= 3; f++) remAfter[i][f] = suf[f];\n        suf[flav[i]]++;\n    }\n\n    generateLayouts();\n    int layoutIdx = chooseLayout();\n    Layout layout = layouts[layoutIdx];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n    for (int i = 0; i < 100; i++) {\n        seed ^= (uint64_t)(flav[i] + 1237 * i);\n        seed *= 0xbf58476d1ce4e5b9ULL;\n    }\n\n    RNG rng(seed ^ 0xdeadbeefcafebabeULL);\n\n    Board board;\n    const char dc[4] = {'F', 'B', 'L', 'R'};\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        board.placeRank(p - 1, flav[t]);\n\n        int dir;\n        if (t == 99) {\n            dir = 0;\n        } else {\n            dir = decideMove(board, t, layout, rng);\n        }\n\n        board.tilt(dir);\n\n        cout << dc[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nconst int MAXN = 100;\nusing Row = array<ull, 2>;\n\nint M;\ndouble EPS, QV;\n\nint Ncur, Bcur, Lcur, Fcur;\nint POSBIN[MAXN];\nint FIDX[10][10];\nvector<int> PAIRCNT;\n\ndouble PMF[MAXN][MAXN];\ndouble NEGLOGP[MAXN][MAXN];\ndouble edgePenalty = 0.0;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct Candidate {\n    uint32_t mask = 0;\n    array<unsigned char, MAXN> deg;\n    int sum = 0;\n};\n\nstruct Codeword {\n    uint32_t mask = 0;\n    array<unsigned char, MAXN> deg;\n    vector<Row> rows;\n    array<double, MAXN> mixNeg;\n    vector<int> blockCnt;\n    string out;\n};\n\nstruct QueryFeat {\n    array<int, MAXN> degSorted;\n    array<int, MAXN> hist;\n    vector<Row> rows;\n    vector<int> blockCnt;\n};\n\nstruct Config {\n    double alpha;\n    double wb;\n    double we;\n};\n\nstruct TrainResult {\n    Config cfg;\n    int err;\n    int samples;\n};\n\nstruct Solution {\n    int N = 0;\n    int B = 0;\n    int Lfeat = 10;\n    vector<Codeword> codes;\n    Config cfg{0.5, 0.0, 0.0};\n    int trainErr = 0;\n    int trainSamples = 0;\n    string name;\n};\n\nstruct EvalResult {\n    int err = 0;\n    int samples = 0;\n};\n\nvector<Codeword> codes;\nConfig bestCfg{0.5, 0.0, 0.0};\n\ninline int thresholdBit(uint32_t mask, int idx, int B, int N) {\n    int b = (long long)idx * B / N;\n    return (mask >> b) & 1u;\n}\n\ninline void setEdge(vector<Row>& rows, int i, int j) {\n    rows[i][j >> 6] |= 1ULL << (j & 63);\n    rows[j][i >> 6] |= 1ULL << (i & 63);\n}\n\ninline bool getEdge(const vector<Row>& rows, int i, int j) {\n    return (rows[i][j >> 6] >> (j & 63)) & 1ULL;\n}\n\ninline double rnd01(mt19937_64& rng) {\n    return (rng() >> 11) * (1.0 / 9007199254740992.0);\n}\n\nstring graphStringRows(const vector<Row>& rows) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(getEdge(rows, i, j) ? '1' : '0');\n        }\n    }\n\n    return s;\n}\n\nstring thresholdGraphString(uint32_t mask) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(thresholdBit(mask, j, Bcur, Ncur) ? '1' : '0');\n        }\n    }\n\n    return s;\n}\n\nvoid thresholdDegrees(uint32_t mask, int B, int N, array<int, MAXN>& degOrig) {\n    degOrig.fill(0);\n\n    int cnt = 0;\n    for (int i = N - 1; i >= 0; --i) {\n        int bit = thresholdBit(mask, i, B, N);\n        if (bit) degOrig[i] = i + cnt;\n        else degOrig[i] = cnt;\n        if (bit) cnt++;\n    }\n}\n\nbool makeCandidate(uint32_t mask, int N, int B, Candidate& c) {\n    array<int, MAXN> dorig{};\n    thresholdDegrees(mask, B, N, dorig);\n\n    c.mask = mask;\n    c.deg.fill(0);\n    c.sum = 0;\n\n    for (int i = 0; i < N; ++i) {\n        c.deg[i] = (unsigned char)dorig[i];\n        c.sum += dorig[i];\n    }\n\n    sort(c.deg.begin(), c.deg.begin() + N);\n    return true;\n}\n\nvector<Candidate> buildPool(int N, int B) {\n    vector<Candidate> pool;\n    int total = 1 << B;\n    pool.reserve(total);\n\n    unordered_set<string> seen;\n    seen.reserve(total * 2);\n\n    for (uint32_t mask = 0; mask < (uint32_t)total; ++mask) {\n        Candidate c;\n        makeCandidate(mask, N, B, c);\n\n        string key;\n        key.resize(N);\n        for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n        if (seen.insert(key).second) {\n            pool.push_back(c);\n        }\n    }\n\n    return pool;\n}\n\ninline int dist2Deg(const array<unsigned char, MAXN>& a,\n                    const array<unsigned char, MAXN>& b,\n                    int N) {\n    int s = 0;\n    for (int i = 0; i < N; ++i) {\n        int d = (int)a[i] - (int)b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstruct Selection {\n    vector<int> idx;\n    int minD2 = 0;\n};\n\nSelection selectFarthest(const vector<Candidate>& pool, int N, int m, int improveIters) {\n    int P = (int)pool.size();\n\n    Selection res;\n    if (P < m) return res;\n\n    vector<int> selected;\n    vector<int> minDist(P, INT_MAX);\n    vector<char> used(P, 0);\n\n    int start = 0;\n    for (int i = 1; i < P; ++i) {\n        if (pool[i].sum < pool[start].sum) start = i;\n    }\n\n    for (int it = 0; it < m; ++it) {\n        int id;\n\n        if (it == 0) {\n            id = start;\n        } else {\n            id = -1;\n            int best = -1;\n\n            for (int i = 0; i < P; ++i) {\n                if (!used[i] && minDist[i] > best) {\n                    best = minDist[i];\n                    id = i;\n                }\n            }\n        }\n\n        used[id] = 1;\n        selected.push_back(id);\n\n        for (int i = 0; i < P; ++i) {\n            if (!used[i]) {\n                int d = dist2Deg(pool[i].deg, pool[id].deg, N);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    for (int rep = 0; rep < improveIters; ++rep) {\n        vector<int> near(m, INT_MAX);\n        int curMin = INT_MAX;\n        int worstPos = -1;\n\n        for (int i = 0; i < m; ++i) {\n            for (int j = 0; j < m; ++j) if (i != j) {\n                int d = dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N);\n                near[i] = min(near[i], d);\n            }\n\n            if (near[i] < curMin) {\n                curMin = near[i];\n                worstPos = i;\n            }\n        }\n\n        int bestP = -1;\n        int bestMd = curMin;\n\n        for (int p = 0; p < P; ++p) if (!used[p]) {\n            int md = INT_MAX;\n\n            for (int i = 0; i < m; ++i) {\n                if (i == worstPos) continue;\n\n                int d = dist2Deg(pool[p].deg, pool[selected[i]].deg, N);\n                md = min(md, d);\n\n                if (md <= curMin) break;\n            }\n\n            if (md > bestMd) {\n                bestMd = md;\n                bestP = p;\n            }\n        }\n\n        if (bestP == -1) break;\n\n        used[selected[worstPos]] = 0;\n        selected[worstPos] = bestP;\n        used[bestP] = 1;\n    }\n\n    int md2 = INT_MAX;\n    for (int i = 0; i < m; ++i) {\n        for (int j = i + 1; j < m; ++j) {\n            md2 = min(md2, dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N));\n        }\n    }\n\n    res.idx = selected;\n    res.minD2 = md2;\n    return res;\n}\n\nvoid setupBlocks(int N, int Lfeat = 10) {\n    Lcur = min(Lfeat, N);\n    Fcur = 0;\n\n    for (int i = 0; i < 10; ++i) {\n        for (int j = 0; j < 10; ++j) {\n            FIDX[i][j] = -1;\n        }\n    }\n\n    for (int a = 0; a < Lcur; ++a) {\n        for (int b = a; b < Lcur; ++b) {\n            FIDX[a][b] = FIDX[b][a] = Fcur++;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        POSBIN[i] = (long long)i * Lcur / N;\n        if (POSBIN[i] >= Lcur) POSBIN[i] = Lcur - 1;\n    }\n\n    PAIRCNT.assign(Fcur, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            int f = FIDX[POSBIN[i]][POSBIN[j]];\n            PAIRCNT[f]++;\n        }\n    }\n}\n\nvector<double> binomDist(int n, double p) {\n    vector<double> d(n + 1, 0.0);\n\n    if (n == 0) {\n        d[0] = 1.0;\n        return d;\n    }\n    if (p < 1e-15) {\n        d[0] = 1.0;\n        return d;\n    }\n    if (1.0 - p < 1e-15) {\n        d[n] = 1.0;\n        return d;\n    }\n\n    double q = 1.0 - p;\n    d[0] = pow(q, n);\n\n    for (int k = 0; k < n; ++k) {\n        d[k + 1] = d[k] * (double)(n - k) / (double)(k + 1) * p / q;\n    }\n\n    return d;\n}\n\nvoid setupPMF(int N) {\n    vector<vector<double>> keep(N), flip(N);\n\n    for (int n = 0; n <= N - 1; ++n) {\n        keep[n] = binomDist(n, 1.0 - EPS);\n        flip[n] = binomDist(n, EPS);\n    }\n\n    for (int d = 0; d <= N - 1; ++d) {\n        for (int x = 0; x <= N - 1; ++x) PMF[d][x] = 0.0;\n\n        int absent = N - 1 - d;\n\n        for (int y = 0; y <= d; ++y) {\n            for (int z = 0; z <= absent; ++z) {\n                PMF[d][y + z] += keep[d][y] * flip[absent][z];\n            }\n        }\n\n        for (int x = 0; x <= N - 1; ++x) {\n            double p = max(PMF[d][x], 1e-300);\n            NEGLOGP[d][x] = -log(p);\n        }\n    }\n}\n\nvector<int> computeBlockCounts(const vector<Row>& rows) {\n    vector<int> cnt(Fcur, 0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, i, j)) {\n                int f = FIDX[POSBIN[i]][POSBIN[j]];\n                cnt[f]++;\n            }\n        }\n    }\n\n    return cnt;\n}\n\nvoid finalizeCodeword(Codeword& c) {\n    c.mixNeg.fill(0.0);\n\n    for (int x = 0; x < Ncur; ++x) {\n        double p = 0.0;\n\n        for (int i = 0; i < Ncur; ++i) {\n            p += PMF[(int)c.deg[i]][x];\n        }\n\n        p /= Ncur;\n        c.mixNeg[x] = -log(max(p, 1e-300));\n    }\n\n    c.blockCnt = computeBlockCounts(c.rows);\n}\n\nCodeword buildThresholdCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = cand.mask;\n    c.deg = cand.deg;\n\n    c.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : c.rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> dorig{};\n    thresholdDegrees(c.mask, Bcur, Ncur, dorig);\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (dorig[a] != dorig[b]) return dorig[a] < dorig[b];\n        return a < b;\n    });\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            int u = ord[a], v = ord[b];\n            int later = max(u, v);\n\n            if (thresholdBit(c.mask, later, Bcur, Ncur)) {\n                setEdge(c.rows, a, b);\n            }\n        }\n    }\n\n    c.out = thresholdGraphString(c.mask);\n    finalizeCodeword(c);\n    return c;\n}\n\nbool isGraphicalDeg(const vector<int>& degAsc, int N) {\n    vector<int> d(degAsc.begin(), degAsc.begin() + N);\n    sort(d.begin(), d.end(), greater<int>());\n\n    long long sum = 0;\n    for (int x : d) {\n        if (x < 0 || x >= N) return false;\n        sum += x;\n    }\n\n    if (sum & 1LL) return false;\n\n    vector<long long> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + d[i];\n\n    for (int k = 1; k <= N; ++k) {\n        long long left = pref[k];\n        long long right = 1LL * k * (k - 1);\n\n        for (int i = k; i < N; ++i) {\n            right += min(d[i], k);\n        }\n\n        if (left > right) return false;\n    }\n\n    return true;\n}\n\nbool constructGraphHH(const array<unsigned char, MAXN>& deg, vector<Row>& rows) {\n    rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    vector<pair<int, int>> v;\n    v.reserve(Ncur);\n\n    for (int i = 0; i < Ncur; ++i) {\n        v.push_back({(int)deg[i], i});\n    }\n\n    while (true) {\n        sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        if (v.empty() || v[0].first == 0) break;\n\n        int d = v[0].first;\n        int u = v[0].second;\n        v.erase(v.begin());\n\n        if (d > (int)v.size()) return false;\n\n        for (int i = 0; i < d; ++i) {\n            if (v[i].first <= 0) return false;\n\n            v[i].first--;\n            setEdge(rows, u, v[i].second);\n\n            if (v[i].first < 0) return false;\n        }\n    }\n\n    return true;\n}\n\nCodeword buildDegreeCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = 0;\n    c.deg = cand.deg;\n\n    bool ok = constructGraphHH(c.deg, c.rows);\n    if (!ok) {\n        c.rows.assign(Ncur, Row{0ULL, 0ULL});\n        for (auto& r : c.rows) r = {0ULL, 0ULL};\n    }\n\n    c.out = graphStringRows(c.rows);\n    finalizeCodeword(c);\n    return c;\n}\n\nvoid addDegreeCandidate(vector<Candidate>& pool,\n                        unordered_set<string>& seen,\n                        vector<int> d) {\n    int N = Ncur;\n    if ((int)d.size() != N) return;\n\n    for (int& x : d) {\n        if (x < 0) x = 0;\n        if (x > N - 1) x = N - 1;\n    }\n\n    sort(d.begin(), d.end());\n\n    long long sum = 0;\n    for (int x : d) sum += x;\n\n    if (sum & 1LL) {\n        bool changed = false;\n\n        for (int i = N - 1; i >= 0; --i) {\n            if (d[i] < N - 1) {\n                d[i]++;\n                changed = true;\n                break;\n            }\n        }\n\n        if (!changed) {\n            for (int i = 0; i < N; ++i) {\n                if (d[i] > 0) {\n                    d[i]--;\n                    changed = true;\n                    break;\n                }\n            }\n        }\n\n        if (!changed) return;\n        sort(d.begin(), d.end());\n    }\n\n    if (!isGraphicalDeg(d, N)) return;\n\n    Candidate c;\n    c.mask = 0;\n    c.deg.fill(0);\n    c.sum = 0;\n\n    for (int i = 0; i < N; ++i) {\n        c.deg[i] = (unsigned char)d[i];\n        c.sum += d[i];\n    }\n\n    string key;\n    key.resize(N);\n    for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n    if (seen.insert(key).second) {\n        pool.push_back(c);\n    }\n}\n\nvector<Candidate> buildDegreePool(int N, int target) {\n    Ncur = N;\n\n    vector<Candidate> pool;\n    pool.reserve(target + 1000);\n\n    unordered_set<string> seen;\n    seen.reserve(target * 3);\n\n    auto addCand = [&](const Candidate& c0) {\n        vector<int> d(N);\n        for (int i = 0; i < N; ++i) d[i] = c0.deg[i];\n        addDegreeCandidate(pool, seen, d);\n    };\n\n    int baseB = min(N, (N >= 70 ? 14 : (N >= 35 ? 13 : 12)));\n    vector<Candidate> th = buildPool(N, baseB);\n    for (const auto& c : th) addCand(c);\n\n    for (int r = 0; r < N; ++r) {\n        vector<int> d(N, r);\n        addDegreeCandidate(pool, seen, d);\n    }\n\n    vector<double> gammas = {0.25, 0.35, 0.5, 0.7, 1.0, 1.4, 2.0, 3.0, 4.5};\n\n    int step = max(1, N / 6);\n    for (int lo = 0; lo < N; lo += step) {\n        for (int hi = lo; hi < N; hi += step) {\n            for (double g : gammas) {\n                vector<int> d(N);\n\n                for (int i = 0; i < N; ++i) {\n                    double x = (N == 1 ? 0.0 : (double)i / (N - 1));\n                    int val = (int)llround(lo + (hi - lo) * pow(x, g));\n                    d[i] = val;\n                }\n\n                addDegreeCandidate(pool, seen, d);\n\n                for (int i = 0; i < N; ++i) d[i] = (N - 1) - d[i];\n                addDegreeCandidate(pool, seen, d);\n            }\n        }\n    }\n\n    mt19937_64 rng(0x3141592653589793ULL\n                   + (uint64_t)M * 1000003ULL\n                   + (uint64_t)N * 9176ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 19260817ULL);\n\n    int finalTarget = min(target, 26000);\n    int attempts = 0;\n    int maxAttempts = finalTarget * 40;\n\n    while ((int)pool.size() < finalTarget && attempts < maxAttempts) {\n        attempts++;\n\n        int mode = rng() % 6;\n        vector<int> d(N, 0);\n\n        if (mode == 0) {\n            int lo = rng() % N;\n            int hi = rng() % N;\n            if (lo > hi) swap(lo, hi);\n\n            double g = exp(log(0.25) + rnd01(rng) * (log(5.0) - log(0.25)));\n            int noise = rng() % max(2, N / 8 + 1);\n\n            for (int i = 0; i < N; ++i) {\n                double x = (N == 1 ? 0.0 : (double)i / (N - 1));\n                int val = (int)llround(lo + (hi - lo) * pow(x, g));\n                val += (int)(rng() % (2 * noise + 1)) - noise;\n                d[i] = val;\n            }\n        } else if (mode == 1) {\n            int K = 2 + (rng() % 8);\n            vector<int> levels(K);\n\n            for (int i = 0; i < K; ++i) levels[i] = rng() % N;\n            sort(levels.begin(), levels.end());\n\n            vector<int> cuts(K + 1);\n            cuts[0] = 0;\n            cuts[K] = N;\n\n            for (int i = 1; i < K; ++i) cuts[i] = rng() % (N + 1);\n            sort(cuts.begin(), cuts.end());\n\n            for (int k = 0; k < K; ++k) {\n                for (int i = cuts[k]; i < cuts[k + 1]; ++i) d[i] = levels[k];\n            }\n        } else if (mode == 2) {\n            vector<int> bit(N);\n\n            for (int i = 0; i < N; ++i) {\n                bit[i] = ((rng() >> (i & 63)) & 1ULL);\n            }\n\n            int cnt = 0;\n            vector<int> tmp(N);\n\n            for (int i = N - 1; i >= 0; --i) {\n                if (bit[i]) tmp[i] = i + cnt;\n                else tmp[i] = cnt;\n                if (bit[i]) cnt++;\n            }\n\n            d = tmp;\n        } else if (mode == 3) {\n            double p = rnd01(rng);\n            vector<double> w(N);\n\n            double gamma = exp(log(0.3) + rnd01(rng) * (log(3.5) - log(0.3)));\n\n            for (int i = 0; i < N; ++i) {\n                w[i] = pow(rnd01(rng), gamma);\n            }\n\n            for (int i = 0; i < N; ++i) d[i] = 0;\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = i + 1; j < N; ++j) {\n                    double pp = 0.15 * p + 0.85 * (w[i] + w[j]) * 0.5;\n                    if (pp < 0.0) pp = 0.0;\n                    if (pp > 1.0) pp = 1.0;\n\n                    if (rnd01(rng) < pp) {\n                        d[i]++;\n                        d[j]++;\n                    }\n                }\n            }\n        } else if (mode == 4) {\n            int a = rng() % N;\n            int b = rng() % N;\n            if (a > b) swap(a, b);\n\n            for (int i = 0; i < N; ++i) {\n                double x = (N == 1 ? 0.0 : (double)i / (N - 1));\n                double y = 0.5 - 0.5 * cos(M_PI * x);\n                d[i] = (int)llround(a + (b - a) * y);\n            }\n        } else {\n            for (int i = 0; i < N; ++i) d[i] = rng() % N;\n            sort(d.begin(), d.end());\n        }\n\n        addDegreeCandidate(pool, seen, d);\n    }\n\n    return pool;\n}\n\nQueryFeat makeFeatureFromRows(const vector<Row>& rowsIn, const array<int, MAXN>& deg) {\n    QueryFeat q;\n    q.hist.fill(0);\n\n    q.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : q.rows) r = {0ULL, 0ULL};\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < Ncur; ++i) {\n        q.degSorted[i] = deg[ord[i]];\n        q.hist[q.degSorted[i]]++;\n    }\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            if (getEdge(rowsIn, ord[a], ord[b])) {\n                setEdge(q.rows, a, b);\n            }\n        }\n    }\n\n    q.blockCnt = computeBlockCounts(q.rows);\n    return q;\n}\n\nQueryFeat featureFromString(const string& s) {\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    int pos = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (s[pos++] == '1') {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    return makeFeatureFromRows(rows, deg);\n}\n\nQueryFeat simulateQuery(int k, mt19937_64& rng) {\n    const Codeword& cw = codes[k];\n\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            int h = getEdge(cw.rows, i, j) ? 1 : 0;\n            if (rnd01(rng) < EPS) h ^= 1;\n\n            if (h) {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    array<int, MAXN> perm{};\n    for (int i = 0; i < Ncur; ++i) perm[i] = i;\n\n    for (int i = Ncur - 1; i >= 1; --i) {\n        int r = rng() % (i + 1);\n        swap(perm[i], perm[r]);\n    }\n\n    vector<Row> shuf(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : shuf) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg2{};\n    deg2.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) deg2[i] = deg[perm[i]];\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, perm[i], perm[j])) {\n                setEdge(shuf, i, j);\n            }\n        }\n    }\n\n    return makeFeatureFromRows(shuf, deg2);\n}\n\nint edgeMismatch(const vector<Row>& A, const vector<Row>& B) {\n    int s = 0;\n\n    for (int i = 0; i < Ncur; ++i) {\n        s += __builtin_popcountll(A[i][0] ^ B[i][0]);\n        if (Ncur > 64) s += __builtin_popcountll(A[i][1] ^ B[i][1]);\n    }\n\n    return s / 2;\n}\n\nstruct Components {\n    double sortedCost;\n    double mixCost;\n    double blockCost;\n    int edgeMis;\n};\n\nComponents computeComponents(const QueryFeat& q, const Codeword& c) {\n    Components comp{0.0, 0.0, 0.0, 0};\n\n    for (int i = 0; i < Ncur; ++i) {\n        comp.sortedCost += NEGLOGP[(int)c.deg[i]][q.degSorted[i]];\n    }\n\n    for (int x = 0; x < Ncur; ++x) {\n        if (q.hist[x]) comp.mixCost += q.hist[x] * c.mixNeg[x];\n    }\n\n    for (int f = 0; f < Fcur; ++f) {\n        int pairs = PAIRCNT[f];\n        if (pairs <= 0) continue;\n\n        double mu = EPS * pairs + QV * c.blockCnt[f];\n        double var = pairs * EPS * (1.0 - EPS) + 1.0;\n        double diff = q.blockCnt[f] - mu;\n\n        comp.blockCost += diff * diff / (2.0 * var);\n    }\n\n    comp.edgeMis = edgeMismatch(q.rows, c.rows);\n    return comp;\n}\n\ninline double scoreWithConfig(const Components& comp, const Config& cfg) {\n    double degCost = cfg.alpha * comp.sortedCost + (1.0 - cfg.alpha) * comp.mixCost;\n    return degCost + cfg.wb * comp.blockCost + cfg.we * edgePenalty * comp.edgeMis;\n}\n\nvector<Config> buildConfigs() {\n    vector<Config> cfgs;\n    cfgs.push_back({0.5, 0.0, 0.0});\n\n    vector<double> alphas = {0.0, 0.25, 0.5, 0.75, 1.0};\n    vector<double> wbs = {0.0, 0.2, 0.5, 1.0, 2.0};\n    vector<double> wes = {0.0, 0.02, 0.05, 0.1, 0.2};\n\n    for (double a : alphas) {\n        for (double wb : wbs) {\n            for (double we : wes) {\n                cfgs.push_back({a, wb, we});\n            }\n        }\n    }\n\n    return cfgs;\n}\n\nTrainResult trainDecoder() {\n    vector<Config> cfgs = buildConfigs();\n    int C = (int)cfgs.size();\n\n    int R = 3;\n    if (EPS > 0.25) R = 5;\n    else if (EPS > 0.12) R = 4;\n\n    if (M <= 20) R += 4;\n    else if (M <= 50) R += 1;\n\n    int samples = M * R;\n    vector<int> errs(C, 0);\n\n    mt19937_64 rng(1234567ULL\n                   + (uint64_t)M * 1009ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 9176ULL\n                   + (uint64_t)Ncur * 1000003ULL\n                   + (uint64_t)Bcur * 19260817ULL);\n\n    vector<double> best(C);\n    vector<int> bestId(C);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n\n            fill(best.begin(), best.end(), 1e300);\n            fill(bestId.begin(), bestId.end(), -1);\n\n            for (int k = 0; k < M; ++k) {\n                Components comp = computeComponents(q, codes[k]);\n\n                for (int ci = 0; ci < C; ++ci) {\n                    double sc = scoreWithConfig(comp, cfgs[ci]);\n\n                    if (sc < best[ci]) {\n                        best[ci] = sc;\n                        bestId[ci] = k;\n                    }\n                }\n            }\n\n            for (int ci = 0; ci < C; ++ci) {\n                if (bestId[ci] != trueId) errs[ci]++;\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int ci = 1; ci < C; ++ci) {\n        if (errs[ci] < errs[bestC]) bestC = ci;\n    }\n\n    return {cfgs[bestC], errs[bestC], samples};\n}\n\nint predict(const QueryFeat& q) {\n    double best = 1e300;\n    int ans = 0;\n\n    for (int k = 0; k < M; ++k) {\n        Components comp = computeComponents(q, codes[k]);\n        double sc = scoreWithConfig(comp, bestCfg);\n\n        if (sc < best) {\n            best = sc;\n            ans = k;\n        }\n    }\n\n    return ans;\n}\n\nint chooseN() {\n    int minN = 4;\n    while (minN < 100 && (1LL << (minN - 1)) < M) minN++;\n\n    double r = sqrt(EPS * (1.0 - EPS)) / QV;\n    int nest = (int)ceil(4.0 + 38.0 * r * sqrt(M / 100.0) + 0.03 * M);\n    nest = max(minN, min(100, nest));\n\n    int start, end;\n\n    if (EPS < 0.05) {\n        start = minN;\n        end = min(100, max(nest + 15, minN + 8));\n    } else {\n        start = max(minN, nest - 20);\n        end = min(100, nest + 25);\n        if (EPS > 0.34) end = 100;\n    }\n\n    vector<int> ns;\n\n    for (int n = start; n <= end;) {\n        ns.push_back(n);\n\n        if (n < 35) n++;\n        else if (n < 75) n += 2;\n        else n += 4;\n    }\n\n    ns.push_back(minN);\n    ns.push_back(nest);\n    ns.push_back(100);\n\n    sort(ns.begin(), ns.end());\n    ns.erase(unique(ns.begin(), ns.end()), ns.end());\n\n    double target = 3.25 + 0.12 * log((double)M);\n\n    if (EPS > 0.25) target += 0.15;\n    if (EPS < 0.03) target -= 0.75;\n    else if (EPS < 0.07) target -= 0.30;\n    if (M <= 20) target -= 0.15;\n\n    target = max(2.4, target);\n\n    for (int n : ns) {\n        if (n < minN || n > 100) continue;\n\n        int Bs = min(n, (n >= 80 ? 12 : 11));\n        vector<Candidate> pool = buildPool(n, Bs);\n\n        if ((int)pool.size() < M) continue;\n\n        Selection sel = selectFarthest(pool, n, M, 0);\n        if (sel.idx.empty()) continue;\n\n        double sigma = sqrt((n - 1) * EPS * (1.0 - EPS));\n        double z = QV * sqrt((double)sel.minD2) / (2.0 * sigma);\n\n        if (z >= target) return n;\n    }\n\n    return 100;\n}\n\nSolution captureSolution(const string& name, const TrainResult& tr) {\n    Solution sol;\n\n    sol.N = Ncur;\n    sol.B = Bcur;\n    sol.Lfeat = Lcur;\n    sol.codes = codes;\n    sol.cfg = bestCfg;\n    sol.trainErr = tr.err;\n    sol.trainSamples = tr.samples;\n    sol.name = name;\n\n    return sol;\n}\n\nvoid activateSolution(const Solution& sol) {\n    Ncur = sol.N;\n    Bcur = sol.B;\n\n    setupBlocks(Ncur, sol.Lfeat);\n    setupPMF(Ncur);\n    edgePenalty = log((1.0 - EPS) / EPS);\n\n    codes = sol.codes;\n    bestCfg = sol.cfg;\n}\n\nSolution buildThresholdSolution(int initialN) {\n    int chosenN = initialN;\n    int attempts = 0;\n\n    while (true) {\n        Ncur = chosenN;\n        Bcur = min(Ncur, (Ncur >= 70 ? 14 : (Ncur >= 35 ? 13 : 12)));\n\n        vector<Candidate> pool = buildPool(Ncur, Bcur);\n\n        if ((int)pool.size() < M) {\n            chosenN++;\n            continue;\n        }\n\n        Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n        setupBlocks(Ncur, 10);\n        setupPMF(Ncur);\n        edgePenalty = log((1.0 - EPS) / EPS);\n\n        codes.clear();\n        codes.reserve(M);\n\n        for (int id : sel.idx) {\n            codes.push_back(buildThresholdCodeword(pool[id]));\n        }\n\n        TrainResult tr = trainDecoder();\n        bestCfg = tr.cfg;\n\n        int allowed;\n        if (EPS < 0.05) allowed = max(4, tr.samples / 50);\n        else allowed = max(3, tr.samples / 100);\n\n        if (tr.err > allowed && chosenN < 100 && attempts < 3) {\n            int inc = (chosenN < 50 ? 10 : 6);\n            if (EPS > 0.3) inc = max(inc, 8);\n\n            chosenN = min(100, chosenN + inc);\n            attempts++;\n            continue;\n        }\n\n        return captureSolution(\"threshold\", tr);\n    }\n}\n\nSolution buildThresholdFixedSolution(int N, int B) {\n    if (B < 1 || B > 20) return Solution{};\n\n    Ncur = N;\n    Bcur = B;\n\n    vector<Candidate> pool = buildPool(Ncur, Bcur);\n    if ((int)pool.size() < M) return Solution{};\n\n    Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n    setupBlocks(Ncur, 10);\n    setupPMF(Ncur);\n    edgePenalty = log((1.0 - EPS) / EPS);\n\n    codes.clear();\n    codes.reserve(M);\n\n    for (int id : sel.idx) {\n        codes.push_back(buildThresholdCodeword(pool[id]));\n    }\n\n    TrainResult tr = trainDecoder();\n    bestCfg = tr.cfg;\n\n    return captureSolution(\"threshold-bplus\", tr);\n}\n\nSolution buildDegreeSolution(int N) {\n    Ncur = N;\n    Bcur = 0;\n\n    setupBlocks(Ncur, 10);\n    setupPMF(Ncur);\n    edgePenalty = log((1.0 - EPS) / EPS);\n\n    int target = 18000;\n    if (EPS >= 0.34) target = 23000;\n    if (M <= 50) target -= 3000;\n    target = max(target, 12000);\n\n    vector<Candidate> pool = buildDegreePool(Ncur, target);\n    if ((int)pool.size() < M) return Solution{};\n\n    Selection sel = selectFarthest(pool, Ncur, M, 0);\n    if ((int)sel.idx.size() < M) return Solution{};\n\n    codes.clear();\n    codes.reserve(M);\n\n    for (int id : sel.idx) {\n        codes.push_back(buildDegreeCodeword(pool[id]));\n    }\n\n    TrainResult tr = trainDecoder();\n    bestCfg = tr.cfg;\n\n    return captureSolution(\"degree\", tr);\n}\n\nEvalResult validateSolution(const Solution& sol, int R, uint64_t seedExtra) {\n    activateSolution(sol);\n\n    int err = 0;\n    int samples = M * R;\n\n    mt19937_64 rng(0x9e3779b97f4a7c15ULL\n                   + seedExtra * 1000003ULL\n                   + (uint64_t)M * 9176ULL\n                   + (uint64_t)Ncur * 19260817ULL\n                   + (uint64_t)Bcur * 1234567ULL\n                   + (uint64_t)Lcur * 314159ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 998244353ULL);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n            int ans = predict(q);\n\n            if (ans != trueId) err++;\n        }\n    }\n\n    return {err, samples};\n}\n\nbool validationBetter(const Solution& base, const EvalResult& eb,\n                      const Solution& alt, const EvalResult& ea) {\n    double Eb = 100.0 * eb.err / max(1, eb.samples);\n    double Ea = 100.0 * ea.err / max(1, ea.samples);\n\n    double need = log((double)alt.N / (double)base.N) / (-log(0.9));\n\n    double margin = 5.0;\n    if (alt.name == \"threshold-bplus\") margin = 3.5;\n    if (EPS >= 0.35) margin -= 0.8;\n    if (M <= 40) margin += 1.0;\n\n    return (Eb - Ea > need + margin);\n}\n\n// Exact solver for epsilon = 0.\nstruct ExactSolver {\n    int n, T;\n    vector<string> reps;\n    vector<int> cmap;\n    vector<array<int, 15>> trans;\n\n    int pairPos[6][6];\n\n    void prepareTrans(int n_) {\n        n = n_;\n        T = n * (n - 1) / 2;\n\n        for (int i = 0; i < 6; ++i) {\n            for (int j = 0; j < 6; ++j) pairPos[i][j] = -1;\n        }\n\n        int p = 0;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                pairPos[i][j] = pairPos[j][i] = p++;\n            }\n        }\n\n        vector<int> perm(n);\n        iota(perm.begin(), perm.end(), 0);\n\n        trans.clear();\n\n        do {\n            array<int, 15> tr{};\n            int pos = 0;\n\n            for (int i = 0; i < n; ++i) {\n                for (int j = i + 1; j < n; ++j) {\n                    int a = perm[i], b = perm[j];\n                    tr[pos++] = pairPos[a][b];\n                }\n            }\n\n            trans.push_back(tr);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    int canonicalMask(int mask) const {\n        int best = INT_MAX;\n\n        for (const auto& tr : trans) {\n            int val = 0;\n\n            for (int i = 0; i < T; ++i) {\n                val = (val << 1) | ((mask >> tr[i]) & 1);\n            }\n\n            if (val < best) best = val;\n        }\n\n        return best;\n    }\n\n    string maskToString(int mask) const {\n        string s;\n        s.resize(T);\n\n        for (int i = 0; i < T; ++i) {\n            s[i] = ((mask >> i) & 1) ? '1' : '0';\n        }\n\n        return s;\n    }\n\n    int stringToMask(const string& s) const {\n        int mask = 0;\n\n        for (int i = 0; i < T; ++i) {\n            if (s[i] == '1') mask |= 1 << i;\n        }\n\n        return mask;\n    }\n\n    void generate(int M) {\n        for (int nn = 4; nn <= 6; ++nn) {\n            prepareTrans(nn);\n\n            reps.clear();\n            cmap.assign(1 << T, -1);\n\n            for (int mask = 0; mask < (1 << T); ++mask) {\n                int c = canonicalMask(mask);\n\n                if (cmap[c] == -1) {\n                    int id = (int)reps.size();\n                    cmap[c] = id;\n                    reps.push_back(maskToString(mask));\n\n                    if ((int)reps.size() == M) return;\n                }\n            }\n        }\n    }\n\n    int decode(const string& s) const {\n        int mask = stringToMask(s);\n        int c = canonicalMask(mask);\n\n        if (0 <= c && c < (int)cmap.size() && cmap[c] != -1) return cmap[c];\n        return 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    cin >> M >> EPS;\n    QV = 1.0 - 2.0 * EPS;\n\n    if (EPS < 1e-12) {\n        ExactSolver ex;\n        ex.generate(M);\n\n        cout << ex.n << '\\n';\n        for (int i = 0; i < M; ++i) {\n            cout << ex.reps[i] << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            cin >> H;\n\n            int ans = ex.decode(H);\n\n            cout << ans << '\\n';\n            cout.flush();\n        }\n\n        return 0;\n    }\n\n    int initialN = chooseN();\n\n    Solution baseSol = buildThresholdSolution(initialN);\n    Solution bestSol = baseSol;\n\n    vector<Solution> alternatives;\n\n    // Same-N, slightly larger threshold pool for medium cases.\n    if (EPS >= 0.10 && EPS <= 0.30 && elapsedSec() < 2.8) {\n        int b2 = baseSol.B + 1;\n        if (b2 <= 14) {\n            Solution s2 = buildThresholdFixedSolution(baseSol.N, b2);\n            if (s2.N > 0) alternatives.push_back(s2);\n        }\n    }\n\n    // General graphical degree-sequence codebook for noisy cases.\n    // It is intentionally guarded by validation to avoid damaging stable cases.\n    if (EPS >= 0.27 && M >= 40 && elapsedSec() < 3.25) {\n        Solution degSol = buildDegreeSolution(baseSol.N);\n        if (degSol.N > 0) alternatives.push_back(degSol);\n    }\n\n    if (!alternatives.empty() && elapsedSec() < 4.55) {\n        int Rv = 4;\n        if (EPS >= 0.30) Rv = 5;\n        if (EPS >= 0.36) Rv = 6;\n        if (M <= 30) Rv++;\n\n        EvalResult bestEval = validateSolution(bestSol, Rv, 1);\n\n        for (int i = 0; i < (int)alternatives.size(); ++i) {\n            if (elapsedSec() > 4.70) break;\n\n            EvalResult altEval = validateSolution(alternatives[i], Rv, 10 + i);\n\n            if (validationBetter(bestSol, bestEval, alternatives[i], altEval)) {\n                bestSol = alternatives[i];\n                bestEval = altEval;\n            }\n        }\n    }\n\n    activateSolution(bestSol);\n\n    cout << Ncur << '\\n';\n    for (int i = 0; i < M; ++i) {\n        cout << codes[i].out << '\\n';\n    }\n    cout.flush();\n\n    for (int q = 0; q < 100; ++q) {\n        string H;\n        cin >> H;\n\n        QueryFeat feat = featureFromString(H);\n        int ans = predict(feat);\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#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() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    static constexpr int INF = 1100000000;\n    static constexpr int UNREACH = 1000000000;\n    static constexpr long long DISCONN_SCORE = 4000000000000000LL;\n\n    struct Edge {\n        int u, v, w;\n        int cell;\n        uint32_t key;\n    };\n    struct Arc {\n        int to, w, id;\n    };\n    struct ScoreRes {\n        long long total;\n        vector<long long> day;\n    };\n    struct State {\n        vector<int> assign;\n        vector<int> count;\n        vector<vector<int>> dayEdges;\n        vector<int> pos;\n        vector<int> inc;\n        vector<double> dayImp;\n        vector<int> cellCnt;\n        vector<int> cutCnt;\n        vector<long long> dayScore;\n        long long totalScore = 0;\n    };\n    struct Cand {\n        int type = 0; // 1: move, 2: swap\n        int e = -1, f = -1;\n        double cheap = 1e100;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Arc>> adj;\n    vector<int> xs, ys;\n    vector<int> origDist;\n    vector<long long> load;\n    vector<vector<int>> cutAdj;\n    vector<double> stretch;\n    vector<double> impNorm;\n    vector<int> target;\n    vector<int> optSources;\n\n    static constexpr int G = 16;\n    static constexpr int C = G * G;\n    vector<vector<int>> neighCells;\n    vector<unsigned char> nearCell;\n\n    RNG rng;\n    chrono::steady_clock::time_point startTime;\n    double localEndTime = 5.65;\n\n    vector<pair<int, int>> heapBuf;\n    vector<int> distBuf;\n    vector<int> bfsVis, bfsQ;\n    int bfsStamp = 1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static uint64_t mix64(uint64_t z) {\n        z += 0x9e3779b97f4a7c15ull;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n\n    uint32_t zOrder(int x, int y) const {\n        uint32_t r = 0;\n        for (int b = 0; b < 11; b++) {\n            r |= ((x >> b) & 1u) << (2 * b);\n            r |= ((y >> b) & 1u) << (2 * b + 1);\n        }\n        return r;\n    }\n\n    int edgeCellFromSum(int sx, int sy) const {\n        int cx = min(G - 1, (sx * G) / 2001);\n        int cy = min(G - 1, (sy * G) / 2001);\n        return cx * G + cy;\n    }\n\n    void setupCells() {\n        neighCells.assign(C, {});\n        nearCell.assign(C * C, 0);\n        for (int cx = 0; cx < G; cx++) {\n            for (int cy = 0; cy < G; cy++) {\n                int c = cx * G + cy;\n                for (int dx = -1; dx <= 1; dx++) {\n                    for (int dy = -1; dy <= 1; dy++) {\n                        int nx = cx + dx, ny = cy + dy;\n                        if (0 <= nx && nx < G && 0 <= ny && ny < G) {\n                            int nc = nx * G + ny;\n                            neighCells[c].push_back(nc);\n                            nearCell[c * C + nc] = 1;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    void readInput() {\n        cin >> N >> M >> D >> K;\n        edges.resize(M);\n        adj.assign(N, {});\n        uint64_t seed = 123456789;\n\n        for (int i = 0; i < M; i++) {\n            int u, v, w;\n            cin >> u >> v >> w;\n            --u; --v;\n            edges[i].u = u;\n            edges[i].v = v;\n            edges[i].w = w;\n            edges[i].cell = 0;\n            edges[i].key = 0;\n            adj[u].push_back({v, w, i});\n            adj[v].push_back({u, w, i});\n            seed ^= mix64((uint64_t)(u + 1) * 1000003ull + (uint64_t)(v + 1) * 1009ull + w);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> xs[i] >> ys[i];\n            seed ^= mix64((uint64_t)(xs[i] + 1) * 10007ull + ys[i] + i * 97ull);\n        }\n        rng.x = seed ? seed : 88172645463325252ull;\n\n        setupCells();\n\n        for (int i = 0; i < M; i++) {\n            int u = edges[i].u, v = edges[i].v;\n            int sx = xs[u] + xs[v];\n            int sy = ys[u] + ys[v];\n            edges[i].cell = edgeCellFromSum(sx, sy);\n            int hx = min(2047, (sx * 2047) / 2000);\n            int hy = min(2047, (sy * 2047) / 2000);\n            edges[i].key = zOrder(hx, hy);\n        }\n\n        target.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) target[d]++;\n\n        distBuf.assign(N, INF);\n        bfsVis.assign(N, 0);\n        bfsQ.assign(N, 0);\n        heapBuf.reserve(max(10000, 4 * M + 2 * N));\n    }\n\n    void heapPush(int d, int v) {\n        pair<int, int> val = {d, v};\n        int i = (int)heapBuf.size();\n        heapBuf.push_back(val);\n        while (i > 0) {\n            int p = (i - 1) >> 1;\n            if (heapBuf[p].first <= val.first) break;\n            heapBuf[i] = heapBuf[p];\n            i = p;\n        }\n        heapBuf[i] = val;\n    }\n\n    pair<int, int> heapPop() {\n        pair<int, int> res = heapBuf[0];\n        pair<int, int> val = heapBuf.back();\n        heapBuf.pop_back();\n        if (!heapBuf.empty()) {\n            int i = 0;\n            int n = (int)heapBuf.size();\n            while (true) {\n                int l = i * 2 + 1;\n                if (l >= n) break;\n                int r = l + 1;\n                int c = l;\n                if (r < n && heapBuf[r].first < heapBuf[l].first) c = r;\n                if (heapBuf[c].first >= val.first) break;\n                heapBuf[i] = heapBuf[c];\n                i = c;\n            }\n            heapBuf[i] = val;\n        }\n        return res;\n    }\n\n    void dijkstraOriginalParent(\n        int src,\n        vector<int>& dist,\n        vector<int>& parV,\n        vector<int>& parE,\n        vector<int>& order\n    ) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        order.clear();\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            order.push_back(v);\n            for (const auto& a : adj[v]) {\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    parV[a.to] = v;\n                    parE[a.to] = a.id;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    void dijkstraDaySource(int src, int day, const vector<int>& assign, vector<int>& dist) {\n        fill(dist.begin(), dist.end(), INF);\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n            for (const auto& a : adj[v]) {\n                if (assign[a.id] == day) continue;\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    int dijkstraBetweenSkipEdge(int src, int dst, int banned) {\n        fill(distBuf.begin(), distBuf.end(), INF);\n        heapBuf.clear();\n\n        distBuf[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != distBuf[v]) continue;\n            if (v == dst) return du;\n            for (const auto& a : adj[v]) {\n                if (a.id == banned) continue;\n                int nd = du + a.w;\n                if (nd < distBuf[a.to]) {\n                    distBuf[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n        return INF;\n    }\n\n    void computeOriginalAndLoad() {\n        origDist.assign(N * N, INF);\n        load.assign(M, 0);\n\n        vector<int> dist(N), parV(N), parE(N), order;\n        vector<int> sub(N);\n\n        for (int s = 0; s < N; s++) {\n            dijkstraOriginalParent(s, dist, parV, parE, order);\n            memcpy(&origDist[s * N], dist.data(), sizeof(int) * N);\n\n            fill(sub.begin(), sub.end(), 1);\n            for (int ii = (int)order.size() - 1; ii >= 0; ii--) {\n                int v = order[ii];\n                int e = parE[v];\n                if (e != -1) {\n                    load[e] += sub[v];\n                    sub[parV[v]] += sub[v];\n                }\n            }\n        }\n    }\n\n    void detectTwoEdgeCuts() {\n        cutAdj.assign(M, {});\n        vector<int> tin(N), low(N);\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), 0);\n            fill(low.begin(), low.end(), 0);\n            int timer = 0;\n\n            auto dfs = [&](auto&& self, int v, int pe) -> void {\n                tin[v] = low[v] = ++timer;\n                for (const auto& a : adj[v]) {\n                    if (a.id == banned || a.id == pe) continue;\n                    int to = a.to;\n                    if (!tin[to]) {\n                        self(self, to, a.id);\n                        low[v] = min(low[v], low[to]);\n                        if (low[to] > tin[v]) {\n                            int f = a.id;\n                            if (banned < f) {\n                                cutAdj[banned].push_back(f);\n                                cutAdj[f].push_back(banned);\n                            }\n                        }\n                    } else {\n                        low[v] = min(low[v], tin[to]);\n                    }\n                }\n            };\n\n            dfs(dfs, 0, -1);\n        }\n\n        for (auto& v : cutAdj) {\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n    }\n\n    void computeStretch() {\n        stretch.assign(M, 0.0);\n        const double deadline = 1.35;\n\n        for (int e = 0; e < M; e++) {\n            if (elapsed() > deadline) break;\n            int u = edges[e].u;\n            int v = edges[e].v;\n            int repl = dijkstraBetweenSkipEdge(u, v, e);\n            int base = origDist[u * N + v];\n            if (repl >= INF) {\n                stretch[e] = 5.0;\n            } else {\n                stretch[e] = max(0.0, (double)(repl - base) / max(1, base));\n                stretch[e] = min(stretch[e], 8.0);\n            }\n        }\n    }\n\n    void computeImportance() {\n        double sumLoad = 0.0;\n        for (auto x : load) sumLoad += (double)x;\n        double meanLoad = max(1.0, sumLoad / max(1, M));\n\n        double avgW = 0.0;\n        for (const auto& e : edges) avgW += e.w;\n        avgW /= max(1, M);\n\n        vector<double> raw(M);\n        double sumRaw = 0.0;\n\n        for (int e = 0; e < M; e++) {\n            double r = (double)load[e] + 0.05 * meanLoad + 1.0;\n            r *= 1.0 + 0.7 * min(5.0, stretch[e]);\n            r *= 1.0 + 0.03 * min(50, (int)cutAdj[e].size());\n            r *= 0.75 + 0.25 * sqrt(max(0.1, edges[e].w / avgW));\n            raw[e] = r;\n            sumRaw += r;\n        }\n\n        double meanRaw = max(1e-9, sumRaw / max(1, M));\n        impNorm.assign(M, 1.0);\n        for (int e = 0; e < M; e++) {\n            impNorm[e] = raw[e] / meanRaw;\n            impNorm[e] = min(60.0, max(0.03, impNorm[e]));\n        }\n    }\n\n    vector<int> selectSources(int P) {\n        P = min(P, N);\n        vector<pair<uint32_t, int>> ord;\n        ord.reserve(N);\n        for (int i = 0; i < N; i++) {\n            int hx = xs[i] * 2047 / 1000;\n            int hy = ys[i] * 2047 / 1000;\n            ord.push_back({zOrder(hx, hy), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        vector<int> res;\n        vector<char> used(N, 0);\n        for (int t = 0; t < P; t++) {\n            int idx = (int)(((long long)(2 * t + 1) * N) / (2 * P));\n            idx = min(idx, N - 1);\n            int v = ord[idx].second;\n            if (used[v]) {\n                for (int k = 0; k < N; k++) {\n                    int nv = ord[(idx + k) % N].second;\n                    if (!used[nv]) {\n                        v = nv;\n                        break;\n                    }\n                }\n            }\n            used[v] = 1;\n            res.push_back(v);\n        }\n        return res;\n    }\n\n    bool isConnectedSkip(const vector<int>& assign, int day, int extraSkip = -1) {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            fill(bfsVis.begin(), bfsVis.end(), 0);\n            bfsStamp = 1;\n        }\n\n        int head = 0, tail = 0;\n        bfsVis[0] = bfsStamp;\n        bfsQ[tail++] = 0;\n        int seen = 1;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            for (const auto& a : adj[v]) {\n                if (a.id == extraSkip) continue;\n                if (assign[a.id] == day) continue;\n                int to = a.to;\n                if (bfsVis[to] == bfsStamp) continue;\n                bfsVis[to] = bfsStamp;\n                bfsQ[tail++] = to;\n                seen++;\n            }\n        }\n        return seen == N;\n    }\n\n    long long computeDayScore(\n        const vector<int>& assign,\n        int day,\n        const vector<int>& sources,\n        int removedCount,\n        bool checkConn\n    ) {\n        if (removedCount == 0) return 0;\n        if (checkConn && !isConnectedSkip(assign, day, -1)) return DISCONN_SCORE;\n\n        long long sum = 0;\n        for (int s : sources) {\n            dijkstraDaySource(s, day, assign, distBuf);\n            int base = s * N;\n            for (int v = 0; v < N; v++) {\n                int d = distBuf[v];\n                int dd = (d >= INF ? UNREACH : d);\n                int diff = dd - origDist[base + v];\n                if (diff > 0) sum += diff;\n            }\n        }\n        return sum;\n    }\n\n    ScoreRes scoreAll(const vector<int>& assign, const vector<int>& sources) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n            cnt[assign[e]]++;\n        }\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] > K) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n        }\n\n        ScoreRes r;\n        r.total = 0;\n        r.day.assign(D, 0);\n        for (int d = 0; d < D; d++) {\n            r.day[d] = computeDayScore(assign, d, sources, cnt[d], true);\n            r.total += r.day[d];\n        }\n        return r;\n    }\n\n    void shuffleVec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int localCellCount(const vector<int>& cellCnt, int day, int cell) const {\n        int s = 0;\n        int base = day * C;\n        for (int nb : neighCells[cell]) s += cellCnt[base + nb];\n        return s;\n    }\n\n    vector<int> buildHilbertLike(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0 || variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                int ax = xs[edges[a].u] + xs[edges[a].v];\n                int bx = xs[edges[b].u] + xs[edges[b].v];\n                if (ax != bx) return ax < bx;\n                int ay = ys[edges[a].u] + ys[edges[a].v];\n                int by = ys[edges[b].u] + ys[edges[b].v];\n                return ay < by;\n            });\n        }\n\n        vector<int> assign(M, 0);\n        vector<int> perm(D);\n        for (int b = 0; b < M; b += D) {\n            iota(perm.begin(), perm.end(), 0);\n            if (variant == 0) {\n                rotate(perm.begin(), perm.begin() + ((b / D) % D), perm.end());\n            } else {\n                shuffleVec(perm);\n            }\n            for (int i = 0; i < D && b + i < M; i++) {\n                assign[order[b + i]] = perm[i];\n            }\n        }\n        return assign;\n    }\n\n    vector<int> buildRandomBalanced() {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffleVec(order);\n\n        vector<int> days;\n        days.reserve(M);\n        for (int d = 0; d < D; d++) {\n            for (int i = 0; i < target[d]; i++) days.push_back(d);\n        }\n        shuffleVec(days);\n\n        vector<int> assign(M);\n        for (int i = 0; i < M; i++) assign[order[i]] = days[i];\n        return assign;\n    }\n\n    vector<int> buildGreedy(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (impNorm[a] != impNorm[b]) return impNorm[a] > impNorm[b];\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (cutAdj[a].size() != cutAdj[b].size()) return cutAdj[a].size() > cutAdj[b].size();\n                return impNorm[a] > impNorm[b];\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 3) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            vector<double> key(M);\n            for (int e = 0; e < M; e++) key[e] = impNorm[e] * (0.6 + 0.8 * rng.nextDouble());\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        }\n\n        vector<int> assign(M, -1);\n        vector<int> count(D, 0);\n        vector<int> inc(N * D, 0);\n        vector<double> dayImp(D, 0.0);\n        vector<int> cellCnt(D * C, 0);\n        vector<int> cutCnt(M * D, 0);\n\n        for (int e : order) {\n            int u = edges[e].u, v = edges[e].v;\n            int cell = edges[e].cell;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(D);\n\n            for (int d = 0; d < D; d++) {\n                if (count[d] >= K) continue;\n\n                int adjCnt = inc[u * D + d] + inc[v * D + d];\n                int loc = localCellCount(cellCnt, d, cell);\n                int cut = cutCnt[e * D + d];\n\n                double over = max(0, count[d] + 1 - target[d]);\n                double cost = 100000000.0 * cut;\n                cost += 25.0 * adjCnt;\n                cost += 2.0 * loc;\n                cost += 4.0 * impNorm[e] * (dayImp[d] / max(1, target[d]));\n                if (count[d] >= target[d]) cost += 600.0 * over * over;\n                else cost += 0.1 * (double)count[d] / max(1, target[d]);\n                cost += 0.01 * rng.nextDouble();\n\n                cand.push_back({cost, d});\n            }\n\n            if (cand.empty()) {\n                int best = min_element(count.begin(), count.end()) - count.begin();\n                cand.push_back({0.0, best});\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int chosen = -1;\n            for (auto [cost, d] : cand) {\n                if (isConnectedSkip(assign, d, e)) {\n                    chosen = d;\n                    break;\n                }\n            }\n            if (chosen == -1) chosen = cand[0].second;\n\n            assign[e] = chosen;\n            count[chosen]++;\n            inc[u * D + chosen]++;\n            inc[v * D + chosen]++;\n            dayImp[chosen] += impNorm[e];\n            cellCnt[chosen * C + cell]++;\n            for (int g : cutAdj[e]) cutCnt[g * D + chosen]++;\n        }\n\n        return assign;\n    }\n\n    State buildState(const vector<int>& assign, const vector<int>& sources) {\n        State st;\n        st.assign = assign;\n        st.count.assign(D, 0);\n        st.dayEdges.assign(D, {});\n        st.pos.assign(M, -1);\n        st.inc.assign(N * D, 0);\n        st.dayImp.assign(D, 0.0);\n        st.cellCnt.assign(D * C, 0);\n        st.cutCnt.assign(M * D, 0);\n        st.dayScore.assign(D, 0);\n        st.totalScore = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            st.pos[e] = (int)st.dayEdges[d].size();\n            st.dayEdges[d].push_back(e);\n            st.count[d]++;\n            st.inc[edges[e].u * D + d]++;\n            st.inc[edges[e].v * D + d]++;\n            st.dayImp[d] += impNorm[e];\n            st.cellCnt[d * C + edges[e].cell]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            for (int g : cutAdj[e]) {\n                st.cutCnt[g * D + d]++;\n            }\n        }\n\n        for (int d = 0; d < D; d++) {\n            st.dayScore[d] = computeDayScore(st.assign, d, sources, st.count[d], true);\n            st.totalScore += st.dayScore[d];\n        }\n\n        return st;\n    }\n\n    bool isCutPair(int a, int b) const {\n        const auto& v = cutAdj[a];\n        return binary_search(v.begin(), v.end(), b);\n    }\n\n    int shareCount(int a, int b) const {\n        int c = 0;\n        if (edges[a].u == edges[b].u || edges[a].u == edges[b].v) c++;\n        if (edges[a].v == edges[b].u || edges[a].v == edges[b].v) c++;\n        return c;\n    }\n\n    double placeCost(const State& st, int e, int d, int removeY) {\n        bool inD = (st.assign[e] == d);\n        int u = edges[e].u, v = edges[e].v;\n        int adjCnt = st.inc[u * D + d] + st.inc[v * D + d];\n        if (inD) adjCnt -= 2;\n        if (removeY >= 0 && st.assign[removeY] == d) {\n            adjCnt -= shareCount(e, removeY);\n        }\n        adjCnt = max(0, adjCnt);\n\n        int cut = st.cutCnt[e * D + d];\n        if (removeY >= 0 && st.assign[removeY] == d && isCutPair(e, removeY)) cut--;\n        cut = max(0, cut);\n\n        int loc = localCellCount(st.cellCnt, d, edges[e].cell);\n        if (inD) loc--;\n        if (removeY >= 0 && st.assign[removeY] == d &&\n            nearCell[edges[e].cell * C + edges[removeY].cell]) {\n            loc--;\n        }\n        loc = max(0, loc);\n\n        double impSum = st.dayImp[d];\n        if (inD) impSum -= impNorm[e];\n        if (removeY >= 0 && st.assign[removeY] == d) impSum -= impNorm[removeY];\n        impSum = max(0.0, impSum);\n\n        double cost = 1000000.0 * cut;\n        cost += 10.0 * adjCnt;\n        cost += 1.5 * loc;\n        cost += 2.0 * impNorm[e] * (impSum / max(1, target[d]));\n        return cost;\n    }\n\n    double edgeBadness(const State& st, int e, int d) {\n        return placeCost(st, e, d, -1) + 0.5 * impNorm[e];\n    }\n\n    int randomNonemptyDay(const State& st, int exclude = -1) {\n        for (int t = 0; t < 50; t++) {\n            int d = rng.nextInt(D);\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        for (int d = 0; d < D; d++) {\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n        return -1;\n    }\n\n    int argMaxDay(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int d = 0; d < D; d++) {\n            if (st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int argMinDay(const State& st, int exclude = -1, bool requireNonempty = true) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int d = 0; d < D; d++) {\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        return best;\n    }\n\n    int tournamentHigh(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n        for (int i = 0; i < 5; i++) {\n            int d = randomNonemptyDay(st);\n            if (d == -1) continue;\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMaxDay(st);\n        return best;\n    }\n\n    int tournamentLow(const State& st, int exclude, bool requireNonempty) {\n        int best = -1;\n        long long val = LLONG_MAX;\n        for (int i = 0; i < 5; i++) {\n            int d = rng.nextInt(D);\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n        if (best == -1) best = argMinDay(st, exclude, requireNonempty);\n        return best;\n    }\n\n    int selectEdge(const State& st, int day, bool bad) {\n        const auto& v = st.dayEdges[day];\n        if (v.empty()) return -1;\n\n        int best = v[rng.nextInt((int)v.size())];\n        double bv = edgeBadness(st, best, day);\n\n        int samples = min(7, (int)v.size());\n        for (int i = 1; i < samples; i++) {\n            int e = v[rng.nextInt((int)v.size())];\n            double val = edgeBadness(st, e, day);\n            if ((bad && val > bv) || (!bad && val < bv)) {\n                bv = val;\n                best = e;\n            }\n        }\n        return best;\n    }\n\n    double cheapDeltaSwap(const State& st, int e, int f) {\n        int a = st.assign[e], b = st.assign[f];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1) + placeCost(st, f, b, -1);\n        double after = placeCost(st, e, b, f) + placeCost(st, f, a, e);\n        return after - before;\n    }\n\n    double cheapDeltaMove(const State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return 1e100;\n        double before = placeCost(st, e, a, -1);\n        double after = placeCost(st, e, b, -1);\n        return after - before;\n    }\n\n    Cand proposeSwap(const State& st) {\n        Cand best;\n        best.type = 2;\n\n        for (int t = 0; t < 14; t++) {\n            int a, b;\n            int mode = rng.nextInt(100);\n\n            if (mode < 45) {\n                a = argMaxDay(st);\n                b = argMinDay(st, a, true);\n            } else if (mode < 80) {\n                a = tournamentHigh(st);\n                b = tournamentLow(st, a, true);\n            } else {\n                a = randomNonemptyDay(st);\n                b = randomNonemptyDay(st, a);\n            }\n\n            if (a < 0 || b < 0 || a == b) continue;\n\n            int e = selectEdge(st, a, true);\n            int f = selectEdge(st, b, false);\n            if (e < 0 || f < 0) continue;\n\n            double cd = cheapDeltaSwap(st, e, f);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = f;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    Cand proposeMove(const State& st) {\n        Cand best;\n        best.type = 1;\n\n        int lowBound = max(0, M / D - 2);\n        int highBound = min(K, (M + D - 1) / D + 2);\n\n        for (int t = 0; t < 12; t++) {\n            int a = -1;\n            long long av = LLONG_MIN;\n\n            if (rng.nextInt(100) < 60) {\n                for (int d = 0; d < D; d++) {\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            } else {\n                for (int k = 0; k < 8; k++) {\n                    int d = rng.nextInt(D);\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            }\n\n            if (a < 0) continue;\n\n            int b = -1;\n            long long bv = LLONG_MAX;\n            for (int k = 0; k < 8; k++) {\n                int d = rng.nextInt(D);\n                if (d == a) continue;\n                if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                if (st.dayScore[d] < bv) {\n                    bv = st.dayScore[d];\n                    b = d;\n                }\n            }\n            if (b < 0) {\n                for (int d = 0; d < D; d++) {\n                    if (d == a) continue;\n                    if (st.count[d] >= highBound || st.count[d] >= K) continue;\n                    if (st.dayScore[d] < bv) {\n                        bv = st.dayScore[d];\n                        b = d;\n                    }\n                }\n            }\n            if (b < 0) continue;\n\n            int e = selectEdge(st, a, true);\n            if (e < 0) continue;\n\n            double cd = cheapDeltaMove(st, e, b);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = b;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    bool acceptDelta(const State& st, long long delta, bool isMove) {\n        if (delta <= 0) return true;\n\n        double avg = max(1.0, st.totalScore / (double)max(1, D));\n        double prog = min(1.0, elapsed() / localEndTime);\n        double factor = isMove ? 0.004 : 0.008;\n        double T = avg * (factor * (1.0 - prog) + 0.00002);\n\n        if (T <= 1.0) return false;\n        if ((double)delta > T * 20.0) return false;\n        return rng.nextDouble() < exp(-(double)delta / T);\n    }\n\n    void applySwap(State& st, int e, int f, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e], pf = st.pos[f];\n        st.dayEdges[a][pe] = f;\n        st.dayEdges[b][pf] = e;\n        st.pos[f] = pe;\n        st.pos[e] = pf;\n\n        auto decEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]--;\n            st.inc[edges[x].v * D + d]--;\n            st.dayImp[d] -= impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]--;\n        };\n        auto incEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]++;\n            st.inc[edges[x].v * D + d]++;\n            st.dayImp[d] += impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]++;\n        };\n\n        decEdge(e, a); incEdge(e, b);\n        decEdge(f, b); incEdge(f, a);\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n        for (int g : cutAdj[f]) {\n            st.cutCnt[g * D + b]--;\n            st.cutCnt[g * D + a]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    void applyMove(State& st, int e, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e];\n        int last = st.dayEdges[a].back();\n        st.dayEdges[a][pe] = last;\n        st.pos[last] = pe;\n        st.dayEdges[a].pop_back();\n\n        st.pos[e] = (int)st.dayEdges[b].size();\n        st.dayEdges[b].push_back(e);\n\n        st.count[a]--;\n        st.count[b]++;\n\n        st.inc[edges[e].u * D + a]--;\n        st.inc[edges[e].v * D + a]--;\n        st.inc[edges[e].u * D + b]++;\n        st.inc[edges[e].v * D + b]++;\n\n        st.dayImp[a] -= impNorm[e];\n        st.dayImp[b] += impNorm[e];\n\n        st.cellCnt[a * C + edges[e].cell]--;\n        st.cellCnt[b * C + edges[e].cell]++;\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    bool trySwap(State& st, int e, int f) {\n        int a = st.assign[e];\n        int b = st.assign[f];\n        if (a == b) return false;\n\n        st.assign[e] = b;\n        st.assign[f] = a;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a], false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b], false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, false);\n\n        if (acc) {\n            applySwap(st, e, f, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            st.assign[f] = b;\n            return false;\n        }\n    }\n\n    bool tryMove(State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return false;\n        if (st.count[b] >= K) return false;\n\n        st.assign[e] = b;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE, newB = DISCONN_SCORE;\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a] - 1, false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b] + 1, false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, true);\n\n        if (acc) {\n            applyMove(st, e, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            return false;\n        }\n    }\n\n    void ensureLegal(vector<int>& assign) {\n        vector<int> cnt(D, 0);\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) assign[e] = 0;\n            cnt[assign[e]]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            if (cnt[d] <= K) continue;\n            int b = -1;\n            for (int j = 0; j < D; j++) {\n                if (cnt[j] < K) {\n                    b = j;\n                    break;\n                }\n            }\n            if (b == -1) break;\n            cnt[d]--;\n            assign[e] = b;\n            cnt[b]++;\n        }\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n        readInput();\n\n        computeOriginalAndLoad();\n        detectTwoEdgeCuts();\n        computeStretch();\n        computeImportance();\n\n        int P = 24;\n        if (D <= 10) P += 8;\n        else if (D <= 18) P += 4;\n        if (M <= 1200) P += 8;\n        else if (M <= 2000) P += 4;\n        if (N <= 700) P += 4;\n        P = min({P, N, 52});\n        optSources = selectSources(P);\n\n        vector<int> bestAssign;\n        long long bestScore = LLONG_MAX;\n\n        auto consider = [&](const vector<int>& assign) {\n            ScoreRes sc = scoreAll(assign, optSources);\n            if (sc.total < bestScore) {\n                bestScore = sc.total;\n                bestAssign = assign;\n            }\n        };\n\n        consider(buildHilbertLike(0));\n        consider(buildGreedy(0));\n\n        const double initDeadline = 2.25;\n        if (elapsed() < initDeadline) consider(buildGreedy(1));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(1));\n        if (elapsed() < initDeadline) consider(buildGreedy(2));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(2));\n        if (elapsed() < initDeadline) consider(buildGreedy(4));\n        if (elapsed() < initDeadline) consider(buildRandomBalanced());\n\n        if (bestAssign.empty()) bestAssign = buildRandomBalanced();\n\n        State st = buildState(bestAssign, optSources);\n        vector<int> bestLocal = st.assign;\n        long long bestLocalScore = st.totalScore;\n\n        localEndTime = 5.65;\n        while (elapsed() < localEndTime) {\n            Cand cand;\n            if (rng.nextInt(100) < 18) cand = proposeMove(st);\n            if (cand.type == 0) cand = proposeSwap(st);\n\n            bool accepted = false;\n            if (cand.type == 1) {\n                accepted = tryMove(st, cand.e, cand.f);\n            } else if (cand.type == 2) {\n                accepted = trySwap(st, cand.e, cand.f);\n            }\n\n            if (accepted && st.totalScore < bestLocalScore) {\n                bestLocalScore = st.totalScore;\n                bestLocal = st.assign;\n            }\n        }\n\n        ensureLegal(bestLocal);\n\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << bestLocal[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    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct I3 { short x, y, z; };\n    struct Rot { int perm[3]; int sign[3]; };\n    struct Transform {\n        bool valid = false;\n        int ori = 0, tx = 0, ty = 0, tz = 0;\n    };\n    struct AlignCand {\n        long long key;\n        int ori, tid, cnt, w;\n    };\n    struct AlignMinCmp {\n        bool operator()(const AlignCand& a, const AlignCand& b) const {\n            return a.key > b.key;\n        }\n    };\n    struct CompCand {\n        bool valid = false;\n        double score = -1e100;\n        int size = 0, cov = 0;\n        int ori = 0, tx = 0, ty = 0, tz = 0;\n        vector<int> cells;\n    };\n    struct Box {\n        int x = 0, y = 0, z = 0;\n        int lx = 0, ly = 0, lz = 0;\n        int cov = -1, vol = 0;\n        bool valid = false;\n    };\n    struct BoxCand {\n        bool valid = false;\n        Box b0, b1;\n        int vol = 0, cov = 0;\n        double score = -1;\n    };\n    struct Bar {\n        int x = 0, y = 0, z = 0;\n        int dir = 0, len = 0, cov = 0;\n        bool valid = false;\n        array<int, 15> nf{}, nr{};\n    };\n    struct BarCand {\n        bool valid = false;\n        Bar b0, b1;\n        int len = 0, cov = 0;\n        double score = -1e100;\n    };\n    struct SimpleBox {\n        int x = 0, y = 0, z = 0;\n        int lx = 0, ly = 0, lz = 0;\n        int vol = 0;\n        bool valid = false;\n    };\n    struct PoolBoxCand {\n        bool valid = false;\n        SimpleBox b0, b1;\n        int vol = 0;\n    };\n    struct PoolCompCand {\n        bool valid = false;\n        double gain = -1e100;\n        int size = 0;\n        int core0 = 0, core1 = 0;\n        int ori = 0, tx = 0, ty = 0, tz = 0;\n        vector<int> cells;\n    };\n\n    int D, D2, N;\n    int rangeT, offsetT, Tcnt;\n    array<vector<string>, 2> F, Rt;\n\n    array<vector<char>, 2> allowed, rem, covF, covR;\n    array<vector<int>, 2> ans;\n    array<vector<unsigned char>, 2> aw;\n\n    vector<int> xs, ys, zs;\n    vector<array<int, 6>> neigh;\n\n    vector<Rot> rots;\n    vector<vector<I3>> rotp;\n\n    int unF[2][15];\n    int unR[2][15];\n\n    int allowedCount[2] = {0, 0};\n    int remCnt[2] = {0, 0};\n    int minAllowed = 0;\n    int totalUncov = 0;\n\n    int label = 0;\n    int commonVol = 0;\n    int uniqueVol[2] = {0, 0};\n    double commonCost = 0.0;\n\n    vector<int> cnt, wcnt;\n    vector<int> mark, vis, qmap;\n    int markToken = 1, visToken = 1;\n    array<vector<int>, 2> tmpF, tmpR;\n    int pixToken = 1;\n\n    vector<int> startTid, curTid, entries;\n\n    array<vector<vector<int>>, 2> blk;\n    vector<char> activeLab;\n\n    chrono::steady_clock::time_point startTime;\n\n    Solver(int D_, const array<vector<string>, 2>& F_, const array<vector<string>, 2>& Rt_)\n        : D(D_), F(F_), Rt(Rt_) {\n        D2 = D * D;\n        N = D * D * D;\n        rangeT = 3 * D - 2;\n        offsetT = D - 1;\n        Tcnt = rangeT * rangeT * rangeT;\n\n        memset(unF, 0, sizeof(unF));\n        memset(unR, 0, sizeof(unR));\n\n        for (int s = 0; s < 2; s++) {\n            allowed[s].assign(N, 0);\n            rem[s].assign(N, 0);\n            covF[s].assign(D2, 0);\n            covR[s].assign(D2, 0);\n            ans[s].assign(N, 0);\n            aw[s].assign(N, 0);\n            tmpF[s].assign(D2, 0);\n            tmpR[s].assign(D2, 0);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        zs.resize(N);\n        neigh.resize(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 v = id(x, y, z);\n                    xs[v] = x;\n                    ys[v] = y;\n                    zs[v] = z;\n                }\n            }\n        }\n\n        for (int v = 0; v < N; v++) {\n            int x = xs[v], y = ys[v], z = zs[v];\n            array<int, 6> nb;\n            nb.fill(-1);\n            if (x > 0) nb[0] = id(x - 1, y, z);\n            if (x + 1 < D) nb[1] = id(x + 1, y, z);\n            if (y > 0) nb[2] = id(x, y - 1, z);\n            if (y + 1 < D) nb[3] = id(x, y + 1, z);\n            if (z > 0) nb[4] = id(x, y, z - 1);\n            if (z + 1 < D) nb[5] = id(x, y, z + 1);\n            neigh[v] = nb;\n        }\n\n        for (int s = 0; s < 2; s++) {\n            for (int z = 0; z < D; z++) {\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1') {\n                        unF[s][z]++;\n                        totalUncov++;\n                    }\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1') {\n                        unR[s][z]++;\n                        totalUncov++;\n                    }\n                }\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                        if (F[s][z][x] == '1' && Rt[s][z][y] == '1') {\n                            int v = id(x, y, z);\n                            allowed[s][v] = 1;\n                            rem[s][v] = 1;\n                            allowedCount[s]++;\n                        }\n                    }\n                }\n            }\n            remCnt[s] = allowedCount[s];\n        }\n\n        minAllowed = min(allowedCount[0], allowedCount[1]);\n\n        generateRotations();\n        rotp.assign(rots.size(), vector<I3>(N));\n        for (int ri = 0; ri < (int)rots.size(); ri++) {\n            for (int v = 0; v < N; v++) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) q[a] = rots[ri].sign[a] * p[rots[ri].perm[a]];\n                rotp[ri][v] = I3{(short)q[0], (short)q[1], (short)q[2]};\n            }\n        }\n\n        cnt.assign(Tcnt, 0);\n        wcnt.assign(Tcnt, 0);\n        startTid.assign(Tcnt, 0);\n        curTid.assign(Tcnt, 0);\n        mark.assign(N, 0);\n        vis.assign(N, 0);\n        qmap.assign(N, -1);\n    }\n\n    inline int id(int x, int y, int z) const {\n        return (x * D + y) * D + z;\n    }\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    void generateRotations() {\n        array<int, 3> p = {0, 1, 2};\n        sort(p.begin(), p.end());\n        do {\n            int inv = 0;\n            for (int i = 0; i < 3; i++) {\n                for (int j = i + 1; j < 3; j++) {\n                    if (p[i] > p[j]) inv++;\n                }\n            }\n            int parity = (inv % 2 == 0 ? 1 : -1);\n            for (int sx : {-1, 1}) {\n                for (int sy : {-1, 1}) {\n                    for (int sz : {-1, 1}) {\n                        if (parity * sx * sy * sz == 1) {\n                            Rot r;\n                            r.perm[0] = p[0];\n                            r.perm[1] = p[1];\n                            r.perm[2] = p[2];\n                            r.sign[0] = sx;\n                            r.sign[1] = sy;\n                            r.sign[2] = sz;\n                            rots.push_back(r);\n                        }\n                    }\n                }\n            }\n        } while (next_permutation(p.begin(), p.end()));\n    }\n\n    inline int activeWeight(int s, int v) const {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int w = 0;\n        if (!covF[s][z * D + x]) w++;\n        if (!covR[s][z * D + y]) w++;\n        return w;\n    }\n\n    void coverCell(int s, int v) {\n        int z = zs[v], x = xs[v], y = ys[v];\n        int fid = z * D + x;\n        int rid = z * D + y;\n\n        if (F[s][z][x] == '1' && !covF[s][fid]) {\n            covF[s][fid] = 1;\n            unF[s][z]--;\n            totalUncov--;\n        }\n        if (Rt[s][z][y] == '1' && !covR[s][rid]) {\n            covR[s][rid] = 1;\n            unR[s][z]--;\n            totalUncov--;\n        }\n    }\n\n    int calcLBNow(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += max(unF[s][z], unR[s][z]);\n        return res;\n    }\n\n    int currentDeficit() const {\n        return max(0, max(calcLBNow(0), calcLBNow(1)) - min(remCnt[0], remCnt[1]));\n    }\n\n    int calcLBAfter(int s, const int* nf, const int* nr) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) {\n            int a = unF[s][z] - nf[z];\n            int b = unR[s][z] - nr[z];\n            if (a < 0) a = 0;\n            if (b < 0) b = 0;\n            res += max(a, b);\n        }\n        return res;\n    }\n\n    void decodeTid(int tid, int& tx, int& ty, int& tz) const {\n        tz = tid % rangeT;\n        tid /= rangeT;\n        ty = tid % rangeT;\n        tx = tid / rangeT;\n        tx -= offsetT;\n        ty -= offsetT;\n        tz -= offsetT;\n    }\n\n    void evalAlignment(int ori, int tid, const vector<int>& list0, CompCand& best) {\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        int inter = 0;\n\n        for (int p : list0) {\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            if (0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D) {\n                int q = id(qx, qy, qz);\n                if (rem[1][q]) {\n                    mark[p] = mt;\n                    qmap[p] = q;\n                    inter++;\n                }\n            }\n        }\n        if (inter == 0) return;\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(inter);\n        comp.reserve(inter);\n\n        int curDef = currentDeficit();\n\n        for (int st : list0) {\n            if (mark[st] != mt || vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int v : comp) {\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n            }\n\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int remCap = min(remCnt[0], remCnt[1]) - sz;\n            int def = max(0, max(lb0, lb1) - remCap);\n            int incDef = max(0, def - curDef);\n\n            double score = (double)cov * sz;\n            score /= (1.0 + 0.18 * incDef);\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponent(int topK, double timeLimit) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if (list0.empty() || list1.empty()) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        priority_queue<AlignCand, vector<AlignCand>, AlignMinCmp> pq1, pq2;\n\n        auto consider = [&](auto& pq, const AlignCand& a) {\n            if ((int)pq.size() < topK) {\n                pq.push(a);\n            } else if (a.key > pq.top().key) {\n                pq.pop();\n                pq.push(a);\n            }\n        };\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int awp = aw[0][p];\n                for (int j = 0; j < n1; j++) {\n                    int tx = qx[j] - rp.x + offsetT;\n                    int ty = qy[j] - rp.y + offsetT;\n                    int tz = qz[j] - rp.z + offsetT;\n                    int tid = (tx * rangeT + ty) * rangeT + tz;\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            for (int tid = 0; tid < Tcnt; tid++) {\n                if (wcnt[tid] == 0) continue;\n                int c = cnt[tid];\n                int w = wcnt[tid];\n                consider(pq1, AlignCand{1LL * c * (w + 1), oi, tid, c, w});\n                consider(pq2, AlignCand{1LL * c * c, oi, tid, c, w});\n            }\n\n            if (elapsed() > timeLimit) break;\n        }\n\n        vector<AlignCand> aligns;\n        while (!pq1.empty()) {\n            aligns.push_back(pq1.top());\n            pq1.pop();\n        }\n        while (!pq2.empty()) {\n            aligns.push_back(pq2.top());\n            pq2.pop();\n        }\n\n        sort(aligns.begin(), aligns.end(), [](const AlignCand& a, const AlignCand& b) {\n            return a.key > b.key;\n        });\n\n        unordered_set<long long> seen;\n        seen.reserve(aligns.size() * 2 + 1);\n\n        int evalCnt = 0;\n        for (const auto& a : aligns) {\n            long long code = 1LL * a.ori * Tcnt + a.tid;\n            if (!seen.insert(code).second) continue;\n            evalAlignment(a.ori, a.tid, list0, best);\n            evalCnt++;\n            if (evalCnt >= topK) break;\n            if (elapsed() > timeLimit) break;\n        }\n\n        return best;\n    }\n\n    void evalBucketAlignment(int ori, int tid, int l, int r, int minSize, int oldNeed, CompCand& best) {\n        if (r - l < minSize) return;\n\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        for (int idx = l; idx < r; idx++) {\n            int p = entries[idx];\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            mark[p] = mt;\n            qmap[p] = id(qx, qy, qz);\n        }\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(r - l);\n        comp.reserve(r - l);\n\n        int curDef = currentDeficit();\n\n        for (int idx = l; idx < r; idx++) {\n            int st = entries[idx];\n            if (vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            if (sz < minSize) continue;\n\n            int token = ++pixToken;\n            int nf0[15] = {}, nr0[15] = {}, nf1[15] = {}, nr1[15] = {};\n            int cov0 = 0, cov1 = 0;\n\n            auto addPixel = [&](int s, int v, int* nf, int* nr, int& cov) {\n                int z = zs[v], x = xs[v], y = ys[v];\n                int fid = z * D + x;\n                int rid = z * D + y;\n                if (F[s][z][x] == '1' && !covF[s][fid] && tmpF[s][fid] != token) {\n                    tmpF[s][fid] = token;\n                    nf[z]++;\n                    cov++;\n                }\n                if (Rt[s][z][y] == '1' && !covR[s][rid] && tmpR[s][rid] != token) {\n                    tmpR[s][rid] = token;\n                    nr[z]++;\n                    cov++;\n                }\n            };\n\n            for (int v : comp) {\n                addPixel(0, v, nf0, nr0, cov0);\n                addPixel(1, qmap[v], nf1, nr1, cov1);\n            }\n\n            int cov = cov0 + cov1;\n            if (cov == 0) continue;\n\n            int lb0 = calcLBAfter(0, nf0, nr0);\n            int lb1 = calcLBAfter(1, nf1, nr1);\n            int newNeed = max(lb0, lb1);\n            int gainNeed = max(0, oldNeed - newNeed);\n            int cap = min(remCnt[0], remCnt[1]) - sz;\n            int def = max(0, newNeed - cap);\n            int incDef = max(0, def - curDef);\n\n            double score =\n                10.0 * gainNeed\n                + 1.0 * cov\n                + 0.7 * log((double)sz + 1.0)\n                + 0.3 * (1.0 - 1.0 / sz)\n                - 4.0 * incDef\n                + 0.0001 * sz;\n\n            if (!best.valid || score > best.score || (abs(score - best.score) < 1e-9 && sz > best.size)) {\n                best.valid = true;\n                best.score = score;\n                best.size = sz;\n                best.cov = cov;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    CompCand findBestComponentExhaustive(double deadline, int minSize) {\n        CompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (rem[0][v]) list0.push_back(v);\n            if (rem[1][v]) list1.push_back(v);\n        }\n        if ((int)list0.size() < minSize || (int)list1.size() < minSize) return best;\n\n        for (int v : list0) aw[0][v] = (unsigned char)activeWeight(0, v);\n        for (int v : list1) aw[1][v] = (unsigned char)activeWeight(1, v);\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        vector<unsigned char> qaw(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n            qaw[i] = aw[1][v];\n        }\n\n        int oldNeed = max(calcLBNow(0), calcLBNow(1));\n        vector<int> activeTids;\n        activeTids.reserve(Tcnt);\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            if (elapsed() > deadline) break;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            fill(wcnt.begin(), wcnt.end(), 0);\n            activeTids.clear();\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n                int awp = aw[0][p];\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    if (cnt[tid] == 0) activeTids.push_back(tid);\n                    cnt[tid]++;\n                    wcnt[tid] += awp + qaw[j];\n                }\n            }\n\n            int total = 0;\n            for (int tid : activeTids) {\n                startTid[tid] = total;\n                curTid[tid] = total;\n                total += cnt[tid];\n            }\n\n            entries.resize(total);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    entries[curTid[tid]++] = p;\n                }\n            }\n\n            for (int tid : activeTids) {\n                if (wcnt[tid] == 0 || cnt[tid] < minSize) continue;\n                evalBucketAlignment(oi, tid, startTid[tid], startTid[tid] + cnt[tid], minSize, oldNeed, best);\n                if (elapsed() > deadline) break;\n            }\n        }\n\n        return best;\n    }\n\n    void placeCommonMapped(const CompCand& c) {\n        int lab = ++label;\n        int sz = (int)c.cells.size();\n\n        for (int p : c.cells) {\n            I3 rp = rotp[c.ori][p];\n            int qx = rp.x + c.tx;\n            int qy = rp.y + c.ty;\n            int qz = rp.z + c.tz;\n            int q = id(qx, qy, qz);\n\n            ans[0][p] = lab;\n            rem[0][p] = 0;\n            coverCell(0, p);\n\n            ans[1][q] = lab;\n            rem[1][q] = 0;\n            coverCell(1, q);\n        }\n\n        remCnt[0] -= sz;\n        remCnt[1] -= sz;\n        commonVol += sz;\n        commonCost += 1.0 / sz;\n    }\n\n    inline int p3id(int x, int y, int z) const {\n        int P = D + 1;\n        return (x * P + y) * P + z;\n    }\n\n    inline int p2id(int a, int b) const {\n        int P = D + 1;\n        return a * P + b;\n    }\n\n    int query3(const vector<int>& ps, int x0, int x1, int y0, int y1, int z0, int z1) const {\n        return ps[p3id(x1, y1, z1)]\n             - ps[p3id(x0, y1, z1)]\n             - ps[p3id(x1, y0, z1)]\n             - ps[p3id(x1, y1, z0)]\n             + ps[p3id(x0, y0, z1)]\n             + ps[p3id(x0, y1, z0)]\n             + ps[p3id(x1, y0, z0)]\n             - ps[p3id(x0, y0, z0)];\n    }\n\n    int query2(const vector<int>& ps, int a0, int a1, int b0, int b1) const {\n        return ps[p2id(a1, b1)]\n             - ps[p2id(a0, b1)]\n             - ps[p2id(a1, b0)]\n             + ps[p2id(a0, b0)];\n    }\n\n    void buildPrefix3(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P * P, 0);\n        for (int x = 1; x <= D; x++) {\n            for (int y = 1; y <= D; y++) {\n                for (int z = 1; z <= D; z++) {\n                    int val = rem[s][id(x - 1, y - 1, z - 1)] ? 1 : 0;\n                    ps[p3id(x, y, z)] =\n                        val\n                        + ps[p3id(x - 1, y, z)]\n                        + ps[p3id(x, y - 1, z)]\n                        + ps[p3id(x, y, z - 1)]\n                        - ps[p3id(x - 1, y - 1, z)]\n                        - ps[p3id(x - 1, y, z - 1)]\n                        - ps[p3id(x, y - 1, z - 1)]\n                        + ps[p3id(x - 1, y - 1, z - 1)];\n                }\n            }\n        }\n    }\n\n    void buildPrefix2F(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int x = 1; x <= D; x++) {\n                int val = (F[s][z - 1][x - 1] == '1' && !covF[s][(z - 1) * D + (x - 1)]) ? 1 : 0;\n                ps[p2id(z, x)] =\n                    val + ps[p2id(z - 1, x)] + ps[p2id(z, x - 1)] - ps[p2id(z - 1, x - 1)];\n            }\n        }\n    }\n\n    void buildPrefix2R(int s, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P, 0);\n        for (int z = 1; z <= D; z++) {\n            for (int y = 1; y <= D; y++) {\n                int val = (Rt[s][z - 1][y - 1] == '1' && !covR[s][(z - 1) * D + (y - 1)]) ? 1 : 0;\n                ps[p2id(z, y)] =\n                    val + ps[p2id(z - 1, y)] + ps[p2id(z, y - 1)] - ps[p2id(z - 1, y - 1)];\n            }\n        }\n    }\n\n    int shapeKey(int a, int b, int c) const {\n        if (a > b) swap(a, b);\n        if (b > c) swap(b, c);\n        if (a > b) swap(a, b);\n        return (a * 15 + b) * 15 + c;\n    }\n\n    void enumerateBoxesSide(int s, vector<Box>& best, double timeLimit) {\n        vector<int> ps3, psF, psR;\n        buildPrefix3(s, ps3);\n        buildPrefix2F(s, psF);\n        buildPrefix2R(s, psR);\n\n        for (int x0 = 0; x0 < D; x0++) {\n            if (elapsed() > timeLimit) return;\n            for (int x1 = x0 + 1; x1 <= D; x1++) {\n                int lx = x1 - x0;\n                for (int y0 = 0; y0 < D; y0++) {\n                    for (int y1 = y0 + 1; y1 <= D; y1++) {\n                        int ly = y1 - y0;\n                        for (int z0 = 0; z0 < D; z0++) {\n                            for (int z1 = z0 + 1; z1 <= D; z1++) {\n                                int lz = z1 - z0;\n                                int vol = lx * ly * lz;\n                                if (vol < 2) continue;\n\n                                if (query3(ps3, x0, x1, y0, y1, z0, z1) != vol) continue;\n\n                                int cov =\n                                    query2(psF, z0, z1, x0, x1)\n                                    + query2(psR, z0, z1, y0, y1);\n\n                                int key = shapeKey(lx, ly, lz);\n                                if (!best[key].valid || cov > best[key].cov) {\n                                    Box b;\n                                    b.x = x0;\n                                    b.y = y0;\n                                    b.z = z0;\n                                    b.lx = lx;\n                                    b.ly = ly;\n                                    b.lz = lz;\n                                    b.cov = cov;\n                                    b.vol = vol;\n                                    b.valid = true;\n                                    best[key] = b;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    BoxCand findBestCuboid(double timeLimit) {\n        const int KEY = 15 * 15 * 15;\n        vector<Box> best0(KEY), best1(KEY);\n\n        enumerateBoxesSide(0, best0, timeLimit);\n        if (elapsed() > timeLimit) return BoxCand();\n        enumerateBoxesSide(1, best1, timeLimit);\n\n        BoxCand res;\n        for (int k = 0; k < KEY; k++) {\n            if (!best0[k].valid || !best1[k].valid) continue;\n            int cov = best0[k].cov + best1[k].cov;\n            if (cov <= 0) continue;\n            int vol = best0[k].vol;\n            double score = (double)cov * vol;\n            if (!res.valid || score > res.score || (abs(score - res.score) < 1e-9 && vol > res.vol)) {\n                res.valid = true;\n                res.b0 = best0[k];\n                res.b1 = best1[k];\n                res.vol = vol;\n                res.cov = cov;\n                res.score = score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBox(const Box& b0, const Box& b1) {\n        int lab = ++label;\n        int vol = b0.vol;\n\n        auto put = [&](int s, const Box& b) {\n            for (int x = b.x; x < b.x + b.lx; x++) {\n                for (int y = b.y; y < b.y + b.ly; y++) {\n                    for (int z = b.z; z < b.z + b.lz; z++) {\n                        int v = id(x, y, z);\n                        ans[s][v] = lab;\n                        rem[s][v] = 0;\n                        coverCell(s, v);\n                    }\n                }\n            }\n        };\n\n        put(0, b0);\n        put(1, b1);\n\n        remCnt[0] -= vol;\n        remCnt[1] -= vol;\n        commonVol += vol;\n        commonCost += 1.0 / vol;\n    }\n\n    void considerBar(vector<Bar>& best, const Bar& b) {\n        if (b.len < 2 || b.cov <= 0) return;\n        if (!best[b.len].valid || b.cov > best[b.len].cov) best[b.len] = b;\n    }\n\n    void enumerateBarsSide(int s, vector<Bar>& best, double deadline) {\n        for (int z = 0; z < D; z++) {\n            for (int y = 0; y < D; y++) {\n                for (int x0 = 0; x0 < D; x0++) {\n                    if (elapsed() > deadline) return;\n                    if (!rem[s][id(x0, y, z)]) continue;\n                    Bar b;\n                    b.x = x0; b.y = y; b.z = z; b.dir = 0;\n                    b.nf.fill(0); b.nr.fill(0);\n                    int cov = 0;\n                    if (!covR[s][z * D + y]) {\n                        b.nr[z] = 1;\n                        cov++;\n                    }\n                    for (int x = x0; x < D && rem[s][id(x, y, z)]; x++) {\n                        if (!covF[s][z * D + x]) {\n                            b.nf[z]++;\n                            cov++;\n                        }\n                        b.len = x - x0 + 1;\n                        b.cov = cov;\n                        b.valid = true;\n                        considerBar(best, b);\n                    }\n                }\n            }\n        }\n\n        for (int z = 0; z < D; z++) {\n            for (int x = 0; x < D; x++) {\n                for (int y0 = 0; y0 < D; y0++) {\n                    if (elapsed() > deadline) return;\n                    if (!rem[s][id(x, y0, z)]) continue;\n                    Bar b;\n                    b.x = x; b.y = y0; b.z = z; b.dir = 1;\n                    b.nf.fill(0); b.nr.fill(0);\n                    int cov = 0;\n                    if (!covF[s][z * D + x]) {\n                        b.nf[z] = 1;\n                        cov++;\n                    }\n                    for (int y = y0; y < D && rem[s][id(x, y, z)]; y++) {\n                        if (!covR[s][z * D + y]) {\n                            b.nr[z]++;\n                            cov++;\n                        }\n                        b.len = y - y0 + 1;\n                        b.cov = cov;\n                        b.valid = true;\n                        considerBar(best, b);\n                    }\n                }\n            }\n        }\n\n        for (int x = 0; x < D; x++) {\n            for (int y = 0; y < D; y++) {\n                for (int z0 = 0; z0 < D; z0++) {\n                    if (elapsed() > deadline) return;\n                    if (!rem[s][id(x, y, z0)]) continue;\n                    Bar b;\n                    b.x = x; b.y = y; b.z = z0; b.dir = 2;\n                    b.nf.fill(0); b.nr.fill(0);\n                    int cov = 0;\n                    for (int z = z0; z < D && rem[s][id(x, y, z)]; z++) {\n                        if (!covF[s][z * D + x]) {\n                            b.nf[z]++;\n                            cov++;\n                        }\n                        if (!covR[s][z * D + y]) {\n                            b.nr[z]++;\n                            cov++;\n                        }\n                        b.len = z - z0 + 1;\n                        b.cov = cov;\n                        b.valid = true;\n                        considerBar(best, b);\n                    }\n                }\n            }\n        }\n    }\n\n    BarCand findBestBar(double deadline) {\n        vector<Bar> best0(D + 1), best1(D + 1);\n        enumerateBarsSide(0, best0, deadline);\n        if (elapsed() > deadline) return BarCand();\n        enumerateBarsSide(1, best1, deadline);\n\n        BarCand res;\n        int curDef = currentDeficit();\n\n        for (int L = 2; L <= D; L++) {\n            if (!best0[L].valid || !best1[L].valid) continue;\n            int cov = best0[L].cov + best1[L].cov;\n            if (cov <= 0) continue;\n\n            int lb0 = calcLBAfter(0, best0[L].nf.data(), best0[L].nr.data());\n            int lb1 = calcLBAfter(1, best1[L].nf.data(), best1[L].nr.data());\n            int newDef = max(0, max(lb0, lb1) - (min(remCnt[0], remCnt[1]) - L));\n            int incDef = max(0, newDef - curDef);\n\n            double score = (double)cov * L + 0.05 * L;\n            score /= (1.0 + 0.8 * incDef);\n\n            if (!res.valid || score > res.score) {\n                res.valid = true;\n                res.b0 = best0[L];\n                res.b1 = best1[L];\n                res.len = L;\n                res.cov = cov;\n                res.score = score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBar(const Bar& b0, const Bar& b1) {\n        int lab = ++label;\n        int len = b0.len;\n\n        auto put = [&](int s, const Bar& b) {\n            for (int t = 0; t < b.len; t++) {\n                int x = b.x + (b.dir == 0 ? t : 0);\n                int y = b.y + (b.dir == 1 ? t : 0);\n                int z = b.z + (b.dir == 2 ? t : 0);\n                int v = id(x, y, z);\n                ans[s][v] = lab;\n                rem[s][v] = 0;\n                coverCell(s, v);\n            }\n        };\n\n        put(0, b0);\n        put(1, b1);\n\n        remCnt[0] -= len;\n        remCnt[1] -= len;\n        commonVol += len;\n        commonCost += 1.0 / len;\n    }\n\n    int findBestCell(int s, bool needActive) const {\n        int best = -1;\n        int bestW = needActive ? 0 : 100;\n        for (int v = 0; v < N; v++) {\n            if (!rem[s][v]) continue;\n            int w = activeWeight(s, v);\n            if (needActive) {\n                if (w > bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            } else {\n                if (best == -1 || w < bestW) {\n                    bestW = w;\n                    best = v;\n                }\n            }\n        }\n        return best;\n    }\n\n    void placeCommonUnit(int a, int b) {\n        int lab = ++label;\n        ans[0][a] = lab;\n        rem[0][a] = 0;\n        coverCell(0, a);\n\n        ans[1][b] = lab;\n        rem[1][b] = 0;\n        coverCell(1, b);\n\n        remCnt[0]--;\n        remCnt[1]--;\n        commonVol += 1;\n        commonCost += 1.0;\n    }\n\n    bool placeUniqueCell(int s, int v) {\n        if (v < 0 || !rem[s][v]) return false;\n        int lab = ++label;\n        ans[s][v] = lab;\n        rem[s][v] = 0;\n        coverCell(s, v);\n        remCnt[s]--;\n        uniqueVol[s]++;\n        return true;\n    }\n\n    void placeCommonUnits() {\n        while (totalUncov > 0) {\n            int a0 = findBestCell(0, true);\n            int a1 = findBestCell(1, true);\n\n            if (a0 == -1 && a1 == -1) break;\n\n            if (a0 != -1 && a1 != -1) {\n                placeCommonUnit(a0, a1);\n            } else if (a0 != -1) {\n                int b = findBestCell(1, false);\n                if (b == -1) break;\n                placeCommonUnit(a0, b);\n            } else {\n                int a = findBestCell(0, false);\n                if (a == -1) break;\n                placeCommonUnit(a, a1);\n            }\n        }\n    }\n\n    int sideUncovered(int s) const {\n        int res = 0;\n        for (int z = 0; z < D; z++) res += unF[s][z] + unR[s][z];\n        return res;\n    }\n\n    int chooseCell(int s, int z, int x, int y) const {\n        if (x >= 0 && y >= 0) {\n            int v = id(x, y, z);\n            if (rem[s][v]) return v;\n        }\n        if (x >= 0) {\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] == '1') {\n                    int v = id(x, yy, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        if (y >= 0) {\n            for (int xx = 0; xx < D; xx++) {\n                if (F[s][z][xx] == '1') {\n                    int v = id(xx, y, z);\n                    if (rem[s][v]) return v;\n                }\n            }\n        }\n        for (int xx = 0; xx < D; xx++) {\n            if (F[s][z][xx] != '1') continue;\n            for (int yy = 0; yy < D; yy++) {\n                if (Rt[s][z][yy] != '1') continue;\n                int v = id(xx, yy, z);\n                if (rem[s][v]) return v;\n            }\n        }\n        return -1;\n    }\n\n    void fillUnique(int s) {\n        int guard = 0;\n        while (sideUncovered(s) > 0 && guard++ < 1000) {\n            bool progress = false;\n\n            for (int z = 0; z < D; z++) {\n                vector<int> X, Y;\n                for (int x = 0; x < D; x++) {\n                    if (F[s][z][x] == '1' && !covF[s][z * D + x]) X.push_back(x);\n                }\n                for (int y = 0; y < D; y++) {\n                    if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) Y.push_back(y);\n                }\n\n                if (X.empty() && Y.empty()) continue;\n\n                if (!X.empty() && !Y.empty()) {\n                    int m = max((int)X.size(), (int)Y.size());\n                    for (int k = 0; k < m; k++) {\n                        int x = (k < (int)X.size() ? X[k] : X[0]);\n                        int y = (k < (int)Y.size() ? Y[k] : Y[0]);\n                        int v = chooseCell(s, z, x, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else if (!X.empty()) {\n                    for (int x : X) {\n                        int v = chooseCell(s, z, x, -1);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                } else {\n                    for (int y : Y) {\n                        int v = chooseCell(s, z, -1, y);\n                        if (placeUniqueCell(s, v)) progress = true;\n                    }\n                }\n            }\n\n            if (!progress) {\n                int v = findBestCell(s, true);\n                if (!placeUniqueCell(s, v)) break;\n            }\n        }\n    }\n\n    void finalRepair() {\n        for (int s = 0; s < 2; s++) {\n            int guard = 0;\n            while (sideUncovered(s) > 0 && guard++ < 1000) {\n                bool progress = false;\n                for (int z = 0; z < D; z++) {\n                    for (int x = 0; x < D; x++) {\n                        if (F[s][z][x] == '1' && !covF[s][z * D + x]) {\n                            int v = chooseCell(s, z, x, -1);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                    for (int y = 0; y < D; y++) {\n                        if (Rt[s][z][y] == '1' && !covR[s][z * D + y]) {\n                            int v = chooseCell(s, z, -1, y);\n                            if (placeUniqueCell(s, v)) progress = true;\n                        }\n                    }\n                }\n                if (!progress) break;\n            }\n        }\n    }\n\n    void buildBlockLists() {\n        for (int s = 0; s < 2; s++) {\n            blk[s].assign(label + 1, vector<int>());\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0 && a <= label) blk[s][a].push_back(v);\n            }\n        }\n\n        activeLab.assign(label + 1, 0);\n        for (int l = 1; l <= label; l++) {\n            if (!blk[0][l].empty() || !blk[1][l].empty()) activeLab[l] = 1;\n        }\n    }\n\n    bool isCommonLabel(int l) const {\n        return l > 0\n            && l < (int)activeLab.size()\n            && activeLab[l]\n            && !blk[0][l].empty()\n            && !blk[1][l].empty();\n    }\n\n    vector<int> canonicalShape(const vector<int>& cells) const {\n        vector<int> best;\n        bool first = true;\n        vector<array<int, 3>> tmp;\n        vector<int> enc;\n        tmp.reserve(cells.size());\n        enc.reserve(cells.size());\n\n        for (const Rot& rr : rots) {\n            tmp.clear();\n            int mn[3] = {INT_MAX, INT_MAX, INT_MAX};\n\n            for (int v : cells) {\n                int p[3] = {xs[v], ys[v], zs[v]};\n                int q[3];\n                for (int a = 0; a < 3; a++) {\n                    q[a] = rr.sign[a] * p[rr.perm[a]];\n                    mn[a] = min(mn[a], q[a]);\n                }\n                tmp.push_back({q[0], q[1], q[2]});\n            }\n\n            enc.clear();\n            for (auto t : tmp) {\n                int a = t[0] - mn[0];\n                int b = t[1] - mn[1];\n                int c = t[2] - mn[2];\n                enc.push_back((a * 64 + b) * 64 + c);\n            }\n            sort(enc.begin(), enc.end());\n\n            if (first || enc < best) {\n                first = false;\n                best = enc;\n            }\n        }\n\n        return best;\n    }\n\n    void pairUniqueUnits() {\n        vector<int> u0, u1;\n        for (int l = 1; l <= label; l++) {\n            if (!activeLab[l]) continue;\n            if (blk[0][l].size() == 1 && blk[1][l].empty()) u0.push_back(l);\n            if (blk[1][l].size() == 1 && blk[0][l].empty()) u1.push_back(l);\n        }\n\n        int m = min((int)u0.size(), (int)u1.size());\n        for (int i = 0; i < m; i++) {\n            int a = u0[i];\n            int b = u1[i];\n            if (!activeLab[a] || !activeLab[b]) continue;\n            if (blk[0][a].size() != 1 || !blk[1][a].empty()) continue;\n            if (blk[1][b].size() != 1 || !blk[0][b].empty()) continue;\n\n            int v = blk[1][b][0];\n            blk[1][a].push_back(v);\n            ans[1][v] = a;\n\n            blk[1][b].clear();\n            activeLab[b] = 0;\n        }\n    }\n\n    bool canMergeCommon(int a, int b) const {\n        if (!isCommonLabel(a) || !isCommonLabel(b)) return false;\n        if (blk[0][a].size() != blk[1][a].size()) return false;\n        if (blk[0][b].size() != blk[1][b].size()) return false;\n\n        vector<int> u0, u1;\n        u0.reserve(blk[0][a].size() + blk[0][b].size());\n        u1.reserve(blk[1][a].size() + blk[1][b].size());\n\n        u0.insert(u0.end(), blk[0][a].begin(), blk[0][a].end());\n        u0.insert(u0.end(), blk[0][b].begin(), blk[0][b].end());\n        u1.insert(u1.end(), blk[1][a].begin(), blk[1][a].end());\n        u1.insert(u1.end(), blk[1][b].begin(), blk[1][b].end());\n\n        if (u0.size() != u1.size()) return false;\n        return canonicalShape(u0) == canonicalShape(u1);\n    }\n\n    void mergeCommonLabels(int a, int b) {\n        if ((int)blk[0][a].size() < (int)blk[0][b].size()) swap(a, b);\n\n        for (int s = 0; s < 2; s++) {\n            for (int v : blk[s][b]) {\n                ans[s][v] = a;\n                blk[s][a].push_back(v);\n            }\n            blk[s][b].clear();\n        }\n        activeLab[b] = 0;\n    }\n\n    void postMergeCommon(double deadline) {\n        while (elapsed() < deadline) {\n            unordered_map<long long, int> flags;\n            flags.reserve(N * 4 + 10);\n\n            for (int s = 0; s < 2; s++) {\n                for (int v = 0; v < N; v++) {\n                    int a = ans[s][v];\n                    if (!isCommonLabel(a)) continue;\n\n                    for (int dir : {1, 3, 5}) {\n                        int nb = neigh[v][dir];\n                        if (nb < 0) continue;\n                        int b = ans[s][nb];\n                        if (a == b || !isCommonLabel(b)) continue;\n                        int x = a, y = b;\n                        if (x > y) swap(x, y);\n                        long long key = ((long long)x << 32) | (unsigned int)y;\n                        flags[key] |= (1 << s);\n                    }\n                }\n            }\n\n            int bestA = -1, bestB = -1;\n            double bestSave = 1e-12;\n            int bestVol = -1;\n\n            for (auto& kv : flags) {\n                if (elapsed() > deadline) return;\n                if (kv.second != 3) continue;\n\n                long long key = kv.first;\n                int a = (int)(key >> 32);\n                int b = (int)(key & 0xffffffffLL);\n                if (!isCommonLabel(a) || !isCommonLabel(b)) continue;\n\n                int va = (int)blk[0][a].size();\n                int vb = (int)blk[0][b].size();\n                if (va <= 0 || vb <= 0) continue;\n\n                double save = 1.0 / va + 1.0 / vb - 1.0 / (va + vb);\n                if (save + 1e-12 < bestSave) continue;\n\n                if (!canMergeCommon(a, b)) continue;\n\n                int vol = va + vb;\n                if (save > bestSave + 1e-12 || vol > bestVol) {\n                    bestSave = save;\n                    bestVol = vol;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n\n            if (bestA == -1) break;\n            mergeCommonLabels(bestA, bestB);\n        }\n    }\n\n    void postProcess(double deadline) {\n        buildBlockLists();\n        pairUniqueUnits();\n        if (elapsed() < deadline) {\n            postMergeCommon(deadline);\n        }\n    }\n\n    double computeScoreForAns(const array<vector<int>, 2>& A, int maxLab) const {\n        vector<int> c0(maxLab + 1, 0), c1(maxLab + 1, 0);\n        for (int v = 0; v < N; v++) {\n            if (A[0][v] > 0 && A[0][v] <= maxLab) c0[A[0][v]]++;\n            if (A[1][v] > 0 && A[1][v] <= maxLab) c1[A[1][v]]++;\n        }\n        double sc = 0.0;\n        for (int l = 1; l <= maxLab; l++) {\n            if (c0[l] && c1[l]) sc += 1.0 / max(1, c0[l]);\n            else if (c0[l]) sc += c0[l];\n            else if (c1[l]) sc += c1[l];\n        }\n        return sc;\n    }\n\n    void buildPrefix3Mask(const vector<char>& mask, vector<int>& ps) {\n        int P = D + 1;\n        ps.assign(P * P * P, 0);\n        for (int x = 1; x <= D; x++) {\n            for (int y = 1; y <= D; y++) {\n                for (int z = 1; z <= D; z++) {\n                    int val = mask[id(x - 1, y - 1, z - 1)] ? 1 : 0;\n                    ps[p3id(x, y, z)] =\n                        val\n                        + ps[p3id(x - 1, y, z)]\n                        + ps[p3id(x, y - 1, z)]\n                        + ps[p3id(x, y, z - 1)]\n                        - ps[p3id(x - 1, y - 1, z)]\n                        - ps[p3id(x - 1, y, z - 1)]\n                        - ps[p3id(x, y - 1, z - 1)]\n                        + ps[p3id(x - 1, y - 1, z - 1)];\n                }\n            }\n        }\n    }\n\n    void enumeratePoolBoxesSide(const vector<char>& pool, vector<SimpleBox>& best, double deadline) {\n        vector<int> ps;\n        buildPrefix3Mask(pool, ps);\n\n        for (int x0 = 0; x0 < D; x0++) {\n            if (elapsed() > deadline) return;\n            for (int x1 = x0 + 1; x1 <= D; x1++) {\n                int lx = x1 - x0;\n                for (int y0 = 0; y0 < D; y0++) {\n                    for (int y1 = y0 + 1; y1 <= D; y1++) {\n                        int ly = y1 - y0;\n                        for (int z0 = 0; z0 < D; z0++) {\n                            for (int z1 = z0 + 1; z1 <= D; z1++) {\n                                int lz = z1 - z0;\n                                int vol = lx * ly * lz;\n                                if (vol < 2) continue;\n                                if (query3(ps, x0, x1, y0, y1, z0, z1) != vol) continue;\n\n                                int key = shapeKey(lx, ly, lz);\n                                if (!best[key].valid || vol > best[key].vol) {\n                                    SimpleBox b;\n                                    b.x = x0; b.y = y0; b.z = z0;\n                                    b.lx = lx; b.ly = ly; b.lz = lz;\n                                    b.vol = vol;\n                                    b.valid = true;\n                                    best[key] = b;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    PoolBoxCand findBestPoolCuboid(array<vector<char>, 2>& pool, double deadline) {\n        const int KEY = 15 * 15 * 15;\n        vector<SimpleBox> best0(KEY), best1(KEY);\n\n        enumeratePoolBoxesSide(pool[0], best0, deadline);\n        if (elapsed() > deadline) return PoolBoxCand();\n        enumeratePoolBoxesSide(pool[1], best1, deadline);\n\n        PoolBoxCand res;\n        for (int k = 0; k < KEY; k++) {\n            if (!best0[k].valid || !best1[k].valid) continue;\n            int vol = best0[k].vol;\n            if (!res.valid || vol > res.vol) {\n                res.valid = true;\n                res.b0 = best0[k];\n                res.b1 = best1[k];\n                res.vol = vol;\n            }\n        }\n        return res;\n    }\n\n    void postRepartitionSmall(int freezeMin, double deadline) {\n        if (elapsed() > deadline) return;\n\n        array<vector<int>, 2> oldAns = ans;\n        int oldLabel = label;\n        double oldScore = computeScoreForAns(oldAns, oldLabel);\n\n        array<vector<vector<int>>, 2> cells;\n        cells[0].assign(label + 1, vector<int>());\n        cells[1].assign(label + 1, vector<int>());\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0 && a <= label) cells[s][a].push_back(v);\n            }\n        }\n\n        array<vector<int>, 2> newAns;\n        newAns[0].assign(N, 0);\n        newAns[1].assign(N, 0);\n\n        array<vector<char>, 2> pool;\n        pool[0].assign(N, 0);\n        pool[1].assign(N, 0);\n\n        int newLabel = 0;\n\n        for (int l = 1; l <= label; l++) {\n            int c0 = cells[0][l].size();\n            int c1 = cells[1][l].size();\n\n            bool freeze = (c0 > 0 && c1 > 0 && c0 == c1 && c0 >= freezeMin);\n\n            if (freeze) {\n                int nl = ++newLabel;\n                for (int s = 0; s < 2; s++) {\n                    for (int v : cells[s][l]) newAns[s][v] = nl;\n                }\n            } else {\n                for (int s = 0; s < 2; s++) {\n                    for (int v : cells[s][l]) pool[s][v] = 1;\n                }\n            }\n        }\n\n        while (elapsed() < deadline) {\n            PoolBoxCand pc = findBestPoolCuboid(pool, deadline);\n            if (!pc.valid || pc.vol < 2) break;\n\n            int nl = ++newLabel;\n\n            auto put = [&](int s, const SimpleBox& b) {\n                for (int x = b.x; x < b.x + b.lx; x++) {\n                    for (int y = b.y; y < b.y + b.ly; y++) {\n                        for (int z = b.z; z < b.z + b.lz; z++) {\n                            int v = id(x, y, z);\n                            newAns[s][v] = nl;\n                            pool[s][v] = 0;\n                        }\n                    }\n                }\n            };\n\n            put(0, pc.b0);\n            put(1, pc.b1);\n        }\n\n        vector<int> rest0, rest1;\n        for (int v = 0; v < N; v++) {\n            if (pool[0][v]) rest0.push_back(v);\n            if (pool[1][v]) rest1.push_back(v);\n        }\n\n        int m = min((int)rest0.size(), (int)rest1.size());\n        for (int i = 0; i < m; i++) {\n            int nl = ++newLabel;\n            newAns[0][rest0[i]] = nl;\n            newAns[1][rest1[i]] = nl;\n        }\n        for (int i = m; i < (int)rest0.size(); i++) {\n            int nl = ++newLabel;\n            newAns[0][rest0[i]] = nl;\n        }\n        for (int i = m; i < (int)rest1.size(); i++) {\n            int nl = ++newLabel;\n            newAns[1][rest1[i]] = nl;\n        }\n\n        double newScore = computeScoreForAns(newAns, newLabel);\n\n        if (newScore + 1e-12 < oldScore) {\n            ans = std::move(newAns);\n            label = newLabel;\n        } else {\n            ans = std::move(oldAns);\n            label = oldLabel;\n        }\n    }\n\n    void evalAvailBucket(\n        int ori,\n        int tid,\n        int l,\n        int r,\n        int minSize,\n        const array<vector<char>, 2>& core,\n        int coreCnt0,\n        int coreCnt1,\n        PoolCompCand& best\n    ) {\n        if (r - l < minSize) return;\n\n        int tx, ty, tz;\n        decodeTid(tid, tx, ty, tz);\n\n        int mt = ++markToken;\n        for (int idx = l; idx < r; idx++) {\n            int p = entries[idx];\n            I3 rp = rotp[ori][p];\n            int qx = rp.x + tx;\n            int qy = rp.y + ty;\n            int qz = rp.z + tz;\n            mark[p] = mt;\n            qmap[p] = id(qx, qy, qz);\n        }\n\n        int vt = ++visToken;\n        vector<int> que;\n        vector<int> comp;\n        que.reserve(r - l);\n        comp.reserve(r - l);\n\n        int beforeUnit = max(coreCnt0, coreCnt1);\n\n        for (int idx = l; idx < r; idx++) {\n            int st = entries[idx];\n            if (vis[st] == vt) continue;\n\n            que.clear();\n            comp.clear();\n            que.push_back(st);\n            vis[st] = vt;\n\n            for (int head = 0; head < (int)que.size(); head++) {\n                int v = que[head];\n                comp.push_back(v);\n                for (int nb : neigh[v]) {\n                    if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                        vis[nb] = vt;\n                        que.push_back(nb);\n                    }\n                }\n            }\n\n            int sz = (int)comp.size();\n            if (sz < minSize) continue;\n\n            int c0 = 0, c1 = 0;\n            for (int v : comp) {\n                if (core[0][v]) c0++;\n                int q = qmap[v];\n                if (core[1][q]) c1++;\n            }\n\n            if (c0 + c1 == 0) continue;\n\n            int afterUnit = max(coreCnt0 - c0, coreCnt1 - c1);\n            double gain = (double)(beforeUnit - afterUnit) - 1.0 / sz;\n            if (gain <= 1e-10) continue;\n\n            if (!best.valid\n                || gain > best.gain + 1e-12\n                || (abs(gain - best.gain) < 1e-12 && sz > best.size)) {\n                best.valid = true;\n                best.gain = gain;\n                best.size = sz;\n                best.core0 = c0;\n                best.core1 = c1;\n                best.ori = ori;\n                best.tx = tx;\n                best.ty = ty;\n                best.tz = tz;\n                best.cells = comp;\n            }\n        }\n    }\n\n    PoolCompCand findBestAvailComponent(\n        const array<vector<char>, 2>& avail,\n        const array<vector<char>, 2>& core,\n        int coreCnt0,\n        int coreCnt1,\n        double deadline,\n        int minSize\n    ) {\n        PoolCompCand best;\n\n        vector<int> list0, list1;\n        list0.reserve(N);\n        list1.reserve(N);\n        for (int v = 0; v < N; v++) {\n            if (avail[0][v]) list0.push_back(v);\n            if (avail[1][v]) list1.push_back(v);\n        }\n\n        if ((int)list0.size() < minSize || (int)list1.size() < minSize) return best;\n\n        int n1 = (int)list1.size();\n        vector<short> qx(n1), qy(n1), qz(n1);\n        for (int i = 0; i < n1; i++) {\n            int v = list1[i];\n            qx[i] = xs[v];\n            qy[i] = ys[v];\n            qz[i] = zs[v];\n        }\n\n        vector<int> activeTids;\n        activeTids.reserve(Tcnt);\n\n        for (int oi = 0; oi < (int)rots.size(); oi++) {\n            if (elapsed() > deadline) break;\n\n            fill(cnt.begin(), cnt.end(), 0);\n            activeTids.clear();\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    if (cnt[tid] == 0) activeTids.push_back(tid);\n                    cnt[tid]++;\n                }\n            }\n\n            int total = 0;\n            for (int tid : activeTids) {\n                startTid[tid] = total;\n                curTid[tid] = total;\n                total += cnt[tid];\n            }\n\n            entries.resize(total);\n\n            for (int p : list0) {\n                I3 rp = rotp[oi][p];\n                int bx = offsetT - rp.x;\n                int by = offsetT - rp.y;\n                int bz = offsetT - rp.z;\n\n                for (int j = 0; j < n1; j++) {\n                    int txi = qx[j] + bx;\n                    int tyi = qy[j] + by;\n                    int tzi = qz[j] + bz;\n                    int tid = (txi * rangeT + tyi) * rangeT + tzi;\n                    entries[curTid[tid]++] = p;\n                }\n            }\n\n            for (int tid : activeTids) {\n                if (cnt[tid] < minSize) continue;\n                evalAvailBucket(\n                    oi,\n                    tid,\n                    startTid[tid],\n                    startTid[tid] + cnt[tid],\n                    minSize,\n                    core,\n                    coreCnt0,\n                    coreCnt1,\n                    best\n                );\n                if (elapsed() > deadline) break;\n            }\n        }\n\n        return best;\n    }\n\n    void postRepartitionExpanded(int freezeMin, double deadline) {\n        if (elapsed() > deadline) return;\n\n        array<vector<int>, 2> oldAns = ans;\n        int oldLabel = label;\n        double oldScore = computeScoreForAns(oldAns, oldLabel);\n\n        array<vector<vector<int>>, 2> cells;\n        cells[0].assign(label + 1, vector<int>());\n        cells[1].assign(label + 1, vector<int>());\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0 && a <= label) cells[s][a].push_back(v);\n            }\n        }\n\n        array<vector<int>, 2> newAns;\n        newAns[0].assign(N, 0);\n        newAns[1].assign(N, 0);\n\n        array<vector<char>, 2> core, avail;\n        for (int s = 0; s < 2; s++) {\n            core[s].assign(N, 0);\n            avail[s].assign(N, 0);\n        }\n\n        int newLabel = 0;\n        int coreCnt[2] = {0, 0};\n\n        for (int l = 1; l <= label; l++) {\n            int c0 = (int)cells[0][l].size();\n            int c1 = (int)cells[1][l].size();\n\n            bool freeze = (c0 > 0 && c1 > 0 && c0 == c1 && c0 >= freezeMin);\n\n            if (freeze) {\n                int nl = ++newLabel;\n                for (int s = 0; s < 2; s++) {\n                    for (int v : cells[s][l]) {\n                        newAns[s][v] = nl;\n                    }\n                }\n            } else {\n                for (int s = 0; s < 2; s++) {\n                    for (int v : cells[s][l]) {\n                        if (!core[s][v]) {\n                            core[s][v] = 1;\n                            coreCnt[s]++;\n                        }\n                    }\n                }\n            }\n        }\n\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                if (core[s][v]) {\n                    avail[s][v] = 1;\n                } else if (newAns[s][v] == 0 && allowed[s][v]) {\n                    avail[s][v] = 1;\n                }\n            }\n        }\n\n        int iter = 0;\n        while (elapsed() < deadline && (coreCnt[0] + coreCnt[1] > 0) && iter++ < 300) {\n            PoolCompCand pc = findBestAvailComponent(avail, core, coreCnt[0], coreCnt[1], deadline, 2);\n            if (!pc.valid || pc.gain <= 1e-10 || pc.size < 2) break;\n\n            int nl = ++newLabel;\n\n            for (int p : pc.cells) {\n                I3 rp = rotp[pc.ori][p];\n                int qx = rp.x + pc.tx;\n                int qy = rp.y + pc.ty;\n                int qz = rp.z + pc.tz;\n                int q = id(qx, qy, qz);\n\n                newAns[0][p] = nl;\n                avail[0][p] = 0;\n                if (core[0][p]) {\n                    core[0][p] = 0;\n                    coreCnt[0]--;\n                }\n\n                newAns[1][q] = nl;\n                avail[1][q] = 0;\n                if (core[1][q]) {\n                    core[1][q] = 0;\n                    coreCnt[1]--;\n                }\n            }\n        }\n\n        vector<int> rest0, rest1;\n        for (int v = 0; v < N; v++) {\n            if (core[0][v]) rest0.push_back(v);\n            if (core[1][v]) rest1.push_back(v);\n        }\n\n        int m = min((int)rest0.size(), (int)rest1.size());\n        for (int i = 0; i < m; i++) {\n            int nl = ++newLabel;\n            newAns[0][rest0[i]] = nl;\n            newAns[1][rest1[i]] = nl;\n        }\n        for (int i = m; i < (int)rest0.size(); i++) {\n            int nl = ++newLabel;\n            newAns[0][rest0[i]] = nl;\n        }\n        for (int i = m; i < (int)rest1.size(); i++) {\n            int nl = ++newLabel;\n            newAns[1][rest1[i]] = nl;\n        }\n\n        double newScore = computeScoreForAns(newAns, newLabel);\n\n        if (newScore + 1e-12 < oldScore) {\n            ans = std::move(newAns);\n            label = newLabel;\n        } else {\n            ans = std::move(oldAns);\n            label = oldLabel;\n        }\n    }\n\n    Transform findLabelTransform(int l) {\n        Transform none;\n        if (!isCommonLabel(l)) return none;\n        if (blk[0][l].size() != blk[1][l].size()) return none;\n        if (blk[0][l].empty()) return none;\n\n        for (int ri = 0; ri < (int)rots.size(); ri++) {\n            int mnR[3] = {INT_MAX, INT_MAX, INT_MAX};\n            int mnQ[3] = {INT_MAX, INT_MAX, INT_MAX};\n\n            for (int p : blk[0][l]) {\n                I3 rp = rotp[ri][p];\n                mnR[0] = min<int>(mnR[0], rp.x);\n                mnR[1] = min<int>(mnR[1], rp.y);\n                mnR[2] = min<int>(mnR[2], rp.z);\n            }\n            for (int q : blk[1][l]) {\n                mnQ[0] = min(mnQ[0], xs[q]);\n                mnQ[1] = min(mnQ[1], ys[q]);\n                mnQ[2] = min(mnQ[2], zs[q]);\n            }\n\n            int tx = mnQ[0] - mnR[0];\n            int ty = mnQ[1] - mnR[1];\n            int tz = mnQ[2] - mnR[2];\n\n            bool ok = true;\n            for (int p : blk[0][l]) {\n                I3 rp = rotp[ri][p];\n                int qx = rp.x + tx;\n                int qy = rp.y + ty;\n                int qz = rp.z + tz;\n                if (!(0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D)) {\n                    ok = false;\n                    break;\n                }\n                int q = id(qx, qy, qz);\n                if (ans[1][q] != l) {\n                    ok = false;\n                    break;\n                }\n            }\n\n            if (ok) {\n                Transform tr;\n                tr.valid = true;\n                tr.ori = ri;\n                tr.tx = tx;\n                tr.ty = ty;\n                tr.tz = tz;\n                return tr;\n            }\n        }\n\n        return none;\n    }\n\n    vector<Transform> findAllLabelTransforms(int l) {\n        vector<Transform> res;\n        if (!isCommonLabel(l)) return res;\n        if (blk[0][l].size() != blk[1][l].size()) return res;\n        if (blk[0][l].empty()) return res;\n\n        unordered_set<long long> seen;\n\n        for (int ri = 0; ri < (int)rots.size(); ri++) {\n            int mnR[3] = {INT_MAX, INT_MAX, INT_MAX};\n            int mnQ[3] = {INT_MAX, INT_MAX, INT_MAX};\n\n            for (int p : blk[0][l]) {\n                I3 rp = rotp[ri][p];\n                mnR[0] = min<int>(mnR[0], rp.x);\n                mnR[1] = min<int>(mnR[1], rp.y);\n                mnR[2] = min<int>(mnR[2], rp.z);\n            }\n            for (int q : blk[1][l]) {\n                mnQ[0] = min(mnQ[0], xs[q]);\n                mnQ[1] = min(mnQ[1], ys[q]);\n                mnQ[2] = min(mnQ[2], zs[q]);\n            }\n\n            int tx = mnQ[0] - mnR[0];\n            int ty = mnQ[1] - mnR[1];\n            int tz = mnQ[2] - mnR[2];\n\n            bool ok = true;\n            for (int p : blk[0][l]) {\n                I3 rp = rotp[ri][p];\n                int qx = rp.x + tx;\n                int qy = rp.y + ty;\n                int qz = rp.z + tz;\n                if (!(0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D)) {\n                    ok = false;\n                    break;\n                }\n                int q = id(qx, qy, qz);\n                if (ans[1][q] != l) {\n                    ok = false;\n                    break;\n                }\n            }\n\n            if (!ok) continue;\n\n            long long key = (((long long)ri * 100 + (tx + 50)) * 100 + (ty + 50)) * 100 + (tz + 50);\n            if (seen.insert(key).second) {\n                Transform tr;\n                tr.valid = true;\n                tr.ori = ri;\n                tr.tx = tx;\n                tr.ty = ty;\n                tr.tz = tz;\n                res.push_back(tr);\n            }\n        }\n\n        return res;\n    }\n\n    bool mapCellByTransform(int p, const Transform& tr, int& q) const {\n        I3 rp = rotp[tr.ori][p];\n        int qx = rp.x + tr.tx;\n        int qy = rp.y + tr.ty;\n        int qz = rp.z + tr.tz;\n        if (!(0 <= qx && qx < D && 0 <= qy && qy < D && 0 <= qz && qz < D)) return false;\n        q = id(qx, qy, qz);\n        return true;\n    }\n\n    bool adjacentToLabel(int s, int v, int l) const {\n        for (int nb : neigh[v]) {\n            if (nb >= 0 && ans[s][nb] == l) return true;\n        }\n        return false;\n    }\n\n    void expandCommonBlocks(double deadline) {\n        if (elapsed() > deadline) return;\n\n        array<vector<int>, 2> oldAns = ans;\n        int oldLabel = label;\n        double oldScore = computeScoreForAns(ans, label);\n\n        buildBlockLists();\n\n        vector<int> labs;\n        for (int l = 1; l <= label; l++) {\n            if (isCommonLabel(l) && blk[0][l].size() == blk[1][l].size()) labs.push_back(l);\n        }\n\n        sort(labs.begin(), labs.end(), [&](int a, int b) {\n            return blk[0][a].size() < blk[0][b].size();\n        });\n\n        for (int l : labs) {\n            if (elapsed() > deadline) break;\n            if (!isCommonLabel(l)) continue;\n            Transform tr = findLabelTransform(l);\n            if (!tr.valid) continue;\n\n            bool progress = true;\n            int loop = 0;\n            while (progress && elapsed() < deadline && loop++ < N) {\n                progress = false;\n                for (int p = 0; p < N; p++) {\n                    if (ans[0][p] != 0 || !allowed[0][p]) continue;\n                    if (!adjacentToLabel(0, p, l)) continue;\n\n                    int q;\n                    if (!mapCellByTransform(p, tr, q)) continue;\n                    if (ans[1][q] != 0 || !allowed[1][q]) continue;\n                    if (!adjacentToLabel(1, q, l)) continue;\n\n                    ans[0][p] = l;\n                    ans[1][q] = l;\n                    blk[0][l].push_back(p);\n                    blk[1][l].push_back(q);\n                    progress = true;\n                }\n            }\n        }\n\n        double newScore = computeScoreForAns(ans, label);\n        if (newScore > oldScore + 1e-12) {\n            ans = std::move(oldAns);\n            label = oldLabel;\n        }\n    }\n\n    void expandCommonBlocksBest(double deadline) {\n        if (elapsed() > deadline) return;\n\n        array<vector<int>, 2> oldAns = ans;\n        int oldLabel = label;\n        double oldScore = computeScoreForAns(ans, label);\n\n        buildBlockLists();\n\n        vector<int> labs;\n        for (int l = 1; l <= label; l++) {\n            if (isCommonLabel(l) && blk[0][l].size() == blk[1][l].size()) labs.push_back(l);\n        }\n\n        sort(labs.begin(), labs.end(), [&](int a, int b) {\n            return blk[0][a].size() < blk[0][b].size();\n        });\n\n        vector<int> que, comp;\n\n        for (int l : labs) {\n            if (elapsed() > deadline) break;\n            if (!isCommonLabel(l)) continue;\n\n            vector<Transform> trs = findAllLabelTransforms(l);\n            if (trs.empty()) continue;\n\n            vector<int> bestCells;\n            Transform bestTr;\n\n            for (const Transform& tr : trs) {\n                if (elapsed() > deadline) break;\n\n                int mt = ++markToken;\n                int vt = ++visToken;\n                que.clear();\n                comp.clear();\n\n                for (int p = 0; p < N; p++) {\n                    if (ans[0][p] != 0 || !allowed[0][p]) continue;\n                    int q;\n                    if (!mapCellByTransform(p, tr, q)) continue;\n                    if (ans[1][q] != 0 || !allowed[1][q]) continue;\n\n                    mark[p] = mt;\n\n                    bool frontier = false;\n                    for (int nb : neigh[p]) {\n                        if (nb >= 0 && ans[0][nb] == l) {\n                            frontier = true;\n                            break;\n                        }\n                    }\n                    if (frontier) {\n                        vis[p] = vt;\n                        que.push_back(p);\n                    }\n                }\n\n                for (int head = 0; head < (int)que.size(); head++) {\n                    int v = que[head];\n                    comp.push_back(v);\n                    for (int nb : neigh[v]) {\n                        if (nb >= 0 && mark[nb] == mt && vis[nb] != vt) {\n                            vis[nb] = vt;\n                            que.push_back(nb);\n                        }\n                    }\n                }\n\n                if (comp.size() > bestCells.size()) {\n                    bestCells = comp;\n                    bestTr = tr;\n                }\n            }\n\n            if (bestCells.empty()) continue;\n\n            for (int p : bestCells) {\n                int q;\n                if (!mapCellByTransform(p, bestTr, q)) continue;\n                if (ans[0][p] == 0 && ans[1][q] == 0 && allowed[0][p] && allowed[1][q]) {\n                    ans[0][p] = l;\n                    ans[1][q] = l;\n                    blk[0][l].push_back(p);\n                    blk[1][l].push_back(q);\n                }\n            }\n        }\n\n        double newScore = computeScoreForAns(ans, label);\n        if (newScore > oldScore + 1e-12) {\n            ans = std::move(oldAns);\n            label = oldLabel;\n        }\n    }\n\n    void pruneRedundantBlocks(double deadline) {\n        if (elapsed() > deadline) return;\n\n        buildBlockLists();\n\n        array<vector<int>, 2> cf, cr;\n        for (int s = 0; s < 2; s++) {\n            cf[s].assign(D2, 0);\n            cr[s].assign(D2, 0);\n            for (int v = 0; v < N; v++) {\n                if (ans[s][v] == 0) continue;\n                int z = zs[v], x = xs[v], y = ys[v];\n                cf[s][z * D + x]++;\n                cr[s][z * D + y]++;\n            }\n        }\n\n        auto saving = [&](int l) -> double {\n            int c0 = (int)blk[0][l].size();\n            int c1 = (int)blk[1][l].size();\n            if (c0 && c1) return 1.0 / max(1, c0);\n            return (double)(c0 + c1);\n        };\n\n        auto canRemove = [&](int l) -> bool {\n            if (l <= 0 || l > label || !activeLab[l]) return false;\n\n            array<vector<int>, 2> tf, tr;\n            array<vector<int>, 2> touchF, touchR;\n            for (int s = 0; s < 2; s++) {\n                tf[s].assign(D2, 0);\n                tr[s].assign(D2, 0);\n            }\n\n            for (int s = 0; s < 2; s++) {\n                for (int v : blk[s][l]) {\n                    int z = zs[v], x = xs[v], y = ys[v];\n                    int fid = z * D + x;\n                    int rid = z * D + y;\n                    if (tf[s][fid]++ == 0) touchF[s].push_back(fid);\n                    if (tr[s][rid]++ == 0) touchR[s].push_back(rid);\n                }\n            }\n\n            for (int s = 0; s < 2; s++) {\n                for (int fid : touchF[s]) {\n                    if (cf[s][fid] <= tf[s][fid]) return false;\n                }\n                for (int rid : touchR[s]) {\n                    if (cr[s][rid] <= tr[s][rid]) return false;\n                }\n            }\n\n            return true;\n        };\n\n        while (elapsed() < deadline) {\n            int best = -1;\n            double bestSave = 1e-12;\n\n            for (int l = 1; l <= label; l++) {\n                if (!activeLab[l]) continue;\n                double sv = saving(l);\n                if (sv <= bestSave) continue;\n                if (!canRemove(l)) continue;\n                bestSave = sv;\n                best = l;\n                if (elapsed() > deadline) break;\n            }\n\n            if (best == -1) break;\n\n            for (int s = 0; s < 2; s++) {\n                for (int v : blk[s][best]) {\n                    int z = zs[v], x = xs[v], y = ys[v];\n                    cf[s][z * D + x]--;\n                    cr[s][z * D + y]--;\n                    ans[s][v] = 0;\n                }\n                blk[s][best].clear();\n            }\n            activeLab[best] = 0;\n        }\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        double compDeadline = 2.35;\n        for (int it = 0; it < 12 && totalUncov > 0 && elapsed() < compDeadline; it++) {\n            CompCand c = findBestComponent(90, compDeadline);\n            if (!c.valid || c.size < 3) break;\n            placeCommonMapped(c);\n        }\n\n        double cuboidDeadline = 4.72;\n        for (int it = 0; it < 180 && totalUncov > 0 && elapsed() < cuboidDeadline; it++) {\n            BoxCand b = findBestCuboid(cuboidDeadline);\n            if (!b.valid || b.vol < 2 || b.cov <= 0) break;\n            placeCommonBox(b.b0, b.b1);\n        }\n\n        double exhaustiveDeadline = 5.16;\n        for (int it = 0; it < 50 && totalUncov > 0 && elapsed() < exhaustiveDeadline; it++) {\n            CompCand c = findBestComponentExhaustive(exhaustiveDeadline, 2);\n            if (!c.valid || c.size < 2 || c.score <= 0.0) break;\n            placeCommonMapped(c);\n        }\n\n        double barDeadline = 5.36;\n        for (int it = 0; it < 300 && totalUncov > 0 && elapsed() < barDeadline; it++) {\n            BarCand b = findBestBar(barDeadline);\n            if (!b.valid || b.len < 2 || b.cov <= 0) break;\n            placeCommonBar(b.b0, b.b1);\n        }\n\n        placeCommonUnits();\n        fillUnique(0);\n        fillUnique(1);\n        finalRepair();\n\n        postProcess(5.45);\n\n        postRepartitionSmall(3, 5.58);\n        postRepartitionSmall(6, 5.66);\n        postRepartitionSmall(12, 5.71);\n\n        postRepartitionExpanded(4, 5.76);\n\n        expandCommonBlocks(5.80);\n        expandCommonBlocksBest(5.86);\n\n        postProcess(5.88);\n        pruneRedundantBlocks(5.91);\n    }\n\n    void print() const {\n        vector<int> mp(label + 1, 0);\n        for (int s = 0; s < 2; s++) {\n            for (int v = 0; v < N; v++) {\n                int a = ans[s][v];\n                if (a > 0 && a <= label) mp[a] = 1;\n            }\n        }\n\n        int n = 0;\n        for (int l = 1; l <= label; l++) {\n            if (mp[l]) mp[l] = ++n;\n        }\n\n        cout << n << '\\n';\n        for (int s = 0; s < 2; s++) {\n            for (int i = 0; i < N; i++) {\n                if (i) cout << ' ';\n                int a = ans[s][i];\n                cout << (a == 0 ? 0 : mp[a]);\n            }\n            cout << '\\n';\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin >> D;\n\n    array<vector<string>, 2> F, R;\n    for (int i = 0; i < 2; i++) {\n        F[i].resize(D);\n        R[i].resize(D);\n        for (int z = 0; z < D; z++) cin >> F[i][z];\n        for (int z = 0; z < D; z++) cin >> R[i][z];\n    }\n\n    Solver solver(D, F, R);\n    solver.run();\n    solver.print();\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 105;\nstatic const int MAXM = 305;\nstatic const long long INFLL = (1LL << 62);\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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} gtimer;\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) {\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);\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 Edge {\n    int u, v;\n    long long w;\n};\n\nstruct RK {\n    unsigned short p;\n    int k;\n};\n\nstruct TreeResult {\n    long long cost = INFLL;\n    bitset<MAXM> mask;\n};\n\nstruct Solution {\n    vector<int> P;\n    TreeResult tree;\n    long long radCost = INFLL;\n    long long total = INFLL;\n};\n\nint N, M, K;\nvector<int> X, Y, RA, RB;\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj;\n\nvector<vector<int>> distSq;\nvector<vector<unsigned short>> ceilD;\nvector<RK> coverList[MAXN];\n\nlong long spDist[MAXN][MAXN];\nbitset<MAXM> pathE[MAXN][MAXN];\nbitset<MAXN> pathV[MAXN][MAXN];\n\nvector<int> edgeOrder;\nbitset<MAXM> globalMSTMask;\nbitset<MAXM> allEdgesMask;\n\nint ceil_sqrt_ll(long long v) {\n    int r = (int) sqrt((long double) v);\n    while (1LL * r * r < v) ++r;\n    while (r > 0 && 1LL * (r - 1) * (r - 1) >= v) --r;\n    return r;\n}\n\nlong long calcRadCost(const vector<int>& P) {\n    long long s = 0;\n    for (int p : P) s += 1LL * p * p;\n    return s;\n}\n\nint computeCovered(const vector<int>& P, vector<char>& covered) {\n    covered.assign(K, 0);\n    int rem = K;\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                if (rem == 0) return K;\n            }\n        }\n    }\n    return K - rem;\n}\n\nbool isFull(const vector<int>& P) {\n    vector<char> covered;\n    return computeCovered(P, covered) == K;\n}\n\nvector<char> makeTerminal(const vector<int>& P) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terminal[i] = 1;\n    }\n    return terminal;\n}\n\nvector<int> makeOrder(const vector<int>& P, int mode, const vector<long long>* branch = nullptr) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            double p2 = 1.0 * P[i] * P[i];\n            double rd = (double) spDist[0][i];\n            if (mode == 0) sc = p2;\n            else if (mode == 1) sc = p2 + 0.7 * rd;\n            else if (mode == 2) sc = 0.2 * p2 + rd;\n            else {\n                long long b = (branch ? (*branch)[i] : 0LL);\n                sc = p2 + (double)b;\n            }\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvector<int> makeOrderWeighted(\n    const vector<int>& P,\n    const vector<long long>& branch,\n    double wp,\n    double wb,\n    double wr\n) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            sc = wp * (double)(1LL * P[i] * P[i])\n               + wb * (double)branch[i]\n               + wr * (double)spDist[0][i];\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvector<int> orderWithLast(const vector<int>& P, int mode, int last, const vector<long long>* branch = nullptr) {\n    vector<int> ord = makeOrder(P, mode, branch);\n    auto it = find(ord.begin(), ord.end(), last);\n    if (it != ord.end()) {\n        ord.erase(it);\n        ord.push_back(last);\n    }\n    return ord;\n}\n\nvoid trimP(vector<int>& P, const vector<int>& order) {\n    vector<int> cnt(K, 0);\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            cnt[rk.k]++;\n        }\n    }\n\n    for (int i : order) {\n        if (P[i] <= 0) continue;\n        int old = P[i];\n        int need = 0;\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > old) break;\n            if (cnt[rk.k] == 1) need = max(need, (int)rk.p);\n        }\n        if (need < old) {\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > old) break;\n                if ((int)rk.p > need) cnt[rk.k]--;\n            }\n            P[i] = need;\n        }\n    }\n}\n\nTreeResult reduceMask(const bitset<MAXM>& mask, const vector<char>& terminal) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    int par[MAXN], sz[MAXN], deg[MAXN];\n    for (int i = 0; i < N; ++i) {\n        par[i] = i;\n        sz[i] = 1;\n        deg[i] = 0;\n    }\n\n    auto findp = [&](int x) {\n        while (par[x] != x) {\n            par[x] = par[par[x]];\n            x = par[x];\n        }\n        return x;\n    };\n\n    auto unite = [&](int a, int b) {\n        a = findp(a);\n        b = findp(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        par[b] = a;\n        sz[a] += sz[b];\n        return true;\n    };\n\n    bitset<MAXM> tree;\n    for (int eid : edgeOrder) {\n        if (!mask.test(eid)) continue;\n        int u = edges[eid].u, v = edges[eid].v;\n        if (unite(u, v)) {\n            tree.set(eid);\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n\n    queue<int> q;\n    for (int i = 0; i < N; ++i) {\n        if (!terminal[i] && deg[i] <= 1) q.push(i);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (terminal[v] || deg[v] != 1) continue;\n\n        int remEdge = -1;\n        for (auto [to, eid] : adj[v]) {\n            if (tree.test(eid)) {\n                remEdge = eid;\n                break;\n            }\n        }\n        if (remEdge == -1) {\n            deg[v] = 0;\n            continue;\n        }\n\n        int to = edges[remEdge].u ^ edges[remEdge].v ^ v;\n        tree.reset(remEdge);\n        deg[v]--;\n        deg[to]--;\n        if (!terminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    char vis[MAXN];\n    for (int i = 0; i < N; ++i) vis[i] = 0;\n\n    queue<int> qq;\n    vis[0] = 1;\n    qq.push(0);\n    while (!qq.empty()) {\n        int v = qq.front();\n        qq.pop();\n        for (auto [to, eid] : adj[v]) {\n            if (!tree.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            qq.push(to);\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (terminal[i] && !vis[i]) return res;\n    }\n\n    long long cost = 0;\n    for (int e = 0; e < M; ++e) {\n        if (tree.test(e)) cost += edges[e].w;\n    }\n    res.cost = cost;\n    res.mask = tree;\n    return res;\n}\n\nbitset<MAXM> buildMetricMSTMask(const vector<char>& terminal) {\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) terms.push_back(i);\n    }\n\n    int T = (int)terms.size();\n    bitset<MAXM> mask;\n    if (T <= 1) return mask;\n\n    vector<char> used(T, 0);\n    vector<long long> key(T, INFLL);\n    vector<int> parent(T, -1);\n    key[0] = 0;\n\n    for (int it = 0; it < T; ++it) {\n        int v = -1;\n        long long best = INFLL;\n        for (int i = 0; i < T; ++i) {\n            if (!used[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) {\n            mask |= pathE[terms[v]][terms[parent[v]]];\n        }\n\n        for (int u = 0; u < T; ++u) {\n            if (!used[u] && spDist[terms[v]][terms[u]] < key[u]) {\n                key[u] = spDist[terms[v]][terms[u]];\n                parent[u] = v;\n            }\n        }\n    }\n    return mask;\n}\n\nbitset<MAXM> buildSPTMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) mask |= pathE[0][i];\n    }\n    return mask;\n}\n\nbitset<MAXM> buildGreedyMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(0);\n\n    while (true) {\n        bool any = false;\n        for (int t = 1; t < N; ++t) {\n            if (terminal[t] && !treeV.test(t)) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n        for (int t = 1; t < N; ++t) {\n            if (!terminal[t] || treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult buildBestTree(const vector<int>& P, const bitset<MAXM>* extraMask = nullptr) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    int termCnt = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminal[i] = 1;\n            termCnt++;\n        }\n    }\n\n    TreeResult best;\n    best.cost = INFLL;\n    best.mask.reset();\n\n    if (termCnt <= 1) {\n        best.cost = 0;\n        return best;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    upd(buildMetricMSTMask(terminal));\n    upd(buildSPTMask(terminal));\n    upd(buildGreedyMask(terminal));\n    upd(globalMSTMask);\n\n    if (extraMask) upd(*extraMask);\n\n    return best;\n}\n\nvector<char> getReachable(const bitset<MAXM>& mask) {\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] : adj[v]) {\n            if (!mask.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return vis;\n}\n\nvector<long long> computeBranch(const vector<int>& P, const TreeResult& tr) {\n    vector<char> terminal = makeTerminal(P);\n\n    vector<long long> branch(N, 0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        vector<char> t2 = terminal;\n        t2[i] = 0;\n        t2[0] = 1;\n        TreeResult r = reduceMask(tr.mask, t2);\n        if (r.cost < INFLL / 2) {\n            branch[i] = max(0LL, tr.cost - r.cost);\n        }\n    }\n    return branch;\n}\n\nSolution evaluateSolution(const vector<int>& P, const bitset<MAXM>* extraMask = nullptr) {\n    Solution s;\n    s.P = P;\n    if (!isFull(P)) {\n        s.total = INFLL;\n        return s;\n    }\n    s.radCost = calcRadCost(P);\n    s.tree = buildBestTree(P, extraMask);\n    if (s.tree.cost >= INFLL / 2) {\n        s.total = INFLL;\n    } else {\n        s.total = s.radCost + s.tree.cost;\n    }\n    return s;\n}\n\nbool greedyRepair(\n    vector<int>& P,\n    const vector<char>& allowed,\n    double connWeight,\n    double exponent,\n    const vector<char>* freeVertices = nullptr,\n    double stopTime = 1e100\n) {\n    for (int i = 0; i < N; ++i) {\n        if (!allowed[i]) P[i] = 0;\n        P[i] = min(5000, max(0, P[i]));\n    }\n\n    vector<char> covered;\n    int cov = computeCovered(P, covered);\n    int rem = K - cov;\n    if (rem == 0) return true;\n\n    vector<long long> minConn(N);\n    for (int i = 0; i < N; ++i) minConn[i] = spDist[0][i];\n\n    if (freeVertices) {\n        for (int v = 0; v < N; ++v) {\n            if (!(*freeVertices)[v]) continue;\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][v]);\n            }\n        }\n    }\n\n    for (int t = 0; t < N; ++t) {\n        if (P[t] > 0) {\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][t]);\n            }\n        }\n    }\n\n    vector<double> denom(K + 1, 1.0);\n    if (fabs(exponent - 1.0) < 1e-9) {\n        for (int i = 1; i <= K; ++i) denom[i] = (double)i;\n    } else {\n        for (int i = 1; i <= K; ++i) denom[i] = pow((double)i, exponent);\n    }\n\n    int iter = 0;\n    while (rem > 0) {\n        if ((iter & 7) == 0 && gtimer.elapsed() > stopTime) return false;\n        if (iter > 1000) {\n            for (int k = 0; k < K && rem > 0; ++k) {\n                if (covered[k]) continue;\n                int bestI = -1, bestP = 0;\n                double bestCost = 1e100;\n\n                for (int i = 0; i < N; ++i) {\n                    if (!allowed[i]) continue;\n                    int p = (int)ceilD[i][k];\n                    if (p > 5000) continue;\n                    int old = P[i];\n                    int np = max(old, p);\n                    double act = 0.0;\n                    if (old == 0 && connWeight != 0.0) {\n                        if (freeVertices && (*freeVertices)[i]) act = 0.0;\n                        else act = connWeight * (double)minConn[i];\n                    }\n                    double cost = (double)(1LL * np * np - 1LL * old * old) + act;\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestI = i;\n                        bestP = np;\n                    }\n                }\n\n                if (bestI == -1) return false;\n\n                int old = P[bestI];\n                P[bestI] = bestP;\n                if (old == 0) {\n                    for (int j = 0; j < N; ++j) {\n                        minConn[j] = min(minConn[j], spDist[j][bestI]);\n                    }\n                }\n\n                for (const auto& rk : coverList[bestI]) {\n                    if ((int)rk.p > bestP) break;\n                    if (!covered[rk.k]) {\n                        covered[rk.k] = 1;\n                        --rem;\n                    }\n                }\n\n                if (gtimer.elapsed() > stopTime) return false;\n            }\n            return rem == 0;\n        }\n\n        ++iter;\n\n        double bestScore = 1e100;\n        double bestAbsCost = 1e100;\n        int bestI = -1, bestP = -1, bestCnt = -1;\n\n        for (int i = 0; i < N; ++i) {\n            if (!allowed[i] || P[i] >= 5000 || coverList[i].empty()) continue;\n\n            int old = P[i];\n            double activation = 0.0;\n            if (old == 0 && connWeight != 0.0) {\n                if (freeVertices && (*freeVertices)[i]) activation = 0.0;\n                else activation = connWeight * (double)minConn[i];\n            }\n\n            int cnt = 0;\n            const auto& lst = coverList[i];\n            int idx = 0, sz = (int)lst.size();\n\n            while (idx < sz && (int)lst[idx].p <= old) idx++;\n\n            while (idx < sz) {\n                int p = (int)lst[idx].p;\n                int add = 0;\n                while (idx < sz && (int)lst[idx].p == p) {\n                    if (!covered[lst[idx].k]) add++;\n                    idx++;\n                }\n                if (add == 0) continue;\n\n                cnt += add;\n                double cost = (double)(1LL * p * p - 1LL * old * old) + activation;\n                double score = cost / denom[cnt];\n\n                if (score < bestScore - 1e-12 ||\n                    (fabs(score - bestScore) <= 1e-12 &&\n                     (cost < bestAbsCost || cnt > bestCnt))) {\n                    bestScore = score;\n                    bestAbsCost = cost;\n                    bestI = i;\n                    bestP = p;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestI == -1) return false;\n\n        int old = P[bestI];\n        P[bestI] = bestP;\n\n        int gained = 0;\n        for (const auto& rk : coverList[bestI]) {\n            if ((int)rk.p > bestP) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                gained++;\n            }\n        }\n\n        if (old == 0) {\n            for (int j = 0; j < N; ++j) {\n                minConn[j] = min(minConn[j], spDist[j][bestI]);\n            }\n        }\n\n        if (gained == 0) return false;\n    }\n\n    return true;\n}\n\nvoid computeShortestPaths() {\n    for (int s = 0; s < N; ++s) {\n        vector<long long> dist(N, INFLL);\n        vector<int> parNode(N, -1), parEdge(N, -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n\n        dist[s] = 0;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n\n            for (auto [to, eid] : adj[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parNode[to] = v;\n                    parEdge[to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        for (int t = 0; t < N; ++t) {\n            spDist[s][t] = dist[t];\n            pathE[s][t].reset();\n            pathV[s][t].reset();\n\n            if (dist[t] >= INFLL / 2) continue;\n\n            int cur = t;\n            pathV[s][t].set(cur);\n            while (cur != s) {\n                int e = parEdge[cur];\n                if (e < 0) break;\n                pathE[s][t].set(e);\n                cur = parNode[cur];\n                pathV[s][t].set(cur);\n            }\n        }\n    }\n}\n\nbitset<MAXM> buildGlobalMST() {\n    DSU d(N);\n    bitset<MAXM> m;\n    for (int eid : edgeOrder) {\n        if (d.unite(edges[eid].u, edges[eid].v)) {\n            m.set(eid);\n        }\n    }\n    return m;\n}\n\nvector<int> nearestSolution(double lambda) {\n    vector<int> P(N, 0);\n    for (int k = 0; k < K; ++k) {\n        double best = 1e100;\n        int bi = -1;\n        for (int i = 0; i < N; ++i) {\n            int p = (int)ceilD[i][k];\n            if (p > 5000) continue;\n            double val = (double)distSq[i][k] + lambda * (double)spDist[0][i];\n            if (val < best) {\n                best = val;\n                bi = i;\n            }\n        }\n\n        if (bi == -1) {\n            int bp = INT_MAX;\n            for (int i = 0; i < N; ++i) {\n                if ((int)ceilD[i][k] < bp) {\n                    bp = (int)ceilD[i][k];\n                    bi = i;\n                }\n            }\n        }\n\n        P[bi] = max(P[bi], (int)ceilD[bi][k]);\n    }\n    return P;\n}\n\nvoid considerCandidate(vector<int> P, vector<Solution>& sols, double stopTime) {\n    for (int& p : P) p = min(5000, max(0, p));\n\n    vector<char> allAllowed(N, 1);\n    if (!isFull(P)) {\n        greedyRepair(P, allAllowed, 0.6, 1.0, nullptr, stopTime);\n    }\n    if (!isFull(P)) return;\n\n    auto add = [&](const vector<int>& Q) {\n        Solution s = evaluateSolution(Q);\n        if (s.total < INFLL / 2) sols.push_back(s);\n    };\n\n    add(P);\n\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<int> q = P;\n        trimP(q, makeOrder(q, mode));\n        add(q);\n    }\n\n    vector<int> q = P;\n    trimP(q, makeOrder(q, 1));\n    trimP(q, makeOrder(q, 0));\n    add(q);\n}\n\nSolution localSearch(Solution cur, double deadline) {\n    vector<char> allAllowed(N, 1);\n\n    for (int pass = 0; pass < 6 && gtimer.elapsed() < deadline; ++pass) {\n        cur = evaluateSolution(cur.P);\n        bool improved = false;\n\n        if (gtimer.elapsed() < deadline) {\n            vector<long long> br = computeBranch(cur.P, cur.tree);\n            vector<int> p2 = cur.P;\n            trimP(p2, makeOrder(p2, 3, &br));\n            Solution ns = evaluateSolution(p2);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        if (gtimer.elapsed() < deadline) {\n            vector<char> avail = getReachable(cur.tree.mask);\n            double exps[2] = {1.0, 1.15};\n            for (double ex : exps) {\n                vector<int> p0(N, 0);\n                if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n                trimP(p0, makeOrder(p0, 0));\n                Solution ns = evaluateSolution(p0);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        vector<int> order = makeOrder(cur.P, 3, &br);\n\n        int stationTried = 0;\n        int maxStations = (pass == 0 ? 50 : 30);\n\n        for (int id : order) {\n            if (cur.P[id] <= 0) continue;\n            if (gtimer.elapsed() > deadline) break;\n            if (stationTried++ >= maxStations) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            vector<int> uniqTargets;\n            for (int t : targets) {\n                if (t < 0 || t >= p) continue;\n                bool seen = false;\n                for (int u : uniqTargets) if (u == t) seen = true;\n                if (!seen) uniqTargets.push_back(t);\n            }\n\n            for (int np : uniqTargets) {\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                p2[id] = np;\n\n                double beta = (np == 0 ? 0.8 : 0.4);\n                if (!greedyRepair(p2, allAllowed, beta, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n        if (improved) continue;\n\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            struct CutCand {\n                long long score;\n                int e;\n                vector<int> terms;\n            };\n            vector<CutCand> cuts;\n\n            for (int e = 0; e < M; ++e) {\n                if (!cur.tree.mask.test(e)) continue;\n\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] : adj[v]) {\n                        if (eid == e || !cur.tree.mask.test(eid) || vis[to]) continue;\n                        vis[to] = 1;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> terms;\n                long long p2sum = 0;\n                for (int v = 0; v < N; ++v) {\n                    if (!vis[v] && cur.P[v] > 0) {\n                        terms.push_back(v);\n                        p2sum += 1LL * cur.P[v] * cur.P[v];\n                    }\n                }\n                if (terms.empty()) continue;\n\n                long long branchCost = edges[e].w;\n                for (int ee = 0; ee < M; ++ee) {\n                    if (ee == e || !cur.tree.mask.test(ee)) continue;\n                    int u = edges[ee].u, v = edges[ee].v;\n                    if (!vis[u] && !vis[v]) branchCost += edges[ee].w;\n                }\n\n                cuts.push_back({branchCost + p2sum, e, terms});\n            }\n\n            sort(cuts.begin(), cuts.end(), [](const CutCand& a, const CutCand& b) {\n                return a.score > b.score;\n            });\n\n            int tried = 0;\n            for (const auto& cc : cuts) {\n                if (tried++ >= 8) break;\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                for (int v : cc.terms) p2[v] = 0;\n\n                if (!greedyRepair(p2, allAllowed, 0.9, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            vector<int> top;\n            for (int id : order) {\n                if (cur.P[id] > 0) {\n                    top.push_back(id);\n                    if ((int)top.size() >= 8) break;\n                }\n            }\n\n            for (int a = 0; a < (int)top.size() && !improved; ++a) {\n                for (int b = a + 1; b < (int)top.size(); ++b) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> p2 = cur.P;\n                    p2[top[a]] = 0;\n                    p2[top[b]] = 0;\n\n                    if (!greedyRepair(p2, allAllowed, 0.85, 1.05, nullptr, deadline)) continue;\n\n                    trimP(p2, makeOrder(p2, 1));\n                    trimP(p2, makeOrder(p2, 0));\n\n                    Solution ns = evaluateSolution(p2);\n                    if (ns.total < cur.total) {\n                        cur = ns;\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution fixedTreeReverseDeleteFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        bool improved = false;\n\n        for (int typ = 0; typ < 7 && gtimer.elapsed() < deadline; ++typ) {\n            vector<int> q(N, 0);\n            for (int i = 0; i < N; ++i) {\n                if (avail[i]) q[i] = 5000;\n            }\n\n            if (typ == 0) {\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 1) {\n                trimP(q, makeOrder(q, 1));\n            } else if (typ == 2) {\n                trimP(q, makeOrder(q, 2));\n            } else if (typ == 3) {\n                trimP(q, makeOrder(q, 1));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 4) {\n                trimP(q, makeOrder(q, 2));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 5) {\n                trimP(q, makeOrder(q, 0));\n                trimP(q, makeOrder(q, 1));\n            } else {\n                trimP(q, makeOrder(q, 0));\n                trimP(q, makeOrder(q, 2));\n            }\n\n            Solution ns = evaluateSolution(q, &baseMask);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution optimizeOnReachableFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        bool improved = false;\n        vector<double> exps = {1.0, 1.15, 0.9, 1.3, 0.75};\n\n        for (double ex : exps) {\n            if (gtimer.elapsed() > deadline) break;\n\n            vector<int> p0(N, 0);\n            if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n\n            vector<vector<int>> candP;\n\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 0));\n                candP.push_back(q);\n            }\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 1));\n                candP.push_back(q);\n            }\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 1));\n                trimP(q, makeOrder(q, 0));\n                candP.push_back(q);\n            }\n\n            for (auto& q : candP) {\n                if (gtimer.elapsed() > deadline) break;\n                Solution ns = evaluateSolution(q, &baseMask);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                }\n            }\n\n            if (improved) break;\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution reachableLocalFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n        bool improved = false;\n\n        vector<int> cnt(K, 0), owner(K, -1);\n        for (int i = 0; i < N; ++i) {\n            if (cur.P[i] <= 0) continue;\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > cur.P[i]) break;\n                if (cnt[rk.k] == 0) owner[rk.k] = i;\n                cnt[rk.k]++;\n            }\n        }\n\n        vector<int> critCnt(N, 0);\n        for (int k = 0; k < K; ++k) {\n            if (cnt[k] == 1 && owner[k] >= 0) critCnt[owner[k]]++;\n        }\n\n        struct AddCand {\n            double score;\n            int v, p;\n        };\n        vector<AddCand> adds;\n\n        for (int v = 0; v < N; ++v) {\n            if (!avail[v] || cur.P[v] > 0 || coverList[v].empty()) continue;\n\n            double gain = 0.0;\n            int critical = 0;\n            double bestScore = -1e100;\n            int bestP = 0;\n            double bestRatio = -1e100;\n            int bestPR = 0;\n\n            int idx = 0, sz = (int)coverList[v].size();\n            while (idx < sz) {\n                int p = (int)coverList[v][idx].p;\n                while (idx < sz && (int)coverList[v][idx].p == p) {\n                    int k = coverList[v][idx].k;\n                    if (cnt[k] == 1) {\n                        int o = owner[k];\n                        if (o >= 0 && critCnt[o] > 0) {\n                            gain += (double)(1LL * cur.P[o] * cur.P[o]) / (double)critCnt[o];\n                            critical++;\n                        }\n                    }\n                    idx++;\n                }\n\n                if (critical >= 3) {\n                    double cost = (double)(1LL * p * p);\n                    double score = gain - cost;\n                    double ratio = gain / (cost + 1.0);\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestP = p;\n                    }\n                    if (ratio > bestRatio) {\n                        bestRatio = ratio;\n                        bestPR = p;\n                    }\n                }\n            }\n\n            if (bestP > 0 && bestScore > 0.0) adds.push_back({bestScore, v, bestP});\n            if (bestPR > 0 && bestRatio > 1.15 && bestPR != bestP) {\n                adds.push_back({bestRatio * 1000000.0, v, bestPR});\n            }\n        }\n\n        sort(adds.begin(), adds.end(), [](const AddCand& a, const AddCand& b) {\n            return a.score > b.score;\n        });\n\n        int addTried = 0;\n        for (const auto& c : adds) {\n            if (gtimer.elapsed() > deadline) break;\n            if (addTried++ >= 7) break;\n\n            vector<int> q = cur.P;\n            q[c.v] = max(q[c.v], c.p);\n\n            trimP(q, orderWithLast(q, 0, c.v));\n            trimP(q, orderWithLast(q, 1, c.v));\n\n            Solution ns = evaluateSolution(q, &baseMask);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n                break;\n            }\n        }\n\n        if (improved) continue;\n\n        vector<int> order = makeOrder(cur.P, 1);\n        int delTried = 0;\n\n        for (int id : order) {\n            if (gtimer.elapsed() > deadline) break;\n            if (cur.P[id] <= 0) continue;\n            if (delTried++ >= 7) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            sort(targets.begin(), targets.end());\n            targets.erase(unique(targets.begin(), targets.end()), targets.end());\n\n            for (int t : targets) {\n                if (gtimer.elapsed() > deadline) break;\n                if (t < 0 || t >= p) continue;\n\n                double exps[2] = {1.0, 1.15};\n                for (double ex : exps) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> q = cur.P;\n                    q[id] = t;\n\n                    vector<char> allow2 = avail;\n                    if (t == 0) allow2[id] = 0;\n\n                    if (!greedyRepair(q, allow2, 0.0, ex, nullptr, deadline)) continue;\n\n                    trimP(q, makeOrder(q, 1));\n                    trimP(q, makeOrder(q, 0));\n\n                    Solution ns = evaluateSolution(q, &baseMask);\n                    if (ns.total < cur.total) {\n                        cur = ns;\n                        improved = true;\n                        break;\n                    }\n                }\n                if (improved) break;\n            }\n            if (improved) break;\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution pairReplaceFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        vector<int> cnt(K, 0), owner(K, -1);\n        for (int i = 0; i < N; ++i) {\n            if (cur.P[i] <= 0) continue;\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > cur.P[i]) break;\n                if (cnt[rk.k] == 0) owner[rk.k] = i;\n                cnt[rk.k]++;\n            }\n        }\n\n        vector<vector<int>> uniqueBy(N);\n        for (int k = 0; k < K; ++k) {\n            if (cnt[k] == 1 && owner[k] >= 0) {\n                uniqueBy[owner[k]].push_back(k);\n            }\n        }\n\n        vector<long long> branch = computeBranch(cur.P, cur.tree);\n\n        vector<long long> minConn(N, INFLL);\n        vector<int> nearV(N, 0);\n        for (int v = 0; v < N; ++v) {\n            for (int u = 0; u < N; ++u) {\n                if (!avail[u]) continue;\n                if (spDist[v][u] < minConn[v]) {\n                    minConn[v] = spDist[v][u];\n                    nearV[v] = u;\n                }\n            }\n        }\n\n        struct Cand {\n            double score;\n            int i, j, req;\n        };\n        vector<Cand> cands;\n\n        for (int i = 0; i < N; ++i) {\n            if (cur.P[i] <= 0 || uniqueBy[i].empty()) continue;\n\n            for (int j = 0; j < N; ++j) {\n                if (i == j || coverList[j].empty()) continue;\n\n                int req = cur.P[j];\n                bool ok = true;\n                for (int k : uniqueBy[i]) {\n                    int d = (int)ceilD[j][k];\n                    if (d > 5000) {\n                        ok = false;\n                        break;\n                    }\n                    req = max(req, d);\n                }\n                if (!ok || req > 5000) continue;\n\n                double conn = 0.0;\n                if (cur.P[j] == 0 && !avail[j]) conn = 0.85 * (double)minConn[j];\n\n                double delta =\n                    (double)(1LL * req * req - 1LL * cur.P[j] * cur.P[j])\n                    - (double)(1LL * cur.P[i] * cur.P[i])\n                    - (double)branch[i]\n                    + conn;\n\n                if (delta < 2.0e6) {\n                    cands.push_back({delta, i, j, req});\n                }\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        bool improved = false;\n        int tried = 0;\n\n        for (const auto& c : cands) {\n            if (gtimer.elapsed() > deadline) break;\n            if (tried++ >= 14) break;\n\n            vector<int> q = cur.P;\n            q[c.i] = 0;\n            q[c.j] = max(q[c.j], c.req);\n\n            trimP(q, orderWithLast(q, 0, c.j));\n            trimP(q, orderWithLast(q, 1, c.j));\n\n            bitset<MAXM> extra = baseMask;\n            if (q[c.j] > 0 && !avail[c.j]) {\n                extra |= pathE[c.j][nearV[c.j]];\n            }\n\n            Solution ns = evaluateSolution(q, &extra);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution multiTrimFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        bitset<MAXM> baseMask = cur.tree.mask;\n        bool improved = false;\n\n        for (int typ = 0; typ < 10 && gtimer.elapsed() < deadline; ++typ) {\n            vector<int> q = cur.P;\n\n            if (typ == 0) {\n                trimP(q, makeOrder(q, 3, &br));\n            } else if (typ == 1) {\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 2) {\n                trimP(q, makeOrder(q, 1));\n            } else if (typ == 3) {\n                trimP(q, makeOrder(q, 2));\n            } else if (typ == 4) {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 2.0, 0.0));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 5) {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 0.5, 0.5));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 6) {\n                trimP(q, makeOrderWeighted(q, br, 0.5, 1.5, 0.2));\n                trimP(q, makeOrder(q, 1));\n            } else if (typ == 7) {\n                trimP(q, makeOrderWeighted(q, br, 0.2, 2.0, 1.0));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 8) {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 1.0, 1.0));\n                trimP(q, makeOrder(q, 0));\n            } else {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 3.0, 0.0));\n                trimP(q, makeOrder(q, 0));\n            }\n\n            Solution ns = evaluateSolution(q, &baseMask);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nbitset<MAXM> buildGreedyFromVertex(int start, const vector<int>& terms) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(start);\n\n    while (true) {\n        bool done = true;\n        for (int t : terms) {\n            if (!treeV.test(t)) {\n                done = false;\n                break;\n            }\n        }\n        if (done) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n\n        for (int t : terms) {\n            if (treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult exactSteinerSmall(const vector<int>& terms, const vector<char>& terminal, double deadline) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    int T = (int)terms.size();\n    if (T <= 1) {\n        res.cost = 0;\n        return res;\n    }\n    if (T > 10) return res;\n    if (T == 10 && gtimer.elapsed() > deadline - 0.025) return res;\n\n    int S = 1 << T;\n    int total = S * N;\n\n    vector<long long> dp(total, INFLL);\n    vector<bitset<MAXM>> bm(total);\n\n    auto id = [&](int mask, int v) {\n        return mask * N + v;\n    };\n\n    for (int i = 0; i < T; ++i) {\n        int mask = 1 << i;\n        for (int v = 0; v < N; ++v) {\n            dp[id(mask, v)] = spDist[terms[i]][v];\n            bm[id(mask, v)] = pathE[terms[i]][v];\n        }\n    }\n\n    for (int mask = 1; mask < S; ++mask) {\n        if ((mask & (mask - 1)) == 0) continue;\n        if ((mask & 3) == 0 && gtimer.elapsed() > deadline) return res;\n\n        int rowM = mask * N;\n\n        for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {\n            int other = mask ^ sub;\n            if (sub > other) continue;\n\n            int rowS = sub * N;\n            int rowO = other * N;\n\n            for (int v = 0; v < N; ++v) {\n                long long a = dp[rowS + v];\n                long long b = dp[rowO + v];\n                if (a >= INFLL / 4 || b >= INFLL / 4) continue;\n                long long nd = a + b;\n                if (nd < dp[rowM + v]) {\n                    dp[rowM + v] = nd;\n                    bm[rowM + v] = bm[rowS + v] | bm[rowO + v];\n                }\n            }\n        }\n\n        long long baseC[MAXN];\n        bitset<MAXM> baseB[MAXN];\n        for (int v = 0; v < N; ++v) {\n            baseC[v] = dp[rowM + v];\n            baseB[v] = bm[rowM + v];\n        }\n\n        for (int s = 0; s < N; ++s) {\n            if (baseC[s] >= INFLL / 4) continue;\n            for (int v = 0; v < N; ++v) {\n                long long nd = baseC[s] + spDist[s][v];\n                if (nd < dp[rowM + v]) {\n                    dp[rowM + v] = nd;\n                    bm[rowM + v] = baseB[s] | pathE[s][v];\n                }\n            }\n        }\n    }\n\n    int full = S - 1;\n    int bestV = -1;\n    long long bestCost = INFLL;\n    for (int v = 0; v < N; ++v) {\n        if (dp[id(full, v)] < bestCost) {\n            bestCost = dp[id(full, v)];\n            bestV = v;\n        }\n    }\n\n    if (bestV != -1) {\n        res = reduceMask(bm[id(full, bestV)], terminal);\n    }\n    return res;\n}\n\nTreeResult finalImproveTree(const vector<int>& P, TreeResult best, double deadline) {\n    vector<char> terminal = makeTerminal(P);\n\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terms.push_back(i);\n    }\n\n    if ((int)terms.size() <= 1) {\n        TreeResult r;\n        r.cost = 0;\n        r.mask.reset();\n        return r;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        if (gtimer.elapsed() > deadline) return;\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        TreeResult rb = best;\n        for (int e = 0; e < M; ++e) {\n            if ((e & 15) == 0 && gtimer.elapsed() > deadline) break;\n            if (best.mask.test(e)) continue;\n            bitset<MAXM> nm = best.mask;\n            nm.set(e);\n            TreeResult r = reduceMask(nm, terminal);\n            if (r.cost < rb.cost) rb = r;\n        }\n        if (rb.cost < best.cost) best = rb;\n        else break;\n    }\n\n    if (gtimer.elapsed() < deadline) {\n        bitset<MAXM> m;\n        for (int i = 0; i < (int)terms.size(); ++i) {\n            for (int j = i + 1; j < (int)terms.size(); ++j) {\n                m |= pathE[terms[i]][terms[j]];\n            }\n        }\n        upd(m);\n    }\n\n    for (int c = 0; c < N && gtimer.elapsed() < deadline; ++c) {\n        bitset<MAXM> m;\n        for (int t : terms) {\n            if (t != c) m |= pathE[c][t];\n        }\n        upd(m);\n    }\n\n    for (int depth = 0; depth < 2 && gtimer.elapsed() < deadline; ++depth) {\n        vector<char> vset(N, 0);\n        for (int t : terms) vset[t] = 1;\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                vset[edges[e].u] = 1;\n                vset[edges[e].v] = 1;\n            }\n        }\n\n        if (depth == 1) {\n            vector<char> ex = vset;\n            for (int e = 0; e < M; ++e) {\n                if (vset[edges[e].u] || vset[edges[e].v]) {\n                    ex[edges[e].u] = 1;\n                    ex[edges[e].v] = 1;\n                }\n            }\n            vset.swap(ex);\n        }\n\n        bitset<MAXM> m;\n        for (int e = 0; e < M; ++e) {\n            if (vset[edges[e].u] && vset[edges[e].v]) m.set(e);\n        }\n        upd(m);\n    }\n\n    {\n        double greedyDeadline = deadline - 0.004;\n        vector<int> starts;\n        vector<char> used(N, 0);\n        auto addStart = [&](int v) {\n            if (!used[v]) {\n                used[v] = 1;\n                starts.push_back(v);\n            }\n        };\n\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                addStart(edges[e].u);\n                addStart(edges[e].v);\n            }\n        }\n        for (int t : terms) addStart(t);\n        for (int v = 0; v < N; ++v) addStart(v);\n\n        for (int s : starts) {\n            if (gtimer.elapsed() > greedyDeadline) break;\n            bitset<MAXM> m = buildGreedyFromVertex(s, terms);\n            TreeResult r = reduceMask(m, terminal);\n            if (r.cost < best.cost) best = r;\n        }\n    }\n\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        vector<char> vset(N, 0);\n        for (int t : terms) vset[t] = 1;\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                vset[edges[e].u] = 1;\n                vset[edges[e].v] = 1;\n            }\n        }\n\n        vector<int> vs;\n        for (int i = 0; i < N; ++i) if (vset[i]) vs.push_back(i);\n\n        TreeResult rb = best;\n        for (int a = 0; a < (int)vs.size() && gtimer.elapsed() < deadline; ++a) {\n            for (int b = a + 1; b < (int)vs.size(); ++b) {\n                if ((b & 15) == 0 && gtimer.elapsed() > deadline) break;\n                bitset<MAXM> nm = best.mask | pathE[vs[a]][vs[b]];\n                TreeResult r = reduceMask(nm, terminal);\n                if (r.cost < rb.cost) rb = r;\n            }\n        }\n\n        if (rb.cost < best.cost) best = rb;\n        else break;\n    }\n\n    double need = ((int)terms.size() <= 9 ? 0.006 : 0.025);\n    if ((int)terms.size() <= 10 && gtimer.elapsed() < deadline - need) {\n        TreeResult r = exactSteinerSmall(terms, terminal, deadline);\n        if (r.cost < best.cost) best = r;\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gtimer.reset();\n\n    cin >> N >> M >> K;\n\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    adj.assign(N, {});\n    for (int j = 0; j < M; ++j) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n        adj[u].push_back({v, j});\n        adj[v].push_back({u, j});\n    }\n\n    RA.resize(K);\n    RB.resize(K);\n    for (int k = 0; k < K; ++k) cin >> RA[k] >> RB[k];\n\n    edgeOrder.resize(M);\n    iota(edgeOrder.begin(), edgeOrder.end(), 0);\n    sort(edgeOrder.begin(), edgeOrder.end(), [&](int a, int b) {\n        if (edges[a].w != edges[b].w) return edges[a].w < edges[b].w;\n        return a < b;\n    });\n\n    allEdgesMask.reset();\n    for (int e = 0; e < M; ++e) allEdgesMask.set(e);\n\n    computeShortestPaths();\n    globalMSTMask = buildGlobalMST();\n\n    distSq.assign(N, vector<int>(K));\n    ceilD.assign(N, vector<unsigned short>(K));\n\n    for (int i = 0; i < N; ++i) {\n        coverList[i].clear();\n        for (int k = 0; k < K; ++k) {\n            long long dx = (long long)X[i] - RA[k];\n            long long dy = (long long)Y[i] - RB[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            distSq[i][k] = (int)d2;\n            ceilD[i][k] = (unsigned short)p;\n            if (p <= 5000) coverList[i].push_back({(unsigned short)p, k});\n        }\n        sort(coverList[i].begin(), coverList[i].end(), [](const RK& a, const RK& b) {\n            if (a.p != b.p) return a.p < b.p;\n            return a.k < b.k;\n        });\n    }\n\n    vector<Solution> sols;\n    const double GEN_DEADLINE = 0.85;\n    const double LOCAL_DEADLINE = 1.90;\n\n    vector<double> lambdas = {0.0, 0.05, 0.2, 0.7, 1.5};\n    for (double l : lambdas) {\n        vector<int> P = nearestSolution(l);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    {\n        vector<int> P(N, 5000);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    vector<pair<double,double>> params = {\n        {0.0, 1.0}, {0.2, 1.0}, {0.5, 1.0}, {0.8, 1.0},\n        {1.2, 1.0}, {2.0, 1.0}, {0.3, 1.15}, {0.8, 1.15},\n        {1.5, 1.15}, {0.5, 0.9}\n    };\n\n    vector<char> allAllowed(N, 1);\n    for (auto [beta, ex] : params) {\n        if (gtimer.elapsed() > GEN_DEADLINE) break;\n        vector<int> P(N, 0);\n        if (greedyRepair(P, allAllowed, beta, ex, nullptr, GEN_DEADLINE)) {\n            considerCandidate(P, sols, GEN_DEADLINE);\n        }\n    }\n\n    if (sols.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        if (!isFull(P)) greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        sols.push_back(evaluateSolution(P));\n    }\n\n    sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b) {\n        return a.total < b.total;\n    });\n\n    vector<Solution> uniq;\n    for (const auto& s : sols) {\n        if (s.total >= INFLL / 2) continue;\n        bool dup = false;\n        for (const auto& u : uniq) {\n            if (u.P == s.P) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniq.push_back(s);\n        if ((int)uniq.size() >= 20) break;\n    }\n\n    if (uniq.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        uniq.push_back(evaluateSolution(P));\n    }\n\n    Solution best = uniq[0];\n\n    int optN = min(5, (int)uniq.size());\n    for (int i = 0; i < optN && gtimer.elapsed() < LOCAL_DEADLINE; ++i) {\n        Solution opt = localSearch(uniq[i], LOCAL_DEADLINE);\n        if (opt.total < best.total) best = opt;\n    }\n\n    best = evaluateSolution(best.P);\n\n    if (gtimer.elapsed() < 1.945) {\n        Solution ns = multiTrimFinal(best, 1.955);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (!isFull(best.P)) {\n        greedyRepair(best.P, allAllowed, 0.0, 1.0);\n        best = evaluateSolution(best.P);\n    } else {\n        best = evaluateSolution(best.P);\n    }\n\n    Solution safeBest = best;\n\n    if (gtimer.elapsed() < 1.958) {\n        Solution ns = fixedTreeReverseDeleteFinal(best, 1.964);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.965) {\n        Solution ns = optimizeOnReachableFinal(best, 1.970);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.970) {\n        Solution ns = reachableLocalFinal(best, 1.974);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.973) {\n        Solution ns = pairReplaceFinal(best, 1.977);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.976) {\n        Solution ns = multiTrimFinal(best, 1.979);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.982) {\n        TreeResult tr = finalImproveTree(best.P, best.tree, 1.992);\n        if (tr.cost < best.tree.cost) {\n            best.tree = tr;\n            best.total = best.radCost + best.tree.cost;\n        }\n    }\n\n    if (!isFull(best.P) || best.total >= INFLL / 2) {\n        best = safeBest;\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 e = 0; e < M; ++e) {\n        if (e) cout << ' ';\n        cout << (best.tree.mask.test(e) ? 1 : 0);\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 int M = N * (N + 1) / 2;\nstatic constexpr int INTERNAL = M - N;\n\nint ID[N][N], Xc[M], Yc[M];\nvector<int> G[M], PAR[M], CH[M];\nvector<pair<int,int>> EDGES;\nvector<pair<int,int>> ADJ;\nvector<int> INCIDENT[M];\nbool ADJMAT[M][M];\n\nbool validXY(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y <= x;\n}\n\nint distHex(int a, int b) {\n    int dx = Xc[a] - Xc[b];\n    int dy = Yc[a] - Yc[b];\n    int dz = (Xc[a] - Yc[a]) - (Xc[b] - Yc[b]);\n    return max({abs(dx), abs(dy), abs(dz)});\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 FastRand {\n    uint64_t x;\n    FastRand(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n};\n\nvoid precompute() {\n    memset(ADJMAT, 0, sizeof(ADJMAT));\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) ID[i][j] = -1;\n\n    int idx = 0;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            ID[x][y] = idx;\n            Xc[idx] = x;\n            Yc[idx] = y;\n            idx++;\n        }\n    }\n\n    int dx[6] = {0, 0, -1, -1, 1, 1};\n    int dy[6] = {-1, 1, -1, 0, 0, 1};\n\n    for (int p = 0; p < M; p++) {\n        int x = Xc[p], y = Yc[p];\n\n        for (int k = 0; k < 6; k++) {\n            int nx = x + dx[k], ny = y + dy[k];\n            if (validXY(nx, ny)) {\n                int q = ID[nx][ny];\n                G[p].push_back(q);\n                ADJMAT[p][q] = true;\n            }\n        }\n\n        if (x + 1 < N) {\n            CH[p].push_back(ID[x + 1][y]);\n            CH[p].push_back(ID[x + 1][y + 1]);\n        }\n        if (x > 0) {\n            if (y > 0) PAR[p].push_back(ID[x - 1][y - 1]);\n            if (y < x) PAR[p].push_back(ID[x - 1][y]);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int c : CH[p]) {\n            int ei = (int)EDGES.size();\n            EDGES.emplace_back(p, c);\n            INCIDENT[p].push_back(ei);\n            INCIDENT[c].push_back(ei);\n        }\n    }\n\n    for (int p = 0; p < M; p++) {\n        for (int q : G[p]) {\n            if (p < q) ADJ.emplace_back(p, q);\n        }\n    }\n}\n\nstruct Work {\n    array<int, M> a;\n    array<int, M> pos;\n    vector<pair<int,int>> ops;\n\n    Work() {}\n\n    Work(const array<int, M>& init) {\n        a = init;\n        for (int i = 0; i < M; i++) pos[a[i]] = i;\n        ops.clear();\n    }\n};\n\ninline void doSwap(Work& w, int u, int v) {\n    int lu = w.a[u], lv = w.a[v];\n    swap(w.a[u], w.a[v]);\n    w.pos[lu] = v;\n    w.pos[lv] = u;\n    w.ops.emplace_back(u, v);\n}\n\nint countViol(const array<int, M>& a) {\n    int e = 0;\n    for (auto [p, c] : EDGES) {\n        if (a[p] > a[c]) e++;\n    }\n    return e;\n}\n\narray<int, M> simulateOps(const array<int, M>& init, const vector<pair<int,int>>& ops) {\n    array<int, M> a = init;\n    for (auto [u, v] : ops) swap(a[u], a[v]);\n    return a;\n}\n\nint centerVal(int p) {\n    return abs(2 * Yc[p] - Xc[p]);\n}\n\nint chooseCand(const vector<int>& cand, int choice, const Work& w) {\n    int best = cand[0];\n    for (int q : cand) {\n        bool take = false;\n        if (choice == 0) {\n            if (w.a[q] > w.a[best]) take = true;\n        } else if (choice == 1) {\n            if (w.a[q] < w.a[best]) take = true;\n        } else if (choice == 2) {\n            if (Yc[q] < Yc[best]) take = true;\n        } else if (choice == 3) {\n            if (Yc[q] > Yc[best]) take = true;\n        } else {\n            int cq = centerVal(q), cb = centerVal(best);\n            if (cq < cb || (cq == cb && w.a[q] > w.a[best])) take = true;\n        }\n        if (take) best = q;\n    }\n    return best;\n}\n\nint chooseCandRand(const vector<int>& cand, int mode, const Work& w, FastRand& rng, int dir) {\n    if ((int)cand.size() == 1) return cand[0];\n\n    if (mode == 0) return cand[rng.nextInt((int)cand.size())];\n\n    if (1 <= mode && mode <= 5) {\n        int base = chooseCand(cand, mode - 1, w);\n        if (rng.nextInt(100) < 75) return base;\n        vector<int> other;\n        for (int q : cand) if (q != base) other.push_back(q);\n        if (other.empty()) return base;\n        return other[rng.nextInt((int)other.size())];\n    }\n\n    int best = cand[0];\n    long long bestSc = LLONG_MIN;\n    for (int q : cand) {\n        long long sc = 0;\n        if (mode == 6) {\n            sc = 100LL * w.a[q] - 15LL * centerVal(q);\n        } else {\n            sc = -100LL * w.a[q] - 15LL * centerVal(q);\n        }\n        if (dir == 0) sc -= 3LL * Xc[q];\n        else sc += 3LL * Xc[q];\n        sc += (long long)(rng.nextInt(301) - 150);\n        if (sc > bestSc) {\n            bestSc = sc;\n            best = q;\n        }\n    }\n    return best;\n}\n\n// Guaranteed finisher.\nbool appendCone(Work& w, int yOrder, int pathMode, int limit) {\n    if (countViol(w.a) == 0) return true;\n\n    for (int x = 0; x <= N - 2; x++) {\n        for (int yi = 0; yi <= x; yi++) {\n            int y = (yOrder == 0 ? yi : x - yi);\n\n            int best = ID[x][y];\n            int bv = w.a[best];\n\n            for (int r = x; r < N; r++) {\n                int c0 = y;\n                int c1 = y + (r - x);\n                for (int c = c0; c <= c1; c++) {\n                    int p = ID[r][c];\n                    if (w.a[p] < bv) {\n                        bv = w.a[p];\n                        best = p;\n                    }\n                }\n            }\n\n            int cur = best;\n            while (Xc[cur] > x) {\n                int cx = Xc[cur], cy = Yc[cur];\n                bool goLeft = false;\n\n                if (pathMode == 0) {\n                    goLeft = (cy > y);\n                } else if (pathMode == 1) {\n                    goLeft = !(cx - cy > x - y);\n                } else {\n                    int rem = cx - x;\n                    int needLeft = cy - y;\n                    if (needLeft <= 0) goLeft = false;\n                    else if (needLeft >= rem) goLeft = true;\n                    else goLeft = (needLeft * 2 >= rem);\n                }\n\n                int np = goLeft ? ID[cx - 1][cy - 1] : ID[cx - 1][cy];\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, cur, np);\n                cur = np;\n            }\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n    return countViol(w.a) == 0;\n}\n\nbool appendSift(Work& w, int dir, int choice, int limit) {\n    if (countViol(w.a) == 0) return true;\n    if ((int)w.ops.size() > limit) return false;\n\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    } else {\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool appendSiftRandom(Work& w, int dir, int mode, uint64_t seed, int limit) {\n    if (countViol(w.a) == 0) return true;\n    if ((int)w.ops.size() > limit) return false;\n\n    FastRand rng(seed);\n    vector<char> fixed(M, 0);\n\n    if (dir == 0) {\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : PAR[p]) if (w.a[q] > v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] < N - 1) internalFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    } else {\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            while (true) {\n                int p = w.pos[v];\n                vector<int> cand;\n                for (int q : CH[p]) if (w.a[q] < v) cand.push_back(q);\n                if (cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if ((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if (fixed[p]) return false;\n            fixed[p] = 1;\n            if (Xc[p] > 0) nonTopFixed++;\n\n            if (countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool solveSift(const array<int, M>& init, int dir, int choice, int limit, Work& out) {\n    Work w(init);\n    if (appendSift(w, dir, choice, limit)) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Loose bidirectional sift.\nint pathLenLoose(const Work& w, int label, int dir, int choice) {\n    int cur = w.pos[label];\n    int len = 0;\n\n    while (len <= 80) {\n        vector<int> cand;\n        if (dir == 0) {\n            for (int q : PAR[cur]) if (w.a[q] > label) cand.push_back(q);\n        } else {\n            for (int q : CH[cur]) if (w.a[q] < label) cand.push_back(q);\n        }\n\n        if (cand.empty()) break;\n        cur = chooseCand(cand, choice, w);\n        len++;\n    }\n\n    if (len > 80) return 1000000;\n    return len;\n}\n\nbool performLoose(Work& w, int label, int dir, int choice, int limit) {\n    int guard = 0;\n\n    while (guard++ <= 80) {\n        int p = w.pos[label];\n        vector<int> cand;\n\n        if (dir == 0) {\n            for (int q : PAR[p]) if (w.a[q] > label) cand.push_back(q);\n        } else {\n            for (int q : CH[p]) if (w.a[q] < label) cand.push_back(q);\n        }\n\n        if (cand.empty()) break;\n\n        int q = chooseCand(cand, choice, w);\n        if ((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, p, q);\n    }\n\n    return guard <= 82;\n}\n\nbool solveBiLoose(const array<int, M>& init, int mode, int choiceSmall, int choiceLarge,\n                  int finishDir, int finishChoice, uint64_t seed, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    FastRand rng(seed);\n    int lo = 0, hi = M - 1;\n    int step = 0;\n\n    while (lo <= hi && countViol(w.a) != 0) {\n        int ls = pathLenLoose(w, lo, 0, choiceSmall);\n        int lb = pathLenLoose(w, hi, 1, choiceLarge);\n\n        bool chooseSmall = true;\n\n        if (mode == 0) chooseSmall = (step % 2 == 0);\n        else if (mode == 1) chooseSmall = (step % 2 == 1);\n        else if (mode == 2) chooseSmall = (ls <= lb);\n        else if (mode == 3) chooseSmall = (2 * ls <= 3 * lb);\n        else if (mode == 4) chooseSmall = (3 * ls <= 2 * lb);\n        else if (mode == 5) chooseSmall = ((step % 3) != 2);\n        else if (mode == 6) chooseSmall = ((step % 3) == 0);\n        else {\n            int total = max(1, ls + lb + 2);\n            chooseSmall = (rng.nextInt(total) >= ls + 1);\n        }\n\n        if (chooseSmall) {\n            if (!performLoose(w, lo, 0, choiceSmall, limit)) return false;\n            lo++;\n        } else {\n            if (!performLoose(w, hi, 1, choiceLarge, limit)) return false;\n            hi--;\n        }\n\n        if ((int)w.ops.size() > limit) return false;\n        step++;\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    if (finishDir >= 0) {\n        if (appendSift(w, finishDir, finishChoice, limit)) {\n            out = move(w);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool parentsFixed(int p, const vector<char>& fixed) {\n    for (int q : PAR[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nbool childrenFixed(int p, const vector<char>& fixed) {\n    for (int q : CH[p]) if (!fixed[q]) return false;\n    return true;\n}\n\nint openInc(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (fixed[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openDec(int p, const vector<char>& fixed) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (fixed[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && !fixed[q]) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nstruct Strat {\n    int w;\n    int row;\n    int center;\n    int open;\n    int randAmp;\n    uint64_t seed;\n};\n\nbool solveBFS(const array<int, M>& init, int dir, const Strat& st, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<char> fixed(M, 0), avail(M, 0);\n\n    if (dir == 0) {\n        avail[ID[0][0]] = 1;\n        int internalFixed = 0;\n\n        for (int v = 0; v < M && internalFixed < INTERNAL; v++) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openInc(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(v + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] < N - 1) internalFixed++;\n\n            for (int ch : CH[best]) {\n                if (!fixed[ch] && parentsFixed(ch, fixed)) avail[ch] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    } else {\n        for (int y = 0; y < N; y++) avail[ID[N - 1][y]] = 1;\n\n        int nonTopFixed = 0;\n\n        for (int v = M - 1; v >= 1 && nonTopFixed < M - 1; v--) {\n            int start = w.pos[v];\n            if (fixed[start]) return false;\n\n            array<int, M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while (head < tail) {\n                int u = que[head++];\n                for (int nb : G[u]) {\n                    if (fixed[nb]) continue;\n                    if (dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n            int step = M - 1 - v;\n\n            for (int p = 0; p < M; p++) {\n                if (!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openDec(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if (st.randAmp > 0) {\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if (best == -1) return false;\n            if ((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for (int cur = best; cur != -1; cur = prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if (Xc[best] > 0) nonTopFixed++;\n\n            for (int pr : PAR[best]) {\n                if (!fixed[pr] && childrenFixed(pr, fixed)) avail[pr] = 1;\n            }\n\n            if (countViol(w.a) == 0) {\n                out = move(w);\n                return true;\n            }\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Bidirectional BFS construction.\nbool parentsTop(int p, const vector<unsigned char>& type) {\n    for (int q : PAR[p]) if (type[q] != 1) return false;\n    return true;\n}\n\nbool childrenBottom(int p, const vector<unsigned char>& type) {\n    for (int q : CH[p]) if (type[q] != 2) return false;\n    return true;\n}\n\nint openTopCnt(int p, const vector<unsigned char>& type) {\n    int res = 0;\n    for (int ch : CH[p]) {\n        if (type[ch]) continue;\n        bool ok = true;\n        for (int q : PAR[ch]) {\n            if (q != p && type[q] != 1) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nint openBottomCnt(int p, const vector<unsigned char>& type) {\n    int res = 0;\n    for (int pr : PAR[p]) {\n        if (type[pr]) continue;\n        bool ok = true;\n        for (int q : CH[pr]) {\n            if (q != p && type[q] != 2) {\n                ok = false;\n                break;\n            }\n        }\n        if (ok) res++;\n    }\n    return res;\n}\n\nstruct BiOpt {\n    bool ok = false;\n    int target = -1;\n    int dist = 0;\n    long long score = 0;\n};\n\nBiOpt getBiOption(\n    const Work& w,\n    const vector<unsigned char>& type,\n    const vector<char>& avail,\n    int label,\n    bool topSide,\n    const Strat& st,\n    int step,\n    array<int, M>& dist,\n    array<int, M>& prv\n) {\n    BiOpt opt;\n    int start = w.pos[label];\n    if (type[start]) return opt;\n\n    dist.fill(-1);\n    prv.fill(-1);\n\n    int que[M], head = 0, tail = 0;\n    dist[start] = 0;\n    que[tail++] = start;\n\n    while (head < tail) {\n        int u = que[head++];\n        for (int nb : G[u]) {\n            if (type[nb]) continue;\n            if (dist[nb] != -1) continue;\n            dist[nb] = dist[u] + 1;\n            prv[nb] = u;\n            que[tail++] = nb;\n        }\n    }\n\n    long long bestSc = LLONG_MAX;\n    int best = -1;\n\n    for (int p = 0; p < M; p++) {\n        if (!avail[p] || type[p] || dist[p] < 0) continue;\n\n        int opn = topSide ? openTopCnt(p, type) : openBottomCnt(p, type);\n        long long sc = 1LL * dist[p] * st.w\n                     + 1LL * st.row * Xc[p]\n                     + 1LL * st.center * centerVal(p)\n                     + 1LL * st.open * opn;\n\n        if (st.randAmp > 0) {\n            uint64_t h = splitmix64(st.seed ^ (uint64_t)(step + 1) * 1000003ULL ^ (uint64_t)p);\n            sc += (long long)(h % (uint64_t)st.randAmp);\n        }\n\n        if (best == -1 || sc < bestSc || (sc == bestSc && p < best)) {\n            best = p;\n            bestSc = sc;\n        }\n    }\n\n    if (best == -1) return opt;\n\n    opt.ok = true;\n    opt.target = best;\n    opt.dist = dist[best];\n    opt.score = bestSc;\n    return opt;\n}\n\nbool solveBiBFS(const array<int, M>& init, const Strat& topSt, const Strat& botSt, int sideBias, int limit, Work& out) {\n    Work w(init);\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n\n    vector<unsigned char> type(M, 0);\n    vector<char> topAvail(M, 0), botAvail(M, 0);\n\n    topAvail[ID[0][0]] = 1;\n    for (int y = 0; y < N; y++) botAvail[ID[N - 1][y]] = 1;\n\n    int lo = 0, hi = M - 1;\n    int step = 0;\n\n    while (lo <= hi) {\n        array<int, M> distTop, prvTop, distBot, prvBot;\n\n        BiOpt ot = getBiOption(w, type, topAvail, lo, true, topSt, step, distTop, prvTop);\n        BiOpt ob = getBiOption(w, type, botAvail, hi, false, botSt, step, distBot, prvBot);\n\n        if (!ot.ok && !ob.ok) return false;\n\n        bool chooseTop;\n        if (!ob.ok) chooseTop = true;\n        else if (!ot.ok) chooseTop = false;\n        else chooseTop = (ot.score + sideBias <= ob.score);\n\n        int target;\n        array<int, M>* prv;\n\n        if (chooseTop) {\n            target = ot.target;\n            prv = &prvTop;\n            if ((int)w.ops.size() + ot.dist > limit) return false;\n        } else {\n            target = ob.target;\n            prv = &prvBot;\n            if ((int)w.ops.size() + ob.dist > limit) return false;\n        }\n\n        vector<int> path;\n        for (int cur = target; cur != -1; cur = (*prv)[cur]) path.push_back(cur);\n        reverse(path.begin(), path.end());\n\n        for (int i = 0; i + 1 < (int)path.size(); i++) doSwap(w, path[i], path[i + 1]);\n\n        if (chooseTop) {\n            type[target] = 1;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            lo++;\n\n            for (int ch : CH[target]) {\n                if (!type[ch] && parentsTop(ch, type)) topAvail[ch] = 1;\n            }\n        } else {\n            type[target] = 2;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            hi--;\n\n            for (int pr : PAR[target]) {\n                if (!type[pr] && childrenBottom(pr, type)) botAvail[pr] = 1;\n            }\n        }\n\n        step++;\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint localDelta(const Work& w, int p, int c) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[c]) add(e);\n\n    int before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        if (w.a[u] > w.a[v]) before++;\n\n        int au = (u == p ? w.a[c] : (u == c ? w.a[p] : w.a[u]));\n        int av = (v == p ? w.a[c] : (v == c ? w.a[p] : w.a[v]));\n        if (au > av) after++;\n    }\n\n    return before - after;\n}\n\nint chooseViolationEdge(const Work& w, int variant) {\n    long long bestKey = LLONG_MIN;\n    int best = -1;\n\n    for (int ei = 0; ei < (int)EDGES.size(); ei++) {\n        auto [p, c] = EDGES[ei];\n        if (w.a[p] <= w.a[c]) continue;\n\n        int diff = w.a[p] - w.a[c];\n        int delta = 0;\n        if (variant >= 6) delta = localDelta(w, p, c);\n\n        long long key = 0;\n        if (variant == 0) {\n            key = diff;\n        } else if (variant == 1) {\n            key = 1LL * (M - w.a[c]) * 1000 + diff;\n        } else if (variant == 2) {\n            key = 1LL * w.a[p] * 1000 + diff;\n        } else if (variant == 3) {\n            key = 1LL * (N - Xc[p]) * 100000 + diff;\n        } else if (variant == 4) {\n            key = 1LL * Xc[p] * 100000 + diff;\n        } else if (variant == 5) {\n            key = 1LL * diff * 1000 + (N - Xc[p]) * 20 + (M - w.a[c]);\n        } else if (variant == 6) {\n            key = 1LL * delta * 1000000 + 1LL * diff * 1000 + (M - w.a[c]);\n        } else if (variant == 7) {\n            key = 1LL * delta * 1000000 + 1LL * (N - Xc[p]) * 1000 + diff;\n        } else {\n            key = 1LL * delta * 1000000 + 1LL * Xc[p] * 1000 + diff;\n        }\n\n        if (key > bestKey) {\n            bestKey = key;\n            best = ei;\n        }\n    }\n\n    return best;\n}\n\nbool runLocalSteps(Work& w, int variant, int steps, int limit) {\n    for (int s = 0; s < steps; s++) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) return true;\n\n        if ((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n    return true;\n}\n\nbool solveLocal(const array<int, M>& init, int variant, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        int ei = chooseViolationEdge(w, variant);\n        if (ei < 0) {\n            out = move(w);\n            return true;\n        }\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool solveSweep(const array<int, M>& init, int xdir, int ydir, int choice, int limit, Work& out) {\n    Work w(init);\n\n    while ((int)w.ops.size() < limit) {\n        bool changed = false;\n\n        for (int xi = 0; xi < N - 1; xi++) {\n            int x = (xdir == 0 ? N - 2 - xi : xi);\n\n            for (int yi = 0; yi <= x; yi++) {\n                int y = (ydir == 0 ? yi : x - yi);\n                int cur = ID[x][y];\n\n                while (Xc[cur] < N - 1) {\n                    vector<int> cand;\n                    for (int q : CH[cur]) {\n                        if (w.a[cur] > w.a[q]) cand.push_back(q);\n                    }\n                    if (cand.empty()) break;\n\n                    int q = chooseCand(cand, choice, w);\n                    if ((int)w.ops.size() + 1 > limit) return false;\n\n                    doSwap(w, cur, q);\n                    cur = q;\n                    changed = true;\n                }\n            }\n        }\n\n        if (countViol(w.a) == 0) {\n            out = move(w);\n            return true;\n        }\n        if (!changed) break;\n    }\n\n    if (countViol(w.a) == 0) {\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\n// Greedy all-adjacent local energy prefix.\nlong long edgeCostVal(int ap, int ac, int W, bool quad) {\n    if (ap <= ac) return 0;\n    long long d = ap - ac;\n    if (quad) return (long long)W + d * d;\n    return (long long)W + d;\n}\n\nlong long swapGainCost(const array<int, M>& a, int p, int q, int W, bool quad) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[q]) add(e);\n\n    long long before = 0, after = 0;\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        before += edgeCostVal(a[u], a[v], W, quad);\n\n        int au = (u == p ? a[q] : (u == q ? a[p] : a[u]));\n        int av = (v == p ? a[q] : (v == q ? a[p] : a[v]));\n        after += edgeCostVal(au, av, W, quad);\n    }\n\n    return before - after;\n}\n\nbool runGreedyCost(Work& w, int W, bool quad, int maxSteps, int limit) {\n    for (int s = 0; s < maxSteps; s++) {\n        if ((int)w.ops.size() >= limit) return countViol(w.a) == 0;\n\n        long long bestGain = 0;\n        long long bestTie = LLONG_MIN;\n        int bu = -1, bv = -1;\n\n        for (auto [u, v] : ADJ) {\n            long long gain = swapGainCost(w.a, u, v, W, quad);\n            if (gain <= 0) continue;\n\n            long long deltaP = 1LL * (w.a[u] - w.a[v]) * (Xc[v] - Xc[u]);\n            long long rowGain = -deltaP;\n\n            if (gain > bestGain || (gain == bestGain && rowGain > bestTie)) {\n                bestGain = gain;\n                bestTie = rowGain;\n                bu = u;\n                bv = v;\n            }\n        }\n\n        if (bu == -1) break;\n\n        doSwap(w, bu, bv);\n        if (countViol(w.a) == 0) return true;\n    }\n\n    return countViol(w.a) == 0;\n}\n\n// Fast reverse pruning.\nbool canSwapKeepValid(const array<int, M>& a, int p, int q) {\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int e : INCIDENT[p]) add(e);\n    for (int e : INCIDENT[q]) add(e);\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n\n        int au = a[u], av = a[v];\n        if (u == p) au = a[q];\n        else if (u == q) au = a[p];\n\n        if (v == p) av = a[q];\n        else if (v == q) av = a[p];\n\n        if (au > av) return false;\n    }\n\n    return true;\n}\n\nvector<pair<int,int>> pruneOpsFast(const array<int, M>& init, const vector<pair<int,int>>& ops, int passes = 3) {\n    vector<pair<int,int>> cur = ops;\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (cur.empty()) break;\n\n        array<int, M> a = simulateOps(init, cur);\n        if (countViol(a) != 0) return cur;\n\n        array<int, M> suff;\n        for (int i = 0; i < M; i++) suff[i] = i;\n\n        vector<unsigned char> keep(cur.size(), 1);\n        int deleted = 0;\n\n        for (int ii = (int)cur.size(); ii-- > 0; ) {\n            int u = cur[ii].first;\n            int v = cur[ii].second;\n\n            int p = suff[u];\n            int q = suff[v];\n\n            if (canSwapKeepValid(a, p, q)) {\n                swap(a[p], a[q]);\n                keep[ii] = 0;\n                deleted++;\n            } else {\n                swap(suff[u], suff[v]);\n            }\n        }\n\n        if (deleted == 0) break;\n\n        vector<pair<int,int>> nxt;\n        nxt.reserve(cur.size() - deleted);\n        for (int i = 0; i < (int)cur.size(); i++) {\n            if (keep[i]) nxt.push_back(cur[i]);\n        }\n        cur.swap(nxt);\n    }\n\n    return cur;\n}\n\nbool validSkipping(const array<int, M>& init, const vector<pair<int,int>>& ops, int s1, int s2 = -1) {\n    array<int, M> a = init;\n    for (int i = 0; i < (int)ops.size(); i++) {\n        if (i == s1 || i == s2) continue;\n        swap(a[ops[i].first], a[ops[i].second]);\n    }\n    return countViol(a) == 0;\n}\n\n// Exact local window replacement preserving same final permutation.\nuint64_t encodePermVec(const vector<int>& p) {\n    uint64_t code = 0;\n    for (int i = 0; i < (int)p.size(); i++) code |= (uint64_t)p[i] << (4 * i);\n    return code;\n}\n\nuint64_t encodeIdentity(int m) {\n    uint64_t code = 0;\n    for (int i = 0; i < m; i++) code |= (uint64_t)i << (4 * i);\n    return code;\n}\n\nvoid decodePerm(uint64_t code, int m, int arr[8]) {\n    for (int i = 0; i < m; i++) arr[i] = (int)((code >> (4 * i)) & 15);\n}\n\nbool shortestLocalPath(int m, const vector<pair<int,int>>& edges, uint64_t target,\n                       int maxDepth, vector<int>& edgePath) {\n    edgePath.clear();\n    uint64_t start = encodeIdentity(m);\n    if (start == target) return true;\n    if (edges.empty() || maxDepth <= 0) return false;\n\n    unordered_map<uint64_t, int> id;\n    id.reserve(10000);\n\n    vector<uint64_t> state;\n    vector<int> par;\n    vector<int> pedge;\n    vector<int> dep;\n\n    id[start] = 0;\n    state.push_back(start);\n    par.push_back(-1);\n    pedge.push_back(-1);\n    dep.push_back(0);\n\n    int arr[8];\n\n    for (int head = 0; head < (int)state.size(); head++) {\n        if ((int)state.size() > 30000) break;\n        if (dep[head] >= maxDepth) continue;\n\n        decodePerm(state[head], m, arr);\n\n        for (int ei = 0; ei < (int)edges.size(); ei++) {\n            auto [a, b] = edges[ei];\n            swap(arr[a], arr[b]);\n\n            uint64_t nc = 0;\n            for (int i = 0; i < m; i++) nc |= (uint64_t)arr[i] << (4 * i);\n\n            if (!id.count(nc)) {\n                int nid = (int)state.size();\n                id[nc] = nid;\n                state.push_back(nc);\n                par.push_back(head);\n                pedge.push_back(ei);\n                dep.push_back(dep[head] + 1);\n\n                if (nc == target) {\n                    int cur = nid;\n                    while (cur != 0) {\n                        edgePath.push_back(pedge[cur]);\n                        cur = par[cur];\n                    }\n                    reverse(edgePath.begin(), edgePath.end());\n                    return true;\n                }\n            }\n\n            swap(arr[a], arr[b]);\n        }\n    }\n\n    return false;\n}\n\ntemplate<class TimeOK>\nvoid optimizeWindows(vector<pair<int,int>>& ops, TimeOK timeOK) {\n    const int MAXLEN = 6;\n\n    for (int pass = 0; pass < 2 && timeOK(); pass++) {\n        bool changedPass = false;\n\n        for (int i = 0; i < (int)ops.size() && timeOK(); ) {\n            bool replaced = false;\n\n            for (int len = MAXLEN; len >= 2 && !replaced; len--) {\n                if (i + len > (int)ops.size()) continue;\n\n                array<int, M> loc;\n                loc.fill(-1);\n                vector<int> verts;\n                verts.reserve(len + 1);\n\n                auto addv = [&](int v) {\n                    if (loc[v] == -1) {\n                        loc[v] = (int)verts.size();\n                        verts.push_back(v);\n                    }\n                };\n\n                for (int j = i; j < i + len; j++) {\n                    addv(ops[j].first);\n                    addv(ops[j].second);\n                }\n\n                int m = (int)verts.size();\n                if (m > 8) continue;\n\n                vector<int> perm(m);\n                iota(perm.begin(), perm.end(), 0);\n\n                bool ok = true;\n                for (int j = i; j < i + len; j++) {\n                    int a = loc[ops[j].first];\n                    int b = loc[ops[j].second];\n                    if (a < 0 || b < 0) {\n                        ok = false;\n                        break;\n                    }\n                    swap(perm[a], perm[b]);\n                }\n                if (!ok) continue;\n\n                uint64_t target = encodePermVec(perm);\n\n                vector<pair<int,int>> localEdges;\n                for (int a = 0; a < m; a++) {\n                    for (int b = a + 1; b < m; b++) {\n                        if (ADJMAT[verts[a]][verts[b]]) localEdges.emplace_back(a, b);\n                    }\n                }\n\n                vector<int> edgePath;\n                if (!shortestLocalPath(m, localEdges, target, len - 1, edgePath)) continue;\n                if ((int)edgePath.size() >= len) continue;\n\n                vector<pair<int,int>> repl;\n                repl.reserve(edgePath.size());\n                for (int ei : edgePath) {\n                    auto [a, b] = localEdges[ei];\n                    repl.emplace_back(verts[a], verts[b]);\n                }\n\n                ops.erase(ops.begin() + i, ops.begin() + i + len);\n                ops.insert(ops.begin() + i, repl.begin(), repl.end());\n\n                i = max(0, i - len);\n                changedPass = true;\n                replaced = true;\n            }\n\n            if (!replaced) i++;\n        }\n\n        if (!changedPass) break;\n    }\n}\n\nvector<array<int, M>> buildSuffixMaps(const vector<pair<int,int>>& ops) {\n    int K = (int)ops.size();\n    vector<array<int, M>> suff(K + 1);\n    for (int i = 0; i < M; i++) suff[K][i] = i;\n\n    for (int i = K - 1; i >= 0; i--) {\n        suff[i] = suff[i + 1];\n        auto [u, v] = ops[i];\n        swap(suff[i][u], suff[i][v]);\n    }\n    return suff;\n}\n\nbool validWithSourceMap(const array<int, M>& a, int src[M], const vector<int>& changed) {\n    int idxs[128];\n    int cnt = 0;\n\n    auto add = [&](int e) {\n        for (int i = 0; i < cnt; i++) if (idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for (int p : changed) {\n        for (int e : INCIDENT[p]) add(e);\n    }\n\n    auto val = [&](int p) {\n        return src[p] >= 0 ? a[src[p]] : a[p];\n    };\n\n    for (int i = 0; i < cnt; i++) {\n        auto [u, v] = EDGES[idxs[i]];\n        if (val(u) > val(v)) return false;\n    }\n    return true;\n}\n\nbool canDeleteBlockFast(const array<int, M>& finalA,\n                        const array<int, M>& suff,\n                        const vector<pair<int,int>>& ops,\n                        int l, int r) {\n    array<int, M> b;\n    array<unsigned char, M> seen;\n    seen.fill(0);\n\n    vector<int> touched;\n    touched.reserve(r - l + 1);\n\n    auto touch = [&](int p) {\n        if (!seen[p]) {\n            seen[p] = 1;\n            b[p] = p;\n            touched.push_back(p);\n        }\n    };\n\n    for (int i = l; i < r; i++) {\n        int u = ops[i].first, v = ops[i].second;\n        touch(u);\n        touch(v);\n        swap(b[u], b[v]);\n    }\n\n    int src[M];\n    for (int i = 0; i < M; i++) src[i] = -1;\n\n    vector<int> changed;\n    changed.reserve(touched.size());\n\n    for (int t : touched) {\n        if (b[t] == t) continue;\n        int fp = suff[t];\n        int fs = suff[b[t]];\n        src[fp] = fs;\n        changed.push_back(fp);\n    }\n\n    if (changed.empty()) return true;\n    return validWithSourceMap(finalA, src, changed);\n}\n\ntemplate<class TimeOK>\nvoid pruneBlocksFast(const array<int, M>& init,\n                     vector<pair<int,int>>& ops,\n                     int maxLen,\n                     TimeOK timeOK) {\n    int deletedBlocks = 0;\n\n    while (timeOK() && deletedBlocks < 80) {\n        array<int, M> finalA = simulateOps(init, ops);\n        if (countViol(finalA) != 0) return;\n\n        auto suff = buildSuffixMaps(ops);\n\n        bool found = false;\n        int K = (int)ops.size();\n\n        for (int i = 0; i < K && timeOK(); i++) {\n            int ml = min(maxLen, K - i);\n            for (int len = ml; len >= 2; len--) {\n                if (canDeleteBlockFast(finalA, suff[i + len], ops, i, i + len)) {\n                    ops.erase(ops.begin() + i, ops.begin() + i + len);\n                    found = true;\n                    deletedBlocks++;\n                    break;\n                }\n            }\n            if (found) break;\n        }\n\n        if (!found) break;\n    }\n}\n\nbool canReplacePermValid(const array<int, M>& finalA,\n                         const array<int, M>& suff,\n                         const vector<int>& verts,\n                         const int permB[8],\n                         const int permR[8],\n                         int m,\n                         int src[M]) {\n    int invB[8];\n    for (int e = 0; e < m; e++) invB[permB[e]] = e;\n\n    vector<int> changed;\n    changed.reserve(m);\n\n    for (int e = 0; e < m; e++) {\n        int token = permR[e];\n        int oldEnd = invB[token];\n\n        int fp = suff[verts[e]];\n        int fs = suff[verts[oldEnd]];\n\n        if (fp != fs) {\n            src[fp] = fs;\n            changed.push_back(fp);\n        }\n    }\n\n    bool ok = true;\n    if (!changed.empty()) ok = validWithSourceMap(finalA, src, changed);\n\n    for (int p : changed) src[p] = -1;\n    return ok;\n}\n\ntemplate<class TimeOK>\nbool findValidReplacement(int m,\n                          const vector<pair<int,int>>& edges,\n                          const array<int, M>& finalA,\n                          const array<int, M>& suff,\n                          const vector<int>& verts,\n                          const int permB[8],\n                          int maxDepth,\n                          vector<int>& edgePath,\n                          TimeOK timeOK) {\n    edgePath.clear();\n    if (m > 8) return false;\n\n    int src[M];\n    for (int i = 0; i < M; i++) src[i] = -1;\n\n    int arr[8];\n\n    auto testCode = [&](uint64_t code) {\n        decodePerm(code, m, arr);\n        return canReplacePermValid(finalA, suff, verts, permB, arr, m, src);\n    };\n\n    uint64_t start = encodeIdentity(m);\n    if (testCode(start)) return true;\n    if (edges.empty() || maxDepth <= 0) return false;\n\n    unordered_map<uint64_t, int> id;\n    id.reserve(10000);\n\n    vector<uint64_t> state;\n    vector<int> par;\n    vector<int> pedge;\n    vector<int> dep;\n\n    id[start] = 0;\n    state.push_back(start);\n    par.push_back(-1);\n    pedge.push_back(-1);\n    dep.push_back(0);\n\n    for (int head = 0; head < (int)state.size() && timeOK(); head++) {\n        if ((int)state.size() > 26000) break;\n        if (dep[head] >= maxDepth) continue;\n\n        decodePerm(state[head], m, arr);\n\n        for (int ei = 0; ei < (int)edges.size(); ei++) {\n            auto [a, b] = edges[ei];\n            swap(arr[a], arr[b]);\n\n            uint64_t nc = 0;\n            for (int i = 0; i < m; i++) nc |= (uint64_t)arr[i] << (4 * i);\n\n            if (!id.count(nc)) {\n                int nid = (int)state.size();\n                id[nc] = nid;\n                state.push_back(nc);\n                par.push_back(head);\n                pedge.push_back(ei);\n                dep.push_back(dep[head] + 1);\n\n                if (testCode(nc)) {\n                    int cur = nid;\n                    while (cur != 0) {\n                        edgePath.push_back(pedge[cur]);\n                        cur = par[cur];\n                    }\n                    reverse(edgePath.begin(), edgePath.end());\n                    return true;\n                }\n            }\n\n            swap(arr[a], arr[b]);\n        }\n    }\n\n    return false;\n}\n\n// Local replacement that may change the final valid heap state.\ntemplate<class TimeOK>\nvoid optimizeWindowsValid(const array<int, M>& init,\n                          vector<pair<int,int>>& ops,\n                          int maxLen,\n                          TimeOK timeOK) {\n    int improvements = 0;\n\n    while (timeOK() && improvements < 40) {\n        array<int, M> finalA = simulateOps(init, ops);\n        if (countViol(finalA) != 0) return;\n\n        auto suff = buildSuffixMaps(ops);\n\n        bool found = false;\n        int K = (int)ops.size();\n\n        for (int i = 0; i < K && timeOK(); i++) {\n            int ml = min(maxLen, K - i);\n\n            for (int len = ml; len >= 2 && timeOK(); len--) {\n                array<int, M> loc;\n                loc.fill(-1);\n\n                vector<int> verts;\n                verts.reserve(len + 1);\n\n                auto addv = [&](int v) {\n                    if (loc[v] == -1) {\n                        loc[v] = (int)verts.size();\n                        verts.push_back(v);\n                    }\n                };\n\n                for (int j = i; j < i + len; j++) {\n                    addv(ops[j].first);\n                    addv(ops[j].second);\n                }\n\n                int m = (int)verts.size();\n                if (m > 8) continue;\n\n                int permB[8];\n                for (int t = 0; t < m; t++) permB[t] = t;\n\n                for (int j = i; j < i + len; j++) {\n                    int a = loc[ops[j].first];\n                    int b = loc[ops[j].second];\n                    swap(permB[a], permB[b]);\n                }\n\n                vector<pair<int,int>> localEdges;\n                for (int a = 0; a < m; a++) {\n                    for (int b = a + 1; b < m; b++) {\n                        if (ADJMAT[verts[a]][verts[b]]) localEdges.emplace_back(a, b);\n                    }\n                }\n\n                vector<int> edgePath;\n                if (!findValidReplacement(m, localEdges, finalA, suff[i + len],\n                                          verts, permB, len - 1, edgePath, timeOK)) {\n                    continue;\n                }\n\n                if ((int)edgePath.size() >= len) continue;\n\n                vector<pair<int,int>> repl;\n                repl.reserve(edgePath.size());\n\n                for (int ei : edgePath) {\n                    auto [a, b] = localEdges[ei];\n                    repl.emplace_back(verts[a], verts[b]);\n                }\n\n                ops.erase(ops.begin() + i, ops.begin() + i + len);\n                ops.insert(ops.begin() + i, repl.begin(), repl.end());\n\n                found = true;\n                improvements++;\n                break;\n            }\n\n            if (found) break;\n        }\n\n        if (!found) break;\n    }\n}\n\n// Append validity-preserving swaps and prune again.\ntemplate<class TimeOK>\nbool tryAppendPruneImprove(const array<int, M>& init,\n                           const array<int, M>& initPos,\n                           vector<pair<int,int>>& bestOps,\n                           uint64_t seed,\n                           TimeOK timeOK) {\n    array<int, M> base = simulateOps(init, bestOps);\n    if (countViol(base) != 0) return false;\n\n    int origK = (int)bestOps.size();\n\n    unordered_map<int, int> freq;\n    freq.reserve(bestOps.size() * 2 + 1);\n    for (auto [u, v] : bestOps) {\n        if (u > v) swap(u, v);\n        freq[u * M + v]++;\n    }\n\n    for (int trial = 0; trial < 24 && timeOK(); trial++) {\n        array<int, M> a = base;\n        vector<pair<int,int>> seq = bestOps;\n        FastRand rng(seed ^ (uint64_t)(trial + 1) * 0x9e3779b97f4a7c15ULL);\n\n        int mode = (trial < 16 ? trial % 4 : 4 + (trial - 16) % 3);\n        int maxSteps;\n        if (mode == 0) maxSteps = 18;\n        else if (mode == 1) maxSteps = 26;\n        else if (mode == 2) maxSteps = 36;\n        else if (mode == 3) maxSteps = 48;\n        else if (mode == 4) maxSteps = 14;\n        else if (mode == 5) maxSteps = 22;\n        else maxSteps = 30;\n\n        int lastU = -1, lastV = -1;\n\n        for (int step = 0; step < maxSteps && timeOK(); step++) {\n            long long bestScore = LLONG_MIN;\n            int bu = -1, bv = -1;\n\n            for (auto [u, v] : ADJ) {\n                if (!canSwapKeepValid(a, u, v)) continue;\n\n                int A = a[u], B = a[v];\n\n                int du0 = distHex(u, initPos[A]);\n                int dv0 = distHex(v, initPos[B]);\n                int du1 = distHex(v, initPos[A]);\n                int dv1 = distHex(u, initPos[B]);\n\n                long long before, after;\n                if (mode == 1) {\n                    before = 1LL * du0 * du0 + 1LL * dv0 * dv0;\n                    after  = 1LL * du1 * du1 + 1LL * dv1 * dv1;\n                } else {\n                    before = du0 + dv0;\n                    after  = du1 + dv1;\n                }\n\n                long long delta = after - before;\n\n                if (mode == 0 && delta >= 0) continue;\n                if (mode == 1 && delta >= 0) continue;\n                if (mode == 2 && delta > 0) continue;\n                if (mode == 3 && delta > 1) continue;\n                if (mode == 4 && delta > 3) continue;\n\n                int x = u, y = v;\n                if (x > y) swap(x, y);\n\n                int f = 0;\n                auto it = freq.find(x * M + y);\n                if (it != freq.end()) f = it->second;\n\n                long long score;\n                if (mode <= 3) {\n                    score = -delta * 100000LL + 500LL * f + (long long)rng.nextInt(5000);\n                } else {\n                    score = 20000LL * f - 5000LL * delta + (long long)rng.nextInt(20000);\n                }\n\n                if ((u == lastV && v == lastU) || (u == lastU && v == lastV)) score -= 10000000LL;\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bu = u;\n                    bv = v;\n                }\n            }\n\n            if (bu == -1) break;\n\n            swap(a[bu], a[bv]);\n            seq.emplace_back(bu, bv);\n            lastU = bu;\n            lastV = bv;\n        }\n\n        if ((int)seq.size() <= origK) continue;\n        if (countViol(a) != 0) continue;\n\n        vector<pair<int,int>> pruned = pruneOpsFast(init, seq, 3);\n        if ((int)pruned.size() < origK) {\n            array<int, M> aa = simulateOps(init, pruned);\n            if (countViol(aa) == 0) {\n                bestOps = move(pruned);\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    array<int, M> init;\n    for (int x = 0; x < N; x++) {\n        for (int y = 0; y <= x; y++) {\n            cin >> init[ID[x][y]];\n        }\n    }\n\n    array<int, M> initPos;\n    for (int i = 0; i < M; i++) initPos[init[i]] = i;\n\n    uint64_t inputHash = 0;\n    for (int i = 0; i < M; i++) {\n        inputHash = splitmix64(inputHash ^ (uint64_t)(init[i] + 1) * 1000003ULL ^ (uint64_t)i);\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto searchOK = [&]() {\n        return elapsed() < 1.78;\n    };\n    auto finalOK = [&]() {\n        return elapsed() < 1.94;\n    };\n\n    vector<pair<int,int>> bestOps;\n    int bestK = 10001;\n    const int PRUNE_MARGIN = 1600;\n\n    auto consider = [&](Work&& w) {\n        int raw = (int)w.ops.size();\n        if (raw > 10000) return;\n        if (countViol(w.a) != 0) return;\n\n        if (bestK <= 10000 && raw >= bestK + PRUNE_MARGIN) return;\n\n        vector<pair<int,int>> pruned = pruneOpsFast(init, w.ops, 3);\n        if ((int)pruned.size() > 10000) return;\n\n        array<int, M> aa = simulateOps(init, pruned);\n        if (countViol(aa) != 0) return;\n\n        int k = (int)pruned.size();\n        if (k < bestK) {\n            bestK = k;\n            bestOps = move(pruned);\n        }\n    };\n\n    auto limitGen = [&]() {\n        if (bestK > 10000) return 10000;\n        return min(10000, bestK + PRUNE_MARGIN);\n    };\n\n    // Guaranteed candidates first.\n    for (int yo = 0; yo < 2; yo++) {\n        for (int pm = 0; pm < 3; pm++) {\n            Work w(init);\n            if (appendCone(w, yo, pm, 10000)) consider(move(w));\n        }\n    }\n\n    // Deterministic sifts.\n    for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n        for (int ch = 0; ch < 5 && searchOK() && bestK > 0; ch++) {\n            Work w;\n            if (solveSift(init, dir, ch, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    // Loose bidirectional sifts.\n    vector<pair<int,int>> looseChoices = {\n        {0, 0}, {1, 1}, {4, 4}, {0, 1}, {1, 0}\n    };\n\n    for (int mode = 0; mode < 8 && searchOK() && bestK > 0; mode++) {\n        for (auto [cs, cl] : looseChoices) {\n            if (!searchOK() || bestK == 0) break;\n            Work w;\n            if (solveBiLoose(init, mode, cs, cl, -1, 0,\n                             inputHash ^ (uint64_t)(mode * 100 + cs * 10 + cl),\n                             limitGen(), w)) {\n                consider(move(w));\n            }\n        }\n    }\n\n    for (int mode : {2, 3, 4, 5, 6}) {\n        for (auto [cs, cl] : vector<pair<int,int>>{{0, 0}, {1, 1}, {4, 4}}) {\n            for (int fd = 0; fd < 2; fd++) {\n                if (!searchOK() || bestK == 0) break;\n                Work w;\n                if (solveBiLoose(init, mode, cs, cl, fd, (fd == 0 ? cs : cl),\n                                 inputHash ^ (uint64_t)(999 + mode * 100 + fd * 10 + cs),\n                                 limitGen(), w)) {\n                    consider(move(w));\n                }\n            }\n        }\n    }\n\n    // Randomized sifts.\n    for (int t = 0; t < 90 && searchOK() && bestK > 0; t++) {\n        int dir = t & 1;\n        int mode = (t / 2) % 8;\n        uint64_t seed = inputHash ^ (uint64_t)(t + 1) * 0x9e3779b97f4a7c15ULL;\n\n        Work w(init);\n        if (appendSiftRandom(w, dir, mode, seed, limitGen())) consider(move(w));\n    }\n\n    // Bidirectional BFS candidates.\n    vector<tuple<Strat, Strat, int>> biStrats;\n    auto addBi = [&](Strat a, Strat b, int bias) {\n        biStrats.emplace_back(a, b, bias);\n    };\n\n    addBi({1000, 5, 0, -20, 0, 0}, {1000, -5, 0, -20, 0, 0}, 0);\n    addBi({1000, 10, 0, -20, 0, 0}, {1000, -10, 0, -20, 0, 0}, 0);\n    addBi({1000, 0, 0, -20, 0, 0}, {1000, 0, 0, -20, 0, 0}, 0);\n    addBi({1000, 5, -3, -20, 0, 0}, {1000, -5, -3, -20, 0, 0}, 0);\n    addBi({1000, 5, 3, -20, 0, 0}, {1000, -5, 3, -20, 0, 0}, 0);\n    addBi({300, 20, 0, -30, 0, 0}, {300, -20, 0, -30, 0, 0}, 0);\n    addBi({500, 10, -5, -30, 80, inputHash ^ 111}, {500, -10, -5, -30, 80, inputHash ^ 222}, 0);\n    addBi({500, 10, 5, -30, 80, inputHash ^ 333}, {500, -10, 5, -30, 80, inputHash ^ 444}, 0);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 555}, {1000, -5, 0, -20, 100, inputHash ^ 666}, -200);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 777}, {1000, -5, 0, -20, 100, inputHash ^ 888}, 200);\n\n    for (auto [ts, bs, bias] : biStrats) {\n        if (!searchOK() || bestK == 0) break;\n        Work w;\n        if (solveBiBFS(init, ts, bs, bias, limitGen(), w)) consider(move(w));\n    }\n\n    // Greedy energy prefixes + sift finishers.\n    vector<tuple<int,bool,int>> gparams = {\n        {10000, false, 120},\n        {10000, false, 300},\n        {3000, false, 300},\n        {1000, false, 500},\n        {300, false, 500},\n        {20000, true, 250}\n    };\n\n    for (auto [W, quad, steps] : gparams) {\n        if (!searchOK() || bestK == 0) break;\n\n        Work pref(init);\n        runGreedyCost(pref, W, quad, steps, limitGen());\n\n        if (countViol(pref.a) == 0) consider(Work(pref));\n\n        for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n            for (int ch : {0, 1, 4}) {\n                if (!searchOK() || bestK == 0) break;\n                Work w = pref;\n                if (appendSift(w, dir, ch, limitGen())) consider(move(w));\n            }\n        }\n    }\n\n    // Local violation prefixes + sift/cone finishers.\n    vector<int> prefVars = {0, 1, 6, 7};\n    vector<int> prefSteps = {80, 180, 350, 700};\n\n    for (int var : prefVars) {\n        for (int stp : prefSteps) {\n            if (!searchOK() || bestK == 0) break;\n\n            Work pref(init);\n            if (!runLocalSteps(pref, var, stp, limitGen())) continue;\n\n            if (countViol(pref.a) == 0) {\n                consider(Work(pref));\n                continue;\n            }\n\n            for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n                for (int ch : {0, 1, 4}) {\n                    if (!searchOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendSift(w, dir, ch, limitGen())) consider(move(w));\n                }\n            }\n\n            for (int yo = 0; yo < 2 && searchOK() && bestK > 0; yo++) {\n                for (int pm = 0; pm < 3; pm++) {\n                    if (!searchOK() || bestK == 0) break;\n                    Work w = pref;\n                    if (appendCone(w, yo, pm, limitGen())) consider(move(w));\n                }\n            }\n        }\n    }\n\n    // BFS topological constructions.\n    vector<Strat> strats;\n    auto addStrat = [&](int w, int r, int c, int o, int ra = 0, uint64_t seed = 0) {\n        strats.push_back({w, r, c, o, ra, seed});\n    };\n\n    addStrat(1000, 0, 0, 0);\n    addStrat(1000, 1, 0, 0);\n    addStrat(1000, -1, 0, 0);\n    addStrat(1000, 0, 1, 0);\n    addStrat(1000, 0, -1, 0);\n    addStrat(1000, 0, 0, -10);\n    addStrat(200, 10, 0, 0);\n    addStrat(200, -10, 0, 0);\n    addStrat(200, 30, 0, 0);\n    addStrat(200, -30, 0, 0);\n    addStrat(200, 0, 10, 0);\n    addStrat(200, 0, -10, 0);\n    addStrat(200, 10, -5, -20);\n    addStrat(200, -10, 5, -20);\n    addStrat(100, 10, 0, -30);\n    addStrat(100, -10, 0, -30);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 1234567);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 9876543);\n    addStrat(700, 5, -3, -15, 150, inputHash ^ 5555555);\n    addStrat(700, -5, 3, -15, 150, inputHash ^ 3141592);\n\n    for (int dir = 0; dir < 2 && searchOK() && bestK > 0; dir++) {\n        for (const auto& st : strats) {\n            if (!searchOK() || bestK == 0) break;\n            Work w;\n            if (solveBFS(init, dir, st, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    // Sweep heapification variants.\n    for (int xd = 0; xd < 2 && searchOK() && bestK > 0; xd++) {\n        for (int yd = 0; yd < 2 && searchOK() && bestK > 0; yd++) {\n            for (int ch = 0; ch < 4 && searchOK() && bestK > 0; ch++) {\n                Work w;\n                if (solveSweep(init, xd, yd, ch, limitGen(), w)) consider(move(w));\n            }\n        }\n    }\n\n    // Pure local violation swapping variants.\n    for (int var = 0; var < 9 && searchOK() && bestK > 0; var++) {\n        Work w;\n        if (solveLocal(init, var, limitGen(), w)) consider(move(w));\n    }\n\n    // Safety fallback.\n    if (bestK > 10000) {\n        Work w(init);\n        appendCone(w, 0, 0, 10000);\n        bestOps = move(w.ops);\n        bestK = (int)bestOps.size();\n    }\n\n    // Final pruning, preserving previous behavior.\n    bestOps = pruneOpsFast(init, bestOps, 5);\n\n    auto slowSingle = [&](bool rev) {\n        if (rev) {\n            for (int i = (int)bestOps.size() - 1; i >= 0 && finalOK(); i--) {\n                if (validSkipping(init, bestOps, i)) {\n                    bestOps.erase(bestOps.begin() + i);\n                }\n            }\n        } else {\n            for (int i = 0; i < (int)bestOps.size() && finalOK(); ) {\n                if (validSkipping(init, bestOps, i)) {\n                    bestOps.erase(bestOps.begin() + i);\n                } else {\n                    i++;\n                }\n            }\n        }\n    };\n\n    auto slowPairs = [&]() {\n        for (int i = 0; i + 1 < (int)bestOps.size() && finalOK(); ) {\n            if (validSkipping(init, bestOps, i, i + 1)) {\n                bestOps.erase(bestOps.begin() + i, bestOps.begin() + i + 2);\n            } else {\n                i++;\n            }\n        }\n    };\n\n    if (finalOK()) slowSingle(false);\n    if (finalOK()) slowSingle(true);\n    if (finalOK()) slowPairs();\n    if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n\n    if (finalOK()) {\n        optimizeWindows(bestOps, finalOK);\n        if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 2);\n    }\n\n    for (int rep = 0; rep < 4 && finalOK(); rep++) {\n        int before = (int)bestOps.size();\n        bool improved = tryAppendPruneImprove(init, initPos, bestOps,\n                                              inputHash ^ (uint64_t)(rep + 12345),\n                                              finalOK);\n        if (!improved) break;\n\n        if (finalOK()) optimizeWindows(bestOps, finalOK);\n        if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n\n        if ((int)bestOps.size() >= before) break;\n    }\n\n    // New fast final-state-changing local optimizations.\n    if (finalOK()) pruneBlocksFast(init, bestOps, 10, finalOK);\n    if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 2);\n    if (finalOK()) optimizeWindowsValid(init, bestOps, 6, finalOK);\n    if (finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n    if (finalOK()) optimizeWindows(bestOps, finalOK);\n\n    // Last safety check.\n    {\n        array<int, M> aa = simulateOps(init, bestOps);\n        if (countViol(aa) != 0 || (int)bestOps.size() > 10000) {\n            Work w(init);\n            appendCone(w, 0, 0, 10000);\n            bestOps = move(w.ops);\n        }\n    }\n\n    cout << bestOps.size() << '\\n';\n    for (auto [u, v] : bestOps) {\n        cout << Xc[u] << ' ' << Yc[u] << ' ' << Xc[v] << ' ' << Yc[v] << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int INF = 1e9;\n\nint D, N, M;\nint rootR, rootC;\nbool obs[9][9];\nint gid[9][9];\n\nvector<pair<int,int>> posi;\nvector<vector<int>> adjList;\nvector<int> rootAdjCells;\nvector<char> isRootAdj;\n\nvector<uint64_t> adjLo, adjHi;\nvector<int> orderP, pIndex;\n\nvector<int> assignedLabel;\nvector<char> unseenLabel;\nint emptyCnt;\n\nchrono::steady_clock::time_point globalStart;\n\nbool timeOver(double lim) {\n    return chrono::duration<double>(chrono::steady_clock::now() - globalStart).count() > lim;\n}\n\nstatic inline bool inside(int r, int c) {\n    return 0 <= r && r < D && 0 <= c && c < D;\n}\n\nstatic inline bool hasBit(uint64_t lo, uint64_t hi, int i) {\n    if (i < 64) return (lo >> i) & 1ULL;\n    return (hi >> (i - 64)) & 1ULL;\n}\n\nstatic inline void setBit(uint64_t &lo, uint64_t &hi, int i) {\n    if (i < 64) lo |= 1ULL << i;\n    else hi |= 1ULL << (i - 64);\n}\n\nstatic inline bool intersects(uint64_t aLo, uint64_t aHi, uint64_t bLo, uint64_t bHi) {\n    return ((aLo & bLo) | (aHi & bHi)) != 0;\n}\n\nstatic inline bool accessibleFrom(int cell, uint64_t lo, uint64_t hi) {\n    return isRootAdj[cell] || intersects(adjLo[cell], adjHi[cell], lo, hi);\n}\n\nstatic inline int countLessMask(uint64_t lo, uint64_t hi, int x) {\n    if (x <= 0) return 0;\n    if (x < 64) {\n        return __builtin_popcountll(lo & ((1ULL << x) - 1));\n    }\n    if (x == 64) return __builtin_popcountll(lo);\n    int h = x - 64;\n    uint64_t mask = (1ULL << h) - 1;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n}\n\n// Checks whether all current empty cells except a,b are reachable from entrance.\nbool connectedAvoid(int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (assignedLabel[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (assignedLabel[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validPlacementCandidates() {\n    vector<int> cand;\n\n    for (int c = 0; c < M; c++) {\n        if (assignedLabel[c] != -1) continue;\n        if (connectedAvoid(c, -1, emptyCnt - 1)) cand.push_back(c);\n    }\n\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (assignedLabel[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nint countNextValidAfter(int c) {\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return 0;\n    if (rem == 1) return 1;\n\n    int cnt = 0;\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (connectedAvoid(c, e, rem - 1)) cnt++;\n    }\n\n    return cnt;\n}\n\nvector<int> collectNextValidAfter(int c) {\n    vector<int> res;\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return res;\n\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (rem == 1 || connectedAvoid(c, e, rem - 1)) {\n            res.push_back(e);\n        }\n    }\n\n    return res;\n}\n\nint invOfValues(const int *seq) {\n    int inv = 0;\n\n    for (int i = 0; i < M; i++) {\n        for (int j = i + 1; j < M; j++) {\n            if (seq[i] > seq[j]) inv++;\n        }\n    }\n\n    return inv;\n}\n\nint sequenceCost(const vector<int> &seq, const vector<int> &lab) {\n    if ((int)seq.size() != M) return INF;\n\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int x = lab[seq[step]];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nbool isLegalSequence(const vector<int> &seq) {\n    if ((int)seq.size() != M) return false;\n\n    vector<char> seen(M, 0);\n    uint64_t lo = 0, hi = 0;\n\n    for (int cell : seq) {\n        if (cell < 0 || cell >= M || seen[cell]) return false;\n        if (!accessibleFrom(cell, lo, hi)) return false;\n\n        seen[cell] = 1;\n        setBit(lo, hi, cell);\n    }\n\n    return true;\n}\n\nint greedyCostLabels(const vector<int> &lab) {\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            if (accessibleFrom(i, rlo, rhi) && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) return INF;\n\n        int x = lab[best];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\n// Lightweight simulation for choosing a single storage template.\nbool connectedAvoidSim(const vector<int> &ass, int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (ass[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (ass[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validCandSim(const vector<int> &ass, int ecnt) {\n    vector<int> cand;\n    for (int c = 0; c < M; c++) {\n        if (ass[c] != -1) continue;\n        if (connectedAvoidSim(ass, c, -1, ecnt - 1)) cand.push_back(c);\n    }\n\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (ass[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nlong long simulateTemplateScore(\n    const vector<int> &ord,\n    const vector<int> &pidx,\n    const vector<vector<int>> &perms\n) {\n    long long total = 0;\n\n    for (const auto &perm : perms) {\n        vector<int> ass(M, -1);\n        vector<char> unseen(M, 1);\n        int ecnt = M;\n\n        for (int step = 0; step < M; step++) {\n            int t = perm[step];\n\n            vector<int> cand = validCandSim(ass, ecnt);\n\n            int rankLabel = 0;\n            for (int x = 0; x < M; x++) {\n                if (unseen[x] && x < t) rankLabel++;\n            }\n\n            int bestCell = cand[0];\n            int bestAbs = INF;\n            int bestPDiff = INF;\n            int bestPos = INF;\n\n            for (int c : cand) {\n                int rankCell = 0;\n                for (int e = 0; e < M; e++) {\n                    if (ass[e] == -1 && pidx[e] < pidx[c]) rankCell++;\n                }\n\n                int ad = abs(rankCell - rankLabel);\n                int pd = abs(pidx[c] - t);\n                int ps = pidx[c];\n\n                if (ad < bestAbs ||\n                    (ad == bestAbs && pd < bestPDiff) ||\n                    (ad == bestAbs && pd == bestPDiff && ps < bestPos)) {\n                    bestAbs = ad;\n                    bestPDiff = pd;\n                    bestPos = ps;\n                    bestCell = c;\n                }\n            }\n\n            ass[bestCell] = t;\n            unseen[t] = 0;\n            ecnt--;\n        }\n\n        int c1 = sequenceCost(ord, ass);\n        int c2 = greedyCostLabels(ass);\n        total += min(c1, c2);\n    }\n\n    return total;\n}\n\nvector<int> chooseStorageOrderBySimulation(const vector<vector<int>> &orders) {\n    if (orders.empty() || N == 0) return orders.empty() ? vector<int>() : orders[0];\n\n    uint64_t seed = 123456789;\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (obs[r][c]) seed = seed * 1000003 + r * 17 + c + 1;\n        }\n    }\n\n    mt19937 rng((unsigned)seed);\n\n    int S = 8;\n    vector<vector<int>> perms(S, vector<int>(M));\n\n    for (int s = 0; s < S; s++) {\n        iota(perms[s].begin(), perms[s].end(), 0);\n        shuffle(perms[s].begin(), perms[s].end(), rng);\n    }\n\n    long long baseScore = LLONG_MAX;\n    long long bestScore = LLONG_MAX;\n    int bestId = 0;\n\n    for (int ti = 0; ti < (int)orders.size(); ti++) {\n        vector<int> pidx(M);\n        for (int i = 0; i < M; i++) pidx[orders[ti][i]] = i;\n\n        long long sc = simulateTemplateScore(orders[ti], pidx, perms);\n\n        if (ti == 0) baseScore = sc;\n\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestId = ti;\n        }\n    }\n\n    // Conservative threshold: switch only if the simulated average gain is clear.\n    if (bestId != 0 && bestScore + 3LL * S < baseScore) {\n        return orders[bestId];\n    }\n\n    return orders[0];\n}\n\nint evaluateHypWithExtra(\n    int c1,\n    int t1,\n    int c2,\n    int t2,\n    const vector<int> &futureLabels,\n    vector<int> &lab,\n    int *seqVals\n) {\n    int ptr = 0;\n    int si = 0;\n\n    for (int cell : orderP) {\n        int v;\n\n        if (assignedLabel[cell] != -1) {\n            v = assignedLabel[cell];\n        } else if (cell == c1) {\n            v = t1;\n        } else if (cell == c2) {\n            v = t2;\n        } else {\n            v = futureLabels[ptr++];\n        }\n\n        lab[cell] = v;\n        seqVals[si++] = v;\n    }\n\n    int fixedInv = invOfValues(seqVals);\n    int greedyInv = greedyCostLabels(lab);\n\n    return min(fixedInv, greedyInv);\n}\n\nvector<int> greedySequenceMinLabel(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            if (accessibleFrom(i, rlo, rhi) && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) break;\n\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n    }\n\n    return seq;\n}\n\nvector<int> greedySequenceLookahead2(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestScore = INT_MAX;\n        int bestCostInc = INT_MAX;\n        int bestLab = INT_MAX;\n\n        for (int c = 0; c < M; c++) {\n            if (hasBit(rlo, rhi, c)) continue;\n            if (!accessibleFrom(c, rlo, rhi)) continue;\n\n            int x = lab[c];\n            int less = countLessMask(llo, lhi, x);\n            int inc1 = x - less;\n            int costInc = step - less;\n\n            uint64_t nrlo = rlo, nrhi = rhi;\n            uint64_t nllo = llo, nlhi = lhi;\n            setBit(nrlo, nrhi, c);\n            setBit(nllo, nlhi, x);\n\n            int inc2 = 0;\n\n            if (step + 1 < M) {\n                inc2 = INT_MAX / 4;\n\n                for (int d = 0; d < M; d++) {\n                    if (hasBit(nrlo, nrhi, d)) continue;\n                    if (!accessibleFrom(d, nrlo, nrhi)) continue;\n\n                    int y = lab[d];\n                    int less2 = countLessMask(nllo, nlhi, y);\n                    inc2 = min(inc2, y - less2);\n                }\n            }\n\n            int score = inc1 + inc2;\n\n            if (score < bestScore ||\n                (score == bestScore && costInc < bestCostInc) ||\n                (score == bestScore && costInc == bestCostInc && x < bestLab)) {\n                bestScore = score;\n                bestCostInc = costInc;\n                bestLab = x;\n                best = c;\n            }\n        }\n\n        if (best == -1) break;\n\n        int x = lab[best];\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return seq;\n}\n\n// Legal single-cell insertion improvement.\nvector<int> improveSequenceByInsertion(vector<int> seq, const vector<int> &lab, int maxIter = 1000) {\n    if (!isLegalSequence(seq)) return seq;\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (timeOver(1.86)) break;\n\n        vector<uint64_t> prefLo(M + 1, 0), prefHi(M + 1, 0);\n        vector<int> arr(M);\n\n        for (int i = 0; i < M; i++) {\n            arr[i] = lab[seq[i]];\n            prefLo[i + 1] = prefLo[i];\n            prefHi[i + 1] = prefHi[i];\n            setBit(prefLo[i + 1], prefHi[i + 1], seq[i]);\n        }\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n\n        for (int j = 1; j < M; j++) {\n            int x = arr[j];\n            int delta = 0;\n\n            for (int i = j - 1; i >= 0; i--) {\n                int y = arr[i];\n\n                if (x > y) delta++;\n                else delta--;\n\n                if (delta < bestDelta && accessibleFrom(seq[j], prefLo[i], prefHi[i])) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        int cell = seq[bestJ];\n        seq.erase(seq.begin() + bestJ);\n        seq.insert(seq.begin() + bestI, cell);\n    }\n\n    return seq;\n}\n\n// Legal block insertion improvement.\n// Move block [j,k] before i if the block itself is removable from prefix i.\nvector<int> improveSequenceByBlockInsertion(vector<int> seq, const vector<int> &lab, int maxIter = 60) {\n    if (!isLegalSequence(seq)) return seq;\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (timeOver(1.84)) break;\n\n        vector<uint64_t> prefCellLo(M + 1, 0), prefCellHi(M + 1, 0);\n        vector<uint64_t> prefLabLo(M + 1, 0), prefLabHi(M + 1, 0);\n\n        for (int i = 0; i < M; i++) {\n            prefCellLo[i + 1] = prefCellLo[i];\n            prefCellHi[i + 1] = prefCellHi[i];\n            prefLabLo[i + 1] = prefLabLo[i];\n            prefLabHi[i + 1] = prefLabHi[i];\n\n            setBit(prefCellLo[i + 1], prefCellHi[i + 1], seq[i]);\n            setBit(prefLabLo[i + 1], prefLabHi[i + 1], lab[seq[i]]);\n        }\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1, bestK = -1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = i + 1; j < M; j++) {\n                int lenA = j - i;\n                uint64_t segLo = prefLabLo[j] & ~prefLabLo[i];\n                uint64_t segHi = prefLabHi[j] & ~prefLabHi[i];\n\n                uint64_t curLo = prefCellLo[i];\n                uint64_t curHi = prefCellHi[i];\n\n                int delta = 0;\n\n                for (int k = j; k < M; k++) {\n                    int cell = seq[k];\n\n                    if (!accessibleFrom(cell, curLo, curHi)) break;\n\n                    int y = lab[cell];\n                    int less = countLessMask(segLo, segHi, y);\n                    delta += 2 * less - lenA;\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                        bestK = k;\n                    }\n\n                    setBit(curLo, curHi, cell);\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        vector<int> ns;\n        ns.reserve(M);\n\n        for (int p = 0; p < bestI; p++) ns.push_back(seq[p]);\n        for (int p = bestJ; p <= bestK; p++) ns.push_back(seq[p]);\n        for (int p = bestI; p < bestJ; p++) ns.push_back(seq[p]);\n        for (int p = bestK + 1; p < M; p++) ns.push_back(seq[p]);\n\n        seq.swap(ns);\n    }\n\n    return seq;\n}\n\n// Exact local DP on a contiguous window.\nvector<int> winDpBuf;\nvector<unsigned char> winParBuf;\nvector<uint64_t> winSubLoBuf, winSubHiBuf, winSubLabLoBuf, winSubLabHiBuf;\n\nvoid ensureWinBuf(int S) {\n    if ((int)winDpBuf.size() < S) {\n        winDpBuf.resize(S);\n        winParBuf.resize(S);\n        winSubLoBuf.resize(S);\n        winSubHiBuf.resize(S);\n        winSubLabLoBuf.resize(S);\n        winSubLabHiBuf.resize(S);\n    }\n}\n\nbool improveWindowAt(vector<int> &seq, const vector<int> &lab, int l, int K, double lim) {\n    if (K <= 1) return false;\n    if (K > 20) K = 20;\n    if (l + K > M) K = M - l;\n    if (K <= 1) return false;\n\n    int cells[20];\n\n    for (int i = 0; i < K; i++) {\n        cells[i] = seq[l + i];\n    }\n\n    int originalInv = 0;\n    for (int i = 0; i < K; i++) {\n        for (int j = i + 1; j < K; j++) {\n            if (lab[cells[i]] > lab[cells[j]]) originalInv++;\n        }\n    }\n\n    if (originalInv == 0) return false;\n\n    uint64_t prefLo = 0, prefHi = 0;\n    for (int i = 0; i < l; i++) {\n        setBit(prefLo, prefHi, seq[i]);\n    }\n\n    uint64_t cellLo[20] = {}, cellHi[20] = {};\n    uint64_t labelLo[20] = {}, labelHi[20] = {};\n\n    for (int i = 0; i < K; i++) {\n        setBit(cellLo[i], cellHi[i], cells[i]);\n        setBit(labelLo[i], labelHi[i], lab[cells[i]]);\n    }\n\n    int S = 1 << K;\n    int full = S - 1;\n\n    ensureWinBuf(S);\n\n    winSubLoBuf[0] = winSubHiBuf[0] = 0;\n    winSubLabLoBuf[0] = winSubLabHiBuf[0] = 0;\n\n    for (int mask = 1; mask < S; mask++) {\n        if ((mask & 8191) == 0 && timeOver(lim)) return false;\n\n        int b = __builtin_ctz((unsigned)mask);\n        int pm = mask ^ (1 << b);\n\n        winSubLoBuf[mask] = winSubLoBuf[pm] | cellLo[b];\n        winSubHiBuf[mask] = winSubHiBuf[pm] | cellHi[b];\n        winSubLabLoBuf[mask] = winSubLabLoBuf[pm] | labelLo[b];\n        winSubLabHiBuf[mask] = winSubLabHiBuf[pm] | labelHi[b];\n    }\n\n    fill(winDpBuf.begin(), winDpBuf.begin() + S, INF);\n    fill(winParBuf.begin(), winParBuf.begin() + S, 255);\n\n    winDpBuf[0] = 0;\n\n    for (int mask = 0; mask < S; mask++) {\n        if ((mask & 4095) == 0 && timeOver(lim)) return false;\n\n        int cur = winDpBuf[mask];\n        if (cur >= originalInv) continue;\n\n        uint64_t rmLo = prefLo | winSubLoBuf[mask];\n        uint64_t rmHi = prefHi | winSubHiBuf[mask];\n\n        int selectedCnt = __builtin_popcount((unsigned)mask);\n\n        for (int j = 0; j < K; j++) {\n            if (mask & (1 << j)) continue;\n\n            int cell = cells[j];\n            if (!accessibleFrom(cell, rmLo, rmHi)) continue;\n\n            int x = lab[cell];\n            int less = countLessMask(winSubLabLoBuf[mask], winSubLabHiBuf[mask], x);\n            int add = selectedCnt - less;\n\n            int nm = mask | (1 << j);\n            int nc = cur + add;\n\n            if (nc < winDpBuf[nm]) {\n                winDpBuf[nm] = nc;\n                winParBuf[nm] = (unsigned char)j;\n            }\n        }\n    }\n\n    if (winDpBuf[full] >= originalInv) return false;\n\n    vector<int> rev;\n    rev.reserve(K);\n\n    int mask = full;\n    while (mask) {\n        int j = winParBuf[mask];\n        if (j < 0 || j >= K) return false;\n\n        rev.push_back(cells[j]);\n        mask ^= (1 << j);\n    }\n\n    reverse(rev.begin(), rev.end());\n\n    for (int i = 0; i < K; i++) {\n        seq[l + i] = rev[i];\n    }\n\n    return true;\n}\n\nvector<int> improveSequenceByWindowDP(vector<int> seq, const vector<int> &lab, int maxK, int passes, double lim) {\n    if (!isLegalSequence(seq)) return seq;\n    maxK = min(maxK, 20);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (timeOver(lim)) break;\n\n        bool any = false;\n\n        if (pass % 2 == 0) {\n            for (int l = 0; l < M - 1; l++) {\n                if (timeOver(lim)) return seq;\n\n                int K = min(maxK, M - l);\n                if (K >= 2 && improveWindowAt(seq, lab, l, K, lim)) {\n                    any = true;\n                }\n            }\n        } else {\n            for (int l = M - 2; l >= 0; l--) {\n                if (timeOver(lim)) return seq;\n\n                int K = min(maxK, M - l);\n                if (K >= 2 && improveWindowAt(seq, lab, l, K, lim)) {\n                    any = true;\n                }\n            }\n        }\n\n        if (!any) break;\n    }\n\n    return seq;\n}\n\nvoid addTemplateOrder(vector<vector<int>> &temps, const vector<int> &ord) {\n    if ((int)ord.size() != M) return;\n    if (!isLegalSequence(ord)) return;\n\n    for (const auto &v : temps) {\n        if (v == ord) return;\n    }\n\n    temps.push_back(ord);\n}\n\nvector<vector<int>> buildFinalTemplates() {\n    vector<vector<int>> temps;\n    addTemplateOrder(temps, orderP);\n\n    const int BIG = 1e9;\n\n    vector<vector<int>> dist(D, vector<int>(D, BIG));\n    queue<pair<int,int>> q;\n\n    dist[rootR][rootC] = 0;\n    q.push({rootR, rootC});\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != BIG) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            q.push({nr, nc});\n        }\n    }\n\n    auto makeDiscOrder = [&](const vector<pair<int,int>> &dirs) {\n        vector<vector<int>> disc(D, vector<int>(D, BIG));\n        queue<pair<int,int>> qq;\n\n        disc[rootR][rootC] = 0;\n        int cnt = 1;\n        qq.push({rootR, rootC});\n\n        while (!qq.empty()) {\n            auto [r, c] = qq.front();\n            qq.pop();\n\n            for (auto [dr, dc] : dirs) {\n                int nr = r + dr;\n                int nc = c + dc;\n\n                if (!inside(nr, nc) || obs[nr][nc]) continue;\n                if (disc[nr][nc] != BIG) continue;\n\n                disc[nr][nc] = cnt++;\n                qq.push({nr, nc});\n            }\n        }\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n\n            return a < b;\n        });\n\n        return ord;\n    };\n\n    addTemplateOrder(temps, makeDiscOrder({{1,0},{0,-1},{0,1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{1,0},{0,1},{0,-1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{0,-1},{1,0},{0,1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{0,1},{1,0},{0,-1},{-1,0}}));\n\n    auto keyOf = [&](int type, int id) -> long long {\n        auto [r, c] = posi[id];\n\n        switch (type) {\n            case 0: return c * 100LL + r;\n            case 1: return -c * 100LL + r;\n            case 2: return llabs(c - rootC) * 100LL + c;\n            case 3: return -llabs(c - rootC) * 100LL + c;\n            case 4: return r * 100LL + c;\n            case 5: return -r * 100LL + c;\n            case 6: return (r + c) * 100LL + c;\n            case 7: return (r - c) * 100LL + c;\n            default: return id;\n        }\n    };\n\n    for (int type = 0; type < 8; type++) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n\n            long long ka = keyOf(type, a);\n            long long kb = keyOf(type, b);\n\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        addTemplateOrder(temps, ord);\n    }\n\n    auto expansionOrder = [&](int type) {\n        vector<int> ord;\n        vector<char> used(M, 0);\n        uint64_t lo = 0, hi = 0;\n\n        auto score = [&](int id) -> long long {\n            auto [r, c] = posi[id];\n\n            switch (type) {\n                case 0: return c * 100LL + r;\n                case 1: return -c * 100LL + r;\n                case 2: return -r * 100LL + c;\n                case 3: return -r * 100LL - c;\n                case 4: return llabs(c - rootC) * 100LL - r;\n                case 5: return -llabs(c - rootC) * 100LL - r;\n                case 6: return (r + c) * 100LL - r;\n                default: return id;\n            }\n        };\n\n        for (int step = 0; step < M; step++) {\n            int best = -1;\n            long long bestScore = LLONG_MAX;\n\n            for (int id = 0; id < M; id++) {\n                if (used[id]) continue;\n                if (!accessibleFrom(id, lo, hi)) continue;\n\n                long long sc = score(id);\n                if (sc < bestScore || (sc == bestScore && (best == -1 || id < best))) {\n                    bestScore = sc;\n                    best = id;\n                }\n            }\n\n            if (best == -1) return vector<int>();\n\n            used[best] = 1;\n            ord.push_back(best);\n            setBit(lo, hi, best);\n        }\n\n        return ord;\n    };\n\n    for (int type = 0; type < 7; type++) {\n        addTemplateOrder(temps, expansionOrder(type));\n    }\n\n    return temps;\n}\n\nstruct Key {\n    uint64_t lo, hi;\n\n    bool operator==(const Key &o) const {\n        return lo == o.lo && hi == o.hi;\n    }\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\nstruct KeyHash {\n    size_t operator()(const Key &k) const {\n        return splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1);\n    }\n};\n\nstruct Node {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nstruct Temp {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nvector<int> beamSearchRemoval(const vector<int> &lab, int upperBound) {\n    const int BEAM = 12000;\n\n    vector<Node> nodes;\n    nodes.reserve((M + 1) * BEAM + 1);\n    nodes.push_back(Node{0, 0, 0, 0, 0, 0, -1, -1});\n\n    vector<int> cur;\n    cur.push_back(0);\n\n    auto betterTemp = [](const Temp &a, const Temp &b) {\n        if (a.forced != b.forced) return a.forced < b.forced;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.lo != b.lo) return a.lo < b.lo;\n        return a.hi < b.hi;\n    };\n\n    for (int depth = 0; depth < M; depth++) {\n        if (timeOver(1.82)) break;\n\n        vector<Temp> temps;\n        size_t reserveSize = min<size_t>((size_t)cur.size() * 40 + 100, 700000);\n        temps.reserve(reserveSize);\n\n        unordered_map<Key, int, KeyHash> mp;\n        mp.reserve(reserveSize * 2);\n\n        for (int idx : cur) {\n            const Node &s = nodes[idx];\n\n            for (int i = 0; i < M; i++) {\n                if (hasBit(s.lo, s.hi, i)) continue;\n                if (!accessibleFrom(i, s.lo, s.hi)) continue;\n\n                int x = lab[i];\n                int less = countLessMask(s.llo, s.lhi, x);\n\n                int cost2 = s.cost + (depth - less);\n                int forced2 = s.forced + (x - less);\n\n                if (forced2 > upperBound) continue;\n\n                uint64_t nlo = s.lo, nhi = s.hi;\n                uint64_t nllo = s.llo, nlhi = s.lhi;\n                setBit(nlo, nhi, i);\n                setBit(nllo, nlhi, x);\n\n                Temp t{nlo, nhi, nllo, nlhi, cost2, forced2, idx, i};\n                Key key{nlo, nhi};\n\n                auto it = mp.find(key);\n\n                if (it == mp.end()) {\n                    int id = (int)temps.size();\n                    temps.push_back(t);\n                    mp.emplace(key, id);\n                } else {\n                    int id = it->second;\n\n                    if (t.cost < temps[id].cost ||\n                        (t.cost == temps[id].cost && t.forced < temps[id].forced)) {\n                        temps[id] = t;\n                    }\n                }\n            }\n        }\n\n        if (temps.empty()) return {};\n\n        if ((int)temps.size() > BEAM) {\n            nth_element(temps.begin(), temps.begin() + BEAM, temps.end(), betterTemp);\n            temps.resize(BEAM);\n        }\n\n        vector<int> nxt;\n        nxt.reserve(temps.size());\n\n        for (const Temp &t : temps) {\n            int id = (int)nodes.size();\n            nodes.push_back(Node{t.lo, t.hi, t.llo, t.lhi, t.cost, t.forced, t.parent, t.cell});\n            nxt.push_back(id);\n        }\n\n        cur.swap(nxt);\n    }\n\n    int bestNode = -1;\n    int bestCost = INF;\n\n    for (int idx : cur) {\n        if (nodes[idx].cost < bestCost &&\n            __builtin_popcountll(nodes[idx].lo) + __builtin_popcountll(nodes[idx].hi) == M) {\n            bestCost = nodes[idx].cost;\n            bestNode = idx;\n        }\n    }\n\n    if (bestNode == -1) return {};\n\n    vector<int> seq;\n\n    while (bestNode != 0 && bestNode != -1) {\n        seq.push_back(nodes[bestNode].cell);\n        bestNode = nodes[bestNode].parent;\n    }\n\n    reverse(seq.begin(), seq.end());\n\n    if ((int)seq.size() != M) return {};\n    return seq;\n}\n\nstruct PQNode {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int forced;\n    int parent;\n    int cell;\n    int depth;\n};\n\nvector<int> bestFirstSearchRemoval(const vector<int> &lab, int upperBound, int nodeLimit = 120000) {\n    if (timeOver(1.72)) return {};\n\n    struct Item {\n        long long eval;\n        int forced;\n        int depth;\n        int id;\n    };\n\n    struct Cmp {\n        bool operator()(const Item &a, const Item &b) const {\n            if (a.eval != b.eval) return a.eval > b.eval;\n            if (a.forced != b.forced) return a.forced > b.forced;\n            return a.depth < b.depth;\n        }\n    };\n\n    vector<PQNode> nodes;\n    nodes.reserve(nodeLimit + 1);\n\n    priority_queue<Item, vector<Item>, Cmp> pq;\n    unordered_map<Key, int, KeyHash> best;\n    best.reserve(nodeLimit * 2);\n\n    nodes.push_back(PQNode{0, 0, 0, 0, 0, -1, -1, 0});\n    best[{0, 0}] = 0;\n    pq.push(Item{0, 0, 0, 0});\n\n    while (!pq.empty() && (int)nodes.size() < nodeLimit) {\n        if (timeOver(1.86)) break;\n\n        Item it = pq.top();\n        pq.pop();\n\n        const PQNode &s = nodes[it.id];\n        Key curKey{s.lo, s.hi};\n\n        auto mit = best.find(curKey);\n        if (mit == best.end() || mit->second != s.forced) continue;\n\n        if (s.depth == M) {\n            if (s.forced >= upperBound) return {};\n\n            vector<int> seq;\n            int v = it.id;\n\n            while (v != -1 && nodes[v].cell != -1) {\n                seq.push_back(nodes[v].cell);\n                v = nodes[v].parent;\n            }\n\n            reverse(seq.begin(), seq.end());\n\n            if ((int)seq.size() == M) return seq;\n            return {};\n        }\n\n        vector<int> cand;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(s.lo, s.hi, i)) continue;\n            if (accessibleFrom(i, s.lo, s.hi)) cand.push_back(i);\n        }\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            return lab[a] < lab[b];\n        });\n\n        for (int cell : cand) {\n            int x = lab[cell];\n            int less = countLessMask(s.llo, s.lhi, x);\n            int nf = s.forced + (x - less);\n\n            if (nf >= upperBound) continue;\n\n            uint64_t nlo = s.lo, nhi = s.hi;\n            uint64_t nllo = s.llo, nlhi = s.lhi;\n            setBit(nlo, nhi, cell);\n            setBit(nllo, nlhi, x);\n\n            Key nk{nlo, nhi};\n            auto bit = best.find(nk);\n\n            if (bit != best.end() && bit->second <= nf) continue;\n\n            best[nk] = nf;\n\n            if ((int)nodes.size() >= nodeLimit) break;\n\n            int nid = (int)nodes.size();\n            nodes.push_back(PQNode{nlo, nhi, nllo, nlhi, nf, it.id, cell, s.depth + 1});\n\n            long long eval = 1000LL * nf - (s.depth + 1);\n            pq.push(Item{eval, nf, s.depth + 1, nid});\n        }\n    }\n\n    return {};\n}\n\nint main() {\n    globalStart = chrono::steady_clock::now();\n\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D >> N;\n\n    rootR = 0;\n    rootC = (D - 1) / 2;\n\n    memset(obs, 0, sizeof(obs));\n    memset(gid, -1, sizeof(gid));\n\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = true;\n    }\n\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (r == rootR && c == rootC) continue;\n            if (obs[r][c]) continue;\n\n            gid[r][c] = (int)posi.size();\n            posi.push_back({r, c});\n        }\n    }\n\n    M = (int)posi.size();\n\n    adjList.assign(M, {});\n    isRootAdj.assign(M, 0);\n    adjLo.assign(M, 0);\n    adjHi.assign(M, 0);\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    for (int id = 0; id < M; id++) {\n        auto [r, c] = posi[id];\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc)) continue;\n\n            if (nr == rootR && nc == rootC) {\n                isRootAdj[id] = 1;\n            } else if (!obs[nr][nc]) {\n                int to = gid[nr][nc];\n                if (to >= 0) adjList[id].push_back(to);\n            }\n        }\n\n        if (isRootAdj[id]) rootAdjCells.push_back(id);\n    }\n\n    for (int i = 0; i < M; i++) {\n        for (int to : adjList[i]) {\n            if (to < 64) adjLo[i] |= 1ULL << to;\n            else adjHi[i] |= 1ULL << (to - 64);\n        }\n    }\n\n    // Distance from entrance.\n    int dist[9][9];\n    int disc[9][9];\n\n    for (int r = 0; r < 9; r++) {\n        for (int c = 0; c < 9; c++) {\n            dist[r][c] = INF;\n            disc[r][c] = INF;\n        }\n    }\n\n    int bfsDirs[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};\n    queue<pair<int,int>> q;\n\n    dist[rootR][rootC] = 0;\n    disc[rootR][rootC] = 0;\n\n    int dcnt = 1;\n    q.push({rootR, rootC});\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : bfsDirs) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != INF) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            disc[nr][nc] = dcnt++;\n            q.push({nr, nc});\n        }\n    }\n\n    auto makeStorageOrder = [&](const vector<pair<int,int>> &dirs) {\n        vector<vector<int>> localDisc(D, vector<int>(D, INF));\n        queue<pair<int,int>> qq;\n\n        localDisc[rootR][rootC] = 0;\n        int cnt = 1;\n        qq.push({rootR, rootC});\n\n        while (!qq.empty()) {\n            auto [r, c] = qq.front();\n            qq.pop();\n\n            for (auto [dr, dc] : dirs) {\n                int nr = r + dr;\n                int nc = c + dc;\n\n                if (!inside(nr, nc) || obs[nr][nc]) continue;\n                if (localDisc[nr][nc] != INF) continue;\n\n                localDisc[nr][nc] = cnt++;\n                qq.push({nr, nc});\n            }\n        }\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (localDisc[ra][ca] != localDisc[rb][cb]) return localDisc[ra][ca] < localDisc[rb][cb];\n\n            return a < b;\n        });\n\n        return ord;\n    };\n\n    vector<vector<int>> storageOrders;\n    auto addStorageOrder = [&](const vector<int> &ord) {\n        if ((int)ord.size() != M) return;\n        if (!isLegalSequence(ord)) return;\n\n        for (auto &v : storageOrders) {\n            if (v == ord) return;\n        }\n\n        storageOrders.push_back(ord);\n    };\n\n    addStorageOrder(makeStorageOrder({{1,0},{0,-1},{0,1},{-1,0}}));\n    addStorageOrder(makeStorageOrder({{1,0},{0,1},{0,-1},{-1,0}}));\n    addStorageOrder(makeStorageOrder({{0,-1},{1,0},{0,1},{-1,0}}));\n    addStorageOrder(makeStorageOrder({{0,1},{1,0},{0,-1},{-1,0}}));\n\n    orderP = chooseStorageOrderBySimulation(storageOrders);\n    if (orderP.empty()) {\n        orderP.resize(M);\n        iota(orderP.begin(), orderP.end(), 0);\n        sort(orderP.begin(), orderP.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n\n            return a < b;\n        });\n    }\n\n    pIndex.assign(M, 0);\n    for (int i = 0; i < M; i++) pIndex[orderP[i]] = i;\n\n    assignedLabel.assign(M, -1);\n    unseenLabel.assign(M, 1);\n    emptyCnt = M;\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<int> cand = validPlacementCandidates();\n\n        vector<int> futureLabels;\n        futureLabels.reserve(emptyCnt - 1);\n\n        int rankLabel = 0;\n\n        for (int x = 0; x < M; x++) {\n            if (!unseenLabel[x]) continue;\n            if (x < t) rankLabel++;\n            if (x != t) futureLabels.push_back(x);\n        }\n\n        bool useLateLookahead = (emptyCnt <= 12 && emptyCnt >= 2 && !timeOver(1.20));\n\n        int bestCell = -1;\n        int bestHyp = INT_MAX;\n        int bestInv = INT_MAX;\n        int bestAbs = INT_MAX;\n        int bestNext = -1;\n        int bestPDiff = INT_MAX;\n        long long bestLateScore = LLONG_MAX / 4;\n        long long bestLatePrimary = LLONG_MAX / 4;\n\n        vector<int> lab(M);\n        int seqVals[85];\n\n        for (int c : cand) {\n            int ptr = 0;\n            int si = 0;\n\n            for (int cell : orderP) {\n                int v;\n\n                if (assignedLabel[cell] != -1) {\n                    v = assignedLabel[cell];\n                } else if (cell == c) {\n                    v = t;\n                } else {\n                    v = futureLabels[ptr++];\n                }\n\n                lab[cell] = v;\n                seqVals[si++] = v;\n            }\n\n            int fixedInv = invOfValues(seqVals);\n            int greedyInv = greedyCostLabels(lab);\n            int hyp = min(fixedInv, greedyInv);\n\n            int rankCell = 0;\n\n            for (int e = 0; e < M; e++) {\n                if (assignedLabel[e] == -1 && pIndex[e] < pIndex[c]) rankCell++;\n            }\n\n            int absDiff = abs(rankCell - rankLabel);\n\n            vector<int> nextCells;\n            int nextValid;\n\n            if (useLateLookahead) {\n                nextCells = collectNextValidAfter(c);\n                nextValid = (int)nextCells.size();\n            } else {\n                nextValid = countNextValidAfter(c);\n            }\n\n            int pDiff = abs(pIndex[c] - t);\n\n            long long lateScore = LLONG_MAX / 4;\n\n            if (useLateLookahead) {\n                long long sum = 0;\n\n                for (int u : futureLabels) {\n                    vector<int> future2;\n                    future2.reserve(futureLabels.size() - 1);\n\n                    for (int x : futureLabels) {\n                        if (x != u) future2.push_back(x);\n                    }\n\n                    int bestU = INF;\n\n                    for (int e : nextCells) {\n                        int val = evaluateHypWithExtra(c, t, e, u, future2, lab, seqVals);\n                        if (val < bestU) bestU = val;\n                    }\n\n                    sum += bestU;\n                }\n\n                lateScore = sum;\n            }\n\n            long long latePrimary = lateScore;\n            if (useLateLookahead && emptyCnt > 10) {\n                latePrimary += 10LL * hyp;\n            }\n\n            bool better = false;\n\n            if (useLateLookahead) {\n                if (latePrimary != bestLatePrimary) better = latePrimary < bestLatePrimary;\n                else if (lateScore != bestLateScore) better = lateScore < bestLateScore;\n                else if (hyp != bestHyp) better = hyp < bestHyp;\n                else if (fixedInv != bestInv) better = fixedInv < bestInv;\n                else if (absDiff != bestAbs) better = absDiff < bestAbs;\n                else if (nextValid != bestNext) better = nextValid > bestNext;\n                else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n            } else {\n                if (hyp != bestHyp) better = hyp < bestHyp;\n                else if (fixedInv != bestInv) better = fixedInv < bestInv;\n                else if (absDiff != bestAbs) better = absDiff < bestAbs;\n                else if (nextValid != bestNext) better = nextValid > bestNext;\n                else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n            }\n\n            if (better) {\n                bestLatePrimary = latePrimary;\n                bestLateScore = lateScore;\n                bestHyp = hyp;\n                bestInv = fixedInv;\n                bestAbs = absDiff;\n                bestNext = nextValid;\n                bestPDiff = pDiff;\n                bestCell = c;\n            }\n        }\n\n        if (bestCell == -1) bestCell = cand[0];\n\n        assignedLabel[bestCell] = t;\n        unseenLabel[t] = 0;\n        emptyCnt--;\n\n        cout << posi[bestCell].first << ' ' << posi[bestCell].second << endl;\n    }\n\n    vector<int> bestSeq = orderP;\n    int bestCost = sequenceCost(bestSeq, assignedLabel);\n\n    auto considerSeq = [&](vector<int> seq, int improveIter) {\n        if ((int)seq.size() != M) return;\n        if (!isLegalSequence(seq)) return;\n\n        int c0 = sequenceCost(seq, assignedLabel);\n\n        if (c0 < bestCost) {\n            bestCost = c0;\n            bestSeq = seq;\n        }\n\n        if (improveIter > 0) {\n            vector<int> imp = improveSequenceByInsertion(seq, assignedLabel, improveIter);\n\n            if (isLegalSequence(imp)) {\n                int c1 = sequenceCost(imp, assignedLabel);\n\n                if (c1 < bestCost) {\n                    bestCost = c1;\n                    bestSeq = imp;\n                }\n            }\n        }\n    };\n\n    vector<vector<int>> finalTemplates = buildFinalTemplates();\n\n    for (const auto &seq : finalTemplates) {\n        considerSeq(seq, 300);\n    }\n\n    vector<int> gseq = greedySequenceMinLabel(assignedLabel);\n    considerSeq(gseq, 1000);\n\n    vector<int> lseq = greedySequenceLookahead2(assignedLabel);\n    considerSeq(lseq, 1000);\n\n    vector<int> impBest = improveSequenceByInsertion(bestSeq, assignedLabel, 1000);\n    considerSeq(impBest, 0);\n\n    // Run exact local DP earlier, before the heavier global searches consume time.\n    if (!timeOver(1.30)) {\n        vector<int> wseq = improveSequenceByWindowDP(bestSeq, assignedLabel, 16, 1, 1.42);\n        considerSeq(wseq, 200);\n    }\n\n    vector<int> bseq = beamSearchRemoval(assignedLabel, bestCost);\n    considerSeq(bseq, 1000);\n\n    if (!timeOver(1.70)) {\n        vector<int> wseq = improveSequenceByWindowDP(bestSeq, assignedLabel, 14, 1, 1.76);\n        considerSeq(wseq, 100);\n    }\n\n    if (!timeOver(1.76)) {\n        vector<int> blk = improveSequenceByBlockInsertion(bestSeq, assignedLabel, 60);\n        considerSeq(blk, 400);\n    }\n\n    if (!timeOver(1.78)) {\n        vector<int> aseq = bestFirstSearchRemoval(assignedLabel, bestCost, 120000);\n        considerSeq(aseq, 800);\n    }\n\n    if (!timeOver(1.84)) {\n        vector<int> blk = improveSequenceByBlockInsertion(bestSeq, assignedLabel, 40);\n        considerSeq(blk, 200);\n    }\n\n    if (!timeOver(1.86)) {\n        vector<int> wseq = improveSequenceByWindowDP(bestSeq, assignedLabel, 12, 1, 1.89);\n        considerSeq(wseq, 0);\n    }\n\n    if (!isLegalSequence(bestSeq)) {\n        bestSeq = orderP;\n    }\n\n    for (int cell : bestSeq) {\n        cout << posi[cell].first << ' ' << posi[cell].second << '\\n';\n    }\n\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 50;\nstatic const int MAXV = MAXN * MAXN;\nstatic const int MAXC = 105;\n\nint N, M, V;\nbool REQ[MAXC][MAXC];\nint GDEP[MAXC], DEGREQ[MAXC], NEED[MAXC];\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\n\nint visArr[MAXV];\nint bfsQ[MAXV];\nint visStamp = 1;\n\ninline int newStamp() {\n    ++visStamp;\n    if (visStamp == INT_MAX) {\n        memset(visArr, 0, sizeof(visArr));\n        visStamp = 1;\n    }\n    return visStamp;\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 RNG {\n    uint64_t s;\n    RNG(uint64_t seed = 1) : s(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (s += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    template<class T>\n    void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            swap(v[i], v[nextInt(i + 1)]);\n        }\n    }\n};\n\nstruct State {\n    array<unsigned char, MAXV> g;\n    int cnt[MAXC];\n    int edge[MAXC][MAXC];\n    int zeros;\n\n    void clear() {\n        g.fill(0);\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n        zeros = 0;\n    }\n\n    inline void addEdgeCnt(int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        edge[a][b] += d;\n        edge[b][a] += d;\n    }\n\n    void rebuild() {\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n\n        for (int p = 0; p < V; ++p) {\n            int a = g[p];\n            cnt[a]++;\n        }\n        zeros = cnt[0];\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int p = r * N + c;\n                int a = g[p];\n\n                if (r + 1 < N) addEdgeCnt(a, g[(r + 1) * N + c], 1);\n                if (c + 1 < N) addEdgeCnt(a, g[r * N + (c + 1)], 1);\n\n                if (r == 0) addEdgeCnt(0, a, 1);\n                if (r == N - 1) addEdgeCnt(0, a, 1);\n                if (c == 0) addEdgeCnt(0, a, 1);\n                if (c == N - 1) addEdgeCnt(0, a, 1);\n            }\n        }\n    }\n\n    inline bool hasZeroAdj(int p) const {\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return true;\n            int q = nr * N + nc;\n            if (g[q] == 0) return true;\n        }\n        return false;\n    }\n\n    bool connectedAfterRemoveColor(int p, int col) const {\n        if (cnt[col] <= 1) return false;\n\n        int r = p / N, c = p % N;\n        int nb[4], k = 0;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (g[q] == col) nb[k++] = q;\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        bool reached[4] = {};\n        reached[0] = true;\n        int found = 1;\n\n        visArr[nb[0]] = stamp;\n        bfsQ[tail++] = nb[0];\n\n        while (head < tail && found < k) {\n            int v = bfsQ[head++];\n            int vr = v / N, vc = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = vr + DR[d], nc = vc + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n\n                visArr[q] = stamp;\n\n                for (int i = 1; i < k; ++i) {\n                    if (!reached[i] && q == nb[i]) {\n                        reached[i] = true;\n                        ++found;\n                        break;\n                    }\n                }\n\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return found == k;\n    }\n\n    bool zeroConnectedAfterRemove(int p) const {\n        if (cnt[0] <= 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int q = r * N + c;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0] - 1;\n    }\n\n    bool connectedColorFull(int col) const {\n        if (col <= 0) return false;\n        if (cnt[col] <= 0) return false;\n\n        int start = -1;\n        for (int p = 0; p < V; ++p) {\n            if (g[p] == col) {\n                start = p;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        visArr[start] = stamp;\n        bfsQ[tail++] = start;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[col];\n    }\n\n    bool zeroConnectedFull() const {\n        if (cnt[0] == 0) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0];\n    }\n\n    bool tryChange(int p, int to) {\n        int from = g[p];\n        if (from == to) return false;\n        if (to < 0 || to > M) return false;\n\n        if (from > 0 && cnt[from] <= 1) return false;\n\n        if (to == 0) {\n            if (from == 0) return false;\n            if (!hasZeroAdj(p)) return false;\n        } else {\n            bool adjTarget = false;\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] == to) {\n                    adjTarget = true;\n                    break;\n                }\n            }\n            if (!adjTarget) return false;\n        }\n\n        int du[16], dv[16], dd[16], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            int nbcol = 0;\n            if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                nbcol = g[nr * N + nc];\n            }\n\n            addDelta(from, nbcol, -1);\n            addDelta(to, nbcol, +1);\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        if (from == 0) {\n            if (!zeroConnectedAfterRemove(p)) return false;\n        } else {\n            if (!connectedAfterRemoveColor(p, from)) return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        cnt[from]--;\n        cnt[to]++;\n\n        if (from == 0) zeros--;\n        if (to == 0) zeros++;\n\n        g[p] = (unsigned char)to;\n        return true;\n    }\n\n    bool tryChange2(int p, int np, int q, int nq) {\n        if (p == q) return false;\n\n        int op = g[p], oq = g[q];\n        if (op == np && oq == nq) return false;\n        if (np < 0 || np > M || nq < 0 || nq > M) return false;\n\n        int cc[8], cd[8], cn = 0;\n\n        auto addCntDelta = [&](int c, int d) {\n            if (d == 0) return;\n            for (int i = 0; i < cn; ++i) {\n                if (cc[i] == c) {\n                    cd[i] += d;\n                    return;\n                }\n            }\n            cc[cn] = c;\n            cd[cn] = d;\n            ++cn;\n        };\n\n        addCntDelta(op, -1);\n        addCntDelta(oq, -1);\n        addCntDelta(np, +1);\n        addCntDelta(nq, +1);\n\n        for (int i = 0; i < cn; ++i) {\n            if (cc[i] > 0 && cnt[cc[i]] + cd[i] <= 0) return false;\n        }\n\n        int du[40], dv[40], dd[40], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        auto oldCol = [&](int x) -> int {\n            if (x == p) return op;\n            if (x == q) return oq;\n            return g[x];\n        };\n\n        auto newCol = [&](int x) -> int {\n            if (x == p) return np;\n            if (x == q) return nq;\n            return g[x];\n        };\n\n        int cells[2] = {p, q};\n\n        for (int ii = 0; ii < 2; ++ii) {\n            int x = cells[ii];\n            int xr = x / N, xc = x % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = xr + DR[d], nc = xc + DC[d];\n\n                int a0 = oldCol(x);\n                int a1 = newCol(x);\n                int b0, b1;\n\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                    b0 = b1 = 0;\n                } else {\n                    int y = nr * N + nc;\n                    if ((y == p || y == q) && x > y) continue;\n                    b0 = oldCol(y);\n                    b1 = newCol(y);\n                }\n\n                addDelta(a0, b0, -1);\n                addDelta(a1, b1, +1);\n            }\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        g[p] = (unsigned char)np;\n        g[q] = (unsigned char)nq;\n\n        for (int i = 0; i < cn; ++i) cnt[cc[i]] += cd[i];\n        zeros = cnt[0];\n\n        int aff[4], an = 0;\n        auto addAff = [&](int c) {\n            for (int i = 0; i < an; ++i) {\n                if (aff[i] == c) return;\n            }\n            aff[an++] = c;\n        };\n\n        addAff(op);\n        addAff(oq);\n        addAff(np);\n        addAff(nq);\n\n        bool ok = true;\n        for (int i = 0; i < an && ok; ++i) {\n            int c = aff[i];\n            if (c == 0) ok = zeroConnectedFull();\n            else ok = connectedColorFull(c);\n        }\n\n        if (!ok) {\n            for (int i = 0; i < cn; ++i) cnt[cc[i]] -= cd[i];\n            zeros = cnt[0];\n            g[p] = (unsigned char)op;\n            g[q] = (unsigned char)oq;\n            return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        return true;\n    }\n};\n\nbool validFast(const State& st) {\n    for (int c = 1; c <= M; ++c) {\n        if (st.cnt[c] <= 0) return false;\n    }\n\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if ((st.edge[i][j] > 0) != REQ[i][j]) return false;\n        }\n    }\n\n    if (st.cnt[0] > 0) {\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (st.g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != st.cnt[0]) return false;\n    }\n\n    static int comp[MAXC];\n    memset(comp, 0, sizeof(comp));\n\n    int stamp = newStamp();\n\n    for (int p = 0; p < V; ++p) {\n        int col = st.g[p];\n        if (col == 0) continue;\n        if (visArr[p] == stamp) continue;\n\n        ++comp[col];\n        if (comp[col] >= 2) return false;\n\n        int head = 0, tail = 0;\n        visArr[p] = stamp;\n        bfsQ[tail++] = p;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n\n    for (int c = 1; c <= M; ++c) {\n        if (comp[c] != 1) return false;\n    }\n\n    return true;\n}\n\nvoid computeGraphInfo() {\n    for (int i = 0; i <= M; ++i) {\n        DEGREQ[i] = 0;\n        for (int j = 0; j <= M; ++j) {\n            if (i != j && REQ[i][j]) DEGREQ[i]++;\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        NEED[i] = max(1, (DEGREQ[i] - 1) / 2);\n    }\n    NEED[0] = 0;\n\n    fill(GDEP, GDEP + MAXC, 1000000);\n    queue<int> q;\n    GDEP[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u = 0; u <= M; ++u) {\n            if (!REQ[v][u]) continue;\n            if (GDEP[u] > GDEP[v] + 1) {\n                GDEP[u] = GDEP[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        if (GDEP[i] > 100000) GDEP[i] = 50;\n    }\n}\n\nvoid computeDist(const State& st, vector<int>& dist) {\n    const int INF = 1e9;\n    dist.assign(V, INF);\n\n    int head = 0, tail = 0;\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] == 0) {\n            dist[p] = 0;\n            bfsQ[tail++] = p;\n        }\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n            int p = r * N + c;\n            if (dist[p] > 1) {\n                dist[p] = 1;\n                bfsQ[tail++] = p;\n            }\n        }\n    }\n\n    while (head < tail) {\n        int v = bfsQ[head++];\n        int r = v / N, c = v % N;\n        int nd = dist[v] + 1;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (dist[q] > nd) {\n                dist[q] = nd;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n}\n\nint greedyDelete(State& st, RNG& rng, int mode = 0) {\n    vector<int> cand;\n    cand.reserve(V * 5);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0 && st.hasZeroAdj(p)) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    if (mode == 1) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            int sa = st.cnt[ca] - NEED[ca];\n            int sb = st.cnt[cb] - NEED[cb];\n            if (sa != sb) return sa > sb;\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 2) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (st.cnt[ca] != st.cnt[cb]) return st.cnt[ca] > st.cnt[cb];\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 3) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return st.cnt[ca] > st.cnt[cb];\n        });\n    }\n\n    int deleted = 0;\n\n    for (size_t idx = 0; idx < cand.size(); ++idx) {\n        int p = cand[idx];\n        if (st.g[p] == 0) continue;\n        if (!st.hasZeroAdj(p)) continue;\n\n        if (st.tryChange(p, 0)) {\n            ++deleted;\n\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) cand.push_back(q);\n            }\n        }\n    }\n\n    return deleted;\n}\n\nint greedyDeleteMulti(State& st, RNG& rng, int repeats, int modeBase) {\n    int old = st.zeros;\n    if (repeats <= 1) {\n        greedyDelete(st, rng, modeBase & 3);\n        return st.zeros - old;\n    }\n\n    State base = st;\n    State best = st;\n\n    for (int r = 0; r < repeats; ++r) {\n        State tmp = base;\n        greedyDelete(tmp, rng, (modeBase + r) & 3);\n        if (tmp.zeros > best.zeros) best = tmp;\n    }\n\n    st = best;\n    return st.zeros - old;\n}\n\nstruct Params {\n    int strategy;\n    int orderMode;\n    int eqProb;\n    bool useLayer;\n    bool targetRandom;\n    bool preDelete;\n    int delRepeats;\n    int delMode;\n};\n\nParams getParams(int run) {\n    switch (run % 20) {\n        case 0:  return {0, 0,  0, false, false, true,  1, 0};\n        case 1:  return {0, 0, 10, true,  false, true,  1, 1};\n        case 2:  return {1, 0, 15, false, false, true,  1, 0};\n        case 3:  return {1, 3, 20, true,  false, true,  1, 1};\n        case 4:  return {3, 0, 15, false, false, true,  1, 2};\n        case 5:  return {4, 0, 10, false, false, true,  1, 1};\n        case 6:  return {2, 1,  0, false, true,  true,  1, 0};\n        case 7:  return {0, 1, 30, false, true,  true,  1, 2};\n        case 8:  return {1, 4, 25, false, false, false, 1, 3};\n        case 9:  return {3, 3, 20, true,  false, false, 1, 1};\n        case 10: return {0, 2,  0, false, true,  true,  1, 0};\n        case 11:return {4, 1, 20, false, true,  true,  1, 2};\n        case 12:return {1, 0,  0, true,  false, true,  2, 0};\n        case 13:return {3, 0, 30, false, false, true,  2, 1};\n        case 14:return {2, 1,  0, false, true,  false, 1, 0};\n        case 15:return {0, 0, 50, false, true,  false, 1, 1};\n        case 16:return {1, 3, 40, false, true,  false, 1, 2};\n        case 17:return {4, 3, 30, true,  false, true,  1, 3};\n        case 18:return {3, 1, 10, false, true,  true,  2, 0};\n        default:return {0, 0, 20, true,  false, true,  1, 0};\n    }\n}\n\nint recolorPass(State& st, const vector<int>& dist, RNG& rng, const Params& par) {\n    const int INF = 1e9;\n\n    int layer[MAXC];\n    for (int i = 0; i < MAXC; ++i) layer[i] = INF;\n    layer[0] = 0;\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a > 0) layer[a] = min(layer[a], dist[p]);\n    }\n\n    vector<int> order;\n    order.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) order.push_back(p);\n    }\n\n    rng.shuffleVec(order);\n\n    if (par.orderMode == 0) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 2) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n    } else if (par.orderMode == 3) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] > GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 4) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    }\n\n    struct Target {\n        int col;\n        int score;\n        int td;\n        int gd;\n        int rnd;\n    };\n\n    int changed = 0;\n\n    for (int p : order) {\n        int a = st.g[p];\n        if (a == 0) continue;\n        if (st.cnt[a] <= 1) continue;\n\n        int dp = dist[p];\n        int r = p / N, c = p % N;\n\n        Target ts[4];\n        int tn = 0;\n\n        auto addTarget = [&](int b, int dq, int score) {\n            int pos = -1;\n            for (int i = 0; i < tn; ++i) {\n                if (ts[i].col == b) {\n                    pos = i;\n                    break;\n                }\n            }\n\n            if (pos == -1) {\n                ts[tn++] = {b, score, dq, GDEP[b], (int)(rng.next() & 0x7fffffff)};\n            } else {\n                if (score > ts[pos].score) {\n                    ts[pos].score = score;\n                    ts[pos].td = min(ts[pos].td, dq);\n                }\n            }\n        };\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int q = nr * N + nc;\n            int b = st.g[q];\n            if (b == 0 || b == a) continue;\n\n            int dq = dist[q];\n            bool ok = false;\n            int score = 0;\n\n            if (par.strategy == 0) {\n                ok = (dq < dp) || (dq == dp && par.eqProb > 0 && rng.nextInt(100) < par.eqProb);\n                if (par.useLayer && layer[b] > layer[a]) ok = false;\n                score = (dp - dq) * 20 + (layer[a] - layer[b]) * 3 + (GDEP[a] - GDEP[b]);\n            } else if (par.strategy == 1) {\n                int da = GDEP[a], db = GDEP[b];\n                ok = (db < da) ||\n                     (db == da && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (dq < dp && db <= da + 1);\n\n                if (par.useLayer && layer[b] > layer[a] + 1) ok = false;\n                score = (da - db) * 30 + (dp - dq) * 5 + (layer[a] - layer[b]);\n            } else if (par.strategy == 2) {\n                ok = true;\n                score = (int)(rng.next() & 0xffff);\n            } else if (par.strategy == 3) {\n                int val =\n                    (GDEP[a] - GDEP[b]) * 18 +\n                    (dp - dq) * 7 +\n                    (layer[a] - layer[b]) * 4 +\n                    ((st.cnt[a] - NEED[a]) - (st.cnt[b] - NEED[b]));\n\n                ok = (val > 0) ||\n                     (val == 0 && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (rng.nextInt(100) < 4);\n\n                score = val;\n            } else {\n                int surplusA = st.cnt[a] - NEED[a];\n                int surplusB = st.cnt[b] - NEED[b];\n                int val =\n                    (surplusA - surplusB) * 5 +\n                    (GDEP[a] - GDEP[b]) * 8 +\n                    (dp - dq) * 3;\n\n                ok = (val > 0) ||\n                     (par.eqProb > 0 && rng.nextInt(100) < par.eqProb / 2);\n\n                score = val;\n            }\n\n            if (!ok) continue;\n            addTarget(b, dq, score);\n        }\n\n        if (tn == 0) continue;\n\n        if (par.targetRandom || par.strategy == 2) {\n            for (int i = tn - 1; i > 0; --i) {\n                swap(ts[i], ts[rng.nextInt(i + 1)]);\n            }\n        } else {\n            for (int i = 0; i < tn; ++i) {\n                for (int j = i + 1; j < tn; ++j) {\n                    bool better = false;\n                    if (ts[j].score != ts[i].score) {\n                        better = ts[j].score > ts[i].score;\n                    } else if (ts[j].td != ts[i].td) {\n                        better = ts[j].td < ts[i].td;\n                    } else if (ts[j].gd != ts[i].gd) {\n                        better = ts[j].gd < ts[i].gd;\n                    } else {\n                        better = ts[j].rnd < ts[i].rnd;\n                    }\n                    if (better) swap(ts[i], ts[j]);\n                }\n            }\n        }\n\n        for (int i = 0; i < tn; ++i) {\n            if (st.tryChange(p, ts[i].col)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid improve(State& st, State& best, RNG& rng, const Params& par, const Timer& timer, double limit) {\n    vector<int> dist;\n    int lastZeros = st.zeros;\n    int stagnant = 0;\n\n    for (int cycle = 0; cycle < 80; ++cycle) {\n        if (timer.elapsed() > limit) break;\n\n        int del = 0;\n\n        if (par.preDelete) {\n            del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode);\n            if (st.zeros > best.zeros) best = st;\n        }\n\n        computeDist(st, dist);\n        int rec = recolorPass(st, dist, rng, par);\n\n        del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode + cycle);\n        if (st.zeros > best.zeros) best = st;\n\n        if (st.zeros > lastZeros) {\n            lastZeros = st.zeros;\n            stagnant = 0;\n        } else {\n            ++stagnant;\n        }\n\n        if (rec + del == 0) break;\n\n        int maxStag = 4;\n        if (par.strategy == 2) maxStag = 3;\n        if (par.eqProb >= 30) maxStag++;\n        if (par.delRepeats >= 2) maxStag++;\n\n        if (stagnant >= maxStag) break;\n    }\n}\n\nint randomInterfaceRecolorPass(State& st, RNG& rng, int limitChanges) {\n    vector<int> cells;\n    cells.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b > 0 && b != a) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cells.push_back(p);\n    }\n\n    rng.shuffleVec(cells);\n\n    int changed = 0;\n\n    for (int p : cells) {\n        if (changed >= limitChanges) break;\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b == 0 || b == a) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint randomExpandPass(State& st, RNG& rng, int quota) {\n    vector<int> cand;\n    cand.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            if (st.g[nr * N + nc] > 0) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n\n    for (int p : cand) {\n        if (changed >= quota) break;\n        if (st.g[p] != 0) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b <= 0) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint swapPass(State& st, RNG& rng, int maxTries, int mode) {\n    vector<pair<int, int>> cand;\n    cand.reserve(2 * V);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n\n            if (r + 1 < N) {\n                int q = (r + 1) * N + c;\n                int a = st.g[p], b = st.g[q];\n                if (a != b) {\n                    bool z = (a == 0 || b == 0);\n                    if (mode == 2 || (mode == 0 && z) || (mode == 1 && !z)) {\n                        cand.push_back({p, q});\n                    }\n                }\n            }\n\n            if (c + 1 < N) {\n                int q = r * N + (c + 1);\n                int a = st.g[p], b = st.g[q];\n                if (a != b) {\n                    bool z = (a == 0 || b == 0);\n                    if (mode == 2 || (mode == 0 && z) || (mode == 1 && !z)) {\n                        cand.push_back({p, q});\n                    }\n                }\n            }\n        }\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n    int tried = 0;\n\n    for (auto [p, q] : cand) {\n        if (tried >= maxTries) break;\n\n        int a = st.g[p], b = st.g[q];\n        if (a == b) continue;\n\n        bool z = (a == 0 || b == 0);\n        if (!(mode == 2 || (mode == 0 && z) || (mode == 1 && !z))) continue;\n\n        ++tried;\n        if (st.tryChange2(p, b, q, a)) {\n            ++changed;\n        }\n    }\n\n    return changed;\n}\n\nint pairDeletePass(State& st, RNG& rng, int maxTries, int mode) {\n    vector<pair<int, int>> cand;\n    cand.reserve(2 * V);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n            int a = st.g[p];\n\n            if (r + 1 < N) {\n                int q = (r + 1) * N + c;\n                int b = st.g[q];\n                if (a > 0 && b > 0 && a != b && (st.hasZeroAdj(p) || st.hasZeroAdj(q))) {\n                    cand.push_back({p, q});\n                }\n            }\n\n            if (c + 1 < N) {\n                int q = r * N + (c + 1);\n                int b = st.g[q];\n                if (a > 0 && b > 0 && a != b && (st.hasZeroAdj(p) || st.hasZeroAdj(q))) {\n                    cand.push_back({p, q});\n                }\n            }\n        }\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n    int tried = 0;\n\n    struct Var {\n        int np, nq;\n        int score;\n    };\n\n    for (auto [p, q] : cand) {\n        if (tried >= maxTries) break;\n\n        int a = st.g[p], b = st.g[q];\n        if (a <= 0 || b <= 0 || a == b) continue;\n\n        bool hp = st.hasZeroAdj(p);\n        bool hq = st.hasZeroAdj(q);\n        if (!hp && !hq) continue;\n\n        ++tried;\n\n        Var vars[2];\n        int vn = 0;\n\n        if (hp) {\n            int lost = b;\n            int invader = a;\n            int score =\n                (st.cnt[lost] - NEED[lost]) * 12 +\n                (GDEP[lost] - GDEP[invader]) * 5 -\n                DEGREQ[lost];\n            vars[vn++] = {0, a, score};\n        }\n\n        if (hq) {\n            int lost = a;\n            int invader = b;\n            int score =\n                (st.cnt[lost] - NEED[lost]) * 12 +\n                (GDEP[lost] - GDEP[invader]) * 5 -\n                DEGREQ[lost];\n            vars[vn++] = {b, 0, score};\n        }\n\n        if (vn == 2) {\n            bool firstSecond = false;\n            if (mode == 0) {\n                firstSecond = rng.nextInt(2);\n            } else if (mode == 3) {\n                firstSecond = vars[1].score < vars[0].score;\n            } else {\n                firstSecond = vars[1].score > vars[0].score;\n            }\n            if (firstSecond) swap(vars[0], vars[1]);\n        }\n\n        for (int i = 0; i < vn; ++i) {\n            if (st.tryChange2(p, vars[i].np, q, vars[i].nq)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid shakeSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    while (timer.elapsed() < limit) {\n        State st = best;\n\n        int rounds = 3 + rng.nextInt(4);\n\n        for (int rd = 0; rd < rounds; ++rd) {\n            if (timer.elapsed() >= limit) break;\n\n            if (st.zeros > best.zeros - 25) {\n                randomExpandPass(st, rng, 2 + rng.nextInt(7));\n            }\n\n            randomInterfaceRecolorPass(st, rng, 80 + rng.nextInt(160));\n            pairDeletePass(st, rng, 120 + rng.nextInt(220), rng.nextInt(4));\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n\n            if (st.zeros > best.zeros) {\n                best = st;\n            }\n\n            if (st.zeros + 30 < best.zeros) break;\n        }\n    }\n}\n\nvoid neutralSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    State cur = best;\n    int stagnant = 0;\n\n    while (timer.elapsed() < limit) {\n        if (stagnant > 9) {\n            cur = best;\n            stagnant = 0;\n        }\n\n        int before = cur.zeros;\n        int total = 0;\n\n        total += pairDeletePass(cur, rng, 300 + rng.nextInt(450), rng.nextInt(4));\n\n        if (total == 0) {\n            total += swapPass(cur, rng, 180 + rng.nextInt(320), rng.nextInt(3));\n            total += randomInterfaceRecolorPass(cur, rng, 50 + rng.nextInt(130));\n            total += pairDeletePass(cur, rng, 180 + rng.nextInt(260), rng.nextInt(4));\n        }\n\n        total += greedyDeleteMulti(cur, rng, 1, rng.nextInt(4));\n\n        if (cur.zeros > best.zeros) {\n            best = cur;\n            stagnant = 0;\n        } else {\n            if (cur.zeros < best.zeros) cur = best;\n            if (cur.zeros == before && total == 0) stagnant += 2;\n            else stagnant++;\n        }\n    }\n}\n\nstruct BandOp {\n    int type;\n    int idx;\n    int len;\n};\n\nvoid applyBandDelete(State& out, const State& st, int type, int idx, int len) {\n    out = st;\n\n    if (type == 0) {\n        for (int r = idx; r + len < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = st.g[(r + len) * N + c];\n            }\n        }\n        for (int r = N - len; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else if (type == 1) {\n        for (int r = idx + len - 1; r >= len; --r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = st.g[(r - len) * N + c];\n            }\n        }\n        for (int r = 0; r < len; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else if (type == 2) {\n        for (int r = 0; r < N; ++r) {\n            for (int c = idx; c + len < N; ++c) {\n                out.g[r * N + c] = st.g[r * N + (c + len)];\n            }\n            for (int c = N - len; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else {\n        for (int r = 0; r < N; ++r) {\n            for (int c = idx + len - 1; c >= len; --c) {\n                out.g[r * N + c] = st.g[r * N + (c - len)];\n            }\n            for (int c = 0; c < len; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    }\n\n    out.rebuild();\n}\n\nbool compactBandsOnce(State& st, RNG& rng, const Timer& timer, double limit, int mode, int maxLen) {\n    vector<BandOp> ops;\n    ops.reserve(4 * N * maxLen);\n\n    for (int len = 1; len <= maxLen; ++len) {\n        for (int idx = 0; idx + len <= N; ++idx) {\n            for (int type = 0; type < 4; ++type) {\n                ops.push_back({type, idx, len});\n            }\n        }\n    }\n\n    rng.shuffleVec(ops);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyBandDelete(tmp, st, op.type, op.idx, op.len);\n\n        if (tmp.zeros <= st.zeros) continue;\n        if (!validFast(tmp)) continue;\n\n        if (mode == 1) {\n            st = tmp;\n            return true;\n        }\n\n        if (!found || tmp.zeros > best.zeros) {\n            best = tmp;\n            found = true;\n        }\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nvoid compactBandSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    int fail = 0;\n\n    while (timer.elapsed() < limit && fail < 4) {\n        State st = best;\n\n        int steps = 0;\n        int mode = (fail == 0 ? 0 : 1);\n        int maxLen = (fail >= 2 ? 3 : 2);\n\n        while (timer.elapsed() < limit && steps < 5) {\n            bool ok = compactBandsOnce(st, rng, timer, limit, mode, maxLen);\n            if (!ok) break;\n\n            ++steps;\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n        }\n\n        if (st.zeros > best.zeros) {\n            best = st;\n            fail = 0;\n        } else {\n            ++fail;\n        }\n    }\n}\n\nvoid applyDeleteLines(State& out, const State& st, int type, uint64_t mask) {\n    out = st;\n\n    if (type == 0) {\n        int nr = 0;\n        for (int r = 0; r < N; ++r) {\n            if ((mask >> r) & 1ULL) continue;\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = st.g[r * N + c];\n            ++nr;\n        }\n        for (; nr < N; ++nr) {\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = 0;\n        }\n    } else if (type == 1) {\n        int nr = N - 1;\n        for (int r = N - 1; r >= 0; --r) {\n            if ((mask >> r) & 1ULL) continue;\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = st.g[r * N + c];\n            --nr;\n        }\n        for (; nr >= 0; --nr) {\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = 0;\n        }\n    } else if (type == 2) {\n        for (int r = 0; r < N; ++r) {\n            int nc = 0;\n            for (int c = 0; c < N; ++c) {\n                if ((mask >> c) & 1ULL) continue;\n                out.g[r * N + nc] = st.g[r * N + c];\n                ++nc;\n            }\n            for (; nc < N; ++nc) out.g[r * N + nc] = 0;\n        }\n    } else {\n        for (int r = 0; r < N; ++r) {\n            int nc = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                if ((mask >> c) & 1ULL) continue;\n                out.g[r * N + nc] = st.g[r * N + c];\n                --nc;\n            }\n            for (; nc >= 0; --nc) out.g[r * N + nc] = 0;\n        }\n    }\n\n    out.rebuild();\n}\n\nstruct LineOp {\n    int type;\n    uint64_t mask;\n    int gain;\n    int score;\n};\n\nbool simpleLineOnce(State& st, RNG& rng, const Timer& timer, double limit) {\n    if (timer.elapsed() > limit - 0.002) return false;\n\n    int rowCnt[MAXN] = {};\n    int colCnt[MAXN] = {};\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (st.g[r * N + c] != 0) {\n                rowCnt[r]++;\n                colCnt[c]++;\n            }\n        }\n    }\n\n    vector<LineOp> ops;\n    ops.reserve(6000);\n\n    auto addOp = [&](int type, uint64_t mask, int gain, int k) {\n        if (gain <= 0) return;\n        int score = gain * 10000 + rng.nextInt(1000) - k * 50;\n        ops.push_back({type, mask, gain, score});\n    };\n\n    for (int i = 0; i < N; ++i) {\n        uint64_t m = 1ULL << i;\n        addOp(0, m, rowCnt[i], 1);\n        addOp(1, m, rowCnt[i], 1);\n        addOp(2, m, colCnt[i], 1);\n        addOp(3, m, colCnt[i], 1);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            uint64_t m = (1ULL << i) | (1ULL << j);\n            addOp(0, m, rowCnt[i] + rowCnt[j], 2);\n            addOp(1, m, rowCnt[i] + rowCnt[j], 2);\n            addOp(2, m, colCnt[i] + colCnt[j], 2);\n            addOp(3, m, colCnt[i] + colCnt[j], 2);\n        }\n    }\n\n    if (ops.empty()) return false;\n\n    auto cmp = [](const LineOp& a, const LineOp& b) {\n        return a.score > b.score;\n    };\n\n    const int MAXCAND = 1400;\n    if ((int)ops.size() > MAXCAND) {\n        nth_element(ops.begin(), ops.begin() + MAXCAND, ops.end(), cmp);\n        ops.resize(MAXCAND);\n    }\n    sort(ops.begin(), ops.end(), cmp);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyDeleteLines(tmp, st, op.type, op.mask);\n\n        if (tmp.zeros <= best.zeros) continue;\n        if (!validFast(tmp)) continue;\n\n        best = tmp;\n        found = true;\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nstruct CrossOp {\n    int rt, r, ct, c;\n    int gain;\n    int score;\n};\n\nvoid applyDeleteCross(State& out, const State& st, int rt, int r, int ct, int c) {\n    State tmp;\n    applyDeleteLines(tmp, st, rt, 1ULL << r);\n    applyDeleteLines(out, tmp, ct, 1ULL << c);\n}\n\nbool simpleCrossOnce(State& st, RNG& rng, const Timer& timer, double limit) {\n    if (timer.elapsed() > limit - 0.002) return false;\n\n    int rowCnt[MAXN] = {};\n    int colCnt[MAXN] = {};\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (st.g[r * N + c] != 0) {\n                rowCnt[r]++;\n                colCnt[c]++;\n            }\n        }\n    }\n\n    vector<CrossOp> ops;\n    ops.reserve(10000);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int gain = rowCnt[r] + colCnt[c] - (st.g[r * N + c] != 0);\n            if (gain <= 0) continue;\n\n            for (int rt = 0; rt < 2; ++rt) {\n                for (int ct = 2; ct < 4; ++ct) {\n                    int score = gain * 10000 + rng.nextInt(1000);\n                    ops.push_back({rt, r, ct, c, gain, score});\n                }\n            }\n        }\n    }\n\n    if (ops.empty()) return false;\n\n    auto cmp = [](const CrossOp& a, const CrossOp& b) {\n        return a.score > b.score;\n    };\n\n    const int MAXCAND = 1200;\n    if ((int)ops.size() > MAXCAND) {\n        nth_element(ops.begin(), ops.begin() + MAXCAND, ops.end(), cmp);\n        ops.resize(MAXCAND);\n    }\n    sort(ops.begin(), ops.end(), cmp);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyDeleteCross(tmp, st, op.rt, op.r, op.ct, op.c);\n\n        if (tmp.zeros <= best.zeros) continue;\n        if (!validFast(tmp)) continue;\n\n        best = tmp;\n        found = true;\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nvoid simpleLineSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    int fail = 0;\n\n    while (timer.elapsed() < limit && fail < 4) {\n        State st = best;\n\n        bool ok;\n        if (fail % 2 == 0) ok = simpleLineOnce(st, rng, timer, limit);\n        else ok = simpleCrossOnce(st, rng, timer, limit);\n\n        if (ok) {\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n\n            if (st.zeros > best.zeros) {\n                best = st;\n                fail = 0;\n            } else {\n                ++fail;\n            }\n        } else {\n            ++fail;\n        }\n    }\n}\n\nbool validateState(const State& st) {\n    State tmp = st;\n    tmp.rebuild();\n    return validFast(tmp);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    V = N * N;\n\n    State init;\n    init.clear();\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int x;\n            cin >> x;\n            init.g[i * N + j] = (unsigned char)x;\n\n            seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    init.rebuild();\n\n    memset(REQ, 0, sizeof(REQ));\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if (init.edge[i][j] > 0) {\n                REQ[i][j] = REQ[j][i] = true;\n            }\n        }\n    }\n\n    computeGraphInfo();\n\n    Timer timer;\n\n    const double MAIN_LIMIT = 1.55;\n    const double SHAKE_LIMIT = 1.73;\n    const double NEUTRAL_LIMIT = 1.83;\n    const double COMPACT_LIMIT = 1.89;\n    const double LINE_LIMIT = 1.897;\n    const double POLISH_LIMIT = 1.93;\n\n    State best = init;\n\n    int run = 0;\n    while (timer.elapsed() < MAIN_LIMIT) {\n        State st;\n\n        if (run >= 4 && run % 3 == 2) {\n            st = best;\n        } else {\n            st = init;\n        }\n\n        uint64_t rseed =\n            seed\n            + 0x9e3779b97f4a7c15ULL * (uint64_t)(run + 1)\n            + 0xbf58476d1ce4e5b9ULL * (uint64_t)(best.zeros + 1);\n\n        RNG rng(rseed);\n        Params par = getParams(run);\n\n        improve(st, best, rng, par, timer, MAIN_LIMIT);\n        ++run;\n    }\n\n    RNG shakeRng(seed ^ 0xd1b54a32d192ed03ULL ^ (uint64_t)best.zeros);\n    shakeSearch(best, shakeRng, timer, SHAKE_LIMIT);\n\n    RNG neutralRng(seed ^ 0x6a09e667f3bcc909ULL ^ ((uint64_t)best.zeros << 17));\n    neutralSearch(best, neutralRng, timer, NEUTRAL_LIMIT);\n\n    RNG compactRng(seed ^ 0xbb67ae8584caa73bULL ^ ((uint64_t)best.zeros << 9));\n    compactBandSearch(best, compactRng, timer, COMPACT_LIMIT);\n\n    RNG lineRng(seed ^ 0x3c6ef372fe94f82bULL ^ ((uint64_t)best.zeros << 23));\n    simpleLineSearch(best, lineRng, timer, LINE_LIMIT);\n\n    RNG finalRng(seed ^ 0x94d049bb133111ebULL);\n    while (timer.elapsed() < POLISH_LIMIT) {\n        int before = best.zeros;\n\n        greedyDeleteMulti(best, finalRng, 2, finalRng.nextInt(4));\n\n        for (int mode = 0; mode < 4; ++mode) {\n            if (timer.elapsed() >= POLISH_LIMIT) break;\n            greedyDelete(best, finalRng, mode);\n            pairDeletePass(best, finalRng, 250, mode);\n            greedyDelete(best, finalRng, mode);\n        }\n\n        if (best.zeros == before) {\n            State tmp = best;\n            swapPass(tmp, finalRng, 300, finalRng.nextInt(3));\n            randomInterfaceRecolorPass(tmp, finalRng, 90);\n            pairDeletePass(tmp, finalRng, 350, finalRng.nextInt(4));\n            greedyDelete(tmp, finalRng, finalRng.nextInt(4));\n\n            if (tmp.zeros > best.zeros) {\n                best = tmp;\n            } else {\n                break;\n            }\n        }\n    }\n\n    if (!validateState(best)) {\n        best = init;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (j) cout << ' ';\n            cout << (int)best.g[i * N + j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, D, Q;\nint qUsed = 0;\nmt19937_64 rng;\nvector<vector<char>> itemCmp;\n\nconstexpr int DP_SCALE_BASE = 500;\nconstexpr int DP_SUM_LIMIT = 80000;\n\nstruct Solution {\n    vector<int> assign;\n    vector<vector<int>> bins;\n    vector<double> load;\n    double obj = 1e100;\n};\n\nchar invCmp(char c) {\n    if (c == '>') return '<';\n    if (c == '<') return '>';\n    return c;\n}\n\nchar ask(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    if (!(cin >> s)) exit(0);\n    qUsed++;\n    return s[0];\n}\n\nchar compareItems(int a, int b) {\n    if (a == b) return '=';\n    if (itemCmp[a][b] != '?') return itemCmp[a][b];\n    if (qUsed >= Q) return '?';\n\n    vector<int> L{a}, R{b};\n    char c = ask(L, R);\n    itemCmp[a][b] = c;\n    itemCmp[b][a] = invCmp(c);\n    return c;\n}\n\ndouble norm_pdf(double x) {\n    static const double INV_SQRT_2PI = 1.0 / sqrt(2.0 * acos(-1.0));\n    if (abs(x) > 40) return 0.0;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble norm_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble truncatedNormalMean(double mu, double sd, double lo, double hi) {\n    if (sd < 1e-12) return clamp(mu, lo, hi);\n\n    double a = (lo - mu) / sd;\n    double b = (hi - mu) / sd;\n    double A = norm_cdf(a);\n    double B = norm_cdf(b);\n    double Z = B - A;\n\n    if (Z < 1e-14) {\n        if (mu < lo) return lo;\n        if (mu > hi) return hi;\n        return clamp(mu, lo, hi);\n    }\n\n    double mean = mu + sd * (norm_pdf(a) - norm_pdf(b)) / Z;\n    return clamp(mean, lo, hi);\n}\n\nvector<double> estimateWeights(const vector<double>& score, int qRand) {\n    vector<double> est(N, 1.0);\n    if (qRand <= 0) return est;\n\n    const double PI = acos(-1.0);\n    const double c = sqrt(2.0 / PI);\n\n    int K = N / 2;\n    double pNonZero = 2.0 * K / N;\n    double lambda = 2.0 * K / (N - 1.0);\n    double ce = c * sqrt(lambda);\n\n    double sigmaZ = sqrt(pNonZero * N) / (ce * sqrt((double)qRand));\n\n    // Prior: Exp(1), truncated at b=N/D, then normalized to mean 1.\n    double cap = (double)N / D;\n    double e = exp(-cap);\n    double Z = 1.0 - e;\n    double meanX = (1.0 - (cap + 1.0) * e) / Z;\n    double secondX = (2.0 - (cap * cap + 2.0 * cap + 2.0) * e) / Z;\n    double varX = max(1e-12, secondX - meanX * meanX);\n    double cv = sqrt(varX) / meanX;\n    double rMax = cap / meanX;\n\n    double tau = max(1e-6, cv * sigmaZ);\n    double rate = meanX;\n\n    for (int i = 0; i < N; i++) {\n        double zObs = score[i] * sqrt((double)N) / (ce * qRand);\n        double obsR = 1.0 + cv * zObs;\n\n        // Posterior with exponential prior:\n        // exp(-rate*r) * Normal(obsR | r, tau^2)\n        double mu = obsR - rate * tau * tau;\n        est[i] = truncatedNormalMean(mu, tau, 0.0, rMax);\n        est[i] = max(est[i], 1e-6);\n    }\n\n    return est;\n}\n\ndouble totalWeight(const vector<double>& w) {\n    return accumulate(w.begin(), w.end(), 0.0);\n}\n\ndouble sqr(double x) {\n    return x * x;\n}\n\ndouble calcObjLoad(const vector<double>& load, double target) {\n    double res = 0.0;\n    for (double x : load) {\n        double d = x - target;\n        res += d * d;\n    }\n    return res;\n}\n\nSolution buildSolution(const vector<int>& assign, const vector<double>& w) {\n    Solution sol;\n    sol.assign = assign;\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    for (int i = 0; i < N; i++) {\n        int b = sol.assign[i];\n        sol.bins[b].push_back(i);\n        sol.load[b] += w[i];\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nvoid eraseItem(vector<int>& v, int x) {\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (v[i] == x) {\n            v[i] = v.back();\n            v.pop_back();\n            return;\n        }\n    }\n}\n\nvoid moveItemSol(Solution& sol, int item, int from, int to, const vector<double>& w) {\n    eraseItem(sol.bins[from], item);\n    sol.bins[to].push_back(item);\n    sol.assign[item] = to;\n    sol.load[from] -= w[item];\n    sol.load[to] += w[item];\n}\n\nvoid swapItemsSol(Solution& sol, int x, int y, int bx, int by, const vector<double>& w) {\n    for (int& v : sol.bins[bx]) {\n        if (v == x) {\n            v = y;\n            break;\n        }\n    }\n    for (int& v : sol.bins[by]) {\n        if (v == y) {\n            v = x;\n            break;\n        }\n    }\n\n    sol.assign[x] = by;\n    sol.assign[y] = bx;\n\n    sol.load[bx] += w[y] - w[x];\n    sol.load[by] += w[x] - w[y];\n}\n\nvoid localImprove(Solution& sol, const vector<double>& w, double target) {\n    for (int iter = 0; iter < 2000; iter++) {\n        double bestDelta = -1e-12;\n        int bestType = 0;\n        int bestI = -1, bestJ = -1;\n        int bestA = -1, bestB = -1;\n\n        // Single-item move\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            if ((int)sol.bins[a].size() <= 1) continue;\n\n            for (int b = 0; b < D; b++) {\n                if (a == b) continue;\n\n                double oldVal =\n                    sqr(sol.load[a] - target) +\n                    sqr(sol.load[b] - target);\n\n                double newVal =\n                    sqr(sol.load[a] - w[i] - target) +\n                    sqr(sol.load[b] + w[i] - target);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        // Swap\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            for (int j = i + 1; j < N; j++) {\n                int b = sol.assign[j];\n                if (a == b) continue;\n\n                double oldVal =\n                    sqr(sol.load[a] - target) +\n                    sqr(sol.load[b] - target);\n\n                double newVal =\n                    sqr(sol.load[a] - w[i] + w[j] - target) +\n                    sqr(sol.load[b] - w[j] + w[i] - target);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestI = i;\n                    bestJ = j;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        if (bestType == 0) break;\n\n        if (bestType == 1) {\n            moveItemSol(sol, bestI, bestA, bestB, w);\n        } else {\n            swapItemsSol(sol, bestI, bestJ, bestA, bestB, w);\n        }\n\n        sol.obj += bestDelta;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nbool pairBalanceDP(Solution& sol, int a, int b, const vector<double>& w, double target) {\n    vector<int> items = sol.bins[a];\n    for (int x : sol.bins[b]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 1) return false;\n\n    double pairSum = sol.load[a] + sol.load[b];\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(w[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1);\n    vector<int> parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    int bestS = -1;\n    int bestDiff = INT_MAX;\n    for (int s = 0; s <= total; s++) {\n        if (!dp[s]) continue;\n        int diff = abs(total - 2 * s);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestS = s;\n        }\n    }\n\n    if (bestS < 0) return false;\n\n    vector<char> inA(M, 0);\n    int cur = bestS;\n    while (cur > 0) {\n        int idx = parItem[cur];\n        if (idx < 0) return false;\n        inA[idx] = 1;\n        cur = parPrev[cur];\n    }\n\n    int cntA = 0;\n    double loadA = 0.0;\n    for (int i = 0; i < M; i++) {\n        if (inA[i]) {\n            cntA++;\n            loadA += w[items[i]];\n        }\n    }\n\n    if (cntA == 0 || cntA == M) return false;\n\n    double loadB = pairSum - loadA;\n\n    // Keep orientation closer to the previous one.\n    double keepCost = abs(loadA - sol.load[a]) + abs(loadB - sol.load[b]);\n    double flipCost = abs(loadB - sol.load[a]) + abs(loadA - sol.load[b]);\n    if (flipCost < keepCost) {\n        for (char& x : inA) x ^= 1;\n        swap(loadA, loadB);\n        cntA = M - cntA;\n    }\n\n    double oldPair =\n        sqr(sol.load[a] - target) +\n        sqr(sol.load[b] - target);\n\n    double newPair =\n        sqr(loadA - target) +\n        sqr(loadB - target);\n\n    if (newPair >= oldPair - 1e-12) return false;\n\n    sol.bins[a].clear();\n    sol.bins[b].clear();\n    sol.load[a] = 0.0;\n    sol.load[b] = 0.0;\n\n    for (int i = 0; i < M; i++) {\n        int item = items[i];\n        if (inA[i]) {\n            sol.assign[item] = a;\n            sol.bins[a].push_back(item);\n            sol.load[a] += w[item];\n        } else {\n            sol.assign[item] = b;\n            sol.bins[b].push_back(item);\n            sol.load[b] += w[item];\n        }\n    }\n\n    sol.obj += newPair - oldPair;\n    return true;\n}\n\nvoid improveSolution(Solution& sol, const vector<double>& w, int sweeps) {\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n\n    localImprove(sol, w, target);\n\n    for (int sw = 0; sw < sweeps; sw++) {\n        double before = sol.obj;\n        vector<tuple<double, int, int>> pairs;\n\n        for (int a = 0; a < D; a++) {\n            for (int b = a + 1; b < D; b++) {\n                pairs.emplace_back(abs(sol.load[a] - sol.load[b]), a, b);\n            }\n        }\n\n        sort(pairs.rbegin(), pairs.rend());\n\n        bool changed = false;\n        for (auto [_, a, b] : pairs) {\n            changed |= pairBalanceDP(sol, a, b, w, target);\n        }\n\n        localImprove(sol, w, target);\n\n        if (!changed || sol.obj >= before - 1e-12) break;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nSolution makeGreedyOrder(const vector<int>& order, const vector<double>& w) {\n    Solution sol;\n    sol.assign.assign(N, -1);\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    vector<int> cnt(D, 0);\n\n    for (int item : order) {\n        int best = 0;\n        for (int b = 1; b < D; b++) {\n            if (sol.load[b] < sol.load[best] - 1e-12 ||\n                (abs(sol.load[b] - sol.load[best]) <= 1e-12 && cnt[b] < cnt[best])) {\n                best = b;\n            }\n        }\n\n        sol.assign[item] = best;\n        sol.bins[best].push_back(item);\n        sol.load[best] += w[item];\n        cnt[best]++;\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nSolution makeSnake(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        int block = i / D;\n        int pos = i % D;\n        int b = (block % 2 == 0) ? pos : (D - 1 - pos);\n        assign[order[i]] = b;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution makeRoundRobin(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        assign[order[i]] = i % D;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution partitionEstimated(const vector<double>& w) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return w[a] > w[b];\n    });\n\n    Solution best;\n\n    auto consider = [&](Solution sol) {\n        improveSolution(sol, w, 2);\n        if (sol.obj < best.obj) best = sol;\n    };\n\n    consider(makeGreedyOrder(order, w));\n    consider(makeSnake(order, w));\n    consider(makeRoundRobin(order, w));\n\n    normal_distribution<double> nd(0.0, 0.35);\n\n    for (int rep = 0; rep < 3; rep++) {\n        vector<pair<double, int>> keys;\n        keys.reserve(N);\n\n        for (int i = 0; i < N; i++) {\n            double key = log(max(1e-9, w[i])) + nd(rng);\n            keys.emplace_back(-key, i);\n        }\n\n        sort(keys.begin(), keys.end());\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto [_, id] : keys) ord.push_back(id);\n\n        consider(makeGreedyOrder(ord, w));\n    }\n\n    improveSolution(best, w, 2);\n    return best;\n}\n\nvector<int> withoutItem(const vector<int>& v, int x) {\n    vector<int> res;\n    res.reserve(v.size());\n    for (int y : v) {\n        if (y != x) res.push_back(y);\n    }\n    return res;\n}\n\nint minMaxCost() {\n    int pairs = D / 2;\n    int sz = pairs + (D % 2);\n    return pairs + max(0, sz - 1) + max(0, sz - 1);\n}\n\nbool findActualMinMax(const vector<vector<int>>& bins, int& mn, int& mx) {\n    vector<int> winners, losers;\n\n    for (int i = 0; i + 1 < D; i += 2) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[i], bins[i + 1]);\n        if (c == '>') {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        } else if (c == '<') {\n            winners.push_back(i + 1);\n            losers.push_back(i);\n        } else {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        }\n    }\n\n    if (D % 2 == 1) {\n        winners.push_back(D - 1);\n        losers.push_back(D - 1);\n    }\n\n    mx = winners[0];\n    for (int i = 1; i < (int)winners.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[winners[i]], bins[mx]);\n        if (c == '>') mx = winners[i];\n    }\n\n    mn = losers[0];\n    for (int i = 1; i < (int)losers.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[losers[i]], bins[mn]);\n        if (c == '<') mn = losers[i];\n    }\n\n    return true;\n}\n\n// H and L must be actual-oriented: H is heavier than L.\n// Every accepted operation is mathematically guaranteed to reduce actual pair variance.\nbool tryImproveOrientedPair(Solution& sol, int H, int L, const vector<double>& est, int moveCap, int swapCap) {\n    if (H == L) return false;\n    if (sol.bins[H].empty() || sol.bins[L].empty()) return false;\n\n    bool success = false;\n\n    // Try moving one item from H to L.\n    // If H - x > L, then x < H-L and the pair variance decreases.\n    if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n        vector<int> items = sol.bins[H];\n        sort(items.begin(), items.end(), [&](int a, int b) {\n            return est[a] < est[b];\n        });\n\n        int rem = Q - qUsed;\n        int moveLimit = min((int)items.size(), min(moveCap, max(1, rem / 3)));\n        if (rem <= 3) moveLimit = min((int)items.size(), rem);\n\n        int bestMove = -1;\n        int tried = 0;\n\n        for (int x : items) {\n            if (tried >= moveLimit || qUsed >= Q) break;\n\n            vector<int> left = withoutItem(sol.bins[H], x);\n            if (left.empty()) break;\n\n            char c = ask(left, sol.bins[L]);\n            tried++;\n\n            if (c == '>') {\n                bestMove = x;\n            } else if (bestMove != -1) {\n                break;\n            }\n        }\n\n        if (bestMove != -1) {\n            moveItemSol(sol, bestMove, H, L, est);\n            return true;\n        }\n    }\n\n    // Try swapping x in H and y in L.\n    // If x > y and H-x > L-y, then 0 < x-y < H-L, so variance decreases.\n    if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n        vector<tuple<double, int, int>> cand;\n\n        for (int x : sol.bins[H]) {\n            for (int y : sol.bins[L]) {\n                double diff = est[x] - est[y];\n                double key = (diff >= 0.0) ? diff : (2.0 + (-diff));\n                cand.emplace_back(key, x, y);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        int tried = 0;\n        for (auto [_, x, y] : cand) {\n            if (tried >= swapCap || qUsed >= Q) break;\n            tried++;\n\n            char xy = compareItems(x, y);\n            if (xy == '?') break;\n            if (xy != '>') continue;\n\n            if ((int)sol.bins[L].size() == 1) {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n\n            vector<int> left = withoutItem(sol.bins[H], x);\n            vector<int> right = withoutItem(sol.bins[L], y);\n\n            if (left.empty()) continue;\n            if (right.empty()) {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n\n            if (qUsed >= Q) break;\n\n            char c = ask(left, right);\n            if (c == '>') {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n        }\n    }\n\n    return success;\n}\n\nbool tryImproveUnknownPair(Solution& sol, int a, int b, const vector<double>& est) {\n    if (a == b) return false;\n    if (qUsed >= Q) return false;\n    if (sol.bins[a].empty() || sol.bins[b].empty()) return false;\n\n    char c = ask(sol.bins[a], sol.bins[b]);\n    if (c == '=') return false;\n\n    int H = a, L = b;\n    if (c == '<') swap(H, L);\n\n    // Lighter settings than exact min/max refinement, to test more pairs.\n    return tryImproveOrientedPair(sol, H, L, est, 4, 10);\n}\n\n// Uses leftover queries after the standard min/max refinement is stuck.\n// Accepted moves are still provably safe.\nbool tryEstimatedPairFallback(Solution& sol, const vector<double>& est, int skipA = -1, int skipB = -1) {\n    if (qUsed >= Q) return false;\n\n    vector<tuple<double, int, int>> pairs;\n\n    for (int a = 0; a < D; a++) {\n        for (int b = a + 1; b < D; b++) {\n            if ((a == skipA && b == skipB) || (a == skipB && b == skipA)) continue;\n\n            if (sol.load[a] >= sol.load[b]) {\n                pairs.emplace_back(sol.load[a] - sol.load[b], a, b);\n            } else {\n                pairs.emplace_back(sol.load[b] - sol.load[a], b, a);\n            }\n        }\n    }\n\n    sort(pairs.rbegin(), pairs.rend());\n\n    int maxPairs = min((int)pairs.size(), max(5, min(80, Q - qUsed)));\n\n    for (int i = 0; i < maxPairs && qUsed < Q; i++) {\n        auto [_, Hest, Lest] = pairs[i];\n        if (tryImproveUnknownPair(sol, Hest, Lest, est)) return true;\n    }\n\n    return false;\n}\n\nint actualRefine(Solution& sol, const vector<double>& est) {\n    int successes = 0;\n\n    while (qUsed < Q) {\n        bool success = false;\n        int failedH = -1, failedL = -1;\n\n        // Original robust strategy: find actual global heaviest/lightest bins.\n        int cost = minMaxCost();\n        if (Q - qUsed >= cost + 1) {\n            int mn = -1, mx = -1;\n            if (!findActualMinMax(sol.bins, mn, mx)) break;\n\n            failedH = mx;\n            failedL = mn;\n\n            if (mx != mn) {\n                success = tryImproveOrientedPair(sol, mx, mn, est, 6, 20);\n            }\n\n            if (success) {\n                successes++;\n                continue;\n            }\n        }\n\n        // New safe fallback: try promising estimated pairs.\n        // If it fails, the partition is unchanged; only otherwise-dummy queries are consumed.\n        if (qUsed < Q) {\n            success = tryEstimatedPairFallback(sol, est, failedH, failedL);\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        break;\n    }\n\n    return successes;\n}\n\nvoid randomBalancedQueries(int cnt, vector<double>& score) {\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n\n    int K = N / 2;\n\n    for (int q = 0; q < cnt && qUsed < Q; q++) {\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L, R;\n        L.reserve(K);\n        R.reserve(K);\n\n        for (int i = 0; i < K; i++) L.push_back(perm[i]);\n        for (int i = 0; i < K; i++) R.push_back(perm[K + i]);\n\n        char c = ask(L, R);\n        int y = 0;\n        if (c == '>') y = 1;\n        else if (c == '<') y = -1;\n\n        if (y != 0) {\n            for (int x : L) score[x] += y;\n            for (int x : R) score[x] -= y;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)N * 1000003ULL;\n    seed ^= (uint64_t)D * 10007ULL;\n    seed ^= (uint64_t)Q * 998244353ULL;\n    rng.seed(seed);\n\n    itemCmp.assign(N, vector<char>(N, '?'));\n    for (int i = 0; i < N; i++) itemCmp[i][i] = '=';\n\n    vector<double> score(N, 0.0);\n\n    int qRefine = min(Q / 5, 2 * N);\n    int qRandom = Q - qRefine;\n\n    randomBalancedQueries(qRandom, score);\n\n    vector<double> est = estimateWeights(score, qRandom);\n\n    Solution sol = partitionEstimated(est);\n\n    actualRefine(sol, est);\n\n    // Remaining queries are consumed safely.\n    while (qUsed < Q) {\n        vector<int> L{0}, R{1};\n        ask(L, R);\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << sol.assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MMAX = 10;\nstatic const int INF = 1000000000;\n\nint nG, mG;\nusing StackArray = array<vector<int>, MMAX>;\n\nstatic bool g_useClearBeam = true;\nstatic int g_clearMaxBlockers = 40;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (double)(next() >> 11) * (1.0 / (double)(1ULL << 53));\n    }\n};\n\nstruct Params {\n    int mode = 2;\n    int badMode = 0;\n    int goodMode = 0;\n    int thresholdMode = 0;\n    int destMode = 0;\n\n    double noise = 0.0;\n\n    double lenW = 0.06;\n    double dirtyW = 1.5;\n    double badW = 3.0;\n    double amountW = 0.05;\n    double slackW = 0.02;\n    double heightW = 0.0;\n    double gW = 0.05;\n\n    int initA = -1, initB = -1;\n};\n\nstruct Result {\n    vector<pair<int,int>> ops;\n    int cost = INF;\n    bool ok = false;\n};\n\nstruct Stats {\n    int len = 0;\n    int maxv = -1;\n    int minv = INF;\n    int internalBad = 0;\n};\n\nResult invalidResult() {\n    return Result{{}, INF, false};\n}\n\npair<int,int> findBox(const StackArray& st, int v) {\n    for (int i = 0; i < mG; 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\nint minStackValue(const StackArray& st, int s) {\n    if (st[s].empty()) return INF;\n    int mn = INF;\n    for (int x : st[s]) mn = min(mn, x);\n    return mn;\n}\n\nint thresholdValue(const StackArray& st, int s, int mode) {\n    if (st[s].empty()) return INF;\n    if (mode == 1) return st[s].back();\n    return minStackValue(st, s);\n}\n\nint aboveMinCountOne(const vector<int>& a) {\n    if (a.empty()) return 0;\n    int mn = INF, pos = -1;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i] < mn) {\n            mn = a[i];\n            pos = i;\n        }\n    }\n    return (int)a.size() - pos - 1;\n}\n\nStats blockStats(const vector<int>& a, int cut) {\n    Stats s;\n    s.len = (int)a.size() - cut;\n    for (int i = cut; i < (int)a.size(); i++) {\n        s.maxv = max(s.maxv, a[i]);\n        s.minv = min(s.minv, a[i]);\n        if (i + 1 < (int)a.size() && a[i] < a[i + 1]) s.internalBad++;\n    }\n    return s;\n}\n\nint countGreaterThan(const vector<int>& a, int cut, int g) {\n    int c = 0;\n    for (int i = cut; i < (int)a.size(); i++) {\n        if (a[i] > g) c++;\n    }\n    return c;\n}\n\nint topCleanStart(const vector<int>& a, int targetPos) {\n    int c = (int)a.size() - 1;\n    while (c - 1 > targetPos && a[c - 1] > a[c]) c--;\n    return c;\n}\n\nbool existsGoodDest(const StackArray& st, int src, const Stats& bs, const Params& p) {\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int g = thresholdValue(st, d, p.thresholdMode);\n        if (bs.maxv < g) return true;\n    }\n    return false;\n}\n\nint chooseDest(const StackArray& st, int src, int cut, const Params& p, XorShift& rng) {\n    Stats bs = blockStats(st[src], cut);\n    int bestDst = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        int g = thresholdValue(st, d, p.thresholdMode);\n        double normG = (g >= INF / 2 ? 1000.0 : (double)g);\n        bool good = (bs.maxv < g);\n        int badCnt = countGreaterThan(st[src], cut, g);\n        int h = (int)st[d].size();\n        int aboveMin = aboveMinCountOne(st[d]);\n\n        double score = 0.0;\n        if (p.destMode == 0) {\n            if (good) score = normG * 10.0 + h * 0.01;\n            else score = 100000.0 - normG * 10.0 + badCnt * 100.0 + h * 0.01;\n        } else if (p.destMode == 1) {\n            if (good) score = normG * 10.0 - h * 0.05;\n            else score = 100000.0 - normG * 10.0 - aboveMin * 5.0 + h * 0.01;\n        } else if (p.destMode == 2) {\n            if (good) score = (g >= INF / 2 ? 0.0 : normG * 10.0) + h * 0.02;\n            else score = 100000.0 + badCnt * 1000.0 - normG * 20.0 - aboveMin * 5.0;\n        } else {\n            if (good) {\n                score = (normG - bs.maxv) * 10.0 + h * 0.1;\n            } else {\n                score = 100000.0 + badCnt * 500.0\n                      + max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g)) * 5.0\n                      - normG * 10.0 + h * 0.1;\n            }\n        }\n\n        if (p.noise > 0.0) {\n            score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestDst = d;\n        }\n    }\n\n    if (bestDst == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return bestDst;\n}\n\nbool applyMove(StackArray& st, vector<pair<int,int>>& ops, int& cost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    int label = st[src][cut];\n\n    ops.push_back({label, dst + 1});\n    cost += len + 1;\n\n    if (cost >= cutoff) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    if ((int)ops.size() > 5000) return false;\n    return true;\n}\n\nstruct Choice {\n    int cut = -1;\n    int dst = -1;\n};\n\nChoice chooseEnumMove(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    int blockers = h - pos - 1;\n\n    vector<int> cuts;\n    auto addCut = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    addCut(h - 1);\n    addCut(pos + 1);\n    int c0 = topCleanStart(a, pos);\n    addCut(c0);\n\n    for (int c = c0; c < h; c++) addCut(c);\n\n    int cur = h - 1;\n    int added = 0;\n    while (cur > pos && added < 12) {\n        int r = cur;\n        while (r - 1 > pos && a[r - 1] > a[r]) r--;\n        addCut(r);\n        cur = r - 1;\n        added++;\n    }\n\n    if (blockers <= 25) {\n        for (int c = pos + 1; c < h; c++) addCut(c);\n    } else {\n        for (int t = 1; t <= 10; t++) {\n            int c = pos + 1 + (int)((long long)(blockers - 1) * t / 11);\n            addCut(c);\n        }\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    Choice best;\n    double bestScore = 1e100;\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(a, cut);\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            int g = thresholdValue(st, d, p.thresholdMode);\n            int badCnt = countGreaterThan(a, cut, g);\n            double normG = (g >= INF / 2 ? 250.0 : (double)g);\n\n            double score = 1.0 - p.lenW * bs.len + p.dirtyW * bs.internalBad;\n\n            if (badCnt == 0) {\n                score += p.slackW * (normG - bs.maxv);\n                score += p.heightW * (int)st[d].size();\n            } else {\n                score += p.badW * badCnt;\n                score += p.amountW * max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g));\n                score -= p.gW * normG;\n                score += p.heightW * (int)st[d].size();\n            }\n\n            if (p.noise > 0.0) {\n                score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best.cut = cut;\n                best.dst = d;\n            }\n        }\n    }\n\n    if (best.cut == -1) {\n        best.cut = h - 1;\n        best.dst = (src == 0 ? 1 : 0);\n    }\n    return best;\n}\n\nChoice chooseActionByParams(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    int h = (int)st[src].size();\n\n    if (p.mode == 3) {\n        return chooseEnumMove(st, src, pos, p, rng);\n    }\n\n    int cut = -1;\n\n    if (p.mode == 0) {\n        cut = pos + 1;\n    } else if (p.mode == 1) {\n        cut = h - 1;\n    } else {\n        int c0 = topCleanStart(st[src], pos);\n        bool selected = false;\n\n        if (p.goodMode == 0) {\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(st[src], c);\n                if (existsGoodDest(st, src, bs, p)) {\n                    cut = c;\n                    selected = true;\n                    break;\n                }\n            }\n        } else if (p.goodMode == 1) {\n            Stats bs = blockStats(st[src], c0);\n            if (existsGoodDest(st, src, bs, p)) {\n                cut = c0;\n                selected = true;\n            }\n        } else {\n            cut = c0;\n            selected = true;\n        }\n\n        if (!selected) {\n            if (p.badMode == 3) {\n                return chooseEnumMove(st, src, pos, p, rng);\n            } else if (p.badMode == 0) {\n                cut = c0;\n            } else if (p.badMode == 1) {\n                cut = pos + 1;\n            } else {\n                cut = h - 1;\n            }\n        }\n    }\n\n    int dst = chooseDest(st, src, cut, p, rng);\n    return {cut, dst};\n}\n\nbool applyMoveCostOnly(StackArray& st, int& cost, int& opCnt,\n                       int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    cost += len + 1;\n    opCnt++;\n    if (cost >= cutoff || opCnt > 5000) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n    return true;\n}\n\nint completeCostPolicy(const StackArray& initial, int startV, Params p, int limit) {\n    if (limit <= 0) return INF;\n\n    StackArray st = initial;\n    int cost = 0;\n    int opCnt = 0;\n    XorShift rng(123456789ULL + (uint64_t)p.mode * 10007ULL\n                 + (uint64_t)p.badMode * 1009ULL\n                 + (uint64_t)p.goodMode * 9176ULL\n                 + (uint64_t)p.destMode * 13331ULL);\n\n    for (int v = startV; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return INF;\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n                return INF;\n            }\n\n            if (!applyMoveCostOnly(st, cost, opCnt, src, ch.cut, ch.dst, limit)) {\n                return INF;\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return INF;\n        st[src].pop_back();\n        opCnt++;\n        if (opCnt > 5000) return INF;\n    }\n\n    return cost;\n}\n\nResult completeOpsPolicy(const StackArray& initial, int startV, Params p, int cutoff) {\n    StackArray st = initial;\n    vector<pair<int,int>> ops;\n    ops.reserve(5000);\n    int cost = 0;\n    XorShift rng(987654321ULL + (uint64_t)p.mode * 10007ULL);\n\n    for (int v = startV; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n                return invalidResult();\n            }\n\n            if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                return invalidResult();\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint completeCostMulti(const StackArray& st, int startV, const vector<Params>& policies, int limit) {\n    if (startV > nG) return 0;\n    int best = INF;\n    for (const Params& p : policies) {\n        int c = completeCostPolicy(st, startV, p, min(limit, best));\n        if (c < best) best = c;\n    }\n    if (best >= limit) return INF;\n    return best;\n}\n\nResult simulateGreedy(const StackArray& init, Params p, uint64_t seed, int cutoff) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n    XorShift rng(seed);\n\n    if (p.initA >= 0 && p.initA < mG && p.initB >= 0 && p.initB < mG &&\n        p.initA != p.initB && !st[p.initA].empty()) {\n        if (!applyMove(st, ops, cost, p.initA, 0, p.initB, cutoff)) {\n            return invalidResult();\n        }\n    }\n\n    for (int v = 1; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) {\n                return invalidResult();\n            }\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    for (int i = 0; i < mG; i++) {\n        if (!st[i].empty()) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint stateBadCount(const StackArray& st) {\n    int cnt = 0;\n    for (int i = 0; i < mG; i++) {\n        int mn = INF;\n        for (int x : st[i]) {\n            if (x > mn) cnt++;\n            mn = min(mn, x);\n        }\n    }\n    return cnt;\n}\n\nint aboveMinTotal(const StackArray& st) {\n    int s = 0;\n    for (int i = 0; i < mG; i++) s += aboveMinCountOne(st[i]);\n    return s;\n}\n\ndouble beamEval(const StackArray& st, int cost, double alpha) {\n    return cost + alpha * stateBadCount(st) + 0.30 * alpha * aboveMinTotal(st);\n}\n\nstruct BeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateBeamWhole(const StackArray& init, int W, double alpha, int cutoff) {\n    BeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(6000);\n    first.eval = beamEval(first.st, first.cost, alpha);\n\n    vector<BeamState> beam;\n    beam.push_back(first);\n\n    for (int v = 1; v <= nG; v++) {\n        vector<BeamState> cand;\n        cand.reserve(beam.size() * mG);\n\n        for (const auto& bs : beam) {\n            if (bs.cost >= cutoff) continue;\n\n            auto [src, pos] = findBox(bs.st, v);\n            if (src < 0) continue;\n\n            int h = (int)bs.st[src].size();\n\n            if (pos == h - 1) {\n                BeamState ns = bs;\n                ns.ops.push_back({v, 0});\n                ns.st[src].pop_back();\n                if ((int)ns.ops.size() > 5000) continue;\n                ns.eval = beamEval(ns.st, ns.cost, alpha);\n                cand.push_back(std::move(ns));\n            } else {\n                int cut = pos + 1;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n\n                    BeamState ns = bs;\n                    if (!applyMove(ns.st, ns.ops, ns.cost, src, cut, d, cutoff)) continue;\n\n                    if (ns.st[src].empty() || ns.st[src].back() != v) continue;\n                    ns.ops.push_back({v, 0});\n                    ns.st[src].pop_back();\n                    if ((int)ns.ops.size() > 5000) continue;\n\n                    ns.eval = beamEval(ns.st, ns.cost, alpha);\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const BeamState& a, const BeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)cand.size() > W) cand.resize(W);\n        beam = std::move(cand);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nint validateCost(const StackArray& init, const vector<pair<int,int>>& ops) {\n    if ((int)ops.size() > 5000) return -1;\n\n    StackArray st = init;\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (auto [v, to] : ops) {\n        if (v < 1 || v > nG) return -1;\n\n        if (to == 0) {\n            if (v != nextRemove) return -1;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!st[s].empty() && st[s].back() == v) {\n                    st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return -1;\n            int dst = to - 1;\n\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)st[s].size(); j++) {\n                    if (st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n            if (src == -1) return -1;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n\n            if (src != dst) {\n                st[dst].insert(st[dst].end(), st[src].begin() + pos, st[src].end());\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return -1;\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return -1;\n    return cost;\n}\n\nParams randomParams(XorShift& rng) {\n    Params p;\n\n    int r = rng.nextInt(100);\n    if (r < 12) p.mode = 0;\n    else if (r < 30) p.mode = 1;\n    else if (r < 82) p.mode = 2;\n    else p.mode = 3;\n\n    p.badMode = rng.nextInt(4);\n    p.goodMode = rng.nextInt(3);\n    p.thresholdMode = (rng.nextInt(100) < 85 ? 0 : 1);\n    p.destMode = rng.nextInt(4);\n\n    p.noise = rng.nextDouble() * 4.0;\n\n    p.lenW = 0.02 + rng.nextDouble() * 0.18;\n    p.dirtyW = 0.5 + rng.nextDouble() * 4.0;\n    p.badW = 1.0 + rng.nextDouble() * 6.0;\n    p.amountW = rng.nextDouble() * 0.25;\n    p.slackW = rng.nextDouble() * 0.08;\n    p.heightW = (rng.nextDouble() - 0.5) * 0.06;\n    p.gW = rng.nextDouble() * 0.20;\n\n    if (mG >= 2 && rng.nextInt(100) < 12) {\n        p.initA = rng.nextInt(mG);\n        p.initB = rng.nextInt(mG - 1);\n        if (p.initB >= p.initA) p.initB++;\n    }\n\n    return p;\n}\n\n/* ---------- Feature-based macro candidates ---------- */\n\nstruct Feature {\n    int bad = 0;\n    int above = 0;\n    int runs = 0;\n    int inc = 0;\n    int empty = 0;\n};\n\nFeature& operator+=(Feature& a, const Feature& b) {\n    a.bad += b.bad;\n    a.above += b.above;\n    a.runs += b.runs;\n    a.inc += b.inc;\n    a.empty += b.empty;\n    return a;\n}\n\nFeature& operator-=(Feature& a, const Feature& b) {\n    a.bad -= b.bad;\n    a.above -= b.above;\n    a.runs -= b.runs;\n    a.inc -= b.inc;\n    a.empty -= b.empty;\n    return a;\n}\n\nFeature calcFeatureParts(const vector<int>& A, int l1, int r1,\n                         const vector<int>& B, int l2, int r2) {\n    Feature f;\n    int len = (r1 - l1) + (r2 - l2);\n    if (len == 0) {\n        f.empty = 1;\n        return f;\n    }\n\n    int idx = 0;\n    int mnBelow = INF;\n    int minVal = INF, minPos = -1;\n    int prevVal = -1;\n    bool hasPrev = false;\n    bool prevBad = false;\n\n    auto process = [&](int x) {\n        if (hasPrev && prevVal < x) f.inc++;\n\n        bool isBad = (x > mnBelow);\n        if (isBad) {\n            f.bad++;\n            if (!prevBad) f.runs++;\n        }\n        prevBad = isBad;\n\n        if (x < minVal) {\n            minVal = x;\n            minPos = idx;\n        }\n        mnBelow = min(mnBelow, x);\n\n        prevVal = x;\n        hasPrev = true;\n        idx++;\n    };\n\n    for (int i = l1; i < r1; i++) process(A[i]);\n    for (int i = l2; i < r2; i++) process(B[i]);\n\n    f.above = len - minPos - 1;\n    return f;\n}\n\nFeature totalFeatures(const StackArray& st, array<Feature, MMAX>* per = nullptr) {\n    Feature total;\n    for (int i = 0; i < mG; i++) {\n        Feature fi = calcFeatureParts(st[i], 0, (int)st[i].size(), st[i], 0, 0);\n        if (per) (*per)[i] = fi;\n        total += fi;\n    }\n    return total;\n}\n\nstruct EvalParam {\n    double A = 2.7;\n    double B = 0.9;\n    double C = 1.2;\n    double D = 0.25;\n    double E = 2.0;\n    double F = 1.5;\n    double beta = 0.75;\n};\n\ndouble heuristicFeature(const Feature& f, const EvalParam& ep) {\n    return ep.A * f.bad + ep.B * f.above + ep.C * f.runs\n         + ep.D * f.inc - ep.E * f.empty;\n}\n\nint aboveBoxCount(const StackArray& st, int v) {\n    if (v > nG) return 0;\n    auto [s, p] = findBox(st, v);\n    if (s < 0) return 0;\n    return (int)st[s].size() - p - 1;\n}\n\ndouble heuristicState(const StackArray& st, int nextv, const EvalParam& ep) {\n    Feature f = totalFeatures(st, nullptr);\n    double h = heuristicFeature(f, ep);\n    if (nextv <= nG) h += ep.F * aboveBoxCount(st, nextv);\n    return h;\n}\n\nFeature featureAfterMoveContext(const StackArray& st,\n                                const array<Feature, MMAX>& sf,\n                                const Feature& total,\n                                int src, int pos, int cut, int dst,\n                                bool popIfExpose) {\n    int h = (int)st[src].size();\n\n    int srcEnd = cut;\n    if (popIfExpose && cut == pos + 1) srcEnd = pos;\n\n    Feature fsrc = calcFeatureParts(st[src], 0, srcEnd, st[src], 0, 0);\n    Feature fdst = calcFeatureParts(st[dst], 0, (int)st[dst].size(), st[src], cut, h);\n\n    Feature nf = total;\n    nf -= sf[src];\n    nf -= sf[dst];\n    nf += fsrc;\n    nf += fdst;\n    return nf;\n}\n\nuint64_t hashState(const StackArray& st) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < mG; i++) {\n        h ^= (uint64_t)(239 + i);\n        h *= 1099511628211ULL;\n        for (int x : st[i]) {\n            h ^= (uint64_t)(x + 1009);\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nstruct Macro {\n    StackArray st;\n    int addCost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n    bool ok = false;\n};\n\nMacro invalidMacro() {\n    Macro m;\n    m.ok = false;\n    m.addCost = INF;\n    return m;\n}\n\nbool macroMove(StackArray& st, vector<pair<int,int>>& ops, int& addCost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    if (addCost + len + 1 >= cutoff) return false;\n\n    int label = st[src][cut];\n    ops.push_back({label, dst + 1});\n    addCost += len + 1;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    return (int)ops.size() <= 5000;\n}\n\nbool macroRemove(StackArray& st, vector<pair<int,int>>& ops, int v) {\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return false;\n    if (pos != (int)st[src].size() - 1) return false;\n    ops.push_back({v, 0});\n    st[src].pop_back();\n    return (int)ops.size() <= 5000;\n}\n\nint bestDestByFeature(const StackArray& st, int src, int pos, int cut, const EvalParam& ep) {\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n    Stats bs = blockStats(st[src], cut);\n\n    int best = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n        double score = heuristicFeature(nf, ep);\n\n        int thr = minStackValue(st, d);\n        double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n\n        if (bs.maxv < thr) score += 0.0005 * thrNorm;\n        else score -= 0.0005 * thrNorm;\n\n        score += 0.00001 * (int)st[d].size();\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = d;\n        }\n    }\n\n    if (best == -1) {\n        for (int d = 0; d < mG; d++) if (d != src) return d;\n    }\n    return best;\n}\n\nvector<int> generateCutsForAction(const StackArray& st, int src, int pos, int maxCuts = 16) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    vector<int> cuts;\n\n    auto add = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    int c0 = topCleanStart(a, pos);\n    add(pos + 1);\n    add(h - 1);\n    add(c0);\n\n    int runLen = h - c0;\n    if (runLen <= 16) {\n        for (int c = c0; c < h; c++) add(c);\n    } else {\n        for (int t = 0; t < 10; t++) {\n            int c = c0 + (int)((long long)(runLen - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    int end = h;\n    int cnt = 0;\n    while (end > pos + 1 && cnt < 12) {\n        int start = end - 1;\n        while (start - 1 > pos && a[start - 1] > a[start]) start--;\n        add(start);\n        end = start;\n        cnt++;\n    }\n\n    int r = h - pos - 1;\n    if (r <= 18) {\n        for (int c = pos + 1; c < h; c++) add(c);\n    } else {\n        for (int t = 1; t <= 8; t++) {\n            int c = pos + 1 + (int)((long long)(r - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int thr = minStackValue(st, d);\n        int mx = -1;\n        int best = -1;\n        for (int c = h - 1; c > pos; c--) {\n            mx = max(mx, a[c]);\n            if (mx < thr) best = c;\n            else break;\n        }\n        if (best != -1) add(best);\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    if ((int)cuts.size() > maxCuts) {\n        vector<int> old = cuts;\n        vector<int> nc;\n        auto add2 = [&](int c) {\n            if (c > pos && c < h) nc.push_back(c);\n        };\n        add2(pos + 1);\n        add2(h - 1);\n        add2(c0);\n\n        int samples = max(1, maxCuts - 3);\n        for (int t = 0; t < samples; t++) {\n            int idx = (int)((long long)(old.size() - 1) * t / max(1, samples - 1));\n            add2(old[idx]);\n        }\n\n        sort(nc.begin(), nc.end());\n        nc.erase(unique(nc.begin(), nc.end()), nc.end());\n        cuts = nc;\n    }\n\n    return cuts;\n}\n\nstruct Action {\n    int cut = -1;\n    int dst = -1;\n    double score = 1e100;\n};\n\nvector<Action> getTopActions(const StackArray& st, int src, int pos,\n                             const EvalParam& ep, double beta, int limit) {\n    vector<Action> actions;\n    if (limit <= 0) return actions;\n\n    auto cuts = generateCutsForAction(st, src, pos, 16);\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n\n    int h = (int)st[src].size();\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(st[src], cut);\n        int len = h - cut;\n\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n            double sc = (len + 1) + beta * heuristicFeature(nf, ep);\n\n            int thr = minStackValue(st, d);\n            double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n            int badCnt = countGreaterThan(st[src], cut, thr);\n\n            if (bs.maxv < thr) {\n                sc += 0.0002 * thrNorm;\n                if (bs.internalBad == 0) sc -= 0.05 * bs.len;\n            } else {\n                sc += 0.20 * badCnt;\n                sc -= 0.0002 * thrNorm;\n            }\n            sc += 0.10 * bs.internalBad;\n\n            actions.push_back({cut, d, sc});\n        }\n    }\n\n    sort(actions.begin(), actions.end(), [](const Action& a, const Action& b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.cut != b.cut) return a.cut < b.cut;\n        return a.dst < b.dst;\n    });\n\n    if ((int)actions.size() > limit) actions.resize(limit);\n    return actions;\n}\n\nvector<Macro> generateClearBeamMacros(const StackArray& st, int v, const EvalParam& ep,\n                                      int cutoff, int beamW, int outLimit, int actionLimit) {\n    vector<Macro> done;\n\n    auto [s0, p0] = findBox(st, v);\n    if (s0 < 0) return done;\n    int initialBlockers = (int)st[s0].size() - p0 - 1;\n    if (initialBlockers <= 0 || initialBlockers > g_clearMaxBlockers) return done;\n\n    struct Node {\n        StackArray st;\n        int cost = 0;\n        vector<pair<int,int>> ops;\n        double eval = 0.0;\n    };\n\n    Node first;\n    first.st = st;\n    first.cost = 0;\n    first.ops.reserve(128);\n    first.eval = heuristicState(first.st, v, ep);\n\n    vector<Node> beam;\n    beam.push_back(std::move(first));\n\n    int maxSteps = min(initialBlockers, 10);\n\n    for (int step = 0; step <= maxSteps; step++) {\n        vector<Node> nxt;\n\n        for (const Node& nd : beam) {\n            auto [src, pos] = findBox(nd.st, v);\n            if (src < 0) continue;\n            int h = (int)nd.st[src].size();\n\n            if (pos == h - 1) {\n                Macro mo;\n                mo.st = nd.st;\n                mo.addCost = nd.cost;\n                mo.ops = nd.ops;\n                if (macroRemove(mo.st, mo.ops, v)) {\n                    mo.ok = true;\n                    mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n                    done.push_back(std::move(mo));\n                }\n                continue;\n            }\n\n            if (step == maxSteps) continue;\n\n            vector<Action> acts = getTopActions(nd.st, src, pos, ep, ep.beta, actionLimit);\n\n            auto addAction = [&](int cut) {\n                if (cut <= pos || cut >= h) return;\n                int dst = bestDestByFeature(nd.st, src, pos, cut, ep);\n                acts.push_back({cut, dst, 1e50});\n            };\n\n            addAction(pos + 1);\n            addAction(h - 1);\n            addAction(topCleanStart(nd.st[src], pos));\n\n            sort(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                if (a.cut != b.cut) return a.cut < b.cut;\n                return a.dst < b.dst;\n            });\n            acts.erase(unique(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                return a.cut == b.cut && a.dst == b.dst;\n            }), acts.end());\n            sort(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                return a.score < b.score;\n            });\n            if ((int)acts.size() > actionLimit + 3) acts.resize(actionLimit + 3);\n\n            for (const Action& ac : acts) {\n                if (ac.cut <= pos || ac.cut >= h || ac.dst == src || ac.dst < 0 || ac.dst >= mG) continue;\n\n                Node nn = nd;\n                if (!macroMove(nn.st, nn.ops, nn.cost, src, ac.cut, ac.dst, cutoff)) continue;\n\n                nn.eval = nn.cost + 0.65 * heuristicState(nn.st, v, ep)\n                        + 0.40 * aboveBoxCount(nn.st, v);\n                nxt.push_back(std::move(nn));\n            }\n        }\n\n        if (nxt.empty()) break;\n\n        sort(nxt.begin(), nxt.end(), [](const Node& a, const Node& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        vector<Node> nb;\n        nb.reserve(beamW);\n        unordered_set<uint64_t> seen;\n        seen.reserve(nxt.size() * 2 + 10);\n\n        for (auto& x : nxt) {\n            uint64_t hs = hashState(x.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(x));\n                if ((int)nb.size() >= beamW) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    sort(done.begin(), done.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.addCost < b.addCost;\n    });\n\n    vector<Macro> out;\n    out.reserve(outLimit);\n    unordered_set<uint64_t> seen;\n    seen.reserve(done.size() * 2 + 10);\n\n    for (auto& mo : done) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= outLimit) break;\n        }\n    }\n\n    return out;\n}\n\nMacro completePolicy(const StackArray& input, int v, int policy,\n                     const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        int cut = -1, dst = -1;\n\n        if (policy == 0) {\n            int c0 = topCleanStart(mo.st[src], pos);\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(mo.st[src], c);\n                bool good = false;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n                    if (bs.maxv < minStackValue(mo.st, d)) {\n                        good = true;\n                        break;\n                    }\n                }\n                if (good) {\n                    cut = c;\n                    break;\n                }\n            }\n            if (cut == -1) cut = c0;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 1) {\n            cut = topCleanStart(mo.st[src], pos);\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 2) {\n            cut = h - 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 3) {\n            cut = pos + 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else {\n            auto acts = getTopActions(mo.st, src, pos, ep, ep.beta, 1);\n            if (acts.empty()) return invalidMacro();\n            cut = acts[0].cut;\n            dst = acts[0].dst;\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, cut, dst, cutoff)) {\n            return invalidMacro();\n        }\n    }\n}\n\nMacro completeCurrentByParams(const StackArray& input, int v, Params p,\n                              const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    XorShift rng(5555555ULL + (uint64_t)p.mode * 10007ULL + (uint64_t)p.destMode * 101ULL);\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        Choice ch = chooseActionByParams(mo.st, src, pos, p, rng);\n        if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n            return invalidMacro();\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, ch.cut, ch.dst, cutoff)) {\n            return invalidMacro();\n        }\n    }\n}\n\nvector<Macro> generateMacros(const StackArray& st, int v,\n                             const EvalParam& ep, int cutoff, int limit) {\n    vector<Macro> res;\n\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return res;\n\n    int h = (int)st[src].size();\n\n    auto pushMacro = [&](Macro&& mo) {\n        if (!mo.ok) return;\n        if (mo.addCost >= cutoff) return;\n        if ((int)mo.ops.size() > 5000) return;\n        mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n        res.push_back(std::move(mo));\n    };\n\n    if (pos == h - 1) {\n        Macro mo;\n        mo.st = st;\n        mo.addCost = 0;\n        mo.ops.reserve(1);\n        if (macroRemove(mo.st, mo.ops, v)) {\n            mo.ok = true;\n            pushMacro(std::move(mo));\n        }\n        return res;\n    }\n\n    int r = h - pos - 1;\n\n    pushMacro(completePolicy(st, v, 0, ep, cutoff));\n    pushMacro(completePolicy(st, v, 1, ep, cutoff));\n    pushMacro(completePolicy(st, v, 2, ep, cutoff));\n    if (r <= 60) pushMacro(completePolicy(st, v, 4, ep, cutoff));\n\n    auto addFirstFinish = [&](int cut, int dst, int finishPolicy) {\n        StackArray tmp = st;\n        vector<pair<int,int>> ops;\n        ops.reserve(256);\n        int cst = 0;\n        if (!macroMove(tmp, ops, cst, src, cut, dst, cutoff)) return;\n\n        Macro rest = completePolicy(tmp, v, finishPolicy, ep, cutoff - cst);\n        if (!rest.ok) return;\n\n        Macro mo;\n        mo.st = rest.st;\n        mo.addCost = cst + rest.addCost;\n        mo.ops = std::move(ops);\n        mo.ops.insert(mo.ops.end(), rest.ops.begin(), rest.ops.end());\n        mo.ok = true;\n        pushMacro(std::move(mo));\n    };\n\n    int wholeCut = pos + 1;\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        addFirstFinish(wholeCut, d, 0);\n    }\n\n    int cleanCut = topCleanStart(st[src], pos);\n    if (cleanCut != wholeCut) {\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n            addFirstFinish(cleanCut, d, 0);\n        }\n    }\n\n    int firstLimit = (r <= 8 ? 8 : 6);\n    auto acts = getTopActions(st, src, pos, ep, ep.beta, firstLimit);\n    for (const auto& ac : acts) {\n        addFirstFinish(ac.cut, ac.dst, 0);\n    }\n\n    if (g_useClearBeam && r <= g_clearMaxBlockers) {\n        int bw = (r <= 35 ? 6 : 4);\n        int ol = (r <= 35 ? 6 : 4);\n        int al = (r <= 35 ? 6 : 5);\n        auto bm = generateClearBeamMacros(st, v, ep, cutoff, bw, ol, al);\n        for (auto& mo : bm) {\n            pushMacro(std::move(mo));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        if (a.addCost != b.addCost) return a.addCost < b.addCost;\n        return a.ops.size() < b.ops.size();\n    });\n\n    vector<Macro> out;\n    out.reserve(min(limit, (int)res.size()));\n    unordered_set<uint64_t> seen;\n    seen.reserve(res.size() * 2 + 10);\n\n    for (auto& mo : res) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= limit) break;\n        }\n    }\n\n    return out;\n}\n\nvector<Macro> collectMacroCandidates(const StackArray& st, int v,\n                                     const vector<Params>& macroParams,\n                                     const EvalParam& ep,\n                                     int remainCutoff,\n                                     int currentOpsSize,\n                                     int candidateLimit) {\n    vector<Macro> candidates;\n    candidates.reserve(candidateLimit + (int)macroParams.size() + 5);\n    unordered_set<uint64_t> seen;\n    seen.reserve(128);\n\n    auto addCandidate = [&](Macro&& mo) {\n        if (!mo.ok) return;\n        if (mo.addCost >= remainCutoff) return;\n        if (currentOpsSize + (int)mo.ops.size() > 5000) return;\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            candidates.push_back(std::move(mo));\n        }\n    };\n\n    for (const Params& p : macroParams) {\n        Macro mo = completeCurrentByParams(st, v, p, ep, remainCutoff);\n        addCandidate(std::move(mo));\n    }\n\n    auto base = generateMacros(st, v, ep, remainCutoff, candidateLimit);\n    for (auto& mo : base) {\n        if ((int)candidates.size() >= candidateLimit) break;\n        addCandidate(std::move(mo));\n    }\n\n    return candidates;\n}\n\nstruct MacroBeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateMacroRollout(const StackArray& init,\n                            const vector<Params>& macroParams,\n                            const vector<Params>& evalParams,\n                            const EvalParam& ep,\n                            int cutoff,\n                            chrono::steady_clock::time_point deadline,\n                            int candidateLimit,\n                            int startV = 1) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) {\n            if (!evalParams.empty()) {\n                Result tail = completeOpsPolicy(st, v, evalParams[0], cutoff - cost);\n                if (tail.ok) {\n                    ops.insert(ops.end(), tail.ops.begin(), tail.ops.end());\n                    if ((int)ops.size() <= 5000) {\n                        return Result{ops, cost + tail.cost, true};\n                    }\n                }\n            }\n            return invalidResult();\n        }\n\n        int remainCutoff = cutoff - cost;\n        if (remainCutoff <= 0) return invalidResult();\n\n        vector<Macro> candidates = collectMacroCandidates(\n            st, v, macroParams, ep, remainCutoff, (int)ops.size(), candidateLimit\n        );\n\n        if (candidates.empty()) return invalidResult();\n\n        int bestIdx = -1;\n        int bestEval = INF;\n\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (chrono::steady_clock::now() > deadline) break;\n\n            const Macro& mo = candidates[i];\n            if (mo.addCost >= remainCutoff) continue;\n\n            int remLimit = remainCutoff - mo.addCost;\n            int cc = completeCostMulti(mo.st, v + 1, evalParams, remLimit);\n            if (cc >= INF) continue;\n\n            int val = mo.addCost + cc;\n            if (val < bestEval) {\n                bestEval = val;\n                bestIdx = i;\n            }\n        }\n\n        if (bestIdx == -1) {\n            if (!evalParams.empty()) {\n                Result tail = completeOpsPolicy(st, v, evalParams[0], cutoff - cost);\n                if (tail.ok) {\n                    ops.insert(ops.end(), tail.ops.begin(), tail.ops.end());\n                    if ((int)ops.size() <= 5000) {\n                        return Result{ops, cost + tail.cost, true};\n                    }\n                }\n            }\n            return invalidResult();\n        }\n\n        Macro& ch = candidates[bestIdx];\n        cost += ch.addCost;\n        ops.insert(ops.end(), ch.ops.begin(), ch.ops.end());\n        if (cost >= cutoff || (int)ops.size() > 5000) return invalidResult();\n        st = std::move(ch.st);\n    }\n\n    for (int i = 0; i < mG; i++) {\n        if (!st[i].empty()) return invalidResult();\n    }\n    return Result{ops, cost, true};\n}\n\nResult simulateMacroRolloutBeam(const StackArray& init,\n                                int startV,\n                                int W,\n                                const vector<Params>& macroParams,\n                                const vector<Params>& evalParams,\n                                const EvalParam& ep,\n                                int cutoff,\n                                chrono::steady_clock::time_point deadline,\n                                int candidateLimit) {\n    MacroBeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(3000);\n    first.eval = 0.0;\n\n    vector<MacroBeamState> beam;\n    beam.push_back(std::move(first));\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) return invalidResult();\n\n        vector<MacroBeamState> cand;\n        cand.reserve(W * candidateLimit);\n\n        for (const auto& bs : beam) {\n            if (chrono::steady_clock::now() > deadline) return invalidResult();\n            if (bs.cost >= cutoff) continue;\n\n            int remainCutoff = cutoff - bs.cost;\n            auto macros = collectMacroCandidates(bs.st, v, macroParams, ep, remainCutoff,\n                                                 (int)bs.ops.size(), candidateLimit);\n\n            for (auto& mo : macros) {\n                int nc = bs.cost + mo.addCost;\n                if (nc >= cutoff) continue;\n\n                int cc = completeCostMulti(mo.st, v + 1, evalParams, cutoff - nc);\n                if (cc >= INF) continue;\n\n                MacroBeamState ns;\n                ns.st = std::move(mo.st);\n                ns.cost = nc;\n                ns.ops = bs.ops;\n                ns.ops.insert(ns.ops.end(), mo.ops.begin(), mo.ops.end());\n                if ((int)ns.ops.size() > 5000) continue;\n\n                ns.eval = nc + cc;\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const MacroBeamState& a, const MacroBeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.ops.size() < b.ops.size();\n        });\n\n        vector<MacroBeamState> nb;\n        nb.reserve(W);\n        unordered_set<uint64_t> seen;\n        seen.reserve(cand.size() * 2 + 10);\n\n        for (auto& c : cand) {\n            uint64_t hs = hashState(c.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(c));\n                if ((int)nb.size() >= W) break;\n            }\n        }\n\n        if (nb.empty()) return invalidResult();\n        beam = std::move(nb);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nResult simulateTailMacroBeam(const StackArray& initState, int startV, int W,\n                             const EvalParam& ep, int cutoff,\n                             chrono::steady_clock::time_point deadline,\n                             int perStateLimit) {\n    if (startV > nG) return Result{{}, 0, true};\n\n    MacroBeamState first;\n    first.st = initState;\n    for (auto& v : first.st) v.reserve(nG);\n    first.cost = 0;\n    first.ops.reserve(1000);\n    first.eval = heuristicState(first.st, startV, ep);\n\n    vector<MacroBeamState> beam;\n    beam.push_back(std::move(first));\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) return invalidResult();\n\n        vector<MacroBeamState> cand;\n        cand.reserve(beam.size() * perStateLimit);\n\n        for (const auto& bs : beam) {\n            if (chrono::steady_clock::now() > deadline) return invalidResult();\n            if (bs.cost >= cutoff) continue;\n\n            auto macros = generateMacros(bs.st, v, ep, cutoff - bs.cost, perStateLimit);\n\n            for (auto& mo : macros) {\n                int nc = bs.cost + mo.addCost;\n                if (nc >= cutoff) continue;\n\n                MacroBeamState ns;\n                ns.st = std::move(mo.st);\n                ns.cost = nc;\n                ns.ops = bs.ops;\n                ns.ops.insert(ns.ops.end(), mo.ops.begin(), mo.ops.end());\n                if ((int)ns.ops.size() > 5000) continue;\n\n                ns.eval = ns.cost + heuristicState(ns.st, v + 1, ep);\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const MacroBeamState& a, const MacroBeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.ops.size() < b.ops.size();\n        });\n\n        vector<MacroBeamState> nb;\n        nb.reserve(W);\n        unordered_set<uint64_t> seen;\n        seen.reserve(cand.size() * 2 + 10);\n\n        for (auto& c : cand) {\n            uint64_t hs = hashState(c.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(c));\n                if ((int)nb.size() >= W) break;\n            }\n        }\n\n        if (nb.empty()) return invalidResult();\n        beam = std::move(nb);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nstruct PrefixResult {\n    StackArray st;\n    vector<pair<int,int>> ops;\n    int cost = 0;\n    bool ok = false;\n};\n\nPrefixResult extractPrefix(const StackArray& init, const vector<pair<int,int>>& fullOps, int stopV) {\n    PrefixResult pr;\n    pr.st = init;\n    pr.ops.reserve(fullOps.size());\n    pr.cost = 0;\n    pr.ok = false;\n\n    if (stopV == 0) {\n        pr.ok = true;\n        return pr;\n    }\n\n    int nextRemove = 1;\n\n    for (auto [v, to] : fullOps) {\n        if (to == 0) {\n            if (v != nextRemove) return pr;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!pr.st[s].empty() && pr.st[s].back() == v) {\n                    pr.st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return pr;\n\n            pr.ops.push_back({v, 0});\n            nextRemove++;\n\n            if (v == stopV) {\n                pr.ok = true;\n                return pr;\n            }\n        } else {\n            int dst = to - 1;\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)pr.st[s].size(); j++) {\n                    if (pr.st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n            if (src < 0) return pr;\n\n            int len = (int)pr.st[src].size() - pos;\n            pr.cost += len + 1;\n            pr.ops.push_back({v, to});\n\n            if (src != dst) {\n                pr.st[dst].insert(pr.st[dst].end(), pr.st[src].begin() + pos, pr.st[src].end());\n                pr.st[src].erase(pr.st[src].begin() + pos, pr.st[src].end());\n            }\n        }\n    }\n\n    return pr;\n}\n\n/* ---------- Fast fixed-sequence simulator and local optimizer ---------- */\n\nstruct FastMoveInfo {\n    int idx = -1;\n    int len = 0;\n    int src = -1;\n    int dst = -1;\n    int v = -1;\n    int to = -1;\n    vector<int> block;\n};\n\nint simulateOpsFast(const StackArray& init,\n                    const vector<pair<int,int>>& ops,\n                    int changeIdx = -1,\n                    int newV = -1,\n                    int newTo = -1,\n                    int skipIdx = -1,\n                    int cutoff = INF,\n                    vector<FastMoveInfo>* rec = nullptr) {\n    if ((int)ops.size() > 5000) return INF;\n\n    StackArray st = init;\n    array<int, 205> ps, pi;\n    ps.fill(-1);\n    pi.fill(-1);\n\n    for (int s = 0; s < mG; s++) {\n        for (int j = 0; j < (int)st[s].size(); j++) {\n            int x = st[s][j];\n            ps[x] = s;\n            pi[x] = j;\n        }\n    }\n\n    if (rec) rec->clear();\n\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (int k = 0; k < (int)ops.size(); k++) {\n        if (k == skipIdx) continue;\n\n        int v = ops[k].first;\n        int to = ops[k].second;\n        if (k == changeIdx) {\n            if (newV != -1) v = newV;\n            if (newTo != -1) to = newTo;\n        }\n\n        if (v < 1 || v > nG) return INF;\n\n        if (to == 0) {\n            if (v != nextRemove) return INF;\n            int s = ps[v];\n            if (s < 0) return INF;\n            int idx = pi[v];\n            if (idx != (int)st[s].size() - 1) return INF;\n            st[s].pop_back();\n            ps[v] = pi[v] = -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return INF;\n            int dst = to - 1;\n\n            int src = ps[v];\n            if (src < 0) return INF;\n            int pos = pi[v];\n            if (pos < 0 || pos >= (int)st[src].size() || st[src][pos] != v) return INF;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n            if (cost >= cutoff) return INF;\n\n            vector<int> moved;\n            if (rec || src != dst) {\n                moved.assign(st[src].begin() + pos, st[src].end());\n            }\n\n            if (rec) {\n                FastMoveInfo info;\n                info.idx = k;\n                info.len = len;\n                info.src = src;\n                info.dst = dst;\n                info.v = v;\n                info.to = to;\n                info.block = moved;\n                rec->push_back(std::move(info));\n            }\n\n            if (src != dst) {\n                int oldDst = (int)st[dst].size();\n\n                st[dst].insert(st[dst].end(), moved.begin(), moved.end());\n                for (int t = 0; t < (int)moved.size(); t++) {\n                    int x = moved[t];\n                    ps[x] = dst;\n                    pi[x] = oldDst + t;\n                }\n\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return INF;\n    for (int s = 0; s < mG; s++) {\n        if (!st[s].empty()) return INF;\n    }\n    return cost;\n}\n\nvoid improveByLocalDest(const StackArray& init,\n                        Result& best,\n                        chrono::steady_clock::time_point deadline) {\n    if (!best.ok) return;\n\n    for (int iter = 0; iter < 60; iter++) {\n        if (chrono::steady_clock::now() > deadline) return;\n\n        vector<FastMoveInfo> rec;\n        int cur = simulateOpsFast(init, best.ops, -1, -1, -1, -1, INF, &rec);\n        if (cur >= INF) return;\n        best.cost = cur;\n\n        sort(rec.begin(), rec.end(), [](const FastMoveInfo& a, const FastMoveInfo& b) {\n            if (a.len != b.len) return a.len > b.len;\n            return a.idx > b.idx;\n        });\n\n        bool changed = false;\n\n        // Delete redundant move operations.\n        for (const auto& info : rec) {\n            if (chrono::steady_clock::now() > deadline) return;\n\n            int nc = simulateOpsFast(init, best.ops, -1, -1, -1, info.idx, best.cost, nullptr);\n            if (nc < best.cost) {\n                best.ops.erase(best.ops.begin() + info.idx);\n                best.cost = nc;\n                changed = true;\n                break;\n            }\n        }\n        if (changed) continue;\n\n        // Pull a later suffix move before a larger earlier move if it becomes valid and cheaper.\n        {\n            int tested = 0;\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n                if (info.len <= 1 || info.block.empty()) continue;\n\n                bool inBlock[205] = {};\n                for (int x : info.block) {\n                    if (1 <= x && x <= nG) inBlock[x] = true;\n                }\n\n                int end = min((int)best.ops.size(), info.idx + 90);\n                for (int j = info.idx + 1; j < end; j++) {\n                    if (chrono::steady_clock::now() > deadline) return;\n                    if (best.ops[j].second == 0) continue;\n\n                    int lbl = best.ops[j].first;\n                    if (lbl < 1 || lbl > nG) continue;\n                    if (!inBlock[lbl] || lbl == info.v) continue;\n\n                    vector<pair<int,int>> cand = best.ops;\n                    auto opB = cand[j];\n                    cand.erase(cand.begin() + j);\n                    cand.insert(cand.begin() + info.idx, opB);\n\n                    int nc = simulateOpsFast(init, cand, -1, -1, -1, -1, best.cost, nullptr);\n                    tested++;\n                    if (nc < best.cost) {\n                        best.ops = std::move(cand);\n                        best.cost = nc;\n                        changed = true;\n                        break;\n                    }\n                    if (tested >= 180) break;\n                }\n                if (changed || tested >= 180) break;\n            }\n        }\n        if (changed) continue;\n\n        // Shorten a move by changing its label to an upper box in the same moved block.\n        {\n            int tested = 0;\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n                if (info.len <= 1 || (int)info.block.size() != info.len) continue;\n\n                vector<int> offs;\n                auto addOff = [&](int x) {\n                    if (x > 0 && x < info.len) offs.push_back(x);\n                };\n\n                for (int x = 1; x <= min(info.len - 1, 5); x++) addOff(x);\n                addOff(info.len / 2);\n                addOff(info.len - 1);\n\n                int clean = info.len - 1;\n                while (clean - 1 >= 0 && info.block[clean - 1] > info.block[clean]) clean--;\n                addOff(clean);\n\n                sort(offs.begin(), offs.end());\n                offs.erase(unique(offs.begin(), offs.end()), offs.end());\n\n                int bestV = -1, bestTo = -1, bestNc = best.cost;\n\n                for (int off : offs) {\n                    if (chrono::steady_clock::now() > deadline) return;\n\n                    int nv = info.block[off];\n\n                    auto tryTo = [&](int to) {\n                        if (to < 1 || to > mG) return;\n                        if (to == info.src + 1) return;\n                        if (chrono::steady_clock::now() > deadline) return;\n\n                        int nc = simulateOpsFast(init, best.ops, info.idx, nv, to, -1, bestNc, nullptr);\n                        tested++;\n                        if (nc < bestNc) {\n                            bestNc = nc;\n                            bestV = nv;\n                            bestTo = to;\n                        }\n                    };\n\n                    tryTo(info.dst + 1);\n\n                    if (off == 1 || off == clean || off == info.len - 1) {\n                        for (int to = 1; to <= mG; to++) {\n                            if (to == info.dst + 1) continue;\n                            tryTo(to);\n                            if (tested >= 220) break;\n                        }\n                    }\n\n                    if (tested >= 220) break;\n                }\n\n                if (bestV != -1) {\n                    best.ops[info.idx].first = bestV;\n                    best.ops[info.idx].second = bestTo;\n                    best.cost = bestNc;\n                    changed = true;\n                    break;\n                }\n\n                if (tested >= 220) break;\n            }\n        }\n        if (changed) continue;\n\n        // Change only destination stack.\n        for (const auto& info : rec) {\n            if (chrono::steady_clock::now() > deadline) return;\n\n            int bestTo = -1;\n            int bestNc = best.cost;\n\n            for (int to = 1; to <= mG; to++) {\n                if (to == info.dst + 1) continue;\n                if (to == info.src + 1) continue;\n\n                int nc = simulateOpsFast(init, best.ops, info.idx, -1, to, -1, bestNc, nullptr);\n                if (nc < bestNc) {\n                    bestNc = nc;\n                    bestTo = to;\n                }\n            }\n\n            if (bestTo != -1) {\n                best.ops[info.idx].second = bestTo;\n                best.cost = bestNc;\n                changed = true;\n                break;\n            }\n        }\n\n        if (!changed) break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> nG >> mG;\n\n    StackArray init;\n    for (int i = 0; i < mG; i++) {\n        init[i].reserve(nG);\n        for (int j = 0; j < nG / mG; j++) {\n            int x;\n            cin >> x;\n            init[i].push_back(x);\n        }\n    }\n\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < mG; i++) {\n        for (int x : init[i]) {\n            seed = seed * 1000003ULL + (uint64_t)x + 97ULL;\n        }\n    }\n    XorShift master(seed);\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto timeUp = [&]() -> bool {\n        return elapsed() > 1.91;\n    };\n\n    Result best;\n\n    auto consider = [&](Result r) {\n        if (!r.ok) return;\n        if ((int)r.ops.size() > 5000) return;\n        if (best.ok && r.cost >= best.cost) return;\n\n        int vc = validateCost(init, r.ops);\n        if (vc < 0 || vc != r.cost) return;\n\n        best = std::move(r);\n    };\n\n    Params pClean;\n    pClean.mode = 2;\n    pClean.goodMode = 0;\n    pClean.badMode = 0;\n    pClean.thresholdMode = 0;\n    pClean.destMode = 0;\n\n    Params pCleanBad = pClean;\n    pCleanBad.badMode = 1;\n\n    Params pCleanD1 = pClean;\n    pCleanD1.destMode = 1;\n\n    Params pWhole;\n    pWhole.mode = 0;\n    pWhole.thresholdMode = 0;\n    pWhole.destMode = 0;\n\n    Params pSingle;\n    pSingle.mode = 1;\n    pSingle.thresholdMode = 0;\n    pSingle.destMode = 0;\n\n    Params pEnum;\n    pEnum.mode = 3;\n    pEnum.thresholdMode = 0;\n    pEnum.lenW = 0.07;\n    pEnum.dirtyW = 1.8;\n    pEnum.badW = 3.0;\n    pEnum.gW = 0.08;\n    pEnum.slackW = 0.02;\n\n    Params pCleanEnum = pClean;\n    pCleanEnum.badMode = 3;\n    pCleanEnum.lenW = 0.07;\n    pCleanEnum.dirtyW = 1.8;\n    pCleanEnum.badW = 3.0;\n    pCleanEnum.gW = 0.08;\n    pCleanEnum.slackW = 0.02;\n\n    vector<Params> macroParams = {pClean, pCleanBad, pCleanD1, pWhole, pSingle, pEnum, pCleanEnum};\n\n    vector<pair<EvalParam, vector<Params>>> rollCfgs;\n    rollCfgs.push_back({\n        EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75},\n        vector<Params>{pClean}\n    });\n    rollCfgs.push_back({\n        EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65},\n        vector<Params>{pClean, pEnum}\n    });\n    rollCfgs.push_back({\n        EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85},\n        vector<Params>{pCleanBad}\n    });\n    rollCfgs.push_back({\n        EvalParam{3.0, 1.0, 2.0, 0.18, 2.8, 2.4, 0.70},\n        vector<Params>{pClean, pCleanD1, pEnum}\n    });\n    rollCfgs.push_back({\n        EvalParam{2.4, 1.2, 1.4, 0.20, 2.2, 1.8, 0.80},\n        vector<Params>{pCleanEnum, pClean}\n    });\n\n    // Guaranteed valid fallback.\n    consider(simulateGreedy(init, pWhole, master.next(), INF));\n\n    auto runParam = [&](Params p) {\n        if (timeUp()) return;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    // Deterministic greedy variants.\n    for (int th = 0; th <= 1; th++) {\n        for (int dm = 0; dm < 4; dm++) {\n            Params p;\n\n            p = Params();\n            p.mode = 0;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            p = Params();\n            p.mode = 1;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            for (int bad = 0; bad <= 2; bad++) {\n                for (int good = 0; good <= 2; good++) {\n                    p = Params();\n                    p.mode = 2;\n                    p.badMode = bad;\n                    p.goodMode = good;\n                    p.thresholdMode = th;\n                    p.destMode = dm;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    runParam(pCleanEnum);\n\n    // Scored-enumeration presets.\n    for (int th = 0; th <= 1; th++) {\n        for (double lw : {0.03, 0.07, 0.13}) {\n            for (double dw : {0.8, 1.8, 3.0}) {\n                Params p;\n                p.mode = 3;\n                p.thresholdMode = th;\n                p.lenW = lw;\n                p.dirtyW = dw;\n                p.badW = 3.0;\n                p.gW = 0.08;\n                p.slackW = 0.02;\n                runParam(p);\n            }\n        }\n    }\n\n    // Expanded deterministic initial empty-stack attempts.\n    {\n        vector<Params> initPool = {pClean, pCleanBad, pCleanD1, pWhole, pSingle, pEnum, pCleanEnum};\n        for (Params base : initPool) {\n            if (timeUp()) break;\n            for (int a = 0; a < mG && !timeUp(); a++) {\n                for (int b = 0; b < mG && !timeUp(); b++) {\n                    if (a == b) continue;\n                    Params p = base;\n                    p.initA = a;\n                    p.initB = b;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    // Whole-suffix beam.\n    for (double alpha : {0.0, 1.0, 2.0, 4.0, 6.0}) {\n        if (timeUp()) break;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateBeamWhole(init, 55, alpha, cutoff));\n    }\n\n    // Rollout-based macro improvement, using both candidate generators.\n    {\n        auto rollEnd = startTime + chrono::milliseconds(1600);\n\n        for (int idx = 0; idx < (int)rollCfgs.size(); idx++) {\n            if (timeUp()) break;\n            if (chrono::steady_clock::now() > rollEnd) break;\n\n            int cutoff = best.ok ? best.cost + 350 : INF;\n\n            g_useClearBeam = true;\n            consider(simulateMacroRollout(init, macroParams, rollCfgs[idx].second, rollCfgs[idx].first,\n                                          cutoff, rollEnd, 20, 1));\n\n            if (idx < 2 && !timeUp() && chrono::steady_clock::now() < rollEnd) {\n                g_useClearBeam = false;\n                consider(simulateMacroRollout(init, macroParams, rollCfgs[idx].second, rollCfgs[idx].first,\n                                              cutoff, rollEnd, 14, 1));\n            }\n            g_useClearBeam = true;\n        }\n    }\n\n    // Try rollout after creating one empty stack.\n    if (!timeUp() && best.ok) {\n        auto initRollEnd = startTime + chrono::milliseconds(1740);\n\n        vector<tuple<int,int,int>> candInit;\n        vector<Params> initEval = {pClean, pEnum, pCleanEnum};\n        int roughLimit = best.cost + 500;\n\n        for (int a = 0; a < mG; a++) {\n            for (int b = 0; b < mG; b++) {\n                if (a == b) continue;\n\n                StackArray st = init;\n                int c0 = (int)st[a].size() + 1;\n                st[b].insert(st[b].end(), st[a].begin(), st[a].end());\n                st[a].clear();\n\n                int tail = completeCostMulti(st, 1, initEval, roughLimit - c0);\n                if (tail < INF) candInit.push_back({c0 + tail, a, b});\n            }\n        }\n\n        sort(candInit.begin(), candInit.end());\n\n        int tried = 0;\n        for (auto [est, a, b] : candInit) {\n            if (tried >= 3) break;\n            if (timeUp() || chrono::steady_clock::now() > initRollEnd) break;\n\n            StackArray st = init;\n            int label = st[a][0];\n            int c0 = (int)st[a].size() + 1;\n            st[b].insert(st[b].end(), st[a].begin(), st[a].end());\n            st[a].clear();\n\n            int cutoffTail = (best.ok ? best.cost + 350 - c0 : INF);\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[(tried + 1) % rollCfgs.size()];\n            g_useClearBeam = true;\n            Result tail = simulateMacroRollout(st, macroParams, cfg.second, cfg.first,\n                                               cutoffTail, initRollEnd, 15, 1);\n            if (tail.ok) {\n                Result r;\n                r.ok = true;\n                r.cost = c0 + tail.cost;\n                r.ops.reserve(tail.ops.size() + 1);\n                r.ops.push_back({label, b + 1});\n                r.ops.insert(r.ops.end(), tail.ops.begin(), tail.ops.end());\n                consider(std::move(r));\n            }\n\n            tried++;\n        }\n    }\n\n    // Suffix rollout re-optimization.\n    if (!timeUp() && best.ok) {\n        auto sufEnd = startTime + chrono::milliseconds(1815);\n\n        vector<int> starts = {121, 141, 161, 181};\n        for (int idx = 0; idx < (int)starts.size(); idx++) {\n            if (timeUp() || chrono::steady_clock::now() > sufEnd) break;\n\n            int startV = starts[idx];\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost + 220;\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[idx % rollCfgs.size()];\n            g_useClearBeam = (idx % 2 == 0);\n\n            Result tail = simulateMacroRollout(pref.st, macroParams, cfg.second, cfg.first,\n                                               cutoffTail, sufEnd, 12, startV);\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n        g_useClearBeam = true;\n    }\n\n    // Rollout beam for the final part.\n    if (!timeUp() && best.ok) {\n        auto rbEnd = startTime + chrono::milliseconds(1840);\n\n        vector<int> starts = {141, 161, 181};\n        for (int idx = 0; idx < (int)starts.size(); idx++) {\n            if (timeUp() || chrono::steady_clock::now() > rbEnd) break;\n\n            int startV = starts[idx];\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost + 180;\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[(idx + 1) % rollCfgs.size()];\n            g_useClearBeam = true;\n\n            Result tail = simulateMacroRolloutBeam(pref.st, startV, 3,\n                                                   macroParams, cfg.second, cfg.first,\n                                                   cutoffTail, rbEnd, 10);\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n    }\n\n    // Feature tail beam.\n    if (!timeUp() && best.ok) {\n        auto tailEnd = startTime + chrono::milliseconds(1850);\n\n        vector<tuple<int,int,int,EvalParam>> tailCfgs;\n        tailCfgs.push_back({151, 45, 10, EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75}});\n        tailCfgs.push_back({161, 60, 12, EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65}});\n        tailCfgs.push_back({171, 80, 14, EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85}});\n        tailCfgs.push_back({181, 100, 16, EvalParam{3.0, 1.0, 2.0, 0.18, 2.8, 2.4, 0.70}});\n\n        for (auto [startV, W, perLimit, ep] : tailCfgs) {\n            if (timeUp() || chrono::steady_clock::now() > tailEnd) break;\n            if (!best.ok) break;\n\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost;\n            if (cutoffTail <= 0) continue;\n\n            Result tail = simulateTailMacroBeam(pref.st, startV, W, ep,\n                                                cutoffTail, tailEnd, perLimit);\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n    }\n\n    auto runRandomOnce = [&]() {\n        Params p = randomParams(master);\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    // Small random search before final local optimization.\n    {\n        auto randEnd = startTime + chrono::milliseconds(1860);\n        while (!timeUp() && chrono::steady_clock::now() < randEnd) {\n            runRandomOnce();\n        }\n    }\n\n    // Final fixed-sequence local search.\n    if (!timeUp() && best.ok) {\n        auto localEnd = startTime + chrono::milliseconds(1905);\n        improveByLocalDest(init, best, localEnd);\n    }\n\n    // Tiny remaining random search.\n    while (!timeUp()) {\n        runRandomOnce();\n    }\n\n    // Final safety.\n    int vc = best.ok ? validateCost(init, best.ops) : -1;\n    if (!best.ok || vc < 0) {\n        best = simulateGreedy(init, pWhole, seed, INF);\n    } else {\n        best.cost = vc;\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIMIT_LEN = 100000;\nstatic const int INTERNAL_LIMIT = 150000;\nstatic const unsigned short INF_DIST = 30000;\n\nint N, V;\nvector<string> hwall, vwall;\nvector<int> dirtv;\nvector<double> rootDirt;\ndouble meanRootDirt = 1.0;\n\nstruct Edge {\n    int to;\n    char ch;\n};\n\nvector<vector<Edge>> adjg;\nvector<unsigned short> distAll;\nvector<int> dist0;\nvector<vector<int>> nearList;\n\ninline int D(int a, int b) {\n    return distAll[a * V + b];\n}\n\ninline char moveChar(int from, int to) {\n    int diff = to - from;\n    if (diff == 1) return 'R';\n    if (diff == -1) return 'L';\n    if (diff == N) return 'D';\n    return 'U';\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 RouteBuilder {\n    int cur = 0;\n    int t = 0;\n    vector<int> seq;\n    string moves;\n    vector<int> last;\n    vector<char> seen;\n    int unseen = 0;\n\n    void init() {\n        cur = 0;\n        t = 0;\n        seq.clear();\n        moves.clear();\n        last.assign(V, 0);\n        seen.assign(V, 0);\n        seen[0] = 1;\n        unseen = V - 1;\n    }\n\n    void addMove(int nb) {\n        moves.push_back(moveChar(cur, nb));\n        cur = nb;\n        ++t;\n        seq.push_back(nb);\n        last[nb] = t;\n        if (!seen[nb]) {\n            seen[nb] = 1;\n            --unseen;\n        }\n    }\n};\n\nvoid computeAllPairsDistances() {\n    distAll.assign(V * V, INF_DIST);\n    vector<int> q(V);\n\n    for (int s = 0; s < V; ++s) {\n        unsigned short* ds = &distAll[s * V];\n        int head = 0, tail = 0;\n        ds[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int x = q[head++];\n            unsigned short nd = ds[x] + 1;\n            for (const auto& e : adjg[x]) {\n                if (ds[e.to] == INF_DIST) {\n                    ds[e.to] = nd;\n                    q[tail++] = e.to;\n                }\n            }\n        }\n    }\n\n    dist0.assign(V, 0);\n    for (int i = 0; i < V; ++i) dist0[i] = D(i, 0);\n}\n\nint chooseNextOnShortestPath(const RouteBuilder& b, int target, bool preferUnseen) {\n    int cur = b.cur;\n    int cd = D(target, cur);\n    int best = -1;\n    long double bestVal = -1e100L;\n\n    for (const auto& e : adjg[cur]) {\n        int nb = e.to;\n        if (D(target, nb) + 1 != cd) continue;\n\n        long long age = (long long)b.t + 1 - b.last[nb];\n        long double val = (long double)dirtv[nb] * age * age;\n\n        if (preferUnseen && !b.seen[nb]) val += 1e30L;\n        val += (long double)(nb % 23) * 1e-9L;\n\n        if (val > bestVal) {\n            bestVal = val;\n            best = nb;\n        }\n    }\n\n    if (best == -1) {\n        for (const auto& e : adjg[cur]) {\n            if (D(target, e.to) + 1 == cd) return e.to;\n        }\n    }\n    return best;\n}\n\nvoid appendPath(RouteBuilder& b, int target, bool preferUnseen) {\n    while (b.cur != target) {\n        int nb = chooseNextOnShortestPath(b, target, preferUnseen);\n        if (nb < 0) break;\n        b.addMove(nb);\n        if (b.t > INTERNAL_LIMIT) break;\n    }\n}\n\nlong double evaluateRange(const vector<int>& seq, int l, int r) {\n    int L = r - l;\n    if (L <= 0 || L > LIMIT_LEN) return 1e100L;\n    if (l < 0 || r > (int)seq.size()) return 1e100L;\n    if (seq[r - 1] != 0) return 1e100L;\n\n    vector<int> first(V, -1), prev(V, -1);\n    vector<long long> gapSum(V, 0);\n\n    for (int idx = l; idx < r; ++idx) {\n        int tt = idx - l + 1;\n        int id = seq[idx];\n\n        if (first[id] == -1) {\n            first[id] = tt;\n        } else {\n            long long g = tt - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = tt;\n    }\n\n    long double total = 0;\n    for (int id = 0; id < V; ++id) {\n        if (first[id] == -1) return 1e100L;\n        long long g = (long long)L - prev[id] + first[id];\n        gapSum[id] += g * (g - 1) / 2;\n        total += (long double)gapSum[id] * dirtv[id];\n    }\n\n    return total / L;\n}\n\nlong double evaluateSeq(const vector<int>& seq, int L) {\n    return evaluateRange(seq, 0, L);\n}\n\nvector<int> rowOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        } else {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> rowOrderBottom() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int ii = 0; ii < N; ++ii) {\n        int i = N - 1 - ii;\n        if (ii % 2 == 0) {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        } else {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int j = 0; j < N; ++j) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        } else {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrderRight() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int jj = 0; jj < N; ++jj) {\n        int j = N - 1 - jj;\n        if (jj % 2 == 0) {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        } else {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvoid rotHilbert(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\nlong long hilbertIndex(int x, int y) {\n    int S = 1;\n    while (S < N) S <<= 1;\n\n    long long d = 0;\n    for (int s = S / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += 1LL * s * s * ((3 * rx) ^ ry);\n        rotHilbert(s, x, y, rx, ry);\n    }\n    return d;\n}\n\nvector<int> hilbertOrder() {\n    vector<pair<long long, int>> a;\n    a.reserve(V);\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            a.push_back({hilbertIndex(j, i), i * N + j});\n        }\n    }\n\n    sort(a.begin(), a.end());\n    vector<int> ord;\n    ord.reserve(V);\n    for (auto [_, id] : a) ord.push_back(id);\n    return ord;\n}\n\nvector<int> metricNearestOrder(double beta, double expv) {\n    vector<double> attr(V);\n    for (int id = 0; id < V; ++id) {\n        attr[id] = pow((double)dirtv[id], expv);\n    }\n\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    int cur = 0;\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int step = 1; step < V; ++step) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (used[id]) continue;\n            double key = (double)D(cur, id) - beta * attr[id] + 0.002 * dist0[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n\n    return ord;\n}\n\nvector<int> metricInsertionOrder(int mode) {\n    vector<int> ids;\n    ids.reserve(V - 1);\n    for (int id = 1; id < V; ++id) ids.push_back(id);\n\n    if (mode == 0) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return dist0[a] > dist0[b];\n        });\n    } else if (mode == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return dirtv[a] > dirtv[b];\n        });\n    } else if (mode == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return rootDirt[a] * (dist0[a] + 1) > rootDirt[b] * (dist0[b] + 1);\n        });\n    } else {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            unsigned ha = (unsigned)(a * 1103515245u + 12345u);\n            unsigned hb = (unsigned)(b * 1103515245u + 12345u);\n            return ha < hb;\n        });\n    }\n\n    vector<int> ord;\n    ord.push_back(0);\n\n    for (int x : ids) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = (i + 1 < m ? ord[i + 1] : 0);\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        ord.insert(ord.begin() + bestPos, x);\n    }\n\n    return ord;\n}\n\nvector<int> highBackboneOrder(double frac, double beta) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<char> high(V, 0);\n    for (int i = 0; i < K; ++i) high[ids[i]] = 1;\n    high[0] = 1;\n\n    vector<int> ord;\n    vector<char> used(V, 0);\n    ord.push_back(0);\n    used[0] = 1;\n\n    int rem = 0;\n    for (int id = 0; id < V; ++id) if (high[id] && !used[id]) ++rem;\n\n    int cur = 0;\n    while (rem > 0) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (!high[id] || used[id]) continue;\n            double key = (double)D(cur, id) - beta * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n        --rem;\n    }\n\n    vector<int> lows;\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) lows.push_back(id);\n    }\n    sort(lows.begin(), lows.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    for (int x : lows) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = ord[(i + 1) % m];\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        if (bestPos >= (int)ord.size()) ord.push_back(x);\n        else ord.insert(ord.begin() + bestPos, x);\n        used[x] = 1;\n    }\n\n    return ord;\n}\n\nRouteBuilder makeRouteByOrder(const vector<int>& ord) {\n    RouteBuilder b;\n    b.init();\n\n    for (int id : ord) {\n        if (!b.seen[id]) appendPath(b, id, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeNearestCover(int variant) {\n    RouteBuilder b;\n    b.init();\n\n    while (b.unseen > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n\n            int r = D(b.cur, id);\n            double key;\n\n            if (variant == 0) {\n                key = r * 1000000.0 + dist0[id];\n            } else if (variant == 1) {\n                key = r * 1000000.0 - dirtv[id] * 200.0;\n            } else if (variant == 2) {\n                key = (r + 0.20 * dist0[id]) * 1000000.0 - dirtv[id] * 10.0;\n            } else if (variant == 3) {\n                unsigned x = (unsigned)(id * 1103515245u + 12345u);\n                key = r * 1000000.0 + (x % 10000) * 0.01;\n            } else {\n                int degUnseen = 0;\n                for (auto& e : adjg[id]) if (!b.seen[e.to]) ++degUnseen;\n                key = r * 1000000.0 + degUnseen * 1000.0 - dirtv[id] * 0.05;\n            }\n\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best == -1) break;\n        appendPath(b, best, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeDFSRoute(const string& dirOrder, int sortMode) {\n    RouteBuilder b;\n    b.init();\n\n    vector<int> rankDir(256, 0);\n    for (int i = 0; i < 4; ++i) rankDir[(unsigned char)dirOrder[i]] = i;\n\n    vector<char> vis(V, 0);\n\n    function<void(int)> dfs = [&](int u) {\n        vis[u] = 1;\n        vector<Edge> es = adjg[u];\n\n        sort(es.begin(), es.end(), [&](const Edge& a, const Edge& c) {\n            if (sortMode == 1 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] > dirtv[c.to];\n            }\n            if (sortMode == 2 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] < dirtv[c.to];\n            }\n            return rankDir[(unsigned char)a.ch] < rankDir[(unsigned char)c.ch];\n        });\n\n        for (auto& e : es) {\n            if (!vis[e.to]) {\n                b.addMove(e.to);\n                dfs(e.to);\n                b.addMove(u);\n            }\n        }\n    };\n\n    dfs(0);\n    return b;\n}\n\nvector<int> firstVisitOrder(const RouteBuilder& b) {\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int id : b.seq) {\n        if (!used[id]) {\n            used[id] = 1;\n            ord.push_back(id);\n        }\n    }\n\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) ord.push_back(id);\n    }\n\n    return ord;\n}\n\nvoid buildNearLists(int K) {\n    K = min(K, V - 1);\n    nearList.assign(V, {});\n\n    for (int a = 0; a < V; ++a) {\n        vector<pair<unsigned short, int>> tmp;\n        tmp.reserve(V - 1);\n\n        for (int b = 0; b < V; ++b) {\n            if (a != b) tmp.push_back({(unsigned short)D(a, b), b});\n        }\n\n        if (K < (int)tmp.size()) {\n            nth_element(tmp.begin(), tmp.begin() + K, tmp.end());\n            tmp.resize(K);\n        }\n\n        sort(tmp.begin(), tmp.end());\n        nearList[a].reserve(K);\n        for (auto [_, id] : tmp) nearList[a].push_back(id);\n    }\n}\n\nvoid rotateZeroFront(vector<int>& ord) {\n    auto it = find(ord.begin(), ord.end(), 0);\n    if (it != ord.end()) rotate(ord.begin(), it, ord.end());\n}\n\nvector<int> improveOrder2Opt(vector<int> ord, double lambda, const Timer& timer,\n                             double deadline, int maxImp) {\n    if (nearList.empty() || (int)ord.size() != V) return ord;\n    rotateZeroFront(ord);\n\n    int n = (int)ord.size();\n    vector<int> pos(V);\n    for (int i = 0; i < n; ++i) pos[ord[i]] = i;\n\n    auto edgeCost = [&](int a, int b) -> double {\n        double base = (double)D(a, b);\n        if (lambda <= 0.0) return base;\n        double w = min(rootDirt[a], rootDirt[b]) / meanRootDirt;\n        return base * (1.0 + lambda * w);\n    };\n\n    int imp = 0;\n\n    while (imp < maxImp && timer.elapsed() < deadline) {\n        bool changed = false;\n\n        for (int i = 0; i < n - 1 && !changed && timer.elapsed() < deadline; ++i) {\n            int a = ord[i];\n            int b = ord[i + 1];\n            double oldAB = edgeCost(a, b);\n\n            auto tryK = [&](int k) -> bool {\n                if (k <= i + 1 || k >= n) return false;\n                if (i == 0 && k == n - 1) return false;\n\n                int c = ord[k];\n                int d = ord[(k + 1) % n];\n\n                double delta = edgeCost(a, c) + edgeCost(b, d) - oldAB - edgeCost(c, d);\n                if (delta < -1e-9) {\n                    reverse(ord.begin() + i + 1, ord.begin() + k + 1);\n                    for (int p = i + 1; p <= k; ++p) pos[ord[p]] = p;\n                    ++imp;\n                    return true;\n                }\n                return false;\n            };\n\n            for (int cnode : nearList[a]) {\n                int k = pos[cnode];\n                if (tryK(k)) {\n                    changed = true;\n                    break;\n                }\n            }\n            if (changed) break;\n\n            for (int dnode : nearList[b]) {\n                int k = pos[dnode] - 1;\n                if (k < 0) k = n - 1;\n                if (tryK(k)) {\n                    changed = true;\n                    break;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n\n    return ord;\n}\n\nvector<int> makeCounts(const vector<double>& weight, double scale, int& M) {\n    vector<int> cnt(V);\n    M = 1;\n\n    for (int id = 0; id < V; ++id) {\n        int c = max(1, (int)(scale * weight[id] + 0.5));\n        cnt[id] = c;\n        M = max(M, c);\n    }\n\n    return cnt;\n}\n\nint initialAccumulator(int pos, int id, int M, int mode) {\n    if (M <= 1) return 0;\n    if (mode == 0) return 0;\n\n    int desired = 0;\n\n    if (mode == 1) {\n        desired = (int)((long long)pos * M / V);\n    } else if (mode == 2) {\n        desired = (int)((long long)(V - 1 - pos) * M / V);\n    } else if (mode == 3) {\n        unsigned x = (unsigned)(pos * 2654435761u + 1013904223u);\n        desired = x % M;\n    } else {\n        unsigned x = (unsigned)(id * 1103515245u + pos * 12345u + 24691u);\n        desired = x % M;\n    }\n\n    int a = M - 1 - desired;\n    a %= M;\n    if (a < 0) a += M;\n    return a;\n}\n\nvector<vector<int>> buildEvents(const vector<int>& ord, const vector<int>& cnt, int M, int mode) {\n    vector<vector<int>> events(M);\n\n    for (int k = 0; k < V; ++k) {\n        int id = ord[k];\n        int c = cnt[id];\n        int a = initialAccumulator(k, id, M, mode);\n\n        for (int m = 1; m <= c; ++m) {\n            long long num = 1LL * m * M - a;\n            int p = (int)((num + c - 1) / c - 1);\n            if (p < 0) p = 0;\n            if (p >= M) p = M - 1;\n            events[p].push_back(id);\n        }\n    }\n\n    return events;\n}\n\nlong long phaseLength(const vector<int>& ord, const vector<double>& weight,\n                      double scale, int mode, long long cap) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    long long len = 0;\n    int cur = 0;\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) {\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                int id = ev[idx];\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        }\n    }\n\n    len += D(cur, 0);\n    return len;\n}\n\nRouteBuilder buildPhaseRoute(const vector<int>& ord, const vector<double>& weight,\n                             double scale, int mode) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    RouteBuilder b;\n    b.init();\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) appendPath(b, id, true);\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                appendPath(b, ev[idx], true);\n            }\n        }\n\n        if (b.t > LIMIT_LEN + 2000) break;\n    }\n\n    appendPath(b, 0, true);\n    return b;\n}\n\ndouble findPhaseScale(const vector<int>& ord, const vector<double>& weight, int mode) {\n    double lo = 0.0, hi = 1.0;\n\n    while (hi < 2048.0 && phaseLength(ord, weight, hi, mode, LIMIT_LEN + 1) <= LIMIT_LEN) {\n        lo = hi;\n        hi *= 2.0;\n    }\n\n    for (int it = 0; it < 13; ++it) {\n        double mid = (lo + hi) * 0.5;\n        if (phaseLength(ord, weight, mid, mode, LIMIT_LEN + 1) <= LIMIT_LEN) lo = mid;\n        else hi = mid;\n    }\n\n    return lo;\n}\n\nRouteBuilder buildChunkGreedy(RouteBuilder prefix, double offset, int minTargetDist,\n                              int chunk, int maxLen, const Timer& timer, double timeLimit) {\n    RouteBuilder b = std::move(prefix);\n\n    auto selectTarget = [&](int md) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (b.t + r + dist0[id] > maxLen) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n\n    while (b.t + D(b.cur, 0) < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        int target = selectTarget(minTargetDist);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n            if (b.t > INTERNAL_LIMIT) break;\n        }\n\n        if (b.t > INTERNAL_LIMIT) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n    return b;\n}\n\nvoid finishCoverAndReturn(RouteBuilder& b, int maxLen) {\n    while (b.unseen > 0 && b.t < maxLen) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n            int r = D(b.cur, id);\n            if (b.t + r + dist0[id] > maxLen) continue;\n            double key = r + 0.15 * dist0[id] - 0.02 * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        appendPath(b, best, true);\n        if (b.t > maxLen) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n}\n\nRouteBuilder buildIntegratedGreedy(double offset, int minTargetDist, int chunk,\n                                   int maxLen, double unseenBonus, double unseenMult,\n                                   const Timer& timer, double timeLimit) {\n    RouteBuilder b;\n    b.init();\n\n    auto selectTarget = [&](int md, bool forceUnseen) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (forceUnseen && b.seen[id]) continue;\n            if (b.t + r + dist0[id] + 2 * b.unseen > maxLen + 1000) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (!b.seen[id]) {\n                score = score * unseenMult + unseenBonus / (r + 1.0);\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n    while (b.t + D(b.cur, 0) + 2 * V + 30 < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        bool force = (b.unseen > 0 && b.t + D(b.cur, 0) + 2 * V + 1500 > maxLen);\n        int target = selectTarget(minTargetDist, force);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1, force);\n        if (target == -1 && force) target = selectTarget(1, false);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n        }\n    }\n\n    finishCoverAndReturn(b, maxLen);\n    return b;\n}\n\nRouteBuilder buildHighSubsetLoop(double frac) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<char> need(V, 0);\n    for (int i = 0; i < K; ++i) need[ids[i]] = 1;\n\n    RouteBuilder b;\n    b.init();\n\n    auto remaining = [&]() {\n        int r = 0;\n        for (int id = 0; id < V; ++id) {\n            if (need[id] && !b.seen[id]) ++r;\n        }\n        return r;\n    };\n\n    while (remaining() > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (!need[id] || b.seen[id]) continue;\n            double key = (double)D(b.cur, id) - 0.35 * rootDirt[id] + 0.01 * dist0[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        appendPath(b, best, true);\n        if (b.t + D(b.cur, 0) > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder composeLoops(const RouteBuilder& cover, const RouteBuilder& loop, int reps) {\n    RouteBuilder b;\n    b.init();\n\n    for (int nb : cover.seq) b.addMove(nb);\n\n    for (int r = 0; r < reps; ++r) {\n        for (int nb : loop.seq) b.addMove(nb);\n    }\n\n    return b;\n}\n\nvector<int> topCellsByDirt(double frac) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    ids.resize(K);\n    return ids;\n}\n\nint chooseMedoid(const vector<int>& cells) {\n    if (cells.empty()) return 0;\n\n    vector<int> cand = cells;\n    sort(cand.begin(), cand.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n    if ((int)cand.size() > 40) cand.resize(40);\n\n    int best = cand[0];\n    long double bestCost = 1e100L;\n\n    for (int a : cand) {\n        long double cost = 0;\n        for (int x : cells) {\n            cost += (long double)D(a, x) * rootDirt[x];\n        }\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = a;\n        }\n    }\n\n    return best;\n}\n\nRouteBuilder makeLocalLoop(int anchor, const vector<int>& cells, double beta) {\n    RouteBuilder b;\n    b.init();\n    b.cur = anchor;\n    b.seen.assign(V, 1);\n    b.unseen = 0;\n    b.last.assign(V, 0);\n\n    vector<char> need(V, 0), done(V, 0);\n    int rem = 0;\n\n    for (int id : cells) {\n        if (!need[id]) {\n            need[id] = 1;\n            ++rem;\n        }\n    }\n\n    if (need[anchor]) {\n        done[anchor] = 1;\n        --rem;\n    }\n\n    auto markNew = [&](int fromIdx) {\n        for (int i = fromIdx; i < b.t; ++i) {\n            int id = b.seq[i];\n            if (need[id] && !done[id]) {\n                done[id] = 1;\n                --rem;\n            }\n        }\n    };\n\n    while (rem > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id : cells) {\n            if (!need[id] || done[id]) continue;\n            double key = D(b.cur, id) + 0.08 * D(id, anchor) - beta * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n\n        int oldT = b.t;\n        appendPath(b, best, false);\n        markNew(oldT);\n\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    appendPath(b, anchor, false);\n    return b;\n}\n\nvector<int> selectAnchors(const vector<int>& cells, int C) {\n    vector<int> sorted = cells;\n    sort(sorted.begin(), sorted.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    vector<int> anchors;\n    if (sorted.empty()) return anchors;\n\n    anchors.push_back(sorted[0]);\n\n    while ((int)anchors.size() < C && (int)anchors.size() < (int)sorted.size()) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int id : sorted) {\n            bool used = false;\n            for (int a : anchors) if (a == id) used = true;\n            if (used) continue;\n\n            int md = 1000000;\n            for (int a : anchors) md = min(md, D(id, a));\n\n            double score = rootDirt[id] * (md + 1);\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        anchors.push_back(best);\n    }\n\n    return anchors;\n}\n\nRouteBuilder composeLocalInsertion(const RouteBuilder& cover, int anchor,\n                                   const RouteBuilder& loop, int reps) {\n    RouteBuilder invalid;\n    if (loop.t <= 0 || reps <= 0) return invalid;\n    if (cover.t + 1LL * reps * loop.t > LIMIT_LEN) return invalid;\n\n    int p = -2;\n    if (anchor == 0) {\n        p = -1;\n    } else {\n        for (int i = 0; i < cover.t; ++i) {\n            if (cover.seq[i] == anchor) {\n                p = i;\n                break;\n            }\n        }\n    }\n\n    if (p == -2) return invalid;\n\n    RouteBuilder b;\n    b.init();\n\n    for (int i = 0; i <= p; ++i) b.addMove(cover.seq[i]);\n\n    for (int r = 0; r < reps; ++r) {\n        for (int nb : loop.seq) b.addMove(nb);\n    }\n\n    for (int i = p + 1; i < cover.t; ++i) b.addMove(cover.seq[i]);\n\n    return b;\n}\n\nRouteBuilder composeMultiLocal(const RouteBuilder& cover,\n                               const vector<int>& anchors,\n                               const vector<RouteBuilder>& loops,\n                               const vector<int>& reps) {\n    RouteBuilder invalid;\n\n    int m = loops.size();\n    long long len = cover.t;\n    for (int i = 0; i < m; ++i) len += 1LL * reps[i] * loops[i].t;\n    if (len <= 0 || len > LIMIT_LEN) return invalid;\n\n    vector<int> pos(m, -2);\n    for (int k = 0; k < m; ++k) {\n        if (anchors[k] == 0) {\n            pos[k] = -1;\n        } else {\n            for (int i = 0; i < cover.t; ++i) {\n                if (cover.seq[i] == anchors[k]) {\n                    pos[k] = i;\n                    break;\n                }\n            }\n        }\n        if (pos[k] == -2) return invalid;\n    }\n\n    RouteBuilder b;\n    b.init();\n\n    for (int k = 0; k < m; ++k) {\n        if (pos[k] == -1) {\n            for (int r = 0; r < reps[k]; ++r) {\n                for (int nb : loops[k].seq) b.addMove(nb);\n            }\n        }\n    }\n\n    for (int i = 0; i < cover.t; ++i) {\n        b.addMove(cover.seq[i]);\n\n        for (int k = 0; k < m; ++k) {\n            if (pos[k] == i) {\n                for (int r = 0; r < reps[k]; ++r) {\n                    for (int nb : loops[k].seq) b.addMove(nb);\n                }\n            }\n        }\n    }\n\n    return b;\n}\n\nuint64_t hashOrder(const vector<int>& ord) {\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\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n\n    cin >> N;\n    V = N * N;\n\n    hwall.resize(N - 1);\n    for (int i = 0; i < N - 1; ++i) cin >> hwall[i];\n\n    vwall.resize(N);\n    for (int i = 0; i < N; ++i) cin >> vwall[i];\n\n    dirtv.assign(V, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> dirtv[i * N + j];\n        }\n    }\n\n    adjg.assign(V, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = i * N + j;\n\n            if (i + 1 < N && hwall[i][j] == '0') {\n                int to = (i + 1) * N + j;\n                adjg[id].push_back({to, 'D'});\n                adjg[to].push_back({id, 'U'});\n            }\n\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int to = i * N + (j + 1);\n                adjg[id].push_back({to, 'R'});\n                adjg[to].push_back({id, 'L'});\n            }\n        }\n    }\n\n    computeAllPairsDistances();\n\n    rootDirt.assign(V, 1.0);\n    meanRootDirt = 0.0;\n    for (int id = 0; id < V; ++id) {\n        rootDirt[id] = sqrt((double)dirtv[id]);\n        meanRootDirt += rootDirt[id];\n    }\n    meanRootDirt /= V;\n    if (meanRootDirt <= 0) meanRootDirt = 1.0;\n\n    long double bestScore = 1e100L;\n    string bestMoves;\n\n    RouteBuilder bestShort;\n    long double bestShortScore = 1e100L;\n\n    RouteBuilder shortestShort;\n    int shortestLen = INT_MAX;\n\n    auto considerSegment = [&](const RouteBuilder& b, int l, int r) {\n        if (l < 0 || r > b.t || l >= r) return;\n        if (r - l > LIMIT_LEN) return;\n        if (l > 0 && b.seq[l - 1] != 0) return;\n        if (b.seq[r - 1] != 0) return;\n\n        long double sc = evaluateRange(b.seq, l, r);\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestMoves = b.moves.substr(l, r - l);\n        }\n    };\n\n    auto considerFull = [&](const RouteBuilder& b) {\n        considerSegment(b, 0, b.t);\n    };\n\n    auto considerShort = [&](const RouteBuilder& b) {\n        if (b.t <= LIMIT_LEN && b.cur == 0 && b.unseen == 0) {\n            long double sc = evaluateSeq(b.seq, b.t);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = b.moves;\n            }\n\n            if (sc < bestShortScore) {\n                bestShortScore = sc;\n                bestShort = b;\n            }\n\n            if (b.t < shortestLen) {\n                shortestLen = b.t;\n                shortestShort = b;\n            }\n        }\n    };\n\n    vector<int> ordRow = rowOrder();\n    vector<int> ordCol = colOrder();\n    vector<int> ordRowB = rowOrderBottom();\n    vector<int> ordColR = colOrderRight();\n    vector<int> ordHilbert = hilbertOrder();\n\n    vector<int> ordMet0 = metricNearestOrder(0.0, 0.5);\n    vector<int> ordMet1 = metricNearestOrder(0.25, 0.5);\n    vector<int> ordMet2 = metricNearestOrder(0.55, 0.5);\n    vector<int> ordHigh25 = highBackboneOrder(0.25, 0.20);\n    vector<int> ordHigh50 = highBackboneOrder(0.50, 0.10);\n    vector<int> ordIns0 = metricInsertionOrder(0);\n    vector<int> ordIns1 = metricInsertionOrder(1);\n    vector<int> ordIns2 = metricInsertionOrder(2);\n\n    vector<RouteBuilder> shortCandidates;\n\n    vector<string> dirs = {\"RDLU\", \"DRUL\", \"LURD\", \"ULDR\", \"RULD\", \"DLUR\"};\n    for (int i = 0; i < (int)dirs.size(); ++i) {\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 0));\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 1));\n        if (i < 2) shortCandidates.push_back(makeDFSRoute(dirs[i], 2));\n    }\n\n    shortCandidates.push_back(makeRouteByOrder(ordRow));\n    shortCandidates.push_back(makeRouteByOrder(ordCol));\n    shortCandidates.push_back(makeRouteByOrder(ordRowB));\n    shortCandidates.push_back(makeRouteByOrder(ordColR));\n    shortCandidates.push_back(makeRouteByOrder(ordMet0));\n    shortCandidates.push_back(makeRouteByOrder(ordMet1));\n    shortCandidates.push_back(makeRouteByOrder(ordHigh25));\n    shortCandidates.push_back(makeRouteByOrder(ordHigh50));\n    shortCandidates.push_back(makeRouteByOrder(ordIns0));\n    shortCandidates.push_back(makeRouteByOrder(ordIns1));\n    shortCandidates.push_back(makeRouteByOrder(ordIns2));\n\n    for (int v = 0; v < 5; ++v) {\n        shortCandidates.push_back(makeNearestCover(v));\n    }\n\n    for (auto& b : shortCandidates) considerShort(b);\n\n    if (bestShort.t == 0) {\n        bestShort = shortCandidates[0];\n        shortestShort = shortCandidates[0];\n        shortestLen = shortestShort.t;\n        considerFull(bestShort);\n    }\n\n    vector<vector<int>> optOrders;\n\n    if (timer.elapsed() < 0.34) {\n        buildNearLists(34);\n\n        vector<vector<int>> bases;\n        bases.push_back(firstVisitOrder(bestShort));\n        bases.push_back(ordMet0);\n        bases.push_back(ordMet1);\n        bases.push_back(ordMet2);\n        bases.push_back(ordHigh25);\n        bases.push_back(ordHigh50);\n        bases.push_back(ordIns0);\n        bases.push_back(ordIns1);\n        bases.push_back(ordIns2);\n        bases.push_back(ordRow);\n        bases.push_back(ordCol);\n\n        for (int i = 0; i < (int)bases.size() && timer.elapsed() < 0.66; ++i) {\n            vector<int> op = improveOrder2Opt(bases[i], 0.0, timer, 0.66, 260);\n            optOrders.push_back(op);\n\n            RouteBuilder rb = makeRouteByOrder(op);\n            shortCandidates.push_back(rb);\n            considerShort(rb);\n\n            if (i < 6 && timer.elapsed() < 0.72) {\n                vector<int> opw = improveOrder2Opt(bases[i], 0.85, timer, 0.72, 180);\n                optOrders.push_back(opw);\n\n                RouteBuilder rbw = makeRouteByOrder(opw);\n                shortCandidates.push_back(rbw);\n                considerShort(rbw);\n            }\n        }\n    }\n\n    if (shortestShort.t == 0) shortestShort = bestShort;\n\n    if (timer.elapsed() < 0.78) {\n        vector<double> fracs = {0.03, 0.06, 0.10, 0.18, 0.30};\n\n        auto tryLocalCover = [&](const RouteBuilder& cover) {\n            for (double f : fracs) {\n                if (timer.elapsed() > 0.92) break;\n\n                vector<int> cells = topCellsByDirt(f);\n                int anchor = chooseMedoid(cells);\n                RouteBuilder loop = makeLocalLoop(anchor, cells, 0.35);\n\n                if (loop.t <= 0 || loop.cur != anchor) continue;\n                int maxR = (LIMIT_LEN - cover.t) / loop.t;\n                if (maxR <= 0) continue;\n\n                vector<int> rs = {1, 2, 3, 5, 8, 13, 21, maxR / 6, maxR / 4, maxR / 2, maxR};\n                sort(rs.begin(), rs.end());\n                rs.erase(unique(rs.begin(), rs.end()), rs.end());\n\n                for (int r : rs) {\n                    if (r <= 0 || r > maxR) continue;\n                    RouteBuilder c = composeLocalInsertion(cover, anchor, loop, r);\n                    if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n                    if (timer.elapsed() > 0.94) break;\n                }\n            }\n        };\n\n        tryLocalCover(shortestShort);\n        if (bestShort.moves != shortestShort.moves && timer.elapsed() < 0.94) tryLocalCover(bestShort);\n    }\n\n    if (timer.elapsed() < 0.95) {\n        vector<double> fracs = {0.10, 0.20, 0.35};\n\n        for (double f : fracs) {\n            if (timer.elapsed() > 1.02) break;\n\n            vector<int> cells = topCellsByDirt(f);\n            vector<int> anchors = selectAnchors(cells, 3);\n            if (anchors.empty()) continue;\n\n            vector<vector<int>> groups(anchors.size());\n            for (int x : cells) {\n                int bi = 0;\n                int bd = D(x, anchors[0]);\n                for (int i = 1; i < (int)anchors.size(); ++i) {\n                    int dd = D(x, anchors[i]);\n                    if (dd < bd) {\n                        bd = dd;\n                        bi = i;\n                    }\n                }\n                groups[bi].push_back(x);\n            }\n\n            vector<int> useAnchors;\n            vector<RouteBuilder> loops;\n            vector<double> vals;\n\n            for (int i = 0; i < (int)anchors.size(); ++i) {\n                if ((int)groups[i].size() <= 1) continue;\n                RouteBuilder lp = makeLocalLoop(anchors[i], groups[i], 0.25);\n                if (lp.t <= 0 || lp.cur != anchors[i]) continue;\n\n                double val = 0;\n                for (int x : groups[i]) val += rootDirt[x];\n\n                useAnchors.push_back(anchors[i]);\n                loops.push_back(lp);\n                vals.push_back(val);\n            }\n\n            int m = loops.size();\n            if (m == 0) continue;\n\n            vector<double> ratios = {0.12, 0.25, 0.40, 0.65};\n            for (double ratio : ratios) {\n                int budget = max(0, (int)((LIMIT_LEN - shortestShort.t) * ratio));\n                vector<int> reps(m, 0);\n                int used = 0;\n\n                while (true) {\n                    int bj = -1;\n                    double bs = -1;\n\n                    for (int j = 0; j < m; ++j) {\n                        if (used + loops[j].t > budget) continue;\n                        double s = vals[j] / ((reps[j] + 1.0) * (reps[j] + 1.0) * loops[j].t);\n                        if (s > bs) {\n                            bs = s;\n                            bj = j;\n                        }\n                    }\n\n                    if (bj < 0) break;\n                    ++reps[bj];\n                    used += loops[bj].t;\n                }\n\n                bool any = false;\n                for (int r : reps) if (r > 0) any = true;\n                if (!any) continue;\n\n                RouteBuilder c = composeMultiLocal(shortestShort, useAnchors, loops, reps);\n                if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n            }\n        }\n    }\n\n    if (timer.elapsed() < 1.03) {\n        vector<double> fracs = {0.05, 0.10, 0.20, 0.35, 0.50};\n\n        for (double f : fracs) {\n            if (timer.elapsed() > 1.08) break;\n\n            RouteBuilder loop = buildHighSubsetLoop(f);\n            if (loop.t <= 0 || loop.cur != 0) continue;\n\n            auto tryCover = [&](const RouteBuilder& cover) {\n                if (cover.t <= 0 || loop.t <= 0) return;\n                int maxR = (LIMIT_LEN - cover.t) / loop.t;\n                if (maxR <= 0) return;\n\n                vector<int> rs = {1, 2, 3, 5, 8, 13, 21, maxR / 4, maxR / 2, maxR};\n                sort(rs.begin(), rs.end());\n                rs.erase(unique(rs.begin(), rs.end()), rs.end());\n\n                for (int r : rs) {\n                    if (r <= 0 || r > maxR) continue;\n                    if (cover.t + 1LL * r * loop.t > LIMIT_LEN) continue;\n\n                    RouteBuilder c = composeLoops(cover, loop, r);\n                    if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n                }\n            };\n\n            tryCover(shortestShort);\n            if (bestShort.moves != shortestShort.moves) tryCover(bestShort);\n        }\n    }\n\n    vector<vector<int>> orders;\n    unordered_set<uint64_t> orderHashes;\n\n    auto addOrder = [&](vector<int> ord) {\n        if ((int)ord.size() != V) return;\n\n        vector<char> seen(V, 0);\n        for (int x : ord) {\n            if (x < 0 || x >= V || seen[x]) return;\n            seen[x] = 1;\n        }\n\n        uint64_t h = hashOrder(ord);\n        if (orderHashes.insert(h).second) orders.push_back(ord);\n    };\n\n    addOrder(firstVisitOrder(bestShort));\n    for (auto& o : optOrders) addOrder(o);\n\n    addOrder(ordMet0);\n    addOrder(ordMet1);\n    addOrder(ordMet2);\n    addOrder(ordHigh25);\n    addOrder(ordHigh50);\n    addOrder(ordIns0);\n    addOrder(ordIns1);\n    addOrder(ordIns2);\n    addOrder(ordRow);\n    addOrder(ordCol);\n    addOrder(ordRowB);\n    addOrder(ordColR);\n    addOrder(ordHilbert);\n\n    for (auto& b : shortCandidates) {\n        addOrder(firstVisitOrder(b));\n    }\n\n    int initialOrderCount = orders.size();\n    for (int i = 0; i < initialOrderCount; ++i) {\n        vector<int> rev = orders[i];\n        reverse(rev.begin(), rev.end());\n        addOrder(rev);\n    }\n\n    vector<double> baseExps = {0.36, 0.44, 0.52, 0.62};\n    vector<double> richExps = {0.28, 0.36, 0.44, 0.52, 0.60, 0.70};\n    vector<double> muls = {1.00, 0.96, 0.90, 0.82, 0.72, 0.60, 0.48, 0.38, 0.30, 1.05};\n\n    double phaseEnd = 1.50;\n\n    for (int oi = 0; oi < (int)orders.size(); ++oi) {\n        if (timer.elapsed() > phaseEnd) break;\n\n        const vector<int>& ord = orders[oi];\n        const vector<double>& exps = (oi < 11 ? richExps : baseExps);\n\n        vector<int> modes;\n        if (oi < 6) modes = {0, 1, 2, 3, 4};\n        else if (oi < 14) modes = {0, 1, 2, 3};\n        else modes = {0, 1};\n\n        for (double ep : exps) {\n            if (timer.elapsed() > phaseEnd) break;\n\n            vector<double> weight(V);\n            for (int id = 0; id < V; ++id) {\n                weight[id] = pow((double)dirtv[id], ep);\n            }\n\n            for (int mode : modes) {\n                if (timer.elapsed() > phaseEnd + 0.02) break;\n\n                double scale = findPhaseScale(ord, weight, mode);\n\n                for (double m : muls) {\n                    double sca = scale * m;\n                    if (sca < 0.0) continue;\n\n                    long long len = phaseLength(ord, weight, sca, mode, LIMIT_LEN + 1);\n                    if (len <= LIMIT_LEN) {\n                        RouteBuilder b = buildPhaseRoute(ord, weight, sca, mode);\n                        if (b.t <= LIMIT_LEN && b.cur == 0) {\n                            considerFull(b);\n                        }\n                    }\n\n                    if (timer.elapsed() > phaseEnd + 0.03) break;\n                }\n            }\n        }\n    }\n\n    auto considerSegments = [&](const RouteBuilder& b, int minGap) {\n        vector<int> zeros;\n        zeros.push_back(0);\n        for (int t = 1; t <= b.t; ++t) {\n            if (b.seq[t - 1] == 0) zeros.push_back(t);\n        }\n\n        int lastPrefix = 0;\n        for (int z : zeros) {\n            if (z > 0 && z - lastPrefix >= minGap) {\n                considerSegment(b, 0, z);\n                lastPrefix = z;\n                if (timer.elapsed() > 1.93) return;\n            }\n        }\n\n        int lastS = -1000000000;\n        int cnt = 0;\n        for (int z : zeros) {\n            int L = b.t - z;\n            if (L <= 0 || L > LIMIT_LEN) continue;\n            if (z - lastS >= max(2000, minGap / 2)) {\n                considerSegment(b, z, b.t);\n                lastS = z;\n                ++cnt;\n                if (cnt >= 30 || timer.elapsed() > 1.93) return;\n            }\n        }\n\n        vector<int> targets = {minGap, 20000, 35000, 50000, 70000, 90000, 100000};\n        unordered_set<unsigned long long> usedPairs;\n        int evals = 0;\n\n        for (int ei = 1; ei < (int)zeros.size() && evals < 45; ++ei) {\n            int e = zeros[ei];\n\n            for (int TL : targets) {\n                int want = e - TL;\n                auto it = lower_bound(zeros.begin(), zeros.begin() + ei, want);\n\n                for (int rep = 0; rep < 2; ++rep) {\n                    if (it == zeros.begin() + ei) {\n                        if (it == zeros.begin()) break;\n                        --it;\n                    }\n\n                    int s = *it;\n                    int L = e - s;\n                    if (L >= max(1000, minGap / 2) && L <= LIMIT_LEN) {\n                        unsigned long long key = ((unsigned long long)(unsigned int)s << 32) ^ (unsigned int)e;\n                        if (usedPairs.insert(key).second) {\n                            considerSegment(b, s, e);\n                            ++evals;\n                            if (timer.elapsed() > 1.93) return;\n                        }\n                    }\n\n                    if (it == zeros.begin()) break;\n                    --it;\n                }\n            }\n        }\n    };\n\n    if (timer.elapsed() < 1.54) {\n        RouteBuilder ig = buildIntegratedGreedy(28.0, 1, 8, 70000, 8e9, 5.0, timer, 1.61);\n        if (ig.cur == 0) {\n            considerFull(ig);\n            considerSegments(ig, 10000);\n        }\n    }\n\n    if (timer.elapsed() < 1.62) {\n        RouteBuilder ig = buildIntegratedGreedy(45.0, 1, 10, LIMIT_LEN, 1.2e10, 7.0, timer, 1.70);\n        if (ig.cur == 0) {\n            considerFull(ig);\n            considerSegments(ig, 12000);\n        }\n    }\n\n    if (timer.elapsed() < 1.70) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 20.0, 1, 4, LIMIT_LEN, timer, 1.78);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 12000);\n            if (bestShort.t < g.t) considerSegment(g, bestShort.t, g.t);\n        }\n    }\n\n    if (timer.elapsed() < 1.78) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 25.0, 1, 1,\n                                          bestShort.t + LIMIT_LEN, timer, 1.86);\n        if (g.cur == 0) {\n            if (bestShort.t < g.t) considerSegment(g, bestShort.t, g.t);\n            considerSegments(g, 14000);\n        }\n    }\n\n    if (timer.elapsed() < 1.86) {\n        RouteBuilder g = buildChunkGreedy(shortestShort, 36.0, 1, 2,\n                                          LIMIT_LEN, timer, 1.92);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 12000);\n            if (shortestShort.t < g.t) considerSegment(g, shortestShort.t, g.t);\n        }\n    }\n\n    if (timer.elapsed() < 1.92) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 70.0, 3, 5,\n                                          76000, timer, 1.96);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 9000);\n        }\n    }\n\n    if (bestMoves.empty()) {\n        bestMoves = shortCandidates[0].moves;\n    }\n\n    cout << bestMoves << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x = 88172645463325252ull;\n    uint32_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n    double nextDouble() { return (next() >> 8) * (1.0 / 16777216.0); }\n};\n\nstruct Solver {\n    static constexpr unsigned short USINF = 30000;\n    int N, M, si, sj, startId;\n    vector<string> grid, words;\n    vector<array<int, 5>> wch;\n    vector<int> letterPos[26];\n    unsigned char distCell[225][225];\n\n    vector<int> lastChar;\n    vector<unsigned char> overlap;\n\n    vector<int> initOff;\n    vector<unsigned short> initData;\n    vector<int> startMinCost, startMin10, startAvg10;\n\n    vector<int> edgeOff;\n    vector<unsigned short> edgeData;\n    vector<int> edgeMin10, edgeAvg10;\n\n    int maxOcc = 0;\n\n    struct Mode {\n        vector<int> edge, start;\n    };\n    vector<Mode> modes;\n\n    struct Move {\n        int type;\n        int a, b;\n        long long delta;\n        int c;\n    };\n\n    struct Candidate {\n        int cost;\n        vector<int> order;\n    };\n\n    struct ExactCtx {\n        int n;\n        vector<int> cnt;\n        vector<int> foff, roff;\n        vector<unsigned short> fdata, rdata;\n        vector<int> prefOff, suffOff;\n        vector<unsigned short> prefData, suffData;\n        int current = 0;\n    };\n\n    Timer timer;\n    XorShift rng;\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    unordered_map<int, int> targetMap;\n    int pow4 = 456976;\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        startId = si * N + sj;\n\n        grid.resize(N);\n        for (int c = 0; c < 26; c++) letterPos[c].clear();\n\n        for (int i = 0; i < N; i++) {\n            cin >> grid[i];\n            for (int j = 0; j < N; j++) {\n                letterPos[grid[i][j] - 'A'].push_back(i * N + j);\n            }\n        }\n\n        words.resize(M);\n        wch.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) wch[i][k] = words[i][k] - 'A';\n        }\n    }\n\n    int encodeWord(const string& s) const {\n        int code = 0;\n        for (char ch : s) code = code * 26 + (ch - 'A');\n        return code;\n    }\n\n    int calcOverlap(int a, int b) const {\n        for (int k = 4; k >= 1; k--) {\n            bool ok = true;\n            for (int p = 0; p < k; p++) {\n                if (words[a][5 - k + p] != words[b][p]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    inline int wordCnt(int w) const {\n        return (int)letterPos[lastChar[w]].size();\n    }\n\n    void precompute() {\n        int V = N * N;\n        for (int a = 0; a < V; a++) {\n            int ai = a / N, aj = a % N;\n            for (int b = 0; b < V; b++) {\n                int bi = b / N, bj = b % N;\n                distCell[a][b] = (unsigned char)(abs(ai - bi) + abs(aj - bj));\n            }\n        }\n\n        maxOcc = 0;\n        for (int c = 0; c < 26; c++) maxOcc = max(maxOcc, (int)letterPos[c].size());\n\n        lastChar.assign(M, 0);\n        for (int i = 0; i < M; i++) lastChar[i] = wch[i][4];\n\n        overlap.assign(M * M, 0);\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) overlap[i * M + j] = (unsigned char)calcOverlap(i, j);\n        }\n\n        targetMap.clear();\n        targetMap.reserve(512);\n        for (int i = 0; i < M; i++) targetMap[encodeWord(words[i])] = i;\n\n        long long sumOccLast = 0;\n        for (int i = 0; i < M; i++) sumOccLast += wordCnt(i);\n\n        initOff.assign(M, 0);\n        startMinCost.assign(M, 0);\n        startMin10.assign(M, 0);\n        startAvg10.assign(M, 0);\n        initData.clear();\n        initData.reserve((size_t)sumOccLast);\n\n        vector<int> cur(maxOcc), nxt(maxOcc);\n        const int INF = 1e9;\n\n        for (int i = 0; i < M; i++) {\n            int c0 = wch[i][0];\n            int cnt = (int)letterPos[c0].size();\n\n            for (int p = 0; p < cnt; p++) cur[p] = (int)distCell[startId][letterPos[c0][p]] + 1;\n\n            int prevC = c0, prevCnt = cnt;\n            for (int h = 1; h < 5; h++) {\n                int nc = wch[i][h];\n                int nextCnt = (int)letterPos[nc].size();\n\n                for (int q = 0; q < nextCnt; q++) {\n                    int best = INF;\n                    int qid = letterPos[nc][q];\n                    for (int p = 0; p < prevCnt; p++) {\n                        int v = cur[p] + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                        if (v < best) best = v;\n                    }\n                    nxt[q] = best;\n                }\n\n                for (int q = 0; q < nextCnt; q++) cur[q] = nxt[q];\n                prevC = nc;\n                prevCnt = nextCnt;\n            }\n\n            initOff[i] = (int)initData.size();\n            int mn = INF;\n            long long sum = 0;\n            for (int p = 0; p < prevCnt; p++) {\n                mn = min(mn, cur[p]);\n                sum += cur[p];\n                initData.push_back((unsigned short)cur[p]);\n            }\n            startMinCost[i] = mn;\n            startMin10[i] = 10 * mn;\n            startAvg10[i] = (int)((10 * sum + prevCnt / 2) / prevCnt);\n        }\n\n        edgeOff.assign(M * M, 0);\n        edgeAvg10.assign(M * M, 0);\n        edgeMin10.assign(M * M, 0);\n        edgeData.clear();\n\n        long long totalMat = sumOccLast * sumOccLast;\n        if (totalMat < 100000000LL) edgeData.reserve((size_t)totalMat);\n\n        vector<int> mat(maxOcc * maxOcc), mat2(maxOcc * maxOcc);\n\n        for (int i = 0; i < M; i++) {\n            int cStart = lastChar[i];\n            int rows = (int)letterPos[cStart].size();\n\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int k = overlap[idx];\n\n                int prevC = cStart, prevCnt = rows;\n\n                fill(mat.begin(), mat.begin() + rows * prevCnt, INF);\n                for (int r = 0; r < rows; r++) mat[r * prevCnt + r] = 0;\n\n                for (int h = k; h < 5; h++) {\n                    int nc = wch[j][h];\n                    int nextCnt = (int)letterPos[nc].size();\n\n                    for (int r = 0; r < rows; r++) {\n                        int baseIdx = r * prevCnt;\n                        int outIdx = r * nextCnt;\n                        for (int q = 0; q < nextCnt; q++) {\n                            int best = INF;\n                            int qid = letterPos[nc][q];\n                            for (int p = 0; p < prevCnt; p++) {\n                                int v = mat[baseIdx + p] + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                                if (v < best) best = v;\n                            }\n                            mat2[outIdx + q] = best;\n                        }\n                    }\n\n                    mat.swap(mat2);\n                    prevC = nc;\n                    prevCnt = nextCnt;\n                }\n\n                int cols = wordCnt(j);\n                edgeOff[idx] = (int)edgeData.size();\n                edgeData.resize(edgeData.size() + rows * cols);\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                int off = edgeOff[idx];\n\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    for (int q = 0; q < cols; q++) {\n                        int v = mat[r * cols + q];\n                        edgeData[off + r * cols + q] = (unsigned short)v;\n                        rowMin = min(rowMin, v);\n                        globalMin = min(globalMin, v);\n                    }\n                    sumRowMin += rowMin;\n                }\n\n                edgeMin10[idx] = 10 * globalMin;\n                edgeAvg10[idx] = (int)((10 * sumRowMin + rows / 2) / rows);\n            }\n        }\n    }\n\n    void buildModes() {\n        modes.clear();\n        modes.resize(4);\n\n        for (auto& mo : modes) {\n            mo.edge.assign(M * M, 0);\n            mo.start.assign(M, 0);\n        }\n\n        for (int i = 0; i < M; i++) {\n            modes[0].start[i] = startAvg10[i];\n            modes[1].start[i] = startMin10[i];\n            modes[2].start[i] = startAvg10[i];\n            modes[3].start[i] = startAvg10[i];\n        }\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int len = 5 - (int)overlap[idx];\n                modes[0].edge[idx] = edgeAvg10[idx];\n                modes[1].edge[idx] = edgeMin10[idx];\n                modes[2].edge[idx] = len * 1000 + edgeAvg10[idx];\n                modes[3].edge[idx] = len * 10000 + edgeAvg10[idx];\n            }\n        }\n    }\n\n    inline long long arc(const Mode& mode, int u, int v) const {\n        if (u < 0 && v < 0) return 0;\n        if (u < 0) return mode.start[v];\n        if (v < 0) return 0;\n        return mode.edge[u * M + v];\n    }\n\n    int exactCost(const vector<int>& ord) const {\n        if (ord.empty()) return 0;\n\n        const int INF = 1e9;\n        int dp[225], ndp[225];\n\n        int first = ord[0];\n        int cnt = wordCnt(first);\n        int off0 = initOff[first];\n\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off0 + i];\n\n        for (int idx = 1; idx < (int)ord.size(); idx++) {\n            int a = ord[idx - 1];\n            int b = ord[idx];\n\n            int rows = wordCnt(a);\n            int cols = wordCnt(b);\n\n            fill(ndp, ndp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[a * M + b]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)mr[c];\n                    if (v < ndp[c]) ndp[c] = v;\n                }\n            }\n\n            for (int c = 0; c < cols; c++) dp[c] = ndp[c];\n        }\n\n        int last = ord.back();\n        int lastCnt = wordCnt(last);\n        int ans = INF;\n        for (int i = 0; i < lastCnt; i++) ans = min(ans, dp[i]);\n        return ans;\n    }\n\n    vector<int> hungarian(const vector<vector<int>>& a) const {\n        int n = (int)a.size();\n        const long long INF = (1LL << 60);\n\n        vector<long long> u(n + 1), v(n + 1);\n        vector<int> p(n + 1), way(n + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<long long> minv(n + 1, INF);\n            vector<char> used(n + 1, false);\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0];\n                int j1 = 0;\n                long long delta = INF;\n\n                for (int j = 1; j <= n; j++) {\n                    if (used[j]) continue;\n                    long long cur = (long long)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\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\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);\n        for (int j = 1; j <= n; j++) ans[p[j] - 1] = j - 1;\n        return ans;\n    }\n\n    vector<int> patchAssignment(const vector<int>& succ, const Mode& mode) const {\n        int D = M;\n        int n = M + 1;\n\n        vector<char> visited(n, false);\n        vector<int> path;\n\n        int cur = succ[D];\n        visited[D] = true;\n        while (cur != D && !visited[cur]) {\n            visited[cur] = true;\n            path.push_back(cur);\n            cur = succ[cur];\n        }\n\n        vector<vector<int>> cycles;\n        for (int i = 0; i < M; i++) {\n            if (visited[i]) continue;\n\n            vector<int> cyc;\n            cur = i;\n            while (!visited[cur]) {\n                visited[cur] = true;\n                cyc.push_back(cur);\n                cur = succ[cur];\n            }\n            if (!cyc.empty()) cycles.push_back(cyc);\n        }\n\n        auto costArc = [&](int u, int v) -> long long {\n            if (u == D && v == D) return 0;\n            if (u == D) return mode.start[v];\n            if (v == D) return 0;\n            return mode.edge[u * M + v];\n        };\n\n        while (!cycles.empty()) {\n            long long bestDelta = (1LL << 60);\n            int bestC = -1, bestE = -1, bestBreak = -1;\n\n            for (int ci = 0; ci < (int)cycles.size(); ci++) {\n                const auto& C = cycles[ci];\n                int k = (int)C.size();\n\n                for (int e = 0; e <= (int)path.size(); e++) {\n                    int u = (e == 0 ? D : path[e - 1]);\n                    int v = (e == (int)path.size() ? D : path[e]);\n                    long long oldCost = costArc(u, v);\n\n                    for (int bidx = 0; bidx < k; bidx++) {\n                        int a = C[bidx];\n                        int b = C[(bidx + 1) % k];\n\n                        long long delta = costArc(u, b) + costArc(a, v)\n                                        - oldCost - costArc(a, b);\n\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestC = ci;\n                            bestE = e;\n                            bestBreak = bidx;\n                        }\n                    }\n                }\n            }\n\n            const auto& C = cycles[bestC];\n            int k = (int)C.size();\n            vector<int> seg;\n            seg.reserve(k);\n            for (int t = 0; t < k; t++) seg.push_back(C[(bestBreak + 1 + t) % k]);\n\n            path.insert(path.begin() + bestE, seg.begin(), seg.end());\n            cycles.erase(cycles.begin() + bestC);\n        }\n\n        return path;\n    }\n\n    vector<int> hungarianPatch(const Mode& mode) const {\n        int n = M + 1;\n        int D = M;\n        const int INF = 100000000;\n\n        vector<vector<int>> cost(n, vector<int>(n, INF));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) cost[i][j] = (i == j ? INF : mode.edge[i * M + j]);\n            cost[i][D] = 0;\n        }\n\n        for (int j = 0; j < M; j++) cost[D][j] = mode.start[j];\n        cost[D][D] = INF;\n\n        vector<int> assign = hungarian(cost);\n        return patchAssignment(assign, mode);\n    }\n\n    vector<int> cheapestInsertion(const Mode& mode) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestDelta = (1LL << 60);\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> regretInsertion(const Mode& mode, int regretW) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestScore = (1LL << 60);\n            int chosen = -1, chosenPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                long long b1 = (1LL << 60), b2 = (1LL << 60);\n                int pos1 = 0;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n\n                    if (delta < b1) {\n                        b2 = b1;\n                        b1 = delta;\n                        pos1 = pos;\n                    } else if (delta < b2) {\n                        b2 = delta;\n                    }\n                }\n\n                if (b2 >= (1LL << 50)) b2 = b1 + 1000000;\n                long long regret = b2 - b1;\n                long long score = b1 * 10 - (long long)regretW * regret;\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    chosen = x;\n                    chosenPos = pos1;\n                }\n            }\n\n            path.insert(path.begin() + chosenPos, chosen);\n            used[chosen] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> nearestNeighborBest(const Mode& mode) const {\n        vector<int> bestPath;\n        long long bestScore = (1LL << 60);\n\n        for (int s = 0; s < M; s++) {\n            vector<char> used(M, false);\n            vector<int> path;\n            path.reserve(M);\n\n            path.push_back(s);\n            used[s] = true;\n\n            long long score = mode.start[s];\n            int last = s;\n\n            for (int step = 1; step < M; step++) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (used[j]) continue;\n                    int c = mode.edge[last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                path.push_back(bestJ);\n                used[bestJ] = true;\n                score += bestC;\n                last = bestJ;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestPath = path;\n            }\n        }\n\n        return bestPath;\n    }\n\n    struct DSU {\n        vector<int> p;\n        DSU(int n = 0) { init(n); }\n        void init(int n) {\n            p.resize(n);\n            iota(p.begin(), p.end(), 0);\n        }\n        int find(int x) {\n            return p[x] == x ? x : p[x] = find(p[x]);\n        }\n        bool unite(int a, int b) {\n            a = find(a);\n            b = find(b);\n            if (a == b) return false;\n            p[b] = a;\n            return true;\n        }\n    };\n\n    vector<int> greedyPathCover(const Mode& mode, bool overlapKey) const {\n        struct E {\n            int u, v, ov, cost;\n        };\n\n        vector<E> es;\n        es.reserve(M * (M - 1));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                es.push_back({i, j, (int)overlap[i * M + j], mode.edge[i * M + j]});\n            }\n        }\n\n        if (overlapKey) {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                if (a.ov != b.ov) return a.ov > b.ov;\n                return a.cost < b.cost;\n            });\n        } else {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                return a.cost < b.cost;\n            });\n        }\n\n        vector<int> out(M, -1), in(M, -1);\n        DSU dsu(M);\n        int added = 0;\n\n        for (const auto& e : es) {\n            if (out[e.u] != -1 || in[e.v] != -1) continue;\n            if (dsu.find(e.u) == dsu.find(e.v)) continue;\n\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n\n            added++;\n            if (added == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) {\n            if (in[i] == -1) {\n                head = i;\n                break;\n            }\n        }\n\n        vector<int> path;\n        while (head != -1) {\n            path.push_back(head);\n            head = out[head];\n        }\n\n        if ((int)path.size() != M) {\n            path.resize(M);\n            iota(path.begin(), path.end(), 0);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedy(int startWord) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = wordCnt(curWord);\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            int bestScore = INF;\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = wordCnt(j);\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                if (minv < bestScore) {\n                    bestScore = minv;\n                    bestJ = j;\n                }\n            }\n\n            int cols = wordCnt(bestJ);\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedyLookahead(int startWord, int futureWeight) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = wordCnt(curWord);\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            long long bestScore = (1LL << 60);\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = wordCnt(j);\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                int fut = 0;\n                if (step + 1 < M && futureWeight != 0) {\n                    fut = INF;\n                    for (int k = 0; k < M; k++) {\n                        if (!used[k] && k != j) fut = min(fut, modes[0].edge[j * M + k]);\n                    }\n                    if (fut == INF) fut = 0;\n                }\n\n                long long score = (long long)minv * 10 + (long long)futureWeight * fut;\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestJ = j;\n                }\n            }\n\n            int cols = wordCnt(bestJ);\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateBeam(vector<int> starts, int beamW, int expandK, int futureWeight, double deadline) {\n        const int INF = 1e9;\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n        if (starts.empty()) return {};\n\n        struct BState {\n            vector<int> path;\n            bitset<200> used;\n            int last;\n            vector<int> dp;\n            int cost;\n            long long score;\n        };\n\n        auto initState = [&](int st) {\n            BState s;\n            s.path = {st};\n            s.used.reset();\n            s.used.set(st);\n            s.last = st;\n\n            int cnt = wordCnt(st);\n            s.dp.resize(cnt);\n\n            int off = initOff[st];\n            int mn = INF;\n            for (int i = 0; i < cnt; i++) {\n                s.dp[i] = initData[off + i];\n                mn = min(mn, s.dp[i]);\n            }\n\n            int fut = INF;\n            for (int k = 0; k < M; k++) if (k != st) fut = min(fut, modes[0].edge[st * M + k]);\n            if (fut == INF) fut = 0;\n\n            s.cost = mn;\n            s.score = (long long)mn * 10 + (long long)futureWeight * fut;\n            return s;\n        };\n\n        auto transMin = [&](const vector<int>& dp, int u, int v) {\n            int rows = (int)dp.size();\n            int cols = wordCnt(v);\n            int tmp[225];\n            fill(tmp, tmp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < tmp[c]) tmp[c] = val;\n                }\n            }\n\n            int mn = INF;\n            for (int c = 0; c < cols; c++) mn = min(mn, tmp[c]);\n            return mn;\n        };\n\n        auto transVec = [&](const vector<int>& dp, int u, int v) {\n            int rows = (int)dp.size();\n            int cols = wordCnt(v);\n            vector<int> ndp(cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < ndp[c]) ndp[c] = val;\n                }\n            }\n\n            return ndp;\n        };\n\n        auto finishFast = [&](BState s) {\n            while ((int)s.path.size() < M) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (s.used.test(j)) continue;\n                    int c = modes[0].edge[s.last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                if (bestJ < 0) break;\n                s.path.push_back(bestJ);\n                s.used.set(bestJ);\n                s.last = bestJ;\n            }\n            return s.path;\n        };\n\n        vector<BState> beam;\n        for (int st : starts) beam.push_back(initState(st));\n\n        sort(beam.begin(), beam.end(), [](const BState& a, const BState& b) {\n            return a.score < b.score;\n        });\n        if ((int)beam.size() > beamW) beam.resize(beamW);\n\n        for (int step = 1; step < M; step++) {\n            if (timer.elapsed() > deadline) {\n                if (beam.empty()) return {};\n                return finishFast(beam[0]);\n            }\n\n            struct Opt {\n                long long score;\n                int j;\n                int cost;\n            };\n\n            vector<BState> nxtStates;\n            nxtStates.reserve(beamW * expandK);\n\n            for (const auto& s : beam) {\n                vector<Opt> opts;\n                opts.reserve(M);\n\n                for (int j = 0; j < M; j++) {\n                    if (s.used.test(j)) continue;\n\n                    int mn = transMin(s.dp, s.last, j);\n\n                    int fut = 0;\n                    if (futureWeight && step + 1 < M) {\n                        fut = INF;\n                        for (int k = 0; k < M; k++) {\n                            if (!s.used.test(k) && k != j) fut = min(fut, modes[0].edge[j * M + k]);\n                        }\n                        if (fut == INF) fut = 0;\n                    }\n\n                    long long score = (long long)mn * 10 + (long long)futureWeight * fut;\n                    opts.push_back({score, j, mn});\n                }\n\n                sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n                    return a.score < b.score;\n                });\n                if ((int)opts.size() > expandK) opts.resize(expandK);\n\n                for (const auto& op : opts) {\n                    BState ns;\n                    ns.path = s.path;\n                    ns.path.push_back(op.j);\n                    ns.used = s.used;\n                    ns.used.set(op.j);\n                    ns.last = op.j;\n                    ns.dp = transVec(s.dp, s.last, op.j);\n                    ns.cost = op.cost;\n                    ns.score = op.score;\n                    nxtStates.push_back(std::move(ns));\n                }\n            }\n\n            sort(nxtStates.begin(), nxtStates.end(), [](const BState& a, const BState& b) {\n                return a.score < b.score;\n            });\n\n            if ((int)nxtStates.size() > beamW) nxtStates.resize(beamW);\n            beam.swap(nxtStates);\n            if (beam.empty()) return {};\n        }\n\n        int best = 0;\n        for (int i = 1; i < (int)beam.size(); i++) {\n            if (beam[i].cost < beam[best].cost) best = i;\n        }\n        return beam[best].path;\n    }\n\n    long long relocateDelta(const vector<int>& ord, int i, int p, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (p == i) return 0;\n\n        int x = ord[i];\n\n        int L = (i > 0 ? ord[i - 1] : -1);\n        int R = (i + 1 < n ? ord[i + 1] : -1);\n\n        long long rem = arc(mode, L, R) - arc(mode, L, x) - arc(mode, x, R);\n\n        auto getRemoved = [&](int idx) -> int {\n            return ord[idx < i ? idx : idx + 1];\n        };\n\n        int left = (p > 0 ? getRemoved(p - 1) : -1);\n        int right = (p < n - 1 ? getRemoved(p) : -1);\n\n        long long ins = arc(mode, left, x) + arc(mode, x, right) - arc(mode, left, right);\n        return rem + ins;\n    }\n\n    long long blockRelocateDelta(const vector<int>& ord, int l, int r, int q, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (q >= l && q <= r + 1) return 0;\n\n        int A = ord[l];\n        int B = ord[r];\n\n        int L = (l > 0 ? ord[l - 1] : -1);\n        int R = (r + 1 < n ? ord[r + 1] : -1);\n\n        int P = (q > 0 ? ord[q - 1] : -1);\n        int Q = (q < n ? ord[q] : -1);\n\n        long long oldCost = arc(mode, L, A) + arc(mode, B, R) + arc(mode, P, Q);\n        long long newCost = arc(mode, L, R) + arc(mode, P, A) + arc(mode, B, Q);\n        return newCost - oldCost;\n    }\n\n    long long blockSwapDelta(const vector<int>& ord, int l1, int r1, int l2, int r2, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (l1 > r1 || l2 > r2 || r1 >= l2) return 0;\n\n        int A = ord[l1], B = ord[r1];\n        int C = ord[l2], D = ord[r2];\n\n        int L = (l1 > 0 ? ord[l1 - 1] : -1);\n        int R = (r2 + 1 < n ? ord[r2 + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (r1 + 1 == l2) {\n            oldCost = arc(mode, L, A) + arc(mode, B, C) + arc(mode, D, R);\n            newCost = arc(mode, L, C) + arc(mode, D, A) + arc(mode, B, R);\n        } else {\n            int E = ord[r1 + 1];\n            int F = ord[l2 - 1];\n\n            oldCost = arc(mode, L, A) + arc(mode, B, E) + arc(mode, F, C) + arc(mode, D, R);\n            newCost = arc(mode, L, C) + arc(mode, D, E) + arc(mode, F, A) + arc(mode, B, R);\n        }\n\n        return newCost - oldCost;\n    }\n\n    long long swapDelta(const vector<int>& ord, int i, int j, const Mode& mode) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int n = (int)ord.size();\n        vector<int> ks;\n        int arr[4] = {i - 1, i, j - 1, j};\n\n        for (int t = 0; t < 4; t++) {\n            int k = arr[t];\n            if (k < -1 || k > n - 1) continue;\n            if (find(ks.begin(), ks.end(), k) == ks.end()) ks.push_back(k);\n        }\n\n        auto nodeNew = [&](int idx) -> int {\n            if (idx == i) return ord[j];\n            if (idx == j) return ord[i];\n            return ord[idx];\n        };\n\n        auto edgeOld = [&](int k) -> long long {\n            if (k == -1) return mode.start[ord[0]];\n            if (k >= n - 1) return 0;\n            return mode.edge[ord[k] * M + ord[k + 1]];\n        };\n\n        auto edgeNew = [&](int k) -> long long {\n            if (k == -1) return mode.start[nodeNew(0)];\n            if (k >= n - 1) return 0;\n            return mode.edge[nodeNew(k) * M + nodeNew(k + 1)];\n        };\n\n        long long oldSum = 0, newSum = 0;\n        for (int k : ks) {\n            oldSum += edgeOld(k);\n            newSum += edgeNew(k);\n        }\n        return newSum - oldSum;\n    }\n\n    long long reverseDeltaSlow(const vector<int>& ord, int l, int r, const Mode& mode) const {\n        int n = (int)ord.size();\n        long long oldCost = 0, newCost = 0;\n\n        if (l == 0) {\n            oldCost += mode.start[ord[l]];\n            newCost += mode.start[ord[r]];\n        } else {\n            oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n            newCost += mode.edge[ord[l - 1] * M + ord[r]];\n        }\n\n        if (r + 1 < n) {\n            oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n            newCost += mode.edge[ord[l] * M + ord[r + 1]];\n        }\n\n        for (int k = l; k < r; k++) {\n            oldCost += mode.edge[ord[k] * M + ord[k + 1]];\n            newCost += mode.edge[ord[k + 1] * M + ord[k]];\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyMove(vector<int>& ord, const Move& mv) const {\n        if (mv.type == 0) {\n            int x = ord[mv.a];\n            ord.erase(ord.begin() + mv.a);\n            ord.insert(ord.begin() + mv.b, x);\n        } else if (mv.type == 1) {\n            swap(ord[mv.a], ord[mv.b]);\n        } else if (mv.type == 2) {\n            reverse(ord.begin() + mv.a, ord.begin() + mv.b + 1);\n        } else if (mv.type == 3) {\n            int l = mv.a, r = mv.b, q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos = (q < l ? q : q - len);\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        } else if (mv.type == 4) {\n            int l1 = mv.a, r1 = mv.b;\n            int l2 = mv.c / 256;\n            int r2 = mv.c % 256;\n\n            vector<int> res;\n            res.reserve(ord.size());\n\n            res.insert(res.end(), ord.begin(), ord.begin() + l1);\n            res.insert(res.end(), ord.begin() + l2, ord.begin() + r2 + 1);\n            res.insert(res.end(), ord.begin() + r1 + 1, ord.begin() + l2);\n            res.insert(res.end(), ord.begin() + l1, ord.begin() + r1 + 1);\n            res.insert(res.end(), ord.begin() + r2 + 1, ord.end());\n\n            ord.swap(res);\n        } else if (mv.type == 5) {\n            int l = mv.a, r = mv.b, q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            reverse(block.begin(), block.end());\n\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos = (q < l ? q : q - len);\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        } else if (mv.type == 6) {\n            int l1 = mv.a, r1 = mv.b;\n            int bits = mv.c & 3;\n            int code = mv.c >> 2;\n            int l2 = code / 256;\n            int r2 = code % 256;\n\n            bool rev1 = bits & 1;\n            bool rev2 = bits & 2;\n\n            vector<int> res;\n            res.reserve(ord.size());\n\n            res.insert(res.end(), ord.begin(), ord.begin() + l1);\n\n            if (rev2) {\n                for (int i = r2; i >= l2; i--) res.push_back(ord[i]);\n            } else {\n                res.insert(res.end(), ord.begin() + l2, ord.begin() + r2 + 1);\n            }\n\n            res.insert(res.end(), ord.begin() + r1 + 1, ord.begin() + l2);\n\n            if (rev1) {\n                for (int i = r1; i >= l1; i--) res.push_back(ord[i]);\n            } else {\n                res.insert(res.end(), ord.begin() + l1, ord.begin() + r1 + 1);\n            }\n\n            res.insert(res.end(), ord.begin() + r2 + 1, ord.end());\n            ord.swap(res);\n        }\n    }\n\n    void improveAdditive(vector<int>& ord, const Mode& mode, int maxIter = 40, int maxBlockLen = 3) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if ((iter & 1) == 0 && timer.elapsed() > 1.48) break;\n\n            long long bestDelta = 0;\n            Move bestMove{-1, 0, 0, 0};\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {0, i, p, d};\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {1, i, j, d};\n                    }\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    long long d = newCost - oldCost;\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {2, l, r, d};\n                    }\n                }\n            }\n\n            bool stopBlock = false;\n            int limLen = min(maxBlockLen, n - 1);\n            for (int len = 2; len <= limLen && !stopBlock; len++) {\n                for (int l = 0; l + len <= n && !stopBlock; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        if (d < bestDelta) {\n                            bestDelta = d;\n                            bestMove = {3, l, r, d, q};\n                        }\n                    }\n                    if ((l & 15) == 0 && timer.elapsed() > 1.48) stopBlock = true;\n                }\n            }\n\n            if (bestDelta < 0) applyMove(ord, bestMove);\n            else break;\n        }\n    }\n\n    Candidate exactRefine(vector<int> ord, double deadline, int rounds, int K) {\n        int cur = exactCost(ord);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestOrder = ord;\n        }\n\n        const Mode& mode = modes[0];\n        int n = (int)ord.size();\n\n        for (int round = 0; round < rounds; round++) {\n            if (timer.elapsed() > deadline) break;\n\n            vector<Move> moves;\n            moves.reserve(n * n * 3);\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    moves.push_back({0, i, p, d});\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    moves.push_back({1, i, j, d});\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    moves.push_back({2, l, r, newCost - oldCost});\n                }\n            }\n\n            int limLen = min(4, n - 1);\n            for (int len = 2; len <= limLen; len++) {\n                for (int l = 0; l + len <= n; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        moves.push_back({3, l, r, d, q});\n                    }\n                }\n            }\n\n            if (timer.elapsed() < deadline - 0.04) {\n                int maxSwapLen = min(3, n);\n                bool stop = false;\n                for (int len1 = 1; len1 <= maxSwapLen && !stop; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n && !stop; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxSwapLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n                                long long d = blockSwapDelta(ord, l1, r1, l2, r2, mode);\n                                if (d < 0) moves.push_back({4, l1, r1, d, l2 * 256 + r2});\n                            }\n                        }\n                        if ((l1 & 15) == 0 && timer.elapsed() > deadline - 0.03) stop = true;\n                    }\n                }\n            }\n\n            sort(moves.begin(), moves.end(), [](const Move& a, const Move& b) {\n                return a.delta < b.delta;\n            });\n\n            int bestLocal = cur;\n            Move bestMv{-1, 0, 0, 0};\n            int lim = min(K, (int)moves.size());\n\n            for (int i = 0; i < lim; i++) {\n                if ((i & 31) == 0 && timer.elapsed() > deadline) break;\n\n                vector<int> cand = ord;\n                applyMove(cand, moves[i]);\n                int nc = exactCost(cand);\n\n                if (nc < bestLocal) {\n                    bestLocal = nc;\n                    bestMv = moves[i];\n                }\n            }\n\n            if (bestMv.type != -1) {\n                applyMove(ord, bestMv);\n                cur = bestLocal;\n\n                if (cur < bestCost) {\n                    bestCost = cur;\n                    bestOrder = ord;\n                }\n            } else {\n                break;\n            }\n        }\n\n        return {cur, ord};\n    }\n\n    void buildExactCtx(const vector<int>& ord, ExactCtx& ctx, bool needRev) const {\n        int n = (int)ord.size();\n        ctx.n = n;\n        ctx.cnt.assign(n, 0);\n        for (int i = 0; i < n; i++) ctx.cnt[i] = wordCnt(ord[i]);\n\n        ctx.foff.assign(n * n, -1);\n        ctx.fdata.clear();\n        ctx.fdata.reserve((size_t)n * n * 90);\n\n        vector<unsigned short> prev, cur;\n\n        for (int l = 0; l < n; l++) {\n            int rows = ctx.cnt[l];\n            prev.assign(rows * rows, USINF);\n            for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n            ctx.foff[l * n + l] = (int)ctx.fdata.size();\n            ctx.fdata.insert(ctx.fdata.end(), prev.begin(), prev.end());\n\n            for (int r = l + 1; r < n; r++) {\n                int mid = ctx.cnt[r - 1];\n                int cols = ctx.cnt[r];\n                cur.assign(rows * cols, USINF);\n\n                const unsigned short* e = &edgeData[edgeOff[ord[r - 1] * M + ord[r]]];\n\n                for (int i = 0; i < rows; i++) {\n                    for (int k = 0; k < mid; k++) {\n                        int base = prev[i * mid + k];\n                        if (base >= USINF) continue;\n                        const unsigned short* er = e + k * cols;\n                        int outBase = i * cols;\n                        for (int j = 0; j < cols; j++) {\n                            int v = base + (int)er[j];\n                            if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                        }\n                    }\n                }\n\n                ctx.foff[l * n + r] = (int)ctx.fdata.size();\n                ctx.fdata.insert(ctx.fdata.end(), cur.begin(), cur.end());\n                prev.swap(cur);\n            }\n        }\n\n        ctx.roff.assign(n * n, -1);\n        ctx.rdata.clear();\n        if (needRev) {\n            ctx.rdata.reserve((size_t)n * n * 90);\n\n            for (int r = 0; r < n; r++) {\n                int rows = ctx.cnt[r];\n                prev.assign(rows * rows, USINF);\n                for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n                ctx.roff[r * n + r] = (int)ctx.rdata.size();\n                ctx.rdata.insert(ctx.rdata.end(), prev.begin(), prev.end());\n\n                for (int l = r - 1; l >= 0; l--) {\n                    int mid = ctx.cnt[l + 1];\n                    int cols = ctx.cnt[l];\n                    cur.assign(rows * cols, USINF);\n\n                    const unsigned short* e = &edgeData[edgeOff[ord[l + 1] * M + ord[l]]];\n\n                    for (int i = 0; i < rows; i++) {\n                        for (int k = 0; k < mid; k++) {\n                            int base = prev[i * mid + k];\n                            if (base >= USINF) continue;\n                            const unsigned short* er = e + k * cols;\n                            int outBase = i * cols;\n                            for (int j = 0; j < cols; j++) {\n                                int v = base + (int)er[j];\n                                if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                            }\n                        }\n                    }\n\n                    ctx.roff[l * n + r] = (int)ctx.rdata.size();\n                    ctx.rdata.insert(ctx.rdata.end(), cur.begin(), cur.end());\n                    prev.swap(cur);\n                }\n            }\n        }\n\n        ctx.prefOff.assign(n, 0);\n        ctx.prefData.clear();\n        ctx.prefData.reserve(n * maxOcc);\n\n        vector<unsigned short> dp, ndp;\n\n        {\n            int w = ord[0];\n            int cnt = ctx.cnt[0];\n            dp.resize(cnt);\n            int off = initOff[w];\n            for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n            ctx.prefOff[0] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        for (int pos = 1; pos < n; pos++) {\n            int rows = ctx.cnt[pos - 1];\n            int cols = ctx.cnt[pos];\n            ndp.assign(cols, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos - 1] * M + ord[pos]]];\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)er[c];\n                    if (v < ndp[c]) ndp[c] = (unsigned short)v;\n                }\n            }\n\n            dp.swap(ndp);\n            ctx.prefOff[pos] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        ctx.current = USINF;\n        for (unsigned short v : dp) ctx.current = min(ctx.current, (int)v);\n\n        vector<vector<unsigned short>> sv(n);\n        sv[n - 1].assign(ctx.cnt[n - 1], 0);\n\n        for (int pos = n - 2; pos >= 0; pos--) {\n            int rows = ctx.cnt[pos];\n            int cols = ctx.cnt[pos + 1];\n            sv[pos].assign(rows, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos] * M + ord[pos + 1]]];\n\n            for (int r = 0; r < rows; r++) {\n                int best = USINF;\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = (int)er[c] + (int)sv[pos + 1][c];\n                    if (v < best) best = v;\n                }\n                sv[pos][r] = (unsigned short)best;\n            }\n        }\n\n        ctx.suffOff.assign(n, 0);\n        ctx.suffData.clear();\n        ctx.suffData.reserve(n * maxOcc);\n        for (int pos = 0; pos < n; pos++) {\n            ctx.suffOff[pos] = (int)ctx.suffData.size();\n            ctx.suffData.insert(ctx.suffData.end(), sv[pos].begin(), sv[pos].end());\n        }\n    }\n\n    inline void loadInitWord(int w, int* a, int& cnt) const {\n        cnt = wordCnt(w);\n        const unsigned short* p = &initData[initOff[w]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void loadPrefPos(const ExactCtx& ctx, int pos, int* a, int& cnt) const {\n        cnt = ctx.cnt[pos];\n        const unsigned short* p = &ctx.prefData[ctx.prefOff[pos]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void applyEdgeArr(int* a, int& cnt, int u, int v, int* tmp) const {\n        const int INF = 1e9;\n        int rows = cnt;\n        int cols = wordCnt(v);\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n        for (int r = 0; r < rows; r++) {\n            int base = a[r];\n            const unsigned short* mr = mat + r * cols;\n            for (int c = 0; c < cols; c++) {\n                int val = base + (int)mr[c];\n                if (val < tmp[c]) tmp[c] = val;\n            }\n        }\n\n        for (int c = 0; c < cols; c++) a[c] = tmp[c];\n        cnt = cols;\n    }\n\n    inline void applyFInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[r];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[l];\n        int cols = ctx.cnt[r];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.fdata[ctx.foff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline void applyRInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[l];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[r];\n        int cols = ctx.cnt[l];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.rdata[ctx.roff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline int finishAt(const ExactCtx& ctx, int pos, int* a, int cnt) const {\n        const unsigned short* s = &ctx.suffData[ctx.suffOff[pos]];\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) {\n            int v = a[i] + (int)s[i];\n            if (v < ans) ans = v;\n        }\n        return ans;\n    }\n\n    inline int minArr(int* a, int cnt) const {\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) ans = min(ans, a[i]);\n        return ans;\n    }\n\n    int evalBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[l], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            }\n\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    int evalRelocateExact(const vector<int>& ord, const ExactCtx& ctx, int i, int p) const {\n        if (i == p) return ctx.current;\n        int q = (p < i ? p : p + 1);\n        return evalBlockExact(ord, ctx, i, i, q);\n    }\n\n    int evalSwapExact(const vector<int>& ord, const ExactCtx& ctx, int i, int j) const {\n        if (i > j) swap(i, j);\n        int n = ctx.n;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (i == 0) {\n            loadInitWord(ord[j], a, cnt);\n        } else {\n            loadPrefPos(ctx, i - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[i - 1], ord[j], tmp);\n        }\n\n        if (j == i + 1) {\n            applyEdgeArr(a, cnt, ord[j], ord[i], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[j], ord[i + 1], tmp);\n            applyFInterval(ctx, i + 1, j - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[j - 1], ord[i], tmp);\n        }\n\n        if (j + 1 < n) {\n            applyEdgeArr(a, cnt, ord[i], ord[j + 1], tmp);\n            return finishAt(ctx, j + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalReverseExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r) const {\n        int n = ctx.n;\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l == 0) {\n            loadInitWord(ord[r], a, cnt);\n        } else {\n            loadPrefPos(ctx, l - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l - 1], ord[r], tmp);\n        }\n\n        applyRInterval(ctx, l, r, a, cnt, tmp);\n\n        if (r + 1 < n) {\n            applyEdgeArr(a, cnt, ord[l], ord[r + 1], tmp);\n            return finishAt(ctx, r + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalBlockSwapExact(const vector<int>& ord, const ExactCtx& ctx, int l1, int r1, int l2, int r2) const {\n        int n = ctx.n;\n        if (r1 >= l2) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l1 == 0) {\n            loadInitWord(ord[l2], a, cnt);\n        } else {\n            loadPrefPos(ctx, l1 - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l1 - 1], ord[l2], tmp);\n        }\n\n        applyFInterval(ctx, l2, r2, a, cnt, tmp);\n\n        if (r1 + 1 < l2) {\n            applyEdgeArr(a, cnt, ord[r2], ord[r1 + 1], tmp);\n            applyFInterval(ctx, r1 + 1, l2 - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l2 - 1], ord[l1], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[r2], ord[l1], tmp);\n        }\n\n        applyFInterval(ctx, l1, r1, a, cnt, tmp);\n\n        if (r2 + 1 < n) {\n            applyEdgeArr(a, cnt, ord[r1], ord[r2 + 1], tmp);\n            return finishAt(ctx, r2 + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalBlockSwapOrientExact(const vector<int>& ord, const ExactCtx& ctx,\n                                 int l1, int r1, int l2, int r2,\n                                 bool rev1, bool rev2) const {\n        int n = ctx.n;\n        if (r1 >= l2) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        int start2 = rev2 ? ord[r2] : ord[l2];\n        int end2 = rev2 ? ord[l2] : ord[r2];\n        int start1 = rev1 ? ord[r1] : ord[l1];\n        int end1 = rev1 ? ord[l1] : ord[r1];\n\n        if (l1 == 0) {\n            loadInitWord(start2, a, cnt);\n        } else {\n            loadPrefPos(ctx, l1 - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l1 - 1], start2, tmp);\n        }\n\n        if (rev2) applyRInterval(ctx, l2, r2, a, cnt, tmp);\n        else applyFInterval(ctx, l2, r2, a, cnt, tmp);\n\n        if (r1 + 1 < l2) {\n            applyEdgeArr(a, cnt, end2, ord[r1 + 1], tmp);\n            applyFInterval(ctx, r1 + 1, l2 - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l2 - 1], start1, tmp);\n        } else {\n            applyEdgeArr(a, cnt, end2, start1, tmp);\n        }\n\n        if (rev1) applyRInterval(ctx, l1, r1, a, cnt, tmp);\n        else applyFInterval(ctx, l1, r1, a, cnt, tmp);\n\n        if (r2 + 1 < n) {\n            applyEdgeArr(a, cnt, end1, ord[r2 + 1], tmp);\n            return finishAt(ctx, r2 + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalRevBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[r], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[r], tmp);\n            }\n\n            applyRInterval(ctx, l, r, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[q - 1], ord[r], tmp);\n            applyRInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[l], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    void improveExactInterval(vector<int>& ord, double deadline, int maxIter) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if (timer.elapsed() > deadline - 0.07) break;\n\n            ExactCtx ctx;\n            buildExactCtx(ord, ctx, true);\n\n            int cur = ctx.current;\n            if (cur < bestCost) {\n                bestCost = cur;\n                bestOrder = ord;\n            }\n\n            int bestVal = cur;\n            Move bestMv{-1, 0, 0, 0};\n\n            int checks = 0;\n            bool timeout = false;\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    int val = evalRelocateExact(ord, ctx, i, p);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {0, i, p, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    int val = evalSwapExact(ord, ctx, i, j);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {1, i, j, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    int val = evalReverseExact(ord, ctx, l, r);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {2, l, r, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(10, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {3, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(9, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalRevBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {5, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(4, n);\n                for (int len1 = 1; len1 <= maxLen; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n\n                                int val = evalBlockSwapExact(ord, ctx, l1, r1, l2, r2);\n                                if (val < bestVal) {\n                                    bestVal = val;\n                                    bestMv = {4, l1, r1, val - cur, l2 * 256 + r2};\n                                }\n\n                                if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                    timeout = true;\n                                    goto ENUM_DONE;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(3, n);\n                for (int len1 = 1; len1 <= maxLen; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n\n                                for (int bits = 1; bits < 4; bits++) {\n                                    if ((bits & 1) && len1 == 1) continue;\n                                    if ((bits & 2) && len2 == 1) continue;\n\n                                    bool rev1 = bits & 1;\n                                    bool rev2 = bits & 2;\n                                    int val = evalBlockSwapOrientExact(ord, ctx, l1, r1, l2, r2, rev1, rev2);\n                                    if (val < bestVal) {\n                                        int code = ((l2 * 256 + r2) << 2) | bits;\n                                        bestVal = val;\n                                        bestMv = {6, l1, r1, val - cur, code};\n                                    }\n\n                                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                        timeout = true;\n                                        goto ENUM_DONE;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n        ENUM_DONE:\n            if (bestMv.type != -1 && bestVal < cur) {\n                applyMove(ord, bestMv);\n                int real = exactCost(ord);\n                if (real < bestCost) {\n                    bestCost = real;\n                    bestOrder = ord;\n                }\n                if (real >= cur) break;\n            } else {\n                break;\n            }\n\n            if (timeout || timer.elapsed() > deadline) break;\n        }\n    }\n\n    vector<int> destroyRepairOrder(const vector<int>& ord, int k, const Mode& mode) {\n        int n = (int)ord.size();\n        if (n <= 2) return ord;\n\n        k = max(1, min(k, n - 1));\n\n        vector<int> pos;\n        vector<char> mark(n, false);\n\n        auto addPos = [&](int p) {\n            if (0 <= p && p < n && !mark[p]) {\n                mark[p] = true;\n                pos.push_back(p);\n            }\n        };\n\n        int tp = rng.nextInt(100);\n\n        if (tp < 25) {\n            int len = k;\n            int st = rng.nextInt(n - len + 1);\n            for (int i = 0; i < len; i++) addPos(st + i);\n        } else if (tp < 55) {\n            vector<pair<long long, int>> bad;\n            bad.reserve(n);\n            for (int i = 0; i < n; i++) {\n                int L = (i > 0 ? ord[i - 1] : -1);\n                int x = ord[i];\n                int R = (i + 1 < n ? ord[i + 1] : -1);\n                long long v = arc(mode, L, x) + arc(mode, x, R) - arc(mode, L, R);\n                v += rng.nextInt(50);\n                bad.push_back({-v, i});\n            }\n            sort(bad.begin(), bad.end());\n            for (auto [neg, p] : bad) {\n                addPos(p);\n                if ((int)pos.size() >= k) break;\n            }\n        } else if (tp < 78) {\n            vector<pair<long long, int>> badEdge;\n            badEdge.reserve(n);\n            badEdge.push_back({-(long long)mode.start[ord[0]], 0});\n            for (int i = 0; i + 1 < n; i++) {\n                long long v = mode.edge[ord[i] * M + ord[i + 1]] + rng.nextInt(50);\n                badEdge.push_back({-v, i + 1});\n            }\n            sort(badEdge.begin(), badEdge.end());\n            int center = badEdge[min((int)badEdge.size() - 1, rng.nextInt(min(5, (int)badEdge.size())))].second;\n            int st = max(0, min(n - k, center - k / 2));\n            for (int i = 0; i < k; i++) addPos(st + i);\n        } else {\n            while ((int)pos.size() < k) addPos(rng.nextInt(n));\n        }\n\n        while ((int)pos.size() < k) addPos(rng.nextInt(n));\n\n        sort(pos.rbegin(), pos.rend());\n\n        vector<int> path = ord;\n        vector<int> removed;\n        removed.reserve(k);\n\n        for (int p : pos) {\n            removed.push_back(path[p]);\n            path.erase(path.begin() + p);\n        }\n\n        for (int i = (int)removed.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(removed[i], removed[j]);\n        }\n\n        int regretW = 2 + rng.nextInt(8);\n\n        while (!removed.empty()) {\n            long long bestScore = (1LL << 60);\n            int bestRi = 0, bestPos = 0;\n\n            for (int ri = 0; ri < (int)removed.size(); ri++) {\n                int x = removed[ri];\n\n                long long b1 = (1LL << 60), b2 = (1LL << 60);\n                int pos1 = 0;\n\n                for (int p = 0; p <= (int)path.size(); p++) {\n                    int u = (p == 0 ? -1 : path[p - 1]);\n                    int v = (p == (int)path.size() ? -1 : path[p]);\n\n                    long long d = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n\n                    if (d < b1) {\n                        b2 = b1;\n                        b1 = d;\n                        pos1 = p;\n                    } else if (d < b2) {\n                        b2 = d;\n                    }\n                }\n\n                if (b2 >= (1LL << 50)) b2 = b1 + 1000000;\n\n                long long regret = b2 - b1;\n                long long score = b1 * 10 - (long long)regretW * regret + rng.nextInt(30);\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestRi = ri;\n                    bestPos = pos1;\n                }\n            }\n\n            int x = removed[bestRi];\n            path.insert(path.begin() + bestPos, x);\n            removed.erase(removed.begin() + bestRi);\n        }\n\n        return path;\n    }\n\n    void intensiveLNS(double deadline) {\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            int mi;\n            int r = rng.nextInt(100);\n            if (r < 65) mi = 0;\n            else if (r < 80) mi = 1;\n            else if (r < 90) mi = 2;\n            else mi = 3;\n\n            int k;\n            if (rng.nextInt(100) < 75) k = 3 + rng.nextInt(8);\n            else k = 10 + rng.nextInt(8);\n\n            vector<int> cand = destroyRepairOrder(bestOrder, k, modes[mi]);\n            int c = exactCost(cand);\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = cand;\n            }\n\n            iter++;\n            if ((iter & 63) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    void simulatedAnnealing(double deadline) {\n        if (timer.elapsed() > deadline) return;\n\n        vector<int> curOrd = bestOrder;\n        int curCost = bestCost;\n        const Mode& mode = modes[0];\n\n        double st = timer.elapsed();\n        int n = (int)curOrd.size();\n        if (n <= 1) return;\n\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            double progress = (timer.elapsed() - st) / max(1e-9, deadline - st);\n            double temp = 18.0 * pow(0.05, progress) + 0.4;\n\n            auto acceptCandidate = [&](vector<int>& cand, int nc) {\n                int diff = nc - curCost;\n                if (diff <= 0 || rng.nextDouble() < exp(-diff / temp)) {\n                    curOrd.swap(cand);\n                    curCost = nc;\n\n                    if (curCost < bestCost) {\n                        bestCost = curCost;\n                        bestOrder = curOrd;\n                    }\n                }\n            };\n\n            int typ = rng.nextInt(100);\n\n            if (typ >= 88) {\n                int mi;\n                int rr = rng.nextInt(100);\n                if (rr < 65) mi = 0;\n                else if (rr < 78) mi = 1;\n                else if (rr < 89) mi = 2;\n                else mi = 3;\n\n                int k = 3 + rng.nextInt(10);\n                vector<int> cand = destroyRepairOrder(curOrd, k, modes[mi]);\n                int nc = exactCost(cand);\n                acceptCandidate(cand, nc);\n\n                iter++;\n                if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n                continue;\n            }\n\n            Move mv{-1, 0, 0, 0};\n\n            if (typ < 23) {\n                int i = rng.nextInt(n);\n                int p = rng.nextInt(n);\n                if (p == i) continue;\n                long long d = relocateDelta(curOrd, i, p, mode);\n                mv = {0, i, p, d};\n            } else if (typ < 42) {\n                int i = rng.nextInt(n);\n                int j = rng.nextInt(n);\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                long long d = swapDelta(curOrd, i, j, mode);\n                mv = {1, i, j, d};\n            } else if (typ < 58) {\n                int l = rng.nextInt(n);\n                int r = rng.nextInt(n);\n                if (l == r) continue;\n                if (l > r) swap(l, r);\n                long long d = reverseDeltaSlow(curOrd, l, r, mode);\n                mv = {2, l, r, d};\n            } else if (typ < 70) {\n                if (n <= 3) continue;\n                int maxL = min(7, n - 1);\n                int len = 2 + rng.nextInt(maxL - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                long long d = blockRelocateDelta(curOrd, l, r, q, mode);\n                mv = {3, l, r, d, q};\n            } else if (typ < 77) {\n                if (n <= 3) continue;\n                int maxL = min(7, n - 1);\n                int len = 2 + rng.nextInt(maxL - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                mv = {5, l, r, 0, q};\n            } else if (typ < 84) {\n                if (n <= 3) continue;\n                int maxL = min(5, n - 1);\n                int len1 = 1 + rng.nextInt(maxL);\n                int len2 = 1 + rng.nextInt(maxL);\n                int l1 = rng.nextInt(n - len1 + 1);\n                int r1 = l1 + len1 - 1;\n                int l2 = rng.nextInt(n - len2 + 1);\n                int r2 = l2 + len2 - 1;\n\n                if (l2 < l1) {\n                    swap(l1, l2);\n                    swap(r1, r2);\n                }\n                if (r1 >= l2) continue;\n                if (len1 == 1 && len2 == 1) continue;\n\n                long long d = blockSwapDelta(curOrd, l1, r1, l2, r2, mode);\n                mv = {4, l1, r1, d, l2 * 256 + r2};\n            } else {\n                if (n <= 3) continue;\n                int maxL = min(4, n - 1);\n                int len1 = 1 + rng.nextInt(maxL);\n                int len2 = 1 + rng.nextInt(maxL);\n                int l1 = rng.nextInt(n - len1 + 1);\n                int r1 = l1 + len1 - 1;\n                int l2 = rng.nextInt(n - len2 + 1);\n                int r2 = l2 + len2 - 1;\n\n                if (l2 < l1) {\n                    swap(l1, l2);\n                    swap(r1, r2);\n                }\n                if (r1 >= l2) continue;\n                if (len1 == 1 && len2 == 1) continue;\n\n                int bits = 1 + rng.nextInt(3);\n                if ((bits & 1) && len1 == 1) continue;\n                if ((bits & 2) && len2 == 1) continue;\n\n                int code = ((l2 * 256 + r2) << 2) | bits;\n                mv = {6, l1, r1, 0, code};\n            }\n\n            if (mv.delta > 3000) continue;\n            if (mv.delta > 800 && rng.nextInt(100) < 95) continue;\n\n            vector<int> cand = curOrd;\n            applyMove(cand, mv);\n            int nc = exactCost(cand);\n            acceptCandidate(cand, nc);\n\n            iter++;\n            if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    string buildString(const vector<int>& ord) const {\n        if (ord.empty()) return \"\";\n\n        string s = words[ord[0]];\n        for (int i = 1; i < (int)ord.size(); i++) {\n            int a = ord[i - 1];\n            int b = ord[i];\n            int k = overlap[a * M + b];\n            s += words[b].substr(k);\n        }\n        return s;\n    }\n\n    bool containsAll(const string& s) const {\n        if ((int)s.size() < 5) return false;\n\n        vector<char> seen(M, false);\n        int got = 0;\n\n        int code = 0;\n        for (int i = 0; i < 5; i++) code = code * 26 + (s[i] - 'A');\n\n        auto mark = [&](int cd) {\n            auto it = targetMap.find(cd);\n            if (it != targetMap.end()) {\n                int id = it->second;\n                if (!seen[id]) {\n                    seen[id] = true;\n                    got++;\n                }\n            }\n        };\n\n        mark(code);\n\n        for (int i = 5; i < (int)s.size(); i++) {\n            code = (code % pow4) * 26 + (s[i] - 'A');\n            mark(code);\n        }\n\n        return got == M;\n    }\n\n    void tryRemoveRedundant(double deadline) {\n        bool improved = true;\n\n        while (improved && timer.elapsed() < deadline) {\n            improved = false;\n\n            for (int p = 0; p < (int)bestOrder.size(); p++) {\n                if (timer.elapsed() > deadline) break;\n                if ((int)bestOrder.size() <= 1) break;\n\n                vector<int> cand = bestOrder;\n                cand.erase(cand.begin() + p);\n\n                string s = buildString(cand);\n                if (!containsAll(s)) continue;\n\n                int c = exactCost(cand);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestOrder = cand;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    void outputStringPath(const string& s) const {\n        int L = (int)s.size();\n        const int INF = 1e9;\n\n        vector<vector<int>> pred(L);\n        vector<int> dpPrev, dpCur;\n\n        for (int idx = 0; idx < L; idx++) {\n            int c = s[idx] - 'A';\n            int cnt = (int)letterPos[c].size();\n\n            dpCur.assign(cnt, INF);\n            pred[idx].assign(cnt, -1);\n\n            if (idx == 0) {\n                for (int q = 0; q < cnt; q++) {\n                    int id = letterPos[c][q];\n                    dpCur[q] = (int)distCell[startId][id] + 1;\n                }\n            } else {\n                int pc = s[idx - 1] - 'A';\n                int pcnt = (int)letterPos[pc].size();\n\n                for (int q = 0; q < cnt; q++) {\n                    int qid = letterPos[c][q];\n                    int best = INF;\n                    int bestP = -1;\n\n                    for (int p = 0; p < pcnt; p++) {\n                        int pid = letterPos[pc][p];\n                        int v = dpPrev[p] + (int)distCell[pid][qid] + 1;\n                        if (v < best) {\n                            best = v;\n                            bestP = p;\n                        }\n                    }\n\n                    dpCur[q] = best;\n                    pred[idx][q] = bestP;\n                }\n            }\n\n            dpPrev.swap(dpCur);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < dpPrev[bestIdx]) bestIdx = i;\n        }\n\n        vector<int> outIds(L);\n        for (int idx = L - 1; idx >= 0; idx--) {\n            int c = s[idx] - 'A';\n            outIds[idx] = letterPos[c][bestIdx];\n            bestIdx = pred[idx][bestIdx];\n        }\n\n        for (int id : outIds) cout << id / N << ' ' << id % N << '\\n';\n    }\n\n    void solve() {\n        timer.reset();\n\n        precompute();\n        buildModes();\n\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = exactCost(bestOrder);\n\n        vector<Candidate> candidates;\n\n        auto consider = [&](const vector<int>& ord) {\n            if ((int)ord.size() != M) return;\n            int c = exactCost(ord);\n            candidates.push_back({c, ord});\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = ord;\n            }\n        };\n\n        consider(bestOrder);\n\n        for (int mi = 0; mi < (int)modes.size(); mi++) {\n            if (timer.elapsed() > 1.25) break;\n\n            {\n                vector<int> ord = hungarianPatch(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = cheapestInsertion(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = nearestNeighborBest(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes[0], false);\n            improveAdditive(ord, modes[0], 35, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes.back(), true);\n            improveAdditive(ord, modes.back(), 35, 3);\n            consider(ord);\n        }\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return startMinCost[a] < startMinCost[b];\n        });\n\n        if (timer.elapsed() < 1.37) {\n            vector<int> bstarts;\n            for (int i = 0; i < min(M, 10); i++) bstarts.push_back(ids[i]);\n\n            vector<int> ord = coordinateBeam(bstarts, 7, 4, 2, 1.44);\n            if (!ord.empty()) {\n                consider(ord);\n                improveAdditive(ord, modes[0], 18, 3);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.39) {\n            vector<int> ord = regretInsertion(modes[0], 10);\n            improveAdditive(ord, modes[0], 24, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.42) {\n            vector<int> ord = regretInsertion(modes[3], 12);\n            improveAdditive(ord, modes[3], 22, 3);\n            consider(ord);\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<int> starts;\n        for (int i = 0; i < min(M, 10); i++) starts.push_back(ids[i]);\n        for (int i = 0; i < min((int)candidates.size(), 8); i++) {\n            if (!candidates[i].order.empty()) starts.push_back(candidates[i].order[0]);\n        }\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        if (timer.elapsed() < 1.445) {\n            vector<int> bstarts = starts;\n            if ((int)bstarts.size() > 10) bstarts.resize(10);\n\n            vector<int> ord = coordinateBeam(bstarts, 6, 4, 1, 1.485);\n            if (!ord.empty()) {\n                consider(ord);\n                improveAdditive(ord, modes[0], 14, 3);\n                consider(ord);\n            }\n        }\n\n        int greedyRuns = 0;\n        int lookRuns = 0;\n        for (int stWord : starts) {\n            if (greedyRuns >= 10 || timer.elapsed() > 1.49) break;\n\n            vector<int> ord = coordinateGreedy(stWord);\n            consider(ord);\n\n            improveAdditive(ord, modes[0], 22, 3);\n            consider(ord);\n\n            if (lookRuns < 4 && timer.elapsed() < 1.485) {\n                vector<int> ord2 = coordinateGreedyLookahead(stWord, 1);\n                consider(ord2);\n                improveAdditive(ord2, modes[0], 16, 3);\n                consider(ord2);\n                lookRuns++;\n            }\n\n            greedyRuns++;\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<vector<int>> refineList;\n        for (const auto& cand : candidates) {\n            bool dup = false;\n            for (const auto& v : refineList) {\n                if (v == cand.order) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) refineList.push_back(cand.order);\n            if ((int)refineList.size() >= 3) break;\n        }\n\n        for (auto& ord : refineList) {\n            if (timer.elapsed() > 1.60) break;\n            Candidate r = exactRefine(ord, 1.60, 3, 350);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.64) {\n            Candidate r = exactRefine(bestOrder, 1.64, 3, 500);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.87) {\n            improveExactInterval(bestOrder, 1.87, 3);\n        }\n\n        intensiveLNS(1.915);\n        simulatedAnnealing(1.955);\n        intensiveLNS(1.965);\n        tryRemoveRedundant(1.970);\n\n        string finalS = buildString(bestOrder);\n\n        if (!containsAll(finalS) || (int)finalS.size() > 5000) {\n            bestOrder.resize(M);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n            finalS = buildString(bestOrder);\n        }\n\n        outputStringPath(finalS);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXC = 400;\nstatic constexpr double EXACT_W = 1e7;\nstatic constexpr double BAN_W = 1e8;\n\nstruct Placement {\n    int di, dj;\n    vector<int> cells;\n    bitset<MAXC> bits;\n};\n\nstruct Field {\n    int area = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> placements;\n    vector<uint16_t> contrib;\n};\n\nstruct Observation {\n    vector<int> cells;\n    int k;\n    int y;\n};\n\nstruct State {\n    bool valid = false;\n    vector<int> pos;\n    vector<int> pred;\n    vector<int> cnt;\n    double score = -1e300;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n    int totalArea = 0;\n    int Q = 0;\n    int stride = 0;\n\n    vector<Field> fields;\n    vector<Observation> obs;\n\n    vector<double> scoreFlat;\n    vector<double> tHat, invVarT;\n\n    vector<unsigned char> drilled;\n    vector<int> drillVal;\n    vector<int> drilledCells;\n    int drilledCount = 0;\n    int knownReserveSum = 0;\n\n    vector<vector<unsigned char>> bannedEqMasks;\n    vector<vector<unsigned char>> subsetMasks;\n\n    vector<int> fallbackRank;\n    vector<int> poolSupport;\n    vector<State> lastPool;\n\n    int opCount = 0;\n    int maxInitialQueries = 0;\n    int adaptiveQueryUsed = 0;\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point startTime;\n\n    double elapsedMs() const {\n        return chrono::duration<double, milli>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    }\n\n    double normalCDF(double x) {\n        return 0.5 * erfc(-x / sqrt(2.0));\n    }\n\n    void readInput() {\n        cin >> N >> M >> eps;\n        C = N * N;\n        alpha = 1.0 - 2.0 * eps;\n        fields.resize(M);\n\n        for (int m = 0; m < M; m++) {\n            int d;\n            cin >> d;\n            fields[m].area = d;\n            fields[m].rel.resize(d);\n            int mx_i = 0, mx_j = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[m].rel[t] = {i, j};\n                mx_i = max(mx_i, i);\n                mx_j = max(mx_j, j);\n            }\n            fields[m].h = mx_i + 1;\n            fields[m].w = mx_j + 1;\n            totalArea += d;\n        }\n\n        generatePlacements();\n\n        drilled.assign(C, 0);\n        drillVal.assign(C, 0);\n        fallbackRank.assign(C, 0);\n        poolSupport.assign(C, 0);\n    }\n\n    void generatePlacements() {\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            for (int di = 0; di + f.h <= N; di++) {\n                for (int dj = 0; dj + f.w <= N; dj++) {\n                    Placement p;\n                    p.di = di;\n                    p.dj = dj;\n                    p.bits.reset();\n                    for (auto [ri, rj] : f.rel) {\n                        int c = (di + ri) * N + (dj + rj);\n                        p.cells.push_back(c);\n                        p.bits.set(c);\n                    }\n                    f.placements.push_back(std::move(p));\n                }\n            }\n        }\n    }\n\n    bool askDivination(vector<int> cells, bool initial) {\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        if ((int)cells.size() < 2) return false;\n        if (initial && (int)obs.size() >= maxInitialQueries) return false;\n\n        cout << \"q \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int y;\n        if (!(cin >> y)) exit(0);\n        if (y < 0) exit(0);\n\n        opCount++;\n        obs.push_back({cells, (int)cells.size(), y});\n        return true;\n    }\n\n    void maybeAskDiv(vector<int> cells) {\n        askDivination(std::move(cells), true);\n    }\n\n    void askInitialQueries() {\n        maxInitialQueries = max(0, C - 10);\n\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            maybeAskDiv(cells);\n        }\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            maybeAskDiv(cells);\n        }\n\n        int B = max(3, (N + 4) / 5);\n        for (int r = 0; r < N; r += B) {\n            for (int c = 0; c < N; c += B) {\n                vector<int> cells;\n                for (int i = r; i < min(N, r + B); i++) {\n                    for (int j = c; j < min(N, c + B); j++) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                maybeAskDiv(cells);\n            }\n        }\n\n        int off = B / 2;\n        if (off > 0) {\n            for (int r = off; r + B <= N; r += B) {\n                for (int c = off; c + B <= N; c += B) {\n                    vector<int> cells;\n                    for (int i = r; i < r + B; i++) {\n                        for (int j = c; j < c + B; j++) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        }\n\n        auto addModQueries = [&](int mod) {\n            for (int a = 0; a < mod; a++) {\n                for (int b = 0; b < mod; b++) {\n                    vector<int> cells;\n                    for (int i = 0; i < N; i++) {\n                        for (int j = 0; j < N; j++) {\n                            if (i % mod == a && j % mod == b) {\n                                cells.push_back(i * N + j);\n                            }\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        };\n        addModQueries(2);\n        if (N >= 13) addModQueries(3);\n\n        int R = (N <= 12 ? N : 2 * N);\n        for (int r = 0; r < R; r++) {\n            vector<int> cells;\n            for (int attempt = 0; attempt < 100; attempt++) {\n                cells.clear();\n                for (int c = 0; c < C; c++) {\n                    if ((int)(rng() % 10000) < 2500) cells.push_back(c);\n                }\n                if ((int)cells.size() >= 2) break;\n            }\n            if ((int)cells.size() < 2) cells = {0, C - 1};\n            maybeAskDiv(cells);\n        }\n    }\n\n    bool submitAnswer(vector<unsigned char> mask) {\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        vector<int> cells;\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) cells.push_back(c);\n        }\n\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int res;\n        if (!(cin >> res)) exit(0);\n        opCount++;\n\n        if (res == 1) exit(0);\n        if (res < 0) exit(0);\n        return false;\n    }\n\n    int drillCell(int c) {\n        if (drilled[c]) return drillVal[c];\n\n        cout << \"q 1 \" << c / N << ' ' << c % N << '\\n';\n        cout.flush();\n\n        int v;\n        if (!(cin >> v)) exit(0);\n        if (v < 0) exit(0);\n\n        opCount++;\n        drilled[c] = 1;\n        drillVal[c] = v;\n        drilledCount++;\n        drilledCells.push_back(c);\n        knownReserveSum += v;\n\n        if (knownReserveSum == totalArea) {\n            vector<unsigned char> mask(C, 0);\n            for (int x : drilledCells) {\n                if (drillVal[x] > 0) mask[x] = 1;\n            }\n            submitAnswer(mask);\n        }\n\n        return v;\n    }\n\n    bool canFallback() const {\n        return opCount + (C - drilledCount) + 1 <= 2 * C;\n    }\n\n    bool canWrongGuessAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    bool canExtraQueryAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    void buildContrib() {\n        Q = (int)obs.size();\n        vector<vector<int>> obsOfCell(C);\n\n        for (int q = 0; q < Q; q++) {\n            for (int c : obs[q].cells) obsOfCell[c].push_back(q);\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            int P = (int)f.placements.size();\n            f.contrib.assign(P * Q, 0);\n\n            for (int p = 0; p < P; p++) {\n                uint16_t *arr = Q ? &f.contrib[p * Q] : nullptr;\n                for (int c : f.placements[p].cells) {\n                    for (int q : obsOfCell[c]) {\n                        arr[q]++;\n                    }\n                }\n            }\n        }\n    }\n\n    void buildScoreTables() {\n        stride = totalArea + 1;\n        scoreFlat.assign(Q * stride, 0.0);\n        tHat.assign(Q, 0.0);\n        invVarT.assign(Q, 1.0);\n\n        for (int q = 0; q < Q; q++) {\n            int k = obs[q].k;\n            int y = obs[q].y;\n\n            double sigma = sqrt(k * eps * (1.0 - eps));\n            double varT = k * eps * (1.0 - eps) / (alpha * alpha)\n                        + 0.25 / (alpha * alpha);\n            invVarT[q] = 1.0 / max(1e-9, varT);\n\n            double th = (y - eps * k) / alpha;\n            th = min<double>(totalArea, max<double>(0.0, th));\n            tHat[q] = th;\n\n            for (int t = 0; t <= totalArea; t++) {\n                double mu = eps * k + alpha * t;\n                double prob;\n\n                if (y == 0) {\n                    prob = normalCDF((0.5 - mu) / sigma);\n                } else {\n                    double lo = (y - 0.5 - mu) / sigma;\n                    double hi = (y + 0.5 - mu) / sigma;\n                    prob = normalCDF(hi) - normalCDF(lo);\n                }\n\n                if (!(prob > 1e-300)) prob = 1e-300;\n                scoreFlat[q * stride + t] = log(prob);\n            }\n        }\n    }\n\n    void addToState(State &s, int m, int p, int sign) {\n        if (Q) {\n            const uint16_t *arr = &fields[m].contrib[p * Q];\n            for (int q = 0; q < Q; q++) s.pred[q] += sign * (int)arr[q];\n        }\n\n        for (int c : fields[m].placements[p].cells) {\n            s.cnt[c] += sign;\n        }\n    }\n\n    double computeExactScore(const vector<int> &cnt) const {\n        long long sq = 0;\n        for (int c : drilledCells) {\n            int diff = cnt[c] - drillVal[c];\n            sq += 1LL * diff * diff;\n        }\n        return -EXACT_W * (double)sq;\n    }\n\n    double computeBanPenalty(const vector<int> &cnt) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = cnt[c] > 0;\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (cnt[c] > 0 && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeBanPenaltyBits(const bitset<MAXC> &uni) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = uni.test(c);\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (uni.test(c) && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeScore(const State &s) const {\n        double sc = 0.0;\n\n        for (int q = 0; q < Q; q++) {\n            sc += scoreFlat[q * stride + s.pred[q]];\n        }\n\n        sc += computeExactScore(s.cnt);\n        sc += computeBanPenalty(s.cnt);\n        return sc;\n    }\n\n    State buildState(const vector<int> &pos) {\n        State s;\n        s.valid = true;\n        s.pos = pos;\n        s.pred.assign(Q, 0);\n        s.cnt.assign(C, 0);\n\n        for (int m = 0; m < M; m++) {\n            addToState(s, m, s.pos[m], +1);\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    bool sameUnionState(const State &a, const State &b) const {\n        if (!a.valid || !b.valid) return false;\n        for (int c = 0; c < C; c++) {\n            if ((a.cnt[c] > 0) != (b.cnt[c] > 0)) return false;\n        }\n        return true;\n    }\n\n    void insertPool(vector<State> &pool, const State &s, int maxKeep) {\n        if (!s.valid) return;\n\n        for (auto &e : pool) {\n            if (sameUnionState(e, s)) {\n                if (s.score > e.score) e = s;\n                return;\n            }\n        }\n\n        pool.push_back(s);\n        sort(pool.begin(), pool.end(), [](const State &a, const State &b) {\n            return a.score > b.score;\n        });\n        if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n    }\n\n    bool placementCoversKnownZero(int m, int p) const {\n        for (int c : fields[m].placements[p].cells) {\n            if (drilled[c] && drillVal[c] == 0) return true;\n        }\n        return false;\n    }\n\n    int randomPlacement(int m) {\n        int P = (int)fields[m].placements.size();\n\n        for (int t = 0; t < 50; t++) {\n            int p = (int)(rng() % P);\n            if (!placementCoversKnownZero(m, p)) return p;\n        }\n\n        vector<int> valid;\n        for (int p = 0; p < P; p++) {\n            if (!placementCoversKnownZero(m, p)) valid.push_back(p);\n        }\n\n        if (!valid.empty()) {\n            return valid[(int)(rng() % valid.size())];\n        }\n        return (int)(rng() % P);\n    }\n\n    State makeRandomState() {\n        vector<int> pos(M);\n        for (int m = 0; m < M; m++) {\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makePerturbedState(const State &base, int changes) {\n        vector<int> pos = base.pos;\n        for (int t = 0; t < changes; t++) {\n            int m = (int)(rng() % M);\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makeGreedyState() {\n        vector<int> pos(M, -1);\n        vector<int> pred(Q, 0);\n        vector<int> cnt(C, 0);\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].area > fields[b].area;\n        });\n\n        int placedArea = 0;\n\n        for (int m : order) {\n            int P = (int)fields[m].placements.size();\n            int newArea = placedArea + fields[m].area;\n\n            double bestVal = 1e300;\n            int bestP = 0;\n\n            for (int p = 0; p < P; p++) {\n                double val = 0.0;\n                const uint16_t *arr = Q ? &fields[m].contrib[p * Q] : nullptr;\n\n                for (int q = 0; q < Q; q++) {\n                    double target = tHat[q] * (double)newArea / (double)totalArea;\n                    double diff = (double)(pred[q] + arr[q]) - target;\n                    val += diff * diff * invVarT[q];\n                }\n\n                for (int c : fields[m].placements[p].cells) {\n                    if (drilled[c]) {\n                        if (drillVal[c] == 0) val += 1e9;\n                        if (cnt[c] + 1 > drillVal[c]) val += 1e9;\n                    }\n                }\n\n                if (val < bestVal - 1e-9 ||\n                    (fabs(val - bestVal) <= 1e-9 && (rng() & 1))) {\n                    bestVal = val;\n                    bestP = p;\n                }\n            }\n\n            pos[m] = bestP;\n            if (Q) {\n                const uint16_t *arr = &fields[m].contrib[bestP * Q];\n                for (int q = 0; q < Q; q++) pred[q] += arr[q];\n            }\n            for (int c : fields[m].placements[bestP].cells) cnt[c]++;\n            placedArea = newArea;\n        }\n\n        return buildState(pos);\n    }\n\n    struct ExactCand {\n        double sc;\n        int p0, p1, p2;\n    };\n\n    struct ExactCandCmp {\n        bool operator()(const ExactCand &a, const ExactCand &b) const {\n            return a.sc > b.sc; // min-heap\n        }\n    };\n\n    State optimizeExactSmall() {\n        State invalid;\n        const int HEAP_KEEP = 36;\n        const int POOL_KEEP = 12;\n\n        if (M == 2) {\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            priority_queue<ExactCand, vector<ExactCand>, ExactCandCmp> pq;\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    double sc = 0.0;\n                    for (int q = 0; q < Q; q++) {\n                        int t = a0[q] + a1[q];\n                        sc += scoreFlat[q * stride + t];\n                    }\n\n                    if (drilledCount > 0) {\n                        long long sq = 0;\n                        for (int c : drilledCells) {\n                            int cnt = (b0.test(c) ? 1 : 0) + (b1.test(c) ? 1 : 0);\n                            int diff = cnt - drillVal[c];\n                            sq += 1LL * diff * diff;\n                        }\n                        sc -= EXACT_W * (double)sq;\n                    }\n\n                    if (hasBan) {\n                        bitset<MAXC> uni = b0 | b1;\n                        sc += computeBanPenaltyBits(uni);\n                    }\n\n                    ExactCand cand{sc, p0, p1, -1};\n                    if ((int)pq.size() < HEAP_KEEP) {\n                        pq.push(cand);\n                    } else if (sc > pq.top().sc) {\n                        pq.pop();\n                        pq.push(cand);\n                    }\n                }\n            }\n\n            vector<ExactCand> nodes;\n            while (!pq.empty()) {\n                nodes.push_back(pq.top());\n                pq.pop();\n            }\n            sort(nodes.begin(), nodes.end(), [](const ExactCand &a, const ExactCand &b) {\n                return a.sc > b.sc;\n            });\n\n            vector<State> pool;\n            for (auto &nd : nodes) {\n                vector<int> pos = {nd.p0, nd.p1};\n                insertPool(pool, buildState(pos), POOL_KEEP);\n            }\n\n            if (pool.empty()) return invalid;\n            lastPool = pool;\n            return pool[0];\n        }\n\n        if (M == 3) {\n            long long prod = 1;\n            for (int m = 0; m < 3; m++) {\n                prod *= (long long)fields[m].placements.size();\n            }\n            if (prod > 250000) return invalid;\n\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n            int P2 = (int)fields[2].placements.size();\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            vector<int> pred01(Q);\n            priority_queue<ExactCand, vector<ExactCand>, ExactCandCmp> pq;\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    for (int q = 0; q < Q; q++) pred01[q] = a0[q] + a1[q];\n\n                    bitset<MAXC> bits01;\n                    if (hasBan) bits01 = b0 | b1;\n\n                    for (int p2 = 0; p2 < P2; p2++) {\n                        const uint16_t *a2 = Q ? &fields[2].contrib[p2 * Q] : nullptr;\n                        const auto &b2 = fields[2].placements[p2].bits;\n\n                        double sc = 0.0;\n                        for (int q = 0; q < Q; q++) {\n                            int t = pred01[q] + a2[q];\n                            sc += scoreFlat[q * stride + t];\n                        }\n\n                        if (drilledCount > 0) {\n                            long long sq = 0;\n                            for (int c : drilledCells) {\n                                int cnt = (b0.test(c) ? 1 : 0)\n                                        + (b1.test(c) ? 1 : 0)\n                                        + (b2.test(c) ? 1 : 0);\n                                int diff = cnt - drillVal[c];\n                                sq += 1LL * diff * diff;\n                            }\n                            sc -= EXACT_W * (double)sq;\n                        }\n\n                        if (hasBan) {\n                            bitset<MAXC> uni = bits01 | b2;\n                            sc += computeBanPenaltyBits(uni);\n                        }\n\n                        ExactCand cand{sc, p0, p1, p2};\n                        if ((int)pq.size() < HEAP_KEEP) {\n                            pq.push(cand);\n                        } else if (sc > pq.top().sc) {\n                            pq.pop();\n                            pq.push(cand);\n                        }\n                    }\n                }\n            }\n\n            vector<ExactCand> nodes;\n            while (!pq.empty()) {\n                nodes.push_back(pq.top());\n                pq.pop();\n            }\n            sort(nodes.begin(), nodes.end(), [](const ExactCand &a, const ExactCand &b) {\n                return a.sc > b.sc;\n            });\n\n            vector<State> pool;\n            for (auto &nd : nodes) {\n                vector<int> pos = {nd.p0, nd.p1, nd.p2};\n                insertPool(pool, buildState(pos), POOL_KEEP);\n            }\n\n            if (pool.empty()) return invalid;\n            lastPool = pool;\n            return pool[0];\n        }\n\n        return invalid;\n    }\n\n    State coordinateDescent(State s, int sweeps, double deadlineMs) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            shuffle(order.begin(), order.end(), rng);\n            bool changed = false;\n\n            for (int m : order) {\n                if (elapsedMs() > deadlineMs) {\n                    s.score = computeScore(s);\n                    return s;\n                }\n\n                int oldP = s.pos[m];\n                addToState(s, m, oldP, -1);\n\n                double baseExact = computeExactScore(s.cnt);\n\n                vector<int> baseDiff(bannedEqMasks.size(), 0);\n                vector<int> baseOut(subsetMasks.size(), 0);\n\n                for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                    const auto &mask = bannedEqMasks[f];\n                    int diff = 0;\n                    for (int c = 0; c < C; c++) {\n                        bool cov = s.cnt[c] > 0;\n                        if (cov != (bool)mask[c]) diff++;\n                    }\n                    baseDiff[f] = diff;\n                }\n\n                for (size_t f = 0; f < subsetMasks.size(); f++) {\n                    const auto &mask = subsetMasks[f];\n                    int out = 0;\n                    for (int c = 0; c < C; c++) {\n                        if (s.cnt[c] > 0 && !mask[c]) out++;\n                    }\n                    baseOut[f] = out;\n                }\n\n                int P = (int)fields[m].placements.size();\n                int bestP = oldP;\n                double bestSc = -1e300;\n\n                for (int p = 0; p < P; p++) {\n                    const auto &pl = fields[m].placements[p];\n                    double total = baseExact;\n\n                    if (Q) {\n                        const uint16_t *arr = &fields[m].contrib[p * Q];\n                        for (int q = 0; q < Q; q++) {\n                            int t = s.pred[q] + arr[q];\n                            total += scoreFlat[q * stride + t];\n                        }\n                    }\n\n                    if (drilledCount > 0) {\n                        for (int c : pl.cells) {\n                            if (drilled[c]) {\n                                int diff = s.cnt[c] - drillVal[c];\n                                total += -EXACT_W *\n                                    (double)((diff + 1) * (diff + 1) - diff * diff);\n                            }\n                        }\n                    }\n\n                    for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                        int diff = baseDiff[f];\n                        const auto &mask = bannedEqMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0) {\n                                if (mask[c]) diff--;\n                                else diff++;\n                            }\n                        }\n\n                        if (diff == 0) total -= BAN_W;\n                    }\n\n                    for (size_t f = 0; f < subsetMasks.size(); f++) {\n                        int out = baseOut[f];\n                        const auto &mask = subsetMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0 && !mask[c]) out++;\n                        }\n\n                        if (out == 0) total -= BAN_W;\n                    }\n\n                    if (total > bestSc + 1e-9 ||\n                        (fabs(total - bestSc) <= 1e-9 && (rng() & 1))) {\n                        bestSc = total;\n                        bestP = p;\n                    }\n                }\n\n                addToState(s, m, bestP, +1);\n                s.pos[m] = bestP;\n                s.score = bestSc;\n                if (bestP != oldP) changed = true;\n            }\n\n            if (!changed) break;\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    State optimize(const State *prev, bool first) {\n        State exact = optimizeExactSmall();\n        if (exact.valid) return exact;\n\n        double now = elapsedMs();\n        double req = first ? 1200.0 : 450.0;\n        double deadline = min(2450.0, now + req);\n        if (deadline < now + 30.0) deadline = now + 30.0;\n\n        int maxRestarts;\n        if (first) {\n            if (M <= 4) maxRestarts = 80;\n            else if (M <= 10) maxRestarts = 50;\n            else maxRestarts = 35;\n        } else {\n            if (M <= 4) maxRestarts = 40;\n            else if (M <= 10) maxRestarts = 25;\n            else maxRestarts = 18;\n        }\n\n        int sweeps = first ? 7 : 5;\n\n        State best;\n        vector<State> pool;\n\n        for (int r = 0; r < maxRestarts && elapsedMs() < deadline; r++) {\n            State s;\n\n            if (r == 0 && prev && prev->valid) {\n                s = buildState(prev->pos);\n            } else if ((r == 0 && (!prev || !prev->valid)) ||\n                       (r == 1 && prev && prev->valid)) {\n                s = makeGreedyState();\n            } else if (prev && prev->valid && r < 6) {\n                int changes = 1 + (r % max(1, M / 2));\n                s = makePerturbedState(*prev, changes);\n            } else {\n                s = makeRandomState();\n            }\n\n            s = coordinateDescent(s, sweeps, deadline);\n            insertPool(pool, s, 12);\n\n            if (!best.valid || s.score > best.score) {\n                best = std::move(s);\n            }\n        }\n\n        if (!best.valid) {\n            if (prev && prev->valid) best = buildState(prev->pos);\n            else best = makeGreedyState();\n        }\n\n        if (pool.empty()) insertPool(pool, best, 12);\n        lastPool = pool;\n\n        return best;\n    }\n\n    int countExactMismatch(const State &s) const {\n        int mism = 0;\n        for (int c : drilledCells) {\n            if (s.cnt[c] != drillVal[c]) mism++;\n        }\n        return mism;\n    }\n\n    vector<unsigned char> unionMask(const State &s) const {\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) mask[c] = 1;\n        }\n        return mask;\n    }\n\n    bool allVerifiedPositive(const vector<unsigned char> &mask) const {\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) {\n                if (!drilled[c]) return false;\n                if (drillVal[c] <= 0) return false;\n            }\n        }\n        return true;\n    }\n\n    bool sameMask(const vector<unsigned char> &a,\n                  const vector<unsigned char> &b) const {\n        return a == b;\n    }\n\n    bool isBannedEq(const vector<unsigned char> &mask) const {\n        for (const auto &x : bannedEqMasks) {\n            if (sameMask(x, mask)) return true;\n        }\n        return false;\n    }\n\n    bool violatesSubsetBan(const vector<unsigned char> &mask) const {\n        for (const auto &s : subsetMasks) {\n            bool outside = false;\n            for (int c = 0; c < C; c++) {\n                if (mask[c] && !s[c]) {\n                    outside = true;\n                    break;\n                }\n            }\n            if (!outside) return true;\n        }\n        return false;\n    }\n\n    void addBannedEq(const vector<unsigned char> &mask) {\n        if (!isBannedEq(mask)) bannedEqMasks.push_back(mask);\n    }\n\n    void addSubsetMask(const vector<unsigned char> &mask) {\n        for (const auto &x : subsetMasks) {\n            if (sameMask(x, mask)) return;\n        }\n        subsetMasks.push_back(mask);\n    }\n\n    int boundaryScore(int c, const vector<unsigned char> &mask) const {\n        int i = c / N;\n        int j = c % N;\n        int score = 0;\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                score++;\n            } else {\n                int nc = ni * N + nj;\n                if (!mask[nc]) score++;\n            }\n        }\n\n        return score;\n    }\n\n    vector<int> cellsToDrillInUnion(const vector<unsigned char> &U) {\n        vector<pair<int,int>> order;\n\n        for (int c = 0; c < C; c++) {\n            if (U[c] && !drilled[c]) {\n                int support = min(100000, poolSupport[c] * 100);\n                int uncertainty = 100000 - support;\n                int key = boundaryScore(c, U) * 150000\n                        + uncertainty\n                        + (int)(rng() % 1000);\n                order.push_back({-key, c});\n            }\n        }\n\n        sort(order.begin(), order.end());\n\n        vector<int> res;\n        for (auto [_, c] : order) res.push_back(c);\n        return res;\n    }\n\n    int adaptiveQueryLimit() const {\n        if (N >= 15) return 10;\n        if (N >= 12) return 7;\n        return 5;\n    }\n\n    void addAdaptiveQueries(const vector<unsigned char> &A) {\n        if (adaptiveQueryUsed >= adaptiveQueryLimit()) return;\n        if (elapsedMs() > 2350.0) return;\n\n        bool added = false;\n\n        auto tryAsk = [&](vector<int> cells) {\n            if (adaptiveQueryUsed >= adaptiveQueryLimit()) return;\n            if (elapsedMs() > 2380.0) return;\n            if (!canExtraQueryAndFallback()) return;\n            if ((int)cells.size() < 2) return;\n            if (askDivination(std::move(cells), false)) {\n                adaptiveQueryUsed++;\n                added = true;\n            }\n        };\n\n        vector<int> inside, outside;\n        inside.reserve(C);\n        outside.reserve(C);\n\n        for (int c = 0; c < C; c++) {\n            if (A[c]) inside.push_back(c);\n            else outside.push_back(c);\n        }\n\n        tryAsk(inside);\n\n        if ((int)lastPool.size() >= 2) {\n            vector<int> freq(C, 0);\n            int K = min<int>(lastPool.size(), 12);\n            for (int t = 0; t < K; t++) {\n                const State &s = lastPool[t];\n                for (int c = 0; c < C; c++) {\n                    if (s.cnt[c] > 0) freq[c]++;\n                }\n            }\n\n            vector<int> uncertain;\n            for (int c = 0; c < C; c++) {\n                if (freq[c] > 0 && freq[c] < K) uncertain.push_back(c);\n            }\n            tryAsk(uncertain);\n        }\n\n        vector<unsigned char> isRing(C, 0);\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int c = 0; c < C; c++) {\n            if (!A[c]) continue;\n            int i = c / N;\n            int j = c % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!A[nc]) isRing[nc] = 1;\n            }\n        }\n\n        vector<int> ring;\n        for (int c = 0; c < C; c++) {\n            if (isRing[c]) ring.push_back(c);\n        }\n        tryAsk(ring);\n\n        tryAsk(outside);\n\n        if (added) {\n            buildContrib();\n            buildScoreTables();\n        }\n    }\n\n    void updateFallbackRank(const State &s) {\n        fallbackRank.assign(C, 0);\n        poolSupport.assign(C, 0);\n\n        for (int idx = 0; idx < (int)lastPool.size(); idx++) {\n            const State &st = lastPool[idx];\n            int w = max(1, 24 - idx * 2);\n            for (int c = 0; c < C; c++) {\n                if (st.cnt[c] > 0) {\n                    poolSupport[c] += w * st.cnt[c];\n                    fallbackRank[c] += w * 4000 * st.cnt[c];\n                }\n            }\n        }\n\n        vector<unsigned char> U(C, 0);\n\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) {\n                U[c] = 1;\n                fallbackRank[c] += 100000 + 1000 * s.cnt[c];\n            }\n        }\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int c = 0; c < C; c++) {\n            if (!U[c]) continue;\n            int i = c / N;\n            int j = c % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!U[nc]) fallbackRank[nc] += 10000;\n            }\n        }\n\n        for (int c : drilledCells) {\n            if (drillVal[c] <= 0) continue;\n            int i = c / N;\n            int j = c % N;\n            int base = 15000 + 3000 * min(drillVal[c], 3);\n\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!drilled[nc]) fallbackRank[nc] += base;\n            }\n        }\n    }\n\n    bool maskForStateGuess(const State &s, vector<unsigned char> &mask) {\n        if (!s.valid) return false;\n        if (countExactMismatch(s) > 0) return false;\n\n        mask = unionMask(s);\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        if (isBannedEq(mask)) return false;\n        if (violatesSubsetBan(mask)) return false;\n        return true;\n    }\n\n    void tryLastChanceGuesses() {\n        if ((int)lastPool.size() < 2) return;\n\n        sort(lastPool.begin(), lastPool.end(), [](const State &a, const State &b) {\n            return a.score > b.score;\n        });\n\n        int tries = 0;\n        double firstScore = -1e300;\n        bool haveFirst = false;\n\n        for (const auto &s : lastPool) {\n            if (tries >= 3) break;\n            if (!canWrongGuessAndFallback()) break;\n\n            vector<unsigned char> mask;\n            if (!maskForStateGuess(s, mask)) continue;\n\n            if (!haveFirst) {\n                haveFirst = true;\n                firstScore = s.score;\n            } else {\n                double gap = firstScore - s.score;\n                if (tries == 1 && gap > 100.0) break;\n                if (tries >= 2 && gap > 60.0) break;\n            }\n\n            submitAnswer(mask);\n            addBannedEq(mask);\n            tries++;\n        }\n    }\n\n    void addNeighborFallbackBonus(int c, int v) {\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        int i = c / N;\n        int j = c % N;\n\n        int nearBonus = 220000 + 50000 * min(v, 3);\n        int farBonus = 8000 + 2000 * min(v, 3);\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n            int nc = ni * N + nj;\n            if (!drilled[nc]) fallbackRank[nc] += nearBonus;\n\n            for (int e = 0; e < 4; e++) {\n                int mi = ni + di[e];\n                int mj = nj + dj[e];\n                if (mi < 0 || mi >= N || mj < 0 || mj >= N) continue;\n                int mc = mi * N + mj;\n                if (!drilled[mc]) fallbackRank[mc] += farBonus;\n            }\n        }\n    }\n\n    void fallback() {\n        tryLastChanceGuesses();\n\n        while (drilledCount < C) {\n            int bestC = -1;\n            int bestKey = INT_MIN;\n\n            for (int c = 0; c < C; c++) {\n                if (drilled[c]) continue;\n                int key = fallbackRank[c] + (int)(rng() % 1000);\n                if (key > bestKey) {\n                    bestKey = key;\n                    bestC = c;\n                }\n            }\n\n            if (bestC == -1) break;\n            int v = drillCell(bestC);\n            if (v > 0) addNeighborFallbackBonus(bestC, v);\n        }\n\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (drillVal[c] > 0) mask[c] = 1;\n        }\n\n        submitAnswer(mask);\n        exit(0);\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        askInitialQueries();\n        buildContrib();\n        buildScoreTables();\n\n        State best = optimize(nullptr, true);\n\n        int maxUnverifiedGuesses = (N >= 15 ? 3 : 2);\n        int unverifiedUsed = 0;\n        int mismatchRetries = 0;\n\n        int probeGuessUsed = 0;\n        int maxProbeGuesses = (N >= 18 ? 3 : (N >= 15 ? 2 : 1));\n\n        while (true) {\n            updateFallbackRank(best);\n\n            if (!canFallback()) {\n                fallback();\n            }\n\n            if (elapsedMs() > 2600.0) {\n                fallback();\n            }\n\n            if (drilledCount == C) {\n                fallback();\n            }\n\n            int mism = countExactMismatch(best);\n            if (mism > 0) {\n                if (mismatchRetries < 3 && elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    mismatchRetries++;\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n            mismatchRetries = 0;\n\n            vector<unsigned char> U = unionMask(best);\n            vector<unsigned char> A = U;\n            for (int c = 0; c < C; c++) {\n                if (drilled[c] && drillVal[c] > 0) A[c] = 1;\n            }\n\n            bool verified = allVerifiedPositive(A);\n\n            if (verified) {\n                submitAnswer(A);\n\n                addSubsetMask(A);\n                addBannedEq(A);\n                addAdaptiveQueries(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            if (unverifiedUsed < maxUnverifiedGuesses &&\n                canWrongGuessAndFallback() &&\n                !isBannedEq(A)) {\n                submitAnswer(A);\n                addBannedEq(A);\n                unverifiedUsed++;\n                addAdaptiveQueries(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            vector<int> todo = cellsToDrillInUnion(U);\n\n            if (todo.empty()) {\n                if (elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n\n            bool contradiction = false;\n            int startIdx = 0;\n\n            if (probeGuessUsed < maxProbeGuesses &&\n                (int)todo.size() >= 10 &&\n                elapsedMs() < 2450.0 &&\n                !isBannedEq(A)) {\n                int probeK = min((int)todo.size(), (N >= 15 ? 5 : 4));\n\n                for (; startIdx < probeK; startIdx++) {\n                    int c = todo[startIdx];\n                    if (drilled[c]) continue;\n                    if (!canFallback()) fallback();\n\n                    int v = drillCell(c);\n                    if (v != best.cnt[c]) {\n                        contradiction = true;\n                        break;\n                    }\n                }\n\n                if (contradiction) {\n                    best = optimize(&best, false);\n                    continue;\n                }\n\n                vector<unsigned char> PA = U;\n                for (int c = 0; c < C; c++) {\n                    if (drilled[c] && drillVal[c] > 0) PA[c] = 1;\n                }\n\n                if (allVerifiedPositive(PA)) {\n                    submitAnswer(PA);\n                    addSubsetMask(PA);\n                    addBannedEq(PA);\n                    addAdaptiveQueries(PA);\n                    best = optimize(&best, false);\n                    continue;\n                }\n\n                if (canWrongGuessAndFallback() && !isBannedEq(PA)) {\n                    submitAnswer(PA);\n                    addBannedEq(PA);\n                    probeGuessUsed++;\n                    addAdaptiveQueries(PA);\n                    best = optimize(&best, false);\n                    continue;\n                }\n            }\n\n            for (int idx = startIdx; idx < (int)todo.size(); idx++) {\n                int c = todo[idx];\n                if (drilled[c]) continue;\n                if (!canFallback()) fallback();\n\n                int v = drillCell(c);\n                if (v != best.cnt[c]) {\n                    contradiction = true;\n                    break;\n                }\n            }\n\n            if (contradiction) {\n                best = optimize(&best, false);\n                continue;\n            } else {\n                continue;\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int W = 1000;\nstatic const int AREA = W * W;\nstatic const unsigned short INF = 30000;\nstatic const int SEG_INF = 1'000'000'000;\nstatic const int MAX_SEG_OPT = 4;\n\nenum { VERT = 0, HOR = 1 };\nenum { POLICY_STATIC_ABS = 0, POLICY_STATIC_RATIO = 1, POLICY_PREV = 2 };\n\nstruct Rect {\n    int y0, x0, y1, x1;\n};\n\nint D, N;\nvector<vector<int>> A;\nvector<int> globalMaxDemand, meanDemand, medDemand, p75Demand, p90Demand, optStaticDemand;\n\nint hMinSeg[55][55], hStaticSeg[55][55];\nint dayHSeg[55][55][55];\n\nint segOptCnt[55][55];\nint segOptH[55][55][MAX_SEG_OPT];\nlong long segOptCost[55][55][MAX_SEG_OPT];\nint segOptTarget[55][55][MAX_SEG_OPT];\nbool segOptSoft[55][55][MAX_SEG_OPT];\n\nvector<vector<vector<Rect>>> dayCand;\nvector<vector<Rect>> staticLibLayouts;\nbool dayCandReady = false;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nint clamp_int(int v, int lo, int hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\nint ceil_div_int(int a, int b) {\n    return (a + b - 1) / b;\n}\n\nbool same_layout(const vector<Rect>& a, const vector<Rect>& b) {\n    if ((int)a.size() != (int)b.size()) return false;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i].y0 != b[i].y0 || a[i].x0 != b[i].x0 ||\n            a[i].y1 != b[i].y1 || a[i].x1 != b[i].x1) return false;\n    }\n    return true;\n}\n\nbool add_unique_layout(vector<vector<Rect>>& cand, const vector<Rect>& layout) {\n    for (const auto& x : cand) {\n        if (same_layout(x, layout)) return false;\n    }\n    cand.push_back(layout);\n    return true;\n}\n\nbool add_unique_layout_cap(vector<vector<Rect>>& cand, const vector<Rect>& layout, int cap) {\n    for (const auto& x : cand) {\n        if (same_layout(x, layout)) return false;\n    }\n    if ((int)cand.size() >= cap) return false;\n    cand.push_back(layout);\n    return true;\n}\n\n/* ---------- exact evaluator, sparse boundary ---------- */\n\nstruct Bound {\n    array<vector<pair<int,int>>, W + 1> H, V;\n    vector<int> nonH, nonV;\n    long long total = 0;\n\n    void clear() {\n        for (int i : nonH) H[i].clear();\n        for (int i : nonV) V[i].clear();\n        nonH.clear();\n        nonV.clear();\n        total = 0;\n    }\n};\n\nvoid merge_intervals(vector<pair<int,int>>& v) {\n    if (v.empty()) return;\n    sort(v.begin(), v.end());\n    int m = 0;\n    for (auto p : v) {\n        if (m == 0 || p.first > v[m-1].second) {\n            v[m++] = p;\n        } else {\n            v[m-1].second = max(v[m-1].second, p.second);\n        }\n    }\n    v.resize(m);\n}\n\nvoid build_bound(const vector<Rect>& rs, Bound& b) {\n    b.clear();\n\n    auto addH = [&](int y, int l, int r) {\n        if (y <= 0 || y >= W || l >= r) return;\n        if (b.H[y].empty()) b.nonH.push_back(y);\n        b.H[y].push_back({l, r});\n    };\n    auto addV = [&](int x, int l, int r) {\n        if (x <= 0 || x >= W || l >= r) return;\n        if (b.V[x].empty()) b.nonV.push_back(x);\n        b.V[x].push_back({l, r});\n    };\n\n    for (const auto& r : rs) {\n        addH(r.y0, r.x0, r.x1);\n        addH(r.y1, r.x0, r.x1);\n        addV(r.x0, r.y0, r.y1);\n        addV(r.x1, r.y0, r.y1);\n    }\n\n    sort(b.nonH.begin(), b.nonH.end());\n    sort(b.nonV.begin(), b.nonV.end());\n\n    for (int i : b.nonH) {\n        merge_intervals(b.H[i]);\n        for (auto [l, r] : b.H[i]) b.total += r - l;\n    }\n    for (int i : b.nonV) {\n        merge_intervals(b.V[i]);\n        for (auto [l, r] : b.V[i]) b.total += r - l;\n    }\n}\n\nlong long inter_line(const vector<pair<int,int>>& a, const vector<pair<int,int>>& b) {\n    long long inter = 0;\n    int i = 0, j = 0;\n    while (i < (int)a.size() && j < (int)b.size()) {\n        int l = max(a[i].first, b[j].first);\n        int r = min(a[i].second, b[j].second);\n        if (l < r) inter += r - l;\n        if (a[i].second < b[j].second) i++;\n        else j++;\n    }\n    return inter;\n}\n\nlong long diff_bound(const Bound& a, const Bound& b) {\n    long long inter = 0;\n\n    int i = 0, j = 0;\n    while (i < (int)a.nonH.size() && j < (int)b.nonH.size()) {\n        int x = a.nonH[i], y = b.nonH[j];\n        if (x == y) {\n            inter += inter_line(a.H[x], b.H[y]);\n            i++;\n            j++;\n        } else if (x < y) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n\n    i = j = 0;\n    while (i < (int)a.nonV.size() && j < (int)b.nonV.size()) {\n        int x = a.nonV[i], y = b.nonV[j];\n        if (x == y) {\n            inter += inter_line(a.V[x], b.V[y]);\n            i++;\n            j++;\n        } else if (x < y) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n\n    return a.total + b.total - 2 * inter;\n}\n\nlong long transition_cost(const vector<Rect>& x, const vector<Rect>& y) {\n    Bound bx, by;\n    build_bound(x, bx);\n    build_bound(y, by);\n    return diff_bound(bx, by);\n}\n\nlong long shortage_day(const vector<Rect>& rs, int d) {\n    long long res = 0;\n    for (int k = 0; k < N; k++) {\n        long long area = 1LL * (rs[k].y1 - rs[k].y0) * (rs[k].x1 - rs[k].x0);\n        if (area < A[d][k]) res += 100LL * (A[d][k] - area);\n    }\n    return res;\n}\n\nlong long evaluate_solution(const vector<vector<Rect>>& sol, long long limit = LLONG_MAX) {\n    long long total = 0;\n    Bound prev, cur;\n    for (int d = 0; d < D; d++) {\n        total += shortage_day(sol[d], d);\n        if (total > limit) return total;\n        build_bound(sol[d], cur);\n        if (d > 0) {\n            total += diff_bound(prev, cur);\n            if (total > limit) return total;\n        }\n        swap(prev, cur);\n    }\n    return total;\n}\n\n/* ---------- slicing tree ---------- */\n\nstruct Node {\n    int l = 0, r = 0;\n    int left = -1, right = -1;\n    int orient = VERT;\n    double ratio = 0.5;\n    int target = 1;\n    int targetCoord = -1;\n\n    bool leaf() const { return left == -1; }\n};\n\nstruct Tree {\n    vector<Node> nodes;\n    int root = 0;\n    vector<int> order;\n};\n\nvoid build_order(Tree& t) {\n    t.order.clear();\n    function<void(int)> dfs = [&](int v) {\n        if (!t.nodes[v].leaf()) {\n            dfs(t.nodes[v].left);\n            dfs(t.nodes[v].right);\n        }\n        t.order.push_back(v);\n    };\n    dfs(t.root);\n}\n\nint choose_split(int l, int r, int mode, const vector<double>& pref) {\n    if (r - l <= 1) return l + 1;\n    if (mode == 1) return (l + r) / 2;\n\n    double total = pref[r] - pref[l];\n    int best = l + 1;\n    double bestScore = 1e100;\n\n    for (int m = l + 1; m <= r - 1; m++) {\n        double af = (pref[m] - pref[l]) / total;\n        double cf = double(m - l) / double(r - l);\n        double score;\n        if (mode == 0) score = fabs(af - 0.5);\n        else score = fabs(af - 0.5) + 0.35 * fabs(cf - 0.5);\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = m;\n        }\n    }\n    return best;\n}\n\nTree build_aspect_tree_box(const vector<int>& base, int splitMode, int orientMode, int rootH, int rootW) {\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    Tree t;\n    function<int(int,int,int,int,int)> rec = [&](int l, int r, int h, int w, int depth) -> int {\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].l = l;\n        t.nodes[idx].r = r;\n\n        if (r - l == 1) return idx;\n\n        int orient;\n        if (orientMode == 0) orient = (w >= h ? VERT : HOR);\n        else if (orientMode == 1) orient = (depth % 2 == 0 ? VERT : HOR);\n        else orient = (depth % 2 == 0 ? HOR : VERT);\n\n        int m = choose_split(l, r, splitMode, pref);\n        double sL = pref[m] - pref[l];\n        double sT = pref[r] - pref[l];\n        double ratio = sL / sT;\n\n        t.nodes[idx].orient = orient;\n        t.nodes[idx].ratio = ratio;\n\n        int hL = h, hR = h, wL = w, wR = w;\n        if (orient == VERT) {\n            int c = (w >= 2 ? clamp_int((int)llround(w * ratio), 1, w - 1) : 1);\n            wL = max(1, c);\n            wR = max(1, w - c);\n        } else {\n            int c = (h >= 2 ? clamp_int((int)llround(h * ratio), 1, h - 1) : 1);\n            hL = max(1, c);\n            hR = max(1, h - c);\n        }\n\n        int li = rec(l, m, hL, wL, depth + 1);\n        int ri = rec(m, r, hR, wR, depth + 1);\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        return idx;\n    };\n\n    t.root = rec(0, N, rootH, rootW, 0);\n    build_order(t);\n    return t;\n}\n\nTree build_aspect_tree(const vector<int>& base, int splitMode, int orientMode) {\n    return build_aspect_tree_box(base, splitMode, orientMode, W, W);\n}\n\nint build_fixed_rec(Tree& t, int l, int r, int orient, int splitMode, const vector<double>& pref) {\n    int idx = (int)t.nodes.size();\n    t.nodes.push_back(Node());\n    t.nodes[idx].l = l;\n    t.nodes[idx].r = r;\n    t.nodes[idx].orient = orient;\n\n    if (r - l == 1) return idx;\n\n    int m = choose_split(l, r, splitMode, pref);\n    double sL = pref[m] - pref[l];\n    double sT = pref[r] - pref[l];\n    t.nodes[idx].ratio = sL / sT;\n\n    int li = build_fixed_rec(t, l, m, orient, splitMode, pref);\n    int ri = build_fixed_rec(t, m, r, orient, splitMode, pref);\n    t.nodes[idx].left = li;\n    t.nodes[idx].right = ri;\n    return idx;\n}\n\nTree build_shelf_tree(const vector<int>& base, int R, int groupMode, int itemSplitMode) {\n    R = clamp_int(R, 1, N);\n\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> groups;\n    int prev = 0;\n    for (int g = 0; g < R; g++) {\n        int en;\n        if (g == R - 1) {\n            en = N;\n        } else {\n            int minEnd = prev + 1;\n            int maxEnd = N - (R - g - 1);\n            if (groupMode == 0) {\n                double target = pref[N] * double(g + 1) / double(R);\n                en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            } else {\n                en = (int)llround(double(N) * double(g + 1) / double(R));\n            }\n            en = clamp_int(en, minEnd, maxEnd);\n        }\n        groups.push_back({prev, en});\n        prev = en;\n    }\n\n    Tree t;\n    vector<int> rowRoot;\n    vector<double> rowPref(R + 1, 0);\n\n    for (int i = 0; i < R; i++) {\n        auto [l, r] = groups[i];\n        rowRoot.push_back(build_fixed_rec(t, l, r, VERT, itemSplitMode, pref));\n        rowPref[i+1] = rowPref[i] + (pref[r] - pref[l]);\n    }\n\n    function<int(int,int)> combine = [&](int lo, int hi) -> int {\n        if (hi - lo == 1) return rowRoot[lo];\n\n        int mid = lo + 1;\n        double total = rowPref[hi] - rowPref[lo];\n        double best = 1e100;\n        for (int m = lo + 1; m <= hi - 1; m++) {\n            double d = fabs((rowPref[m] - rowPref[lo]) - total * 0.5);\n            if (d < best) {\n                best = d;\n                mid = m;\n            }\n        }\n\n        int li = combine(lo, mid);\n        int ri = combine(mid, hi);\n\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        t.nodes[idx].l = t.nodes[li].l;\n        t.nodes[idx].r = t.nodes[ri].r;\n        t.nodes[idx].orient = HOR;\n        t.nodes[idx].ratio = (rowPref[mid] - rowPref[lo]) / (rowPref[hi] - rowPref[lo]);\n        return idx;\n    };\n\n    t.root = combine(0, R);\n    build_order(t);\n    return t;\n}\n\n/* ---------- slicing DP ---------- */\n\nstruct DPComputer {\n    const Tree* tr;\n    bool freeOrient;\n    vector<array<unsigned short, W + 1>> dp;\n    vector<array<unsigned short, W + 1>> mh;\n\n    DPComputer(const Tree& t, bool f) : tr(&t), freeOrient(f) {\n        dp.resize(t.nodes.size());\n        mh.resize(t.nodes.size());\n    }\n\n    void compute_mh_from_dp(int idx) {\n        auto& P = dp[idx];\n        auto& M = mh[idx];\n        for (int i = 0; i <= W; i++) M[i] = INF;\n\n        int prev = W + 1;\n        for (int h = 1; h <= W; h++) {\n            int v = P[h];\n            if (v <= W && v < prev) {\n                for (int w = v; w < prev; w++) M[w] = h;\n                prev = v;\n            }\n        }\n    }\n\n    void horizontal_merge(int L, int R, array<unsigned short, W + 1>& out) {\n        for (int i = 0; i <= W; i++) out[i] = INF;\n        int prev = W + 1;\n        for (int w = 1; w <= W; w++) {\n            int hL = mh[L][w], hR = mh[R][w];\n            int req = (hL >= INF || hR >= INF ? INF : hL + hR);\n            if (req <= W && req < prev) {\n                for (int h = req; h < prev; h++) out[h] = w;\n                prev = req;\n            }\n        }\n    }\n\n    void compute(const vector<int>& demand) {\n        for (int idx : tr->order) {\n            const Node& nd = tr->nodes[idx];\n            auto& P = dp[idx];\n            auto& M = mh[idx];\n\n            if (nd.leaf()) {\n                long long a = demand[nd.l];\n                P[0] = M[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    long long v = (a + h - 1) / h;\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                for (int w = 1; w <= W; w++) {\n                    long long v = (a + w - 1) / w;\n                    M[w] = (v <= W ? (unsigned short)v : INF);\n                }\n                continue;\n            }\n\n            int L = nd.left, R = nd.right;\n\n            if (!freeOrient && nd.orient == VERT) {\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                compute_mh_from_dp(idx);\n            } else if (!freeOrient && nd.orient == HOR) {\n                horizontal_merge(L, R, P);\n                compute_mh_from_dp(idx);\n            } else {\n                array<unsigned short, W + 1> HP;\n                horizontal_merge(L, R, HP);\n\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    if (v > W) v = INF;\n                    P[h] = (unsigned short)min(v, (int)HP[h]);\n                }\n                compute_mh_from_dp(idx);\n            }\n        }\n    }\n};\n\n/* ---------- target assignment / reconstruction ---------- */\n\nbool assign_targets_dp_rec(Tree& t, int idx, int y, int x, int h, int w, const DPComputer& comp) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return true;\n\n    int L = nd.left, R = nd.right;\n\n    if (nd.orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(w * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        nd.target = c;\n        nd.targetCoord = x + c;\n        return assign_targets_dp_rec(t, L, y, x, h, c, comp) &&\n               assign_targets_dp_rec(t, R, y, x + c, h, w - c, comp);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(h * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        nd.target = c;\n        nd.targetCoord = y + c;\n        return assign_targets_dp_rec(t, L, y, x, c, w, comp) &&\n               assign_targets_dp_rec(t, R, y + c, x, h - c, w, comp);\n    }\n}\n\nvoid assign_targets_ratio_rec(Tree& t, int idx, int y, int x, int h, int w) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return;\n\n    if (nd.orient == VERT) {\n        int c = (w >= 2 ? clamp_int((int)llround(w * nd.ratio), 1, w - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = x + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, h, max(1, c));\n        assign_targets_ratio_rec(t, nd.right, y, x + c, h, max(1, w - c));\n    } else {\n        int c = (h >= 2 ? clamp_int((int)llround(h * nd.ratio), 1, h - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = y + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, max(1, c), w);\n        assign_targets_ratio_rec(t, nd.right, y + c, x, max(1, h - c), w);\n    }\n}\n\nvoid assign_targets_box(Tree& t, const vector<int>& demand, int rootH, int rootW) {\n    for (auto& nd : t.nodes) {\n        nd.target = 1;\n        nd.targetCoord = -1;\n    }\n\n    DPComputer comp(t, false);\n    comp.compute(demand);\n\n    bool ok = (comp.dp[t.root][rootH] <= rootW);\n    if (ok) ok = assign_targets_dp_rec(t, t.root, 0, 0, rootH, rootW, comp);\n\n    if (!ok) assign_targets_ratio_rec(t, t.root, 0, 0, rootH, rootW);\n}\n\nvoid assign_targets(Tree& t, const vector<int>& demand) {\n    assign_targets_box(t, demand, W, W);\n}\n\nbool feasible_vert(const DPComputer& comp, int L, int R, int h, int w) {\n    if (w < 2) return false;\n    int a = comp.dp[L][h], b = comp.dp[R][h];\n    return a < INF && b < INF && a + b <= w;\n}\n\nbool feasible_hor(const DPComputer& comp, int L, int R, int h, int w) {\n    if (h < 2) return false;\n    int a = comp.mh[L][w], b = comp.mh[R][w];\n    return a < INF && b < INF && a + b <= h;\n}\n\nint target_size_for(\n    const Tree& t,\n    int idx,\n    int orient,\n    int dim,\n    int originCoord,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (policy == POLICY_PREV && prevOrient[idx] == orient && prevCoord[idx] >= 0) {\n        return prevCoord[idx] - originCoord;\n    }\n\n    if (policy == POLICY_STATIC_RATIO || orient != nd.orient || nd.targetCoord < 0) {\n        return (int)llround(dim * nd.ratio);\n    }\n\n    return nd.targetCoord - originCoord;\n}\n\nbool reconstruct_rec(\n    const Tree& t,\n    int idx,\n    int y,\n    int x,\n    int h,\n    int w,\n    const DPComputer& comp,\n    vector<Rect>& rects,\n    bool freeOrient,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord,\n    vector<int>& curOrient,\n    vector<int>& curCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (nd.leaf()) {\n        if (h <= 0 || w <= 0) return false;\n        rects[nd.l] = {y, x, y + h, x + w};\n        return true;\n    }\n\n    int L = nd.left, R = nd.right;\n    bool canV = feasible_vert(comp, L, R, h, w);\n    bool canH = feasible_hor(comp, L, R, h, w);\n\n    int orient = nd.orient;\n    if (freeOrient) {\n        int po = (policy == POLICY_PREV ? prevOrient[idx] : -1);\n        if (po == VERT && canV) orient = VERT;\n        else if (po == HOR && canH) orient = HOR;\n        else if (nd.orient == VERT && canV) orient = VERT;\n        else if (nd.orient == HOR && canH) orient = HOR;\n        else if (canV) orient = VERT;\n        else if (canH) orient = HOR;\n        else return false;\n    } else {\n        if (orient == VERT && !canV) return false;\n        if (orient == HOR && !canH) return false;\n    }\n\n    if (orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, VERT, w, x, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        curOrient[idx] = VERT;\n        curCoord[idx] = x + c;\n\n        return reconstruct_rec(t, L, y, x, h, c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y, x + c, h, w - c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, HOR, h, y, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        curOrient[idx] = HOR;\n        curCoord[idx] = y + c;\n\n        return reconstruct_rec(t, L, y, x, c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y + c, x, h - c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    }\n}\n\nbool make_solution(const Tree& t, bool freeOrient, int policy, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n\n    DPComputer comp(t, freeOrient);\n    int M = (int)t.nodes.size();\n\n    vector<int> prevOrient(M, -1), prevCoord(M, -1);\n    for (int i = 0; i < M; i++) {\n        if (!t.nodes[i].leaf()) {\n            prevOrient[i] = t.nodes[i].orient;\n            prevCoord[i] = t.nodes[i].targetCoord;\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        comp.compute(A[d]);\n        if (comp.dp[t.root][W] > W) return false;\n\n        vector<int> curOrient(M, -1), curCoord(M, -1);\n        bool ok = reconstruct_rec(\n            t, t.root, 0, 0, W, W, comp, sol[d],\n            freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord\n        );\n        if (!ok) return false;\n\n        if (policy == POLICY_PREV) {\n            prevOrient.swap(curOrient);\n            prevCoord.swap(curCoord);\n        }\n    }\n    return true;\n}\n\nbool make_static_solution(const Tree& t, const vector<int>& demand, bool freeOrient, vector<vector<Rect>>& sol) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][W] > W) return false;\n\n    vector<Rect> one(N);\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    bool ok = reconstruct_rec(\n        t, t.root, 0, 0, W, W, comp, one,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n    if (!ok) return false;\n\n    sol.assign(D, one);\n    return true;\n}\n\n/* ---------- solution management ---------- */\n\nvector<vector<Rect>> bestSol;\nlong long bestScore = LLONG_MAX;\n\nvoid consider_solution(const vector<vector<Rect>>& sol) {\n    if (dayCandReady && (int)sol.size() == D) {\n        for (int d = 0; d < D; d++) {\n            add_unique_layout_cap(dayCand[d], sol[d], 160);\n        }\n    }\n\n    long long sc = evaluate_solution(sol, bestScore);\n    if (sc < bestScore) {\n        bestScore = sc;\n        bestSol = sol;\n    }\n}\n\nvector<vector<Rect>> make_fallback() {\n    vector<vector<Rect>> sol(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; d++) {\n        vector<int> h(N, 1);\n        int rem = W - N;\n\n        auto gain = [&](int k) -> int {\n            long long covered = 1LL * h[k] * W;\n            if (covered >= A[d][k]) return 0;\n            return (int)min<long long>(W, A[d][k] - covered);\n        };\n\n        priority_queue<pair<int,int>> pq;\n        for (int k = 0; k < N; k++) pq.push({gain(k), k});\n\n        while (rem > 0 && !pq.empty()) {\n            auto [g, k] = pq.top();\n            pq.pop();\n            int cg = gain(k);\n            if (cg != g) {\n                pq.push({cg, k});\n                continue;\n            }\n            if (cg <= 0) break;\n            h[k]++;\n            rem--;\n            pq.push({gain(k), k});\n        }\n\n        h[N-1] += rem;\n\n        int y = 0;\n        for (int k = 0; k < N; k++) {\n            sol[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    return sol;\n}\n\nvector<int> scale_to_limit(const vector<int>& v) {\n    long long s = 0;\n    for (int x : v) s += x;\n    if (s <= AREA) return v;\n\n    vector<int> r(N);\n    double f = double(AREA) / double(s);\n    long long sr = 0;\n    for (int i = 0; i < N; i++) {\n        r[i] = max(1, (int)floor(v[i] * f));\n        sr += r[i];\n    }\n\n    while (sr > AREA) {\n        int id = -1;\n        for (int i = 0; i < N; i++) {\n            if (r[i] > 1 && (id == -1 || r[i] > r[id])) id = i;\n        }\n        if (id == -1) break;\n        r[id]--;\n        sr--;\n    }\n    return r;\n}\n\nvector<int> compute_opt_static_area() {\n    struct Seg {\n        int slope, k, len;\n    };\n    vector<Seg> segs;\n\n    for (int k = 0; k < N; k++) {\n        vector<int> vals;\n        for (int d = 0; d < D; d++) vals.push_back(A[d][k]);\n        sort(vals.begin(), vals.end());\n\n        int prev = 0;\n        for (int i = 0; i < D; i++) {\n            int v = vals[i];\n            if (v > prev) {\n                segs.push_back({D - i, k, v - prev});\n                prev = v;\n            }\n        }\n    }\n\n    sort(segs.begin(), segs.end(), [](const Seg& a, const Seg& b) {\n        if (a.slope != b.slope) return a.slope > b.slope;\n        return a.k < b.k;\n    });\n\n    vector<int> c(N, 0);\n    long long rem = AREA;\n\n    for (int p = 0; p < (int)segs.size() && rem > 0; ) {\n        int q = p;\n        while (q < (int)segs.size() && segs[q].slope == segs[p].slope) q++;\n\n        long long totalLen = 0;\n        for (int i = p; i < q; i++) totalLen += segs[i].len;\n\n        if (totalLen <= rem) {\n            for (int i = p; i < q; i++) c[segs[i].k] += segs[i].len;\n            rem -= totalLen;\n        } else {\n            vector<pair<long double,int>> frac;\n            long long used = 0;\n            for (int i = p; i < q; i++) {\n                long double ideal = (long double)rem * segs[i].len / (long double)totalLen;\n                int add = (int)floor(ideal);\n                add = min(add, segs[i].len);\n                c[segs[i].k] += add;\n                used += add;\n                frac.push_back({ideal - add, i});\n            }\n            long long left = rem - used;\n            sort(frac.rbegin(), frac.rend());\n            for (int z = 0; z < (int)frac.size() && left > 0; z++) {\n                int i = frac[z].second;\n                if (c[segs[i].k] < globalMaxDemand[segs[i].k]) {\n                    c[segs[i].k]++;\n                    left--;\n                }\n            }\n            break;\n        }\n\n        p = q;\n    }\n\n    long long s = 0;\n    for (int k = 0; k < N; k++) {\n        c[k] = max(1, c[k]);\n        s += c[k];\n    }\n    while (s > AREA) {\n        int id = max_element(c.begin(), c.end()) - c.begin();\n        if (c[id] <= 1) break;\n        c[id]--;\n        s--;\n    }\n    return c;\n}\n\n/* ---------- per-day candidate pool ---------- */\n\nvoid init_day_candidates() {\n    dayCand.assign(D, {});\n    dayCandReady = true;\n    for (int d = 0; d < D; d++) add_unique_layout(dayCand[d], bestSol[d]);\n}\n\nbool try_single_tree_layout_box(\n    Tree t,\n    const vector<int>& demand,\n    bool freeOrient,\n    int rootH,\n    int rootW,\n    vector<Rect>& layout\n) {\n    if (rootH <= 0 || rootW <= 0 || rootH > W || rootW > W) return false;\n\n    assign_targets_box(t, demand, rootH, rootW);\n\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][rootH] > rootW) return false;\n\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    layout.assign(N, Rect{0, 0, 1, 1});\n    return reconstruct_rec(\n        t, t.root, 0, 0, rootH, rootW, comp, layout,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n}\n\nint find_min_height_for_tree(const Tree& t, const vector<int>& demand, bool freeOrient) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    for (int h = 1; h <= W; h++) {\n        if (comp.dp[t.root][h] <= W) return h;\n    }\n    return -1;\n}\n\nint find_min_width_for_tree(const Tree& t, const vector<int>& demand, bool freeOrient) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    int w = comp.dp[t.root][W];\n    if (w <= W) return w;\n    return -1;\n}\n\nbool make_single_tree_layout_relaxed_mode(\n    const Tree& baseTree,\n    const vector<int>& trueDemand,\n    bool freeOrient,\n    int compactMode,\n    vector<Rect>& layout\n) {\n    static const double factors[] = {1.0, 0.999, 0.997, 0.995, 0.990, 0.980, 0.960, 0.930, 0.900, 0.850};\n\n    vector<int> dem(N);\n    for (double f : factors) {\n        for (int k = 0; k < N; k++) dem[k] = max(1, (int)floor(trueDemand[k] * f));\n\n        int rootH = W, rootW = W;\n        if (compactMode == 1) {\n            rootH = find_min_height_for_tree(baseTree, dem, freeOrient);\n            rootW = W;\n            if (rootH < 0) continue;\n        } else if (compactMode == 2) {\n            rootH = W;\n            rootW = find_min_width_for_tree(baseTree, dem, freeOrient);\n            if (rootW < 0) continue;\n        }\n\n        if (try_single_tree_layout_box(baseTree, dem, freeOrient, rootH, rootW, layout)) return true;\n    }\n    return false;\n}\n\nvoid generate_day_slicing_candidates(double TL) {\n    if (dayCand.empty()) init_day_candidates();\n\n    vector<pair<int,int>> combos = {\n        {0, 0}, {2, 0}, {1, 0}, {0, 1}, {0, 2}\n    };\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) break;\n\n        long long sumA = 0;\n        for (int x : A[d]) sumA += x;\n        int approx = clamp_int((int)((sumA + W - 1) / W), 1, W);\n\n        for (int ci = 0; ci < (int)combos.size(); ci++) {\n            if (elapsed_sec() > TL) break;\n\n            auto [sm, om] = combos[ci];\n            vector<Rect> layout;\n\n            Tree fullT = build_aspect_tree_box(A[d], sm, om, W, W);\n            if (make_single_tree_layout_relaxed_mode(fullT, A[d], false, 0, layout)) {\n                add_unique_layout_cap(dayCand[d], layout, 160);\n            }\n            if (ci <= 1 && elapsed_sec() < TL) {\n                if (make_single_tree_layout_relaxed_mode(fullT, A[d], true, 0, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n            }\n\n            if (ci <= 2 && elapsed_sec() < TL) {\n                Tree topT = build_aspect_tree_box(A[d], sm, om, approx, W);\n                if (make_single_tree_layout_relaxed_mode(topT, A[d], false, 1, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n                if (ci == 0 && elapsed_sec() < TL) {\n                    if (make_single_tree_layout_relaxed_mode(topT, A[d], true, 1, layout)) {\n                        add_unique_layout_cap(dayCand[d], layout, 160);\n                    }\n                }\n            }\n\n            if (ci <= 1 && elapsed_sec() < TL) {\n                Tree leftT = build_aspect_tree_box(A[d], sm, om, W, approx);\n                if (make_single_tree_layout_relaxed_mode(leftT, A[d], false, 2, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n            }\n        }\n    }\n}\n\nlong long rough_perim_score(const vector<Rect>& layout) {\n    long long res = 0;\n    for (const auto& r : layout) {\n        int h = r.y1 - r.y0;\n        int w = r.x1 - r.x0;\n        if (r.y0 > 0) res += w;\n        if (r.y1 < W) res += w;\n        if (r.x0 > 0) res += h;\n        if (r.x1 < W) res += h;\n    }\n    return res;\n}\n\nvoid run_day_candidate_dp(bool addCurrentBest, double TL) {\n    if (dayCand.empty()) return;\n    if (addCurrentBest) {\n        for (int d = 0; d < D; d++) add_unique_layout_cap(dayCand[d], bestSol[d], 160);\n    }\n    if (elapsed_sec() > TL) return;\n\n    const int MAXC = 50;\n\n    for (int d = 0; d < D; d++) {\n        if ((int)dayCand[d].size() <= MAXC) continue;\n\n        int C = dayCand[d].size();\n        vector<int> keep;\n        auto pin = [&](int id) {\n            if (id < 0 || id >= C) return;\n            if (find(keep.begin(), keep.end(), id) == keep.end()) keep.push_back(id);\n        };\n\n        pin(0);\n        for (int i = 0; i < C; i++) {\n            if (same_layout(dayCand[d][i], bestSol[d])) pin(i);\n        }\n        for (const auto& lib : staticLibLayouts) {\n            for (int i = 0; i < C; i++) {\n                if (same_layout(dayCand[d][i], lib)) {\n                    pin(i);\n                    break;\n                }\n            }\n        }\n\n        vector<tuple<long long,long long,int>> ord;\n        ord.reserve(C);\n        for (int i = 0; i < C; i++) {\n            ord.push_back({shortage_day(dayCand[d][i], d), rough_perim_score(dayCand[d][i]), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        for (auto [sh, pe, id] : ord) {\n            if ((int)keep.size() >= MAXC) break;\n            pin(id);\n        }\n\n        sort(keep.begin(), keep.end());\n        vector<vector<Rect>> nd;\n        for (int id : keep) nd.push_back(dayCand[d][id]);\n        dayCand[d].swap(nd);\n    }\n\n    vector<vector<Bound>> bounds(D);\n    vector<vector<long long>> sh(D);\n    for (int d = 0; d < D; d++) {\n        int C = dayCand[d].size();\n        bounds[d].resize(C);\n        sh[d].resize(C);\n        for (int c = 0; c < C; c++) {\n            sh[d][c] = shortage_day(dayCand[d][c], d);\n            build_bound(dayCand[d][c], bounds[d][c]);\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(D);\n    vector<vector<int>> par(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = dayCand[d].size();\n        dp[d].assign(C, BIG);\n        par[d].assign(C, -1);\n    }\n\n    for (int c = 0; c < (int)dayCand[0].size(); c++) dp[0][c] = sh[0][c];\n\n    for (int d = 1; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n\n        for (int c = 0; c < (int)dayCand[d].size(); c++) {\n            for (int pc = 0; pc < (int)dayCand[d-1].size(); pc++) {\n                if (dp[d-1][pc] >= BIG / 2) continue;\n                long long tr = diff_bound(bounds[d-1][pc], bounds[d][c]);\n                long long nv = dp[d-1][pc] + sh[d][c] + tr;\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = -1;\n    long long best = BIG;\n    for (int c = 0; c < (int)dayCand[D-1].size(); c++) {\n        if (dp[D-1][c] < best) {\n            best = dp[D-1][c];\n            bestC = c;\n        }\n    }\n    if (bestC < 0) return;\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = dayCand[d][cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- shrink variants ---------- */\n\nRect shrink_one_rect(const Rect& r, int demand, int mode) {\n    int H = r.y1 - r.y0;\n    int B = r.x1 - r.x0;\n    long long area = 1LL * H * B;\n    if (area <= demand) return r;\n\n    int bestH = H, bestW = B, bestY = r.y0, bestX = r.x0;\n    long long bestScore = LLONG_MAX;\n\n    int minH = max(1, ceil_div_int(demand, B));\n    for (int h = minH; h <= H; h++) {\n        int w = ceil_div_int(demand, h);\n        if (w <= 0 || w > B) continue;\n\n        int y, x;\n        if (mode == 2) {\n            y = r.y0 + (H - h) / 2;\n            x = r.x0 + (B - w) / 2;\n        } else {\n            bool bottom = (mode == 1 && r.y1 == W && r.y0 != 0);\n            bool right = (mode == 1 && r.x1 == W && r.x0 != 0);\n            y = bottom ? r.y1 - h : r.y0;\n            x = right ? r.x1 - w : r.x0;\n        }\n\n        long long internal = 0;\n        if (y > 0) internal += w;\n        if (y + h < W) internal += w;\n        if (x > 0) internal += h;\n        if (x + w < W) internal += h;\n\n        long long surplus = 1LL * h * w - demand;\n        long long aspect = llabs(h - w);\n        long long score = internal * 1000000LL + surplus * 10LL + aspect;\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestH = h;\n            bestW = w;\n            bestY = y;\n            bestX = x;\n        }\n    }\n\n    return {bestY, bestX, bestY + bestH, bestX + bestW};\n}\n\nvector<Rect> shrink_layout_day(const vector<Rect>& layout, int d, int mode) {\n    vector<Rect> out = layout;\n    for (int k = 0; k < N; k++) {\n        out[k] = shrink_one_rect(layout[k], A[d][k], mode);\n    }\n    return out;\n}\n\nvoid add_shrunk_day_candidates(double TL) {\n    if (dayCand.empty()) return;\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n\n        int C = dayCand[d].size();\n        vector<pair<long long,int>> ord;\n        for (int i = 0; i < C; i++) {\n            ord.push_back({shortage_day(dayCand[d][i], d), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        int lim = min((int)ord.size(), 24);\n        for (int t = 0; t < lim; t++) {\n            if (elapsed_sec() > TL) return;\n            int id = ord[t].second;\n            long long baseSh = ord[t].first;\n            if (baseSh > 20000) continue;\n\n            for (int mode = 0; mode < 3; mode++) {\n                vector<Rect> shr = shrink_layout_day(dayCand[d][id], d, mode);\n                if (shortage_day(shr, d) <= baseSh) {\n                    add_unique_layout_cap(dayCand[d], shr, 160);\n                }\n            }\n        }\n    }\n}\n\n/* ---------- static library ---------- */\n\nstring layout_key(const vector<Rect>& layout) {\n    string s;\n    s.reserve(layout.size() * 24);\n    for (const auto& r : layout) {\n        s += to_string(r.y0); s.push_back(',');\n        s += to_string(r.x0); s.push_back(',');\n        s += to_string(r.y1); s.push_back(',');\n        s += to_string(r.x1); s.push_back(';');\n    }\n    return s;\n}\n\nlong long total_shortage_layout_all_days(const vector<Rect>& layout) {\n    vector<long long> area(N);\n    for (int k = 0; k < N; k++) {\n        area[k] = 1LL * (layout[k].y1 - layout[k].y0) * (layout[k].x1 - layout[k].x0);\n    }\n\n    long long res = 0;\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            if (area[k] < A[d][k]) res += 100LL * (A[d][k] - area[k]);\n        }\n    }\n    return res;\n}\n\nvoid add_static_library_candidates(int maxLib, double TL, bool addToDayCand) {\n    staticLibLayouts.clear();\n    if (dayCand.empty() || elapsed_sec() > TL) return;\n\n    unordered_set<string> seen;\n    vector<vector<Rect>> libs;\n\n    auto addLib = [&](const vector<Rect>& layout) {\n        string key = layout_key(layout);\n        if (seen.insert(key).second) libs.push_back(layout);\n    };\n\n    for (int d = 0; d < D; d++) addLib(bestSol[d]);\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) break;\n        for (const auto& layout : dayCand[d]) addLib(layout);\n    }\n\n    vector<pair<long long,int>> score;\n    for (int i = 0; i < (int)libs.size(); i++) {\n        if (elapsed_sec() > TL) break;\n        score.push_back({total_shortage_layout_all_days(libs[i]), i});\n    }\n    sort(score.begin(), score.end());\n\n    int lim = min(maxLib, (int)score.size());\n    for (int z = 0; z < lim; z++) {\n        int id = score[z].second;\n        long long sc = score[z].first;\n        staticLibLayouts.push_back(libs[id]);\n\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestSol.assign(D, libs[id]);\n        }\n\n        if (addToDayCand) {\n            for (int d = 0; d < D; d++) {\n                add_unique_layout_cap(dayCand[d], libs[id], 160);\n            }\n        }\n    }\n}\n\nvoid copy_library_dp(double TL) {\n    if (elapsed_sec() > TL) return;\n\n    vector<vector<Rect>> lib;\n    unordered_set<string> seen;\n\n    auto addLib = [&](const vector<Rect>& layout) {\n        string key = layout_key(layout);\n        if (seen.insert(key).second) lib.push_back(layout);\n    };\n\n    for (int d = 0; d < D; d++) addLib(bestSol[d]);\n    for (const auto& layout : staticLibLayouts) addLib(layout);\n\n    const int MAX_LIB = 70;\n    if ((int)lib.size() > MAX_LIB) lib.resize(MAX_LIB);\n    int C = lib.size();\n    if (C == 0) return;\n\n    vector<Bound> bounds(C);\n    for (int i = 0; i < C; i++) {\n        if (elapsed_sec() > TL) return;\n        build_bound(lib[i], bounds[i]);\n    }\n\n    vector<vector<long long>> trans(C, vector<long long>(C, 0));\n    for (int i = 0; i < C; i++) {\n        if (elapsed_sec() > TL) return;\n        for (int j = 0; j < C; j++) trans[i][j] = diff_bound(bounds[i], bounds[j]);\n    }\n\n    vector<vector<long long>> sh(D, vector<long long>(C));\n    for (int d = 0; d < D; d++) {\n        for (int c = 0; c < C; c++) sh[d][c] = shortage_day(lib[c], d);\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(D, vector<long long>(C, BIG));\n    vector<vector<int>> par(D, vector<int>(C, -1));\n\n    for (int c = 0; c < C; c++) dp[0][c] = sh[0][c];\n\n    for (int d = 1; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n        for (int c = 0; c < C; c++) {\n            for (int pc = 0; pc < C; pc++) {\n                long long nv = dp[d-1][pc] + trans[pc][c] + sh[d][c];\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int c = 1; c < C; c++) {\n        if (dp[D-1][c] < dp[D-1][bestC]) bestC = c;\n    }\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = lib[cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- shelf utilities ---------- */\n\nbool check_day_segment_h(int d, int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(A[d][k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_day_hmin_segment(int d, int l, int r) {\n    if (!check_day_segment_h(d, l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_day_segment_h(d, l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nvoid precompute_day_segments() {\n    for (int d = 0; d < D; d++) {\n        for (int l = 0; l < N; l++) {\n            for (int r = l + 1; r <= N; r++) {\n                dayHSeg[d][l][r] = compute_day_hmin_segment(d, l, r);\n            }\n        }\n    }\n}\n\nbool check_static_h(int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(globalMaxDemand[k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_hstatic_segment(int l, int r) {\n    if (!check_static_h(l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_static_h(l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nint base_value_for_target(int type, int k) {\n    if (type == 0) return globalMaxDemand[k];\n    if (type == 1) return p90Demand[k];\n    if (type == 2) return p75Demand[k];\n    if (type == 3) return meanDemand[k];\n    if (type == 4) return optStaticDemand[k];\n    return medDemand[k];\n}\n\nvector<int> normalize_widths(vector<int> w) {\n    int m = (int)w.size();\n    int s = accumulate(w.begin(), w.end(), 0);\n    while (s < W) {\n        w[m - 1]++;\n        s++;\n    }\n    while (s > W) {\n        bool done = false;\n        for (int i = m - 1; i >= 0 && s > W; i--) {\n            if (w[i] > 1) {\n                w[i]--;\n                s--;\n                done = true;\n            }\n        }\n        if (!done) break;\n    }\n    return w;\n}\n\nvector<int> allocate_by_weights(const vector<int>& lower, const vector<double>& weights) {\n    int m = (int)lower.size();\n    int sumL = accumulate(lower.begin(), lower.end(), 0);\n    if (sumL > W) {\n        vector<int> w(m, 1);\n        int rem = W - m;\n        for (int i = 0; i < m && rem > 0; i++, rem--) w[i]++;\n        if (rem > 0) w[m-1] += rem;\n        return w;\n    }\n\n    vector<int> w = lower;\n    int rem = W - sumL;\n    if (rem == 0) return w;\n\n    double sw = 0;\n    for (double x : weights) sw += max(1e-9, x);\n    if (sw <= 0) sw = m;\n\n    vector<pair<double,int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; i++) {\n        double ideal = rem * max(1e-9, weights[i]) / sw;\n        int add = (int)floor(ideal);\n        w[i] += add;\n        used += add;\n        frac.push_back({ideal - add, i});\n    }\n    int left = rem - used;\n    sort(frac.rbegin(), frac.rend());\n    for (int i = 0; i < left; i++) w[frac[i % m].second]++;\n    return normalize_widths(w);\n}\n\nvector<int> make_target_widths(int l, int r, int h, int targetType) {\n    int m = r - l;\n    vector<int> lower(m, 1);\n    long long sumL = 0;\n    for (int i = 0; i < m; i++) {\n        int b = base_value_for_target(targetType, l + i);\n        lower[i] = max(1, ceil_div_int(b, h));\n        sumL += lower[i];\n    }\n    if (sumL > W) fill(lower.begin(), lower.end(), 1);\n\n    vector<double> weights(m);\n    for (int i = 0; i < m; i++) weights[i] = max(1, base_value_for_target(targetType, l + i));\n    return allocate_by_weights(lower, weights);\n}\n\nvector<int> project_near(vector<int> ref, const vector<int>& lb) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    vector<int> w = ref;\n    for (int i = 0; i < m; i++) {\n        if (w[i] >= lb[i]) continue;\n        int need = lb[i] - w[i];\n        w[i] = lb[i];\n\n        while (need > 0) {\n            int best = -1;\n            for (int j = 0; j < m; j++) {\n                if (w[j] <= lb[j]) continue;\n                if (best == -1 ||\n                    abs(j - i) < abs(best - i) ||\n                    (abs(j - i) == abs(best - i) && w[j] - lb[j] > w[best] - lb[best])) {\n                    best = j;\n                }\n            }\n            if (best == -1) break;\n            int x = min(need, w[best] - lb[best]);\n            w[best] -= x;\n            need -= x;\n        }\n    }\n    return normalize_widths(w);\n}\n\nvoid make_day_lb(int l, int r, int h, int d, const vector<int>& ref, bool soft, vector<int>& lb) {\n    int m = r - l;\n    lb.assign(m, 1);\n    for (int i = 0; i < m; i++) {\n        int a = A[d][l + i];\n        int q = ceil_div_int(a, h);\n        if (soft && (int)ref.size() == m && ref[i] < q && q > 1) {\n            int rem = a - h * (q - 1);\n            if (100LL * rem < 2LL * h) q--;\n        }\n        lb[i] = max(1, q);\n    }\n}\n\nvector<int> shortage_widths(const vector<int>& refIn, int l, int r, int h, int d) {\n    int m = r - l;\n    vector<int> cur(m, 1);\n    int rem = W - m;\n    if (rem < 0) rem = 0;\n\n    auto gain = [&](int i) -> int {\n        long long covered = 1LL * cur[i] * h;\n        if (covered >= A[d][l + i]) return 0;\n        return (int)min<long long>(h, A[d][l + i] - covered);\n    };\n\n    using Tup = tuple<int,int,int,int>;\n    priority_queue<Tup> pq;\n    vector<int> ref = normalize_widths(refIn);\n    for (int i = 0; i < m; i++) {\n        int pref = (i < (int)ref.size() ? ref[i] - cur[i] : 0);\n        pq.push({gain(i), pref, -i, cur[i]});\n    }\n\n    while (rem > 0 && !pq.empty()) {\n        auto [g, pref, ni, old] = pq.top();\n        pq.pop();\n        int i = -ni;\n        if (old != cur[i]) continue;\n        int cg = gain(i);\n        if (cg <= 0) break;\n        cur[i]++;\n        rem--;\n        int np = (i < (int)ref.size() ? ref[i] - cur[i] : 0);\n        pq.push({gain(i), np, -i, cur[i]});\n    }\n    if (rem > 0) cur[m-1] += rem;\n    return normalize_widths(cur);\n}\n\nint symdiff_cut_count(const vector<int>& a, const vector<int>& b) {\n    int m = (int)a.size();\n    vector<int> ca, cb;\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += a[i];\n        ca.push_back(s);\n    }\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += b[i];\n        cb.push_back(s);\n    }\n    int i = 0, j = 0, common = 0;\n    while (i < (int)ca.size() && j < (int)cb.size()) {\n        if (ca[i] == cb[j]) {\n            common++;\n            i++;\n            j++;\n        } else if (ca[i] < cb[j]) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n    return (int)ca.size() + (int)cb.size() - 2 * common;\n}\n\nlong long row_shortage_cost(int l, int r, int h, int d, const vector<int>& w) {\n    long long res = 0;\n    for (int i = 0; i < r - l; i++) {\n        long long area = 1LL * h * w[i];\n        if (area < A[d][l + i]) res += 100LL * (A[d][l + i] - area);\n    }\n    return res;\n}\n\nlong long simulate_row_fast(int l, int r, int h, int targetType, bool soft) {\n    vector<int> target = make_target_widths(l, r, h, targetType);\n    vector<int> prev;\n    long long cost = 0;\n\n    for (int d = 0; d < D; d++) {\n        vector<int> ref = (d == 0 ? target : prev);\n        vector<int> lb;\n        make_day_lb(l, r, h, d, ref, soft, lb);\n        int sumLB = accumulate(lb.begin(), lb.end(), 0);\n\n        vector<int> w;\n        if (sumLB <= W) w = project_near(ref, lb);\n        else w = shortage_widths(ref, l, r, h, d);\n\n        cost += row_shortage_cost(l, r, h, d, w);\n        if (d > 0) cost += 1LL * h * symdiff_cut_count(prev, w);\n        prev = w;\n    }\n    return cost;\n}\n\nvoid best_row_option(int l, int r, int h, long long& best, int& bestT, bool& bestS) {\n    if (hStaticSeg[l][r] < SEG_INF && h >= hStaticSeg[l][r]) {\n        best = 0;\n        bestT = 0;\n        bestS = false;\n        return;\n    }\n\n    best = (1LL << 62);\n    bestT = 0;\n    bestS = false;\n\n    for (int t = 0; t < 5; t++) {\n        for (int s = 0; s <= 1; s++) {\n            long long c = simulate_row_fast(l, r, h, t, s);\n            if (c < best) {\n                best = c;\n                bestT = t;\n                bestS = (bool)s;\n            }\n        }\n    }\n}\n\nvector<int> choose_widths_overlap(vector<int> ref, const vector<int>& lb, vector<int> target) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n    target = normalize_widths(target);\n\n    if (m == 1) return vector<int>{W};\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    vector<int> oldSet(W + 1, 0);\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += ref[i];\n        if (0 <= s && s <= W) oldSet[s] = 1;\n    }\n\n    vector<int> targetCut(m - 1);\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += target[i];\n        targetCut[i] = s;\n    }\n\n    const int NEG = -1'000'000'000;\n    const int MATCH = 1'000'000;\n\n    vector<int> prev(W + 1, NEG), cur(W + 1, NEG);\n    vector<int> prefVal(W + 1), prefPos(W + 1);\n    vector<vector<short>> par(m, vector<short>(W + 1, -1));\n\n    prev[0] = 0;\n\n    vector<int> prefLB(m + 1, 0), suffLB(m + 1, 0);\n    for (int i = 0; i < m; i++) prefLB[i+1] = prefLB[i] + lb[i];\n    for (int i = m - 1; i >= 0; i--) suffLB[i] = suffLB[i+1] + lb[i];\n\n    for (int i = 1; i <= m - 1; i++) {\n        prefVal[0] = prev[0];\n        prefPos[0] = 0;\n        for (int x = 1; x <= W; x++) {\n            if (prev[x] > prefVal[x-1]) {\n                prefVal[x] = prev[x];\n                prefPos[x] = x;\n            } else {\n                prefVal[x] = prefVal[x-1];\n                prefPos[x] = prefPos[x-1];\n            }\n        }\n\n        fill(cur.begin(), cur.end(), NEG);\n\n        int minX = prefLB[i];\n        int maxX = W - suffLB[i];\n        for (int x = minX; x <= maxX; x++) {\n            int lim = x - lb[i-1];\n            if (lim < 0) continue;\n            int val = prefVal[lim];\n            if (val <= NEG / 2) continue;\n            int p = prefPos[lim];\n\n            int bonus = (oldSet[x] ? MATCH : 0) - abs(x - targetCut[i-1]);\n            int nv = val + bonus;\n            if (nv > cur[x]) {\n                cur[x] = nv;\n                par[i][x] = (short)p;\n            }\n        }\n        prev.swap(cur);\n    }\n\n    int bestP = -1, bestVal = NEG;\n    int maxP = W - lb[m-1];\n    for (int p = 0; p <= maxP; p++) {\n        if (prev[p] > bestVal) {\n            bestVal = prev[p];\n            bestP = p;\n        }\n    }\n\n    if (bestP < 0) return project_near(ref, lb);\n\n    vector<int> cuts(m + 1);\n    cuts[0] = 0;\n    cuts[m] = W;\n    cuts[m-1] = bestP;\n\n    for (int i = m - 1; i >= 1; i--) {\n        int p = par[i][cuts[i]];\n        if (p < 0) return project_near(ref, lb);\n        cuts[i-1] = p;\n    }\n\n    vector<int> w(m);\n    for (int i = 0; i < m; i++) {\n        w[i] = cuts[i+1] - cuts[i];\n        if (w[i] < lb[i] || w[i] <= 0) return project_near(ref, lb);\n    }\n    return normalize_widths(w);\n}\n\n/* ---------- daily shelves ---------- */\n\nstruct TmpRow {\n    int l, r, h;\n};\n\nbool get_daily_rows(int d, int mode, vector<TmpRow>& rows) {\n    rows.clear();\n\n    if (mode == 0) {\n        vector<int> dp(N + 1, SEG_INF), cnt(N + 1, SEG_INF), par(N + 1, -1);\n        dp[0] = 0;\n        cnt[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            for (int i = 0; i < j; i++) {\n                int h = dayHSeg[d][i][j];\n                if (h >= SEG_INF || dp[i] >= SEG_INF) continue;\n                int nv = dp[i] + h;\n                int nc = cnt[i] + 1;\n                if (nv < dp[j] || (nv == dp[j] && nc < cnt[j])) {\n                    dp[j] = nv;\n                    cnt[j] = nc;\n                    par[j] = i;\n                }\n            }\n        }\n\n        if (dp[N] > W) return false;\n\n        int cur = N;\n        while (cur > 0) {\n            int p = par[cur];\n            if (p < 0) return false;\n            rows.push_back({p, cur, dayHSeg[d][p][cur]});\n            cur = p;\n        }\n        reverse(rows.begin(), rows.end());\n        return true;\n    } else {\n        const int BIG = 1'000'000'000;\n        vector<vector<int>> dp(N + 1, vector<int>(W + 1, BIG));\n        vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n        vector<vector<short>> parU(N + 1, vector<short>(W + 1, -1));\n\n        dp[0][0] = 0;\n\n        for (int i = 0; i < N; i++) {\n            for (int used = 0; used <= W; used++) {\n                if (dp[i][used] >= BIG) continue;\n\n                for (int j = i + 1; j <= N; j++) {\n                    int h = dayHSeg[d][i][j];\n                    if (h >= SEG_INF) continue;\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    int len = j - i;\n                    int add = 1000 + h * max(0, len - 1);\n                    int nv = dp[i][used] + add;\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parU[j][nu] = (short)used;\n                    }\n                }\n            }\n        }\n\n        int bestU = -1, best = BIG;\n        for (int u = 0; u <= W; u++) {\n            if (dp[N][u] < best) {\n                best = dp[N][u];\n                bestU = u;\n            }\n        }\n        if (bestU < 0) return false;\n\n        int cur = N, used = bestU;\n        while (cur > 0) {\n            int p = parI[cur][used];\n            int pu = parU[cur][used];\n            if (p < 0 || pu < 0) return false;\n            rows.push_back({p, cur, dayHSeg[d][p][cur]});\n            cur = p;\n            used = pu;\n        }\n        reverse(rows.begin(), rows.end());\n        return true;\n    }\n}\n\nbool make_daily_shelf_layout_day(int d, int mode, int slackMode, bool compact, vector<Rect>& layout) {\n    vector<TmpRow> rows;\n    if (!get_daily_rows(d, mode, rows)) return false;\n\n    int sumH = 0;\n    for (auto& row : rows) sumH += row.h;\n    if (sumH > W) return false;\n\n    int slack = W - sumH;\n    if (!compact && slack > 0) {\n        int idx = (int)rows.size() - 1;\n        if (slackMode == 1) {\n            int bestCnt = 1e9;\n            for (int i = 0; i < (int)rows.size(); i++) {\n                int cnt = rows[i].r - rows[i].l - 1;\n                if (cnt <= bestCnt) {\n                    bestCnt = cnt;\n                    idx = i;\n                }\n            }\n        }\n        rows[idx].h += slack;\n    }\n\n    layout.assign(N, Rect{0, 0, 1, 1});\n\n    int y = 0;\n    for (auto& row : rows) {\n        int m = row.r - row.l;\n        vector<int> lb(m);\n        vector<double> weights(m);\n\n        for (int i = 0; i < m; i++) {\n            int k = row.l + i;\n            lb[i] = max(1, ceil_div_int(A[d][k], row.h));\n            weights[i] = max(1, A[d][k]);\n        }\n\n        vector<int> w = allocate_by_weights(lb, weights);\n        int x = 0;\n        for (int i = 0; i < m; i++) {\n            int k = row.l + i;\n            layout[k] = {y, x, y + row.h, x + w[i]};\n            x += w[i];\n        }\n        if (x != W) return false;\n        y += row.h;\n    }\n\n    return y <= W;\n}\n\nvoid add_daily_shelf_candidates(double TL) {\n    if (dayCand.empty()) init_day_candidates();\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) break;\n\n        vector<Rect> layout;\n        for (int mode = 0; mode <= 1; mode++) {\n            for (int slack = 0; slack <= 1; slack++) {\n                if (make_daily_shelf_layout_day(d, mode, slack, false, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n            }\n            if (make_daily_shelf_layout_day(d, mode, 0, true, layout)) {\n                add_unique_layout_cap(dayCand[d], layout, 160);\n            }\n        }\n    }\n}\n\nbool make_daily_shelf_solution(int mode, int slackMode, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n    for (int d = 0; d < D; d++) {\n        vector<Rect> layout;\n        if (!make_daily_shelf_layout_day(d, mode, slackMode, false, layout)) return false;\n        sol[d] = layout;\n    }\n    return true;\n}\n\n/* ---------- variable/fixed shelf candidates ---------- */\n\nvector<pair<int,int>> make_global_dp_partition(int type, int lambda) {\n    const long long BIG = (1LL << 60);\n    vector<long long> dp(N + 1, BIG);\n    vector<int> par(N + 1, -1);\n    dp[0] = 0;\n\n    for (int j = 1; j <= N; j++) {\n        for (int i = 0; i < j; i++) {\n            bool ok = true;\n            long long sumH = 0;\n            int maxH = 0;\n            for (int d = 0; d < D; d++) {\n                int h = dayHSeg[d][i][j];\n                if (h >= SEG_INF) {\n                    ok = false;\n                    break;\n                }\n                sumH += h;\n                maxH = max(maxH, h);\n            }\n            if (!ok || dp[i] >= BIG) continue;\n\n            long long segCost;\n            if (type == 0) segCost = sumH;\n            else if (type == 1) segCost = 1LL * maxH * D;\n            else segCost = sumH + 1LL * maxH * D / 2;\n\n            segCost += lambda;\n            long long nv = dp[i] + segCost;\n            if (nv < dp[j]) {\n                dp[j] = nv;\n                par[j] = i;\n            }\n        }\n    }\n\n    if (par[N] < 0) return {};\n\n    vector<pair<int,int>> g;\n    int cur = N;\n    while (cur > 0) {\n        int p = par[cur];\n        if (p < 0) return {};\n        g.push_back({p, cur});\n        cur = p;\n    }\n    reverse(g.begin(), g.end());\n    return g;\n}\n\nvector<pair<int,int>> make_equal_partition_groups(int R) {\n    R = clamp_int(R, 1, N);\n    vector<pair<int,int>> g;\n    int prev = 0;\n    for (int i = 0; i < R; i++) {\n        int en = (i == R - 1 ? N : (int)llround(1.0 * N * (i + 1) / R));\n        en = clamp_int(en, prev + 1, N - (R - i - 1));\n        g.push_back({prev, en});\n        prev = en;\n    }\n    return g;\n}\n\nvector<pair<int,int>> make_area_partition_groups(const vector<int>& base, int R) {\n    R = clamp_int(R, 1, N);\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> g;\n    int prev = 0;\n    for (int i = 0; i < R; i++) {\n        int en;\n        if (i == R - 1) {\n            en = N;\n        } else {\n            double target = pref[N] * (i + 1) / R;\n            en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            en = clamp_int(en, prev + 1, N - (R - i - 1));\n        }\n        g.push_back({prev, en});\n        prev = en;\n    }\n    return g;\n}\n\nvector<pair<int,int>> make_daily_partition_groups(int d, int mode) {\n    vector<TmpRow> rows;\n    if (!get_daily_rows(d, mode, rows)) return {};\n    vector<pair<int,int>> g;\n    for (auto& row : rows) g.push_back({row.l, row.r});\n    return g;\n}\n\nbool valid_partition_groups(const vector<pair<int,int>>& g) {\n    if (g.empty()) return false;\n    int cur = 0;\n    for (auto [l, r] : g) {\n        if (l != cur || l >= r || r > N) return false;\n        cur = r;\n    }\n    return cur == N;\n}\n\nstring partition_key(const vector<pair<int,int>>& g) {\n    string s;\n    for (auto [l, r] : g) {\n        s += to_string(l);\n        s += '-';\n        s += to_string(r);\n        s += ',';\n    }\n    return s;\n}\n\nbool build_fixed_variable_shelf_solution(\n    const vector<pair<int,int>>& groups,\n    vector<vector<Rect>>& sol,\n    bool overlap,\n    int targetType\n) {\n    if (!valid_partition_groups(groups)) return false;\n\n    int R = (int)groups.size();\n    vector<int> maxH(R, 0);\n    vector<double> avgH(R, 1.0), weightH(R, 1.0);\n\n    for (int ri = 0; ri < R; ri++) {\n        auto [l, r] = groups[ri];\n        long long sum = 0;\n        for (int d = 0; d < D; d++) {\n            int h = dayHSeg[d][l][r];\n            if (h >= SEG_INF) return false;\n            maxH[ri] = max(maxH[ri], h);\n            sum += h;\n        }\n        avgH[ri] = max(1.0, (double)sum / D);\n        weightH[ri] = max(1.0, avgH[ri] * max(1, r - l - 1));\n    }\n\n    for (int d = 0; d < D; d++) {\n        int sumL = 0;\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            sumL += dayHSeg[d][l][r];\n        }\n        if (sumL > W) return false;\n    }\n\n    int sumMax = accumulate(maxH.begin(), maxH.end(), 0);\n    vector<int> staticTarget;\n    if (sumMax <= W) staticTarget = allocate_by_weights(maxH, weightH);\n    else {\n        vector<int> ones(R, 1);\n        staticTarget = allocate_by_weights(ones, avgH);\n    }\n\n    sol.assign(D, vector<Rect>(N));\n    vector<int> prevH;\n    vector<vector<int>> prevWidths(R);\n\n    for (int d = 0; d < D; d++) {\n        vector<int> lowerH(R);\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            lowerH[ri] = dayHSeg[d][l][r];\n        }\n\n        vector<int> h;\n        if (d == 0) h = project_near(staticTarget, lowerH);\n        else h = (overlap ? choose_widths_overlap(prevH, lowerH, staticTarget) : project_near(prevH, lowerH));\n\n        int y = 0;\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            int m = r - l;\n            vector<int> lb(m);\n            int sumLB = 0;\n            for (int i = 0; i < m; i++) {\n                int k = l + i;\n                lb[i] = max(1, ceil_div_int(A[d][k], h[ri]));\n                sumLB += lb[i];\n            }\n            if (sumLB > W) return false;\n\n            vector<int> targetW = make_target_widths(l, r, h[ri], targetType);\n            vector<int> ref = (d == 0 || prevWidths[ri].empty() ? targetW : prevWidths[ri]);\n            vector<int> w = (overlap ? choose_widths_overlap(ref, lb, targetW) : project_near(ref, lb));\n\n            int x = 0;\n            for (int i = 0; i < m; i++) {\n                int k = l + i;\n                sol[d][k] = {y, x, y + h[ri], x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            y += h[ri];\n            prevWidths[ri] = w;\n        }\n        if (y != W) return false;\n        prevH = h;\n    }\n\n    return true;\n}\n\nvoid run_daily_variable_shelf_candidates() {\n    vector<vector<Rect>> sol;\n\n    for (int mode = 0; mode <= 1; mode++) {\n        for (int slack = 0; slack <= 1; slack++) {\n            if (bestScore == 0) return;\n            if (make_daily_shelf_solution(mode, slack, sol)) consider_solution(sol);\n        }\n    }\n\n    if (bestScore == 0) return;\n\n    vector<vector<pair<int,int>>> parts;\n    set<string> seen;\n\n    auto addPart = [&](const vector<pair<int,int>>& g) {\n        if (!valid_partition_groups(g)) return;\n        string key = partition_key(g);\n        if (seen.insert(key).second) parts.push_back(g);\n    };\n\n    vector<int> lambdas = {0, 300, 1000, 3000, 10000};\n    for (int lam : lambdas) {\n        addPart(make_global_dp_partition(0, lam));\n        addPart(make_global_dp_partition(1, lam));\n    }\n\n    vector<int> Rs;\n    auto addR = [&](int r) {\n        r = clamp_int(r, 1, N);\n        if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n    };\n\n    int sq = max(1, (int)llround(sqrt((double)N)));\n    addR(sq);\n    addR(sq + 1);\n    addR(N / 4);\n    addR(N / 3);\n    addR(N / 2);\n    addR(2 * sq);\n\n    for (int r : Rs) {\n        addPart(make_equal_partition_groups(r));\n        addPart(make_area_partition_groups(meanDemand, r));\n        addPart(make_area_partition_groups(p90Demand, r));\n        addPart(make_area_partition_groups(optStaticDemand, r));\n    }\n\n    addPart(make_daily_partition_groups(0, 1));\n    addPart(make_daily_partition_groups(D / 2, 1));\n    addPart(make_daily_partition_groups(D - 1, 1));\n\n    const double TL_NEW = 1.75;\n    int idx = 0;\n    for (auto& g : parts) {\n        if (bestScore == 0 || elapsed_sec() > TL_NEW) break;\n\n        if (build_fixed_variable_shelf_solution(g, sol, false, 1)) consider_solution(sol);\n        if (bestScore == 0) break;\n\n        if (idx < 7 && elapsed_sec() < TL_NEW) {\n            if (build_fixed_variable_shelf_solution(g, sol, true, 1)) consider_solution(sol);\n        }\n        idx++;\n    }\n}\n\nstruct ShelfRowChoice {\n    int l, r, h;\n    int targetType;\n    bool soft;\n};\n\nbool build_fixed_shelf_solution(const vector<ShelfRowChoice>& rows, vector<vector<Rect>>& sol, bool overlap) {\n    sol.assign(D, vector<Rect>(N));\n    int y = 0;\n\n    for (const auto& row : rows) {\n        if (y + row.h > W) return false;\n\n        vector<int> target = make_target_widths(row.l, row.r, row.h, row.targetType);\n        vector<int> prev;\n\n        for (int d = 0; d < D; d++) {\n            vector<int> ref = (d == 0 ? target : prev);\n            vector<int> lb;\n            make_day_lb(row.l, row.r, row.h, d, ref, row.soft, lb);\n\n            int sumLB = accumulate(lb.begin(), lb.end(), 0);\n            vector<int> w;\n            if (sumLB <= W) w = (overlap ? choose_widths_overlap(ref, lb, target) : project_near(ref, lb));\n            else w = shortage_widths(ref, row.l, row.r, row.h, d);\n\n            int x = 0;\n            for (int i = 0; i < row.r - row.l; i++) {\n                int k = row.l + i;\n                if (w[i] <= 0) return false;\n                sol[d][k] = {y, x, y + row.h, x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            prev = w;\n        }\n        y += row.h;\n    }\n\n    return y <= W;\n}\n\nvoid run_fixed_shelf_dp() {\n    for (int l = 0; l <= N; l++) {\n        for (int r = 0; r <= N; r++) {\n            hMinSeg[l][r] = hStaticSeg[l][r] = SEG_INF;\n            segOptCnt[l][r] = 0;\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            bool ok = true;\n            int mx = 0;\n            for (int d = 0; d < D; d++) {\n                if (dayHSeg[d][l][r] >= SEG_INF) {\n                    ok = false;\n                    break;\n                }\n                mx = max(mx, dayHSeg[d][l][r]);\n            }\n            hMinSeg[l][r] = ok ? mx : SEG_INF;\n            hStaticSeg[l][r] = compute_hstatic_segment(l, r);\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            int hm = hMinSeg[l][r];\n            if (hm >= SEG_INF) continue;\n\n            vector<int> hs;\n            auto addH = [&](int h) {\n                if (h < 1 || h > W) return;\n                if (find(hs.begin(), hs.end(), h) == hs.end()) hs.push_back(h);\n            };\n\n            addH(hm);\n\n            int hsStatic = hStaticSeg[l][r];\n            if (hsStatic < SEG_INF) {\n                addH(hsStatic);\n                if (hsStatic - hm >= 2) addH((hm + hsStatic) / 2);\n            } else if (hm < W) {\n                addH((hm + W) / 2);\n            }\n\n            sort(hs.begin(), hs.end());\n            if ((int)hs.size() > MAX_SEG_OPT) hs.resize(MAX_SEG_OPT);\n\n            for (int h : hs) {\n                int idx = segOptCnt[l][r]++;\n                segOptH[l][r][idx] = h;\n\n                long long c;\n                int t;\n                bool s;\n                best_row_option(l, r, h, c, t, s);\n\n                segOptCost[l][r][idx] = c;\n                segOptTarget[l][r][idx] = t;\n                segOptSoft[l][r][idx] = s;\n            }\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, BIG));\n    vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> parUsed(N + 1, vector<short>(W + 1, -1));\n    vector<vector<signed char>> parOpt(N + 1, vector<signed char>(W + 1, -1));\n\n    dp[0][0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        for (int used = 0; used <= W; used++) {\n            if (dp[i][used] >= BIG / 2) continue;\n\n            for (int j = i + 1; j <= N; j++) {\n                for (int oi = 0; oi < segOptCnt[i][j]; oi++) {\n                    int h = segOptH[i][j][oi];\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    long long nv = dp[i][used] + segOptCost[i][j][oi];\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parUsed[j][nu] = (short)used;\n                        parOpt[j][nu] = (signed char)oi;\n                    }\n                }\n            }\n        }\n    }\n\n    long long best = BIG;\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 < 0) return;\n\n    vector<ShelfRowChoice> rows;\n    int curI = N, curH = bestH;\n    while (curI > 0) {\n        int pi = parI[curI][curH];\n        int pu = parUsed[curI][curH];\n        int oi = parOpt[curI][curH];\n        if (pi < 0 || pu < 0 || oi < 0) return;\n\n        rows.push_back({\n            pi,\n            curI,\n            segOptH[pi][curI][oi],\n            segOptTarget[pi][curI][oi],\n            segOptSoft[pi][curI][oi]\n        });\n\n        curI = pi;\n        curH = pu;\n    }\n    reverse(rows.begin(), rows.end());\n\n    vector<vector<Rect>> sol;\n    if (build_fixed_shelf_solution(rows, sol, false)) consider_solution(sol);\n    if (bestScore == 0) return;\n    if (build_fixed_shelf_solution(rows, sol, true)) consider_solution(sol);\n}\n\n/* ---------- static horizontal strips ---------- */\n\nvoid consider_static_horizontal_knapsack() {\n    const long long BIG = (1LL << 62);\n\n    vector<vector<long long>> cost(N, vector<long long>(W + 1, 0));\n    for (int k = 0; k < N; k++) {\n        for (int h = 1; h <= W; h++) {\n            long long c = 0;\n            for (int d = 0; d < D; d++) {\n                long long area = 1LL * h * W;\n                if (area < A[d][k]) c += 100LL * (A[d][k] - area);\n            }\n            cost[k][h] = c;\n        }\n    }\n\n    vector<long long> dp(W + 1, BIG), ndp(W + 1, BIG);\n    vector<vector<short>> par(N + 1, vector<short>(W + 1, -1));\n    dp[0] = 0;\n\n    for (int k = 0; k < N; k++) {\n        fill(ndp.begin(), ndp.end(), BIG);\n        int remainItems = N - k - 1;\n        for (int used = 0; used <= W; used++) {\n            if (dp[used] >= BIG / 2) continue;\n            int maxh = W - used - remainItems;\n            for (int h = 1; h <= maxh; h++) {\n                long long nv = dp[used] + cost[k][h];\n                int nu = used + h;\n                if (nv < ndp[nu]) {\n                    ndp[nu] = nv;\n                    par[k+1][nu] = (short)h;\n                }\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    long long best = BIG;\n    int bestUsed = -1;\n    for (int used = 0; used <= W; used++) {\n        if (dp[used] < best) {\n            best = dp[used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0) return;\n\n    vector<int> h(N);\n    int used = bestUsed;\n    for (int k = N; k >= 1; k--) {\n        int x = par[k][used];\n        if (x <= 0) return;\n        h[k-1] = x;\n        used -= x;\n    }\n\n    vector<Rect> one(N);\n    int y = 0;\n    for (int k = 0; k < N; k++) {\n        one[k] = {y, 0, y + h[k], W};\n        y += h[k];\n    }\n\n    vector<vector<Rect>> sol(D, one);\n    consider_solution(sol);\n}\n\n/* ---------- old slicing candidate handling ---------- */\n\nconst double TL_CAND = 2.65;\nconst double TL_POST = 2.90;\n\nvoid process_tree(Tree t, const vector<int>& base, int level) {\n    if (elapsed_sec() > TL_CAND || bestScore == 0) return;\n\n    vector<int> target = scale_to_limit(base);\n    assign_targets(t, target);\n\n    vector<vector<Rect>> sol;\n\n    if (elapsed_sec() < TL_CAND && make_static_solution(t, target, false, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, globalMaxDemand, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_PREV, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 1 && elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_STATIC_ABS, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, target, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_solution(t, true, POLICY_PREV, sol)) {\n        consider_solution(sol);\n    }\n}\n\nvoid try_all_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto orig = bestSol;\n    for (int t = 0; t < D && elapsed_sec() < TL_POST; t++) {\n        vector<vector<Rect>> sol(D, orig[t]);\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n}\n\nvoid smooth_by_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto sol = bestSol;\n\n    auto local_cost = [&](int d, const vector<Rect>& cand) -> long long {\n        long long c = shortage_day(cand, d);\n        if (d > 0) c += transition_cost(sol[d-1], cand);\n        if (d + 1 < D) c += transition_cost(cand, sol[d+1]);\n        return c;\n    };\n\n    for (int pass = 0; pass < 5 && elapsed_sec() < TL_POST; pass++) {\n        bool improved = false;\n\n        for (int d = 0; d < D && elapsed_sec() < TL_POST; d++) {\n            long long old = local_cost(d, sol[d]);\n\n            if (d > 0) {\n                long long nw = local_cost(d, sol[d-1]);\n                if (nw < old) {\n                    sol[d] = sol[d-1];\n                    old = nw;\n                    improved = true;\n                }\n            }\n\n            if (d + 1 < D) {\n                long long nw = local_cost(d, sol[d+1]);\n                if (nw < old) {\n                    sol[d] = sol[d+1];\n                    old = nw;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    long long curScore = evaluate_solution(sol);\n    if (curScore < bestScore) {\n        bestScore = curScore;\n        bestSol = sol;\n    }\n}\n\n/* ---------- main ---------- */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int inputW;\n    cin >> inputW >> 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    globalMaxDemand.assign(N, 1);\n    meanDemand.assign(N, 1);\n    medDemand.assign(N, 1);\n    p75Demand.assign(N, 1);\n    p90Demand.assign(N, 1);\n\n    for (int k = 0; k < N; k++) {\n        long long s = 0;\n        vector<int> vals;\n        for (int d = 0; d < D; d++) {\n            s += A[d][k];\n            vals.push_back(A[d][k]);\n            globalMaxDemand[k] = max(globalMaxDemand[k], A[d][k]);\n        }\n        sort(vals.begin(), vals.end());\n        meanDemand[k] = max(1, (int)(s / D));\n        medDemand[k] = vals[D / 2];\n        p75Demand[k] = vals[min(D - 1, (int)llround(0.75 * (D - 1)))];\n        p90Demand[k] = vals[min(D - 1, (int)llround(0.90 * (D - 1)))];\n    }\n\n    optStaticDemand = compute_opt_static_area();\n\n    bestSol = make_fallback();\n    bestScore = evaluate_solution(bestSol);\n\n    consider_static_horizontal_knapsack();\n\n    precompute_day_segments();\n\n    init_day_candidates();\n    generate_day_slicing_candidates(1.23);\n    add_daily_shelf_candidates(1.36);\n    add_shrunk_day_candidates(1.43);\n    add_static_library_candidates(6, 1.50, true);\n    run_day_candidate_dp(false, 1.60);\n\n    if (bestScore != 0) run_daily_variable_shelf_candidates();\n    if (bestScore != 0) run_fixed_shelf_dp();\n\n    if (bestScore != 0) {\n        vector<pair<int,int>> quick = {{0,0}, {2,0}, {0,1}};\n        for (auto [sm, om] : quick) {\n            if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n            Tree t = build_aspect_tree(optStaticDemand, sm, om);\n            process_tree(t, optStaticDemand, 2);\n        }\n    }\n\n    if (bestScore != 0) {\n        vector<vector<int>> bases;\n        bases.push_back(globalMaxDemand);\n        bases.push_back(p90Demand);\n        bases.push_back(p75Demand);\n        bases.push_back(meanDemand);\n        bases.push_back(medDemand);\n\n        vector<pair<int,int>> combos = {\n            {0, 0}, {2, 0}, {1, 0}, {0, 1}, {0, 2}\n        };\n\n        for (int bi = 0; bi < (int)bases.size(); bi++) {\n            for (int ci = 0; ci < (int)combos.size(); ci++) {\n                if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n\n                int splitMode = combos[ci].first;\n                int orientMode = combos[ci].second;\n                Tree t = build_aspect_tree(bases[bi], splitMode, orientMode);\n\n                int level = 1;\n                if (ci == 0 && bi <= 3) level = 2;\n                process_tree(t, bases[bi], level);\n            }\n            if (bestScore == 0) break;\n        }\n\n        vector<int> Rs;\n        auto addR = [&](int r) {\n            r = clamp_int(r, 1, N);\n            if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n        };\n\n        int sq = max(1, (int)llround(sqrt((double)N)));\n        addR(sq);\n        addR(sq + 1);\n        addR(sq - 1);\n        addR(N / 4);\n        addR(N / 3);\n        addR(N / 2);\n        addR(2 * sq);\n        addR(5);\n        addR(8);\n        addR(10);\n        addR(15);\n        addR(20);\n        addR(N);\n        addR(1);\n\n        vector<int> shelfBaseIds = {0, 1, 3, 2};\n        for (int bi : shelfBaseIds) {\n            for (int groupMode = 0; groupMode <= 1; groupMode++) {\n                for (int r : Rs) {\n                    if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n                    Tree t = build_shelf_tree(bases[bi], r, groupMode, 0);\n                    int level = (groupMode == 0 ? 1 : 0);\n                    process_tree(t, bases[bi], level);\n                }\n                if (bestScore == 0) break;\n            }\n            if (bestScore == 0) break;\n        }\n    }\n\n    add_shrunk_day_candidates(2.74);\n    add_static_library_candidates(12, 2.80, true);\n    run_day_candidate_dp(true, 2.86);\n    copy_library_dp(2.89);\n\n    try_all_copy();\n    smooth_by_copy();\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            const Rect& r = bestSol[d][k];\n            cout << r.y0 << ' ' << r.x0 << ' ' << r.y1 << ' ' << r.x1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int BN = 9;\nstatic const int AP = 7;\nstatic const int KMAX = 81;\nstatic const int MOD = 998244353;\nstatic const int MAX_MULTI = 6;\n\nint N, M, K;\narray<int, KMAX> initBoard;\nlong long initScore = 0;\nint stampVal[20][9];\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\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} timer;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n} rng(123456789);\n\nstruct Action {\n    int m, p, q;\n    int anchor;\n    int idx[9];\n    int val[9];\n    uint64_t maskLo, maskHi;\n};\n\nstruct Option {\n    unsigned char cnt;\n    unsigned char s1, s2;\n    int val[9];\n};\n\nstruct MultiOption {\n    unsigned char cnt;\n    unsigned char st[MAX_MULTI];\n    int val[9];\n};\n\nstruct PairInfo {\n    unsigned short a, b;\n    unsigned char len;\n    unsigned char idx[18];\n    int val[18];\n};\n\nvector<Action> actions;\narray<array<int, 9>, 49> anchorCells;\nvector<int> cellCovers[81];\nvector<Option> options;\nvector<MultiOption> multiOpts[MAX_MULTI + 1];\nbool anchorOverlap[49][49];\nvector<PairInfo> overlapPairs;\nstatic int pairIndexMat[1000][1000];\n\ninline bool actionCoversCell(int aid, int cell) {\n    const Action& a = actions[aid];\n    if (cell < 64) return (a.maskLo >> cell) & 1ULL;\n    return (a.maskHi >> (cell - 64)) & 1ULL;\n}\n\ninline long long evalAdd(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalSub(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applyAdd(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applySub(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalPairInfo(const array<int, KMAX>& b, const PairInfo& pi) {\n    long long delta = 0;\n    for (int t = 0; t < pi.len; t++) {\n        int idx = pi.idx[t];\n        int old = b[idx];\n        int nv = old + pi.val[t];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalAdd2(const array<int, KMAX>& b, int a, int c) {\n    if (a < 0 && c < 0) return 0;\n    if (a < 0) return evalAdd(b, c);\n    if (c < 0) return evalAdd(b, a);\n\n    if (!anchorOverlap[actions[a].anchor][actions[c].anchor]) {\n        return evalAdd(b, a) + evalAdd(b, c);\n    }\n\n    int id = pairIndexMat[a][c];\n    if (id >= 0) return evalPairInfo(b, overlapPairs[id]);\n\n    int idxs[18];\n    int vals[18];\n    int len = 0;\n\n    auto addCell = [&](int idx, int val) {\n        for (int t = 0; t < len; t++) {\n            if (idxs[t] == idx) {\n                int nv = vals[t] + val;\n                if (nv >= MOD) nv -= MOD;\n                vals[t] = nv;\n                return;\n            }\n        }\n        idxs[len] = idx;\n        vals[len] = val;\n        len++;\n    };\n\n    for (int k = 0; k < 9; k++) addCell(actions[a].idx[k], actions[a].val[k]);\n    for (int k = 0; k < 9; k++) addCell(actions[c].idx[k], actions[c].val[k]);\n\n    long long delta = 0;\n    for (int t = 0; t < len; t++) {\n        int old = b[idxs[t]];\n        int nv = old + vals[t];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalMultiAtAnchor(const array<int, KMAX>& b, int anc, const MultiOption& op) {\n    long long delta = 0;\n    const auto& cells = anchorCells[anc];\n    for (int k = 0; k < 9; k++) {\n        int old = b[cells[k]];\n        int nv = old + op.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\nlong long combLL(int n, int r) {\n    if (r < 0 || r > n) return 0;\n    r = min(r, n - r);\n    long long res = 1;\n    for (int i = 1; i <= r; i++) {\n        res = res * (n - r + i) / i;\n    }\n    return res;\n}\n\nvoid genMultiRec(int target, int start, vector<int>& chosen, array<int, 9>& vals) {\n    if ((int)chosen.size() == target) {\n        MultiOption op{};\n        op.cnt = (unsigned char)target;\n        for (int i = 0; i < MAX_MULTI; i++) op.st[i] = 0;\n        for (int i = 0; i < target; i++) op.st[i] = (unsigned char)chosen[i];\n        for (int k = 0; k < 9; k++) op.val[k] = vals[k];\n        multiOpts[target].push_back(op);\n        return;\n    }\n\n    for (int m = start; m < M; m++) {\n        auto oldVals = vals;\n        chosen.push_back(m);\n        for (int k = 0; k < 9; k++) {\n            int v = vals[k] + stampVal[m][k];\n            if (v >= MOD) v -= MOD;\n            vals[k] = v;\n        }\n        genMultiRec(target, m, chosen, vals);\n        chosen.pop_back();\n        vals = oldVals;\n    }\n}\n\nvoid precomputeMultiOptions() {\n    for (int c = 0; c <= MAX_MULTI; c++) multiOpts[c].clear();\n\n    MultiOption zero{};\n    zero.cnt = 0;\n    for (int i = 0; i < MAX_MULTI; i++) zero.st[i] = 0;\n    for (int k = 0; k < 9; k++) zero.val[k] = 0;\n    multiOpts[0].push_back(zero);\n\n    for (int target = 1; target <= MAX_MULTI; target++) {\n        multiOpts[target].reserve((size_t)combLL(M + target - 1, target));\n        vector<int> chosen;\n        array<int, 9> vals{};\n        genMultiRec(target, 0, chosen, vals);\n    }\n}\n\nvoid precomputeOverlapPairs() {\n    int A = (int)actions.size();\n    for (int i = 0; i < A; i++) {\n        for (int j = 0; j < A; j++) pairIndexMat[i][j] = -1;\n    }\n\n    overlapPairs.clear();\n    overlapPairs.reserve(180000);\n\n    for (int a = 0; a < A; a++) {\n        for (int b = a; b < A; b++) {\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) continue;\n\n            PairInfo pi{};\n            pi.a = (unsigned short)a;\n            pi.b = (unsigned short)b;\n            pi.len = 0;\n\n            auto addCell = [&](int idx, int val) {\n                for (int t = 0; t < pi.len; t++) {\n                    if (pi.idx[t] == idx) {\n                        int nv = pi.val[t] + val;\n                        if (nv >= MOD) nv -= MOD;\n                        pi.val[t] = nv;\n                        return;\n                    }\n                }\n                pi.idx[pi.len] = (unsigned char)idx;\n                pi.val[pi.len] = val;\n                pi.len++;\n            };\n\n            for (int k = 0; k < 9; k++) addCell(actions[a].idx[k], actions[a].val[k]);\n            for (int k = 0; k < 9; k++) addCell(actions[b].idx[k], actions[b].val[k]);\n\n            int id = (int)overlapPairs.size();\n            overlapPairs.push_back(pi);\n            pairIndexMat[a][b] = id;\n            pairIndexMat[b][a] = id;\n        }\n    }\n}\n\nvoid precompute() {\n    actions.reserve(49 * M);\n\n    for (int p = 0; p < AP; p++) {\n        for (int q = 0; q < AP; q++) {\n            int aid = p * AP + q;\n            int t = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    anchorCells[aid][t++] = (p + di) * BN + (q + dj);\n                }\n            }\n        }\n    }\n\n    for (int a = 0; a < 49; a++) {\n        int p1 = a / AP, q1 = a % AP;\n        for (int b = 0; b < 49; b++) {\n            int p2 = b / AP, q2 = b % AP;\n            anchorOverlap[a][b] = (abs(p1 - p2) <= 2 && abs(q1 - q2) <= 2);\n        }\n    }\n\n    for (int anc = 0; anc < 49; anc++) {\n        int p = anc / AP;\n        int q = anc % AP;\n\n        for (int m = 0; m < M; m++) {\n            Action a;\n            a.m = m;\n            a.p = p;\n            a.q = q;\n            a.anchor = anc;\n            a.maskLo = a.maskHi = 0;\n\n            for (int k = 0; k < 9; k++) {\n                int idx = anchorCells[anc][k];\n                a.idx[k] = idx;\n                a.val[k] = stampVal[m][k];\n                if (idx < 64) a.maskLo |= 1ULL << idx;\n                else a.maskHi |= 1ULL << (idx - 64);\n            }\n\n            actions.push_back(a);\n        }\n    }\n\n    for (int r = 0; r < BN; r++) {\n        for (int c = 0; c < BN; c++) {\n            int cell = r * BN + c;\n            for (int p = max(0, r - 2); p <= min(AP - 1, r); p++) {\n                for (int q = max(0, c - 2); q <= min(AP - 1, c); q++) {\n                    cellCovers[cell].push_back(p * AP + q);\n                }\n            }\n        }\n    }\n\n    Option none{};\n    none.cnt = 0;\n    none.s1 = none.s2 = 0;\n    for (int k = 0; k < 9; k++) none.val[k] = 0;\n    options.push_back(none);\n\n    for (int m = 0; m < M; m++) {\n        Option op{};\n        op.cnt = 1;\n        op.s1 = m;\n        op.s2 = 0;\n        for (int k = 0; k < 9; k++) op.val[k] = stampVal[m][k];\n        options.push_back(op);\n    }\n\n    for (int a = 0; a < M; a++) {\n        for (int b = a; b < M; b++) {\n            Option op{};\n            op.cnt = 2;\n            op.s1 = a;\n            op.s2 = b;\n            for (int k = 0; k < 9; k++) {\n                int v = stampVal[a][k] + stampVal[b][k];\n                if (v >= MOD) v -= MOD;\n                op.val[k] = v;\n            }\n            options.push_back(op);\n        }\n    }\n\n    precomputeMultiOptions();\n    precomputeOverlapPairs();\n}\n\nstruct Solution {\n    array<int, KMAX> board;\n    array<int, KMAX> slot;\n    long long score;\n};\n\nvoid rebuild(Solution& sol) {\n    sol.board = initBoard;\n    sol.score = initScore;\n    for (int i = 0; i < K; i++) {\n        if (sol.slot[i] >= 0) {\n            sol.score += applyAdd(sol.board, sol.slot[i]);\n        }\n    }\n}\n\nSolution makeSolutionFromOps(const vector<int>& ops) {\n    Solution sol;\n    sol.slot.fill(-1);\n    int L = min((int)ops.size(), K);\n    for (int i = 0; i < L; i++) sol.slot[i] = ops[i];\n    rebuild(sol);\n    return sol;\n}\n\nSolution greedySolution() {\n    Solution sol;\n    sol.board = initBoard;\n    sol.slot.fill(-1);\n    sol.score = initScore;\n\n    for (int step = 0; step < K; step++) {\n        long long bestDelta = 0;\n        int best = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long d = evalAdd(sol.board, aid);\n            if (d > bestDelta) {\n                bestDelta = d;\n                best = aid;\n            }\n        }\n\n        if (best == -1) break;\n\n        sol.slot[step] = best;\n        sol.score += applyAdd(sol.board, best);\n    }\n\n    return sol;\n}\n\nvoid coordinateDescent(Solution& sol, int maxSweeps, double timeLimit) {\n    array<int, KMAX> ord;\n    for (int i = 0; i < K; i++) ord[i] = i;\n\n    for (int sweep = 0; sweep < maxSweeps; sweep++) {\n        if (timer.elapsed() > timeLimit) break;\n\n        for (int i = K - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int oi = 0; oi < K; oi++) {\n            if ((oi & 15) == 0 && timer.elapsed() > timeLimit) return;\n\n            int pos = ord[oi];\n            int old = sol.slot[pos];\n            long long oldScore = sol.score;\n\n            if (old >= 0) {\n                sol.score += applySub(sol.board, old);\n            }\n\n            long long base = sol.score;\n            int best = old;\n            long long bestScore = oldScore;\n\n            if (base > bestScore) {\n                bestScore = base;\n                best = -1;\n            }\n\n            for (int aid = 0; aid < (int)actions.size(); aid++) {\n                long long cand = base + evalAdd(sol.board, aid);\n                if (cand > bestScore) {\n                    bestScore = cand;\n                    best = aid;\n                }\n            }\n\n            sol.score = base;\n\n            if (best >= 0) {\n                sol.score += applyAdd(sol.board, best);\n            }\n\n            sol.slot[pos] = best;\n\n            if (sol.score > oldScore) improved = true;\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid anchorGroupOptimize(Solution& sol, int maxPasses, double timeLimit) {\n    for (int pass = 0; pass < maxPasses; pass++) {\n        bool improved = false;\n\n        for (int ii = 0; ii < 49; ii++) {\n            if (timer.elapsed() > timeLimit) return;\n\n            int anc = (pass & 1) ? (48 - ii) : ii;\n\n            vector<int> slots;\n            for (int i = 0; i < K; i++) {\n                int a = sol.slot[i];\n                if (a >= 0 && actions[a].anchor == anc) slots.push_back(i);\n            }\n\n            int c = (int)slots.size();\n            if (c <= 1 || c > MAX_MULTI) continue;\n\n            vector<int> oldActs(c);\n            long long oldScore = sol.score;\n\n            for (int t = 0; t < c; t++) {\n                oldActs[t] = sol.slot[slots[t]];\n                sol.score += applySub(sol.board, oldActs[t]);\n                sol.slot[slots[t]] = -1;\n            }\n\n            long long base = sol.score;\n            long long bestScore = oldScore;\n            int bestCnt = -1;\n            int bestIdx = -1;\n            bool timedOut = false;\n            int chk = 0;\n\n            for (int cnt = 0; cnt <= c && !timedOut; cnt++) {\n                const auto& vec = multiOpts[cnt];\n                for (int oi = 0; oi < (int)vec.size(); oi++) {\n                    if ((chk++ & 8191) == 0 && timer.elapsed() > timeLimit) {\n                        timedOut = true;\n                        break;\n                    }\n\n                    long long cand = base + evalMultiAtAnchor(sol.board, anc, vec[oi]);\n                    if (cand > bestScore) {\n                        bestScore = cand;\n                        bestCnt = cnt;\n                        bestIdx = oi;\n                    }\n                }\n            }\n\n            sol.score = base;\n\n            if (timedOut) {\n                for (int t = 0; t < c; t++) {\n                    sol.slot[slots[t]] = oldActs[t];\n                    sol.score += applyAdd(sol.board, oldActs[t]);\n                }\n                return;\n            }\n\n            if (bestCnt >= 0) {\n                const MultiOption& op = multiOpts[bestCnt][bestIdx];\n                for (int t = 0; t < bestCnt; t++) {\n                    int aid = anc * M + (int)op.st[t];\n                    sol.slot[slots[t]] = aid;\n                    sol.score += applyAdd(sol.board, aid);\n                }\n                improved = true;\n            } else {\n                for (int t = 0; t < c; t++) {\n                    sol.slot[slots[t]] = oldActs[t];\n                    sol.score += applyAdd(sol.board, oldActs[t]);\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nlong long orderCost(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    int cnt[49] = {};\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        cnt[br]++;\n    }\n\n    int maxc = 0;\n    int sumsq = 0;\n    int zero = 0;\n\n    for (int i = 0; i < 49; i++) {\n        maxc = max(maxc, cnt[i]);\n        sumsq += cnt[i] * cnt[i];\n        if (cnt[i] == 0) zero++;\n    }\n\n    return (long long)maxc * 1000000LL + (long long)sumsq * 1000LL + zero;\n}\n\nvector<int> findBalancedOrder() {\n    vector<int> base(49);\n    iota(base.begin(), base.end(), 0);\n\n    vector<int> best = base;\n    long long bestCost = orderCost(best);\n\n    const int REPS = 10;\n    const int ITERS = 1300;\n\n    for (int rep = 0; rep < REPS; rep++) {\n        vector<int> perm = base;\n\n        for (int i = 48; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(perm[i], perm[j]);\n        }\n\n        long long cur = orderCost(perm);\n\n        for (int it = 0; it < ITERS; it++) {\n            int a = rng.nextInt(49);\n            int b = rng.nextInt(49);\n            if (a == b) continue;\n\n            swap(perm[a], perm[b]);\n            long long nc = orderCost(perm);\n\n            if (nc <= cur) {\n                cur = nc;\n            } else {\n                swap(perm[a], perm[b]);\n            }\n        }\n\n        if (cur < bestCost) {\n            bestCost = cur;\n            best = perm;\n        }\n    }\n\n    return best;\n}\n\nvector<vector<int>> computeFinalCells(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    vector<vector<int>> finalCells(49);\n\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        finalCells[br].push_back(cell);\n    }\n\n    return finalCells;\n}\n\nstruct BeamState {\n    array<int, KMAX> cell;\n    long long fin;\n    long long total;\n    long long key;\n    int parent;\n    short opt;\n    unsigned char used;\n};\n\nvector<int> beamSearch(const vector<int>& order, int perWidth, long long finalWeight) {\n    vector<vector<int>> finalCells = computeFinalCells(order);\n\n    vector<vector<BeamState>> layers;\n    layers.reserve(50);\n\n    BeamState init{};\n    init.cell = initBoard;\n    init.fin = 0;\n    init.total = initScore;\n    init.key = initScore;\n    init.parent = -1;\n    init.opt = -1;\n    init.used = 0;\n\n    layers.push_back(vector<BeamState>{init});\n\n    vector<vector<BeamState>> buckets(K + 1);\n    int reserveEach = perWidth * (int)options.size() + 8;\n    for (auto& b : buckets) b.reserve(reserveEach);\n\n    auto cmpState = [](const BeamState& a, const BeamState& b) {\n        if (a.key != b.key) return a.key > b.key;\n        if (a.fin != b.fin) return a.fin > b.fin;\n        return a.total > b.total;\n    };\n\n    for (int step = 0; step < 49; step++) {\n        for (auto& b : buckets) b.clear();\n\n        const vector<BeamState>& cur = layers.back();\n        int anc = order[step];\n        const auto& cells = anchorCells[anc];\n        const vector<int>& fins = finalCells[step];\n\n        for (int si = 0; si < (int)cur.size(); si++) {\n            const BeamState& st = cur[si];\n\n            for (int oid = 0; oid < (int)options.size(); oid++) {\n                const Option& op = options[oid];\n                int nu = (int)st.used + (int)op.cnt;\n                if (nu > K) continue;\n\n                BeamState ns;\n                ns.cell = st.cell;\n                ns.fin = st.fin;\n                ns.total = st.total;\n                ns.parent = si;\n                ns.opt = (short)oid;\n                ns.used = (unsigned char)nu;\n\n                if (op.cnt) {\n                    for (int k = 0; k < 9; k++) {\n                        int idx = cells[k];\n                        int old = ns.cell[idx];\n                        int nv = old + op.val[k];\n                        if (nv >= MOD) nv -= MOD;\n                        ns.cell[idx] = nv;\n                        ns.total += (long long)nv - old;\n                    }\n                }\n\n                for (int idx : fins) {\n                    ns.fin += ns.cell[idx];\n                }\n\n                ns.key = ns.fin * finalWeight + (ns.total - ns.fin);\n                buckets[nu].push_back(std::move(ns));\n            }\n        }\n\n        vector<BeamState> next;\n        next.reserve((K + 1) * perWidth);\n\n        for (int u = 0; u <= K; u++) {\n            auto& v = buckets[u];\n            if ((int)v.size() > perWidth) {\n                nth_element(v.begin(), v.begin() + perWidth, v.end(), cmpState);\n                v.resize(perWidth);\n            }\n            for (auto& s : v) next.push_back(std::move(s));\n        }\n\n        layers.push_back(std::move(next));\n    }\n\n    const vector<BeamState>& last = layers.back();\n    int bestIdx = 0;\n    for (int i = 1; i < (int)last.size(); i++) {\n        if (last[i].fin > last[bestIdx].fin) bestIdx = i;\n    }\n\n    vector<int> optAt(49);\n    int idx = bestIdx;\n\n    for (int step = 48; step >= 0; step--) {\n        const BeamState& st = layers[step + 1][idx];\n        optAt[step] = st.opt;\n        idx = st.parent;\n    }\n\n    vector<int> ops;\n    ops.reserve(K);\n\n    for (int step = 0; step < 49; step++) {\n        int anc = order[step];\n        const Option& op = options[optAt[step]];\n\n        if (op.cnt >= 1) ops.push_back(anc * M + (int)op.s1);\n        if (op.cnt >= 2) ops.push_back(anc * M + (int)op.s2);\n    }\n\n    if ((int)ops.size() > K) ops.resize(K);\n    return ops;\n}\n\nbool optimizePairApprox(Solution& sol, int i, int j, int topC) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    long long base = sol.score;\n\n    vector<pair<long long, int>> all;\n    all.reserve(actions.size());\n\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        all.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    auto cmpPair = [](const pair<long long, int>& a, const pair<long long, int>& b) {\n        return a.first > b.first;\n    };\n\n    if ((int)all.size() > topC) {\n        nth_element(all.begin(), all.begin() + topC, all.end(), cmpPair);\n        all.resize(topC);\n    }\n\n    vector<pair<long long, int>> firsts = all;\n    firsts.push_back({base, -1});\n\n    for (int t = 0; t < 5; t++) {\n        int aid = rng.nextInt((int)actions.size());\n        firsts.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    long long bestScore = oldScore;\n    int best1 = old1;\n    int best2 = old2;\n\n    for (auto [dummyScore, f] : firsts) {\n        long long d1 = 0;\n        if (f >= 0) d1 = applyAdd(sol.board, f);\n        long long sc1 = base + d1;\n\n        long long localBest = sc1;\n        int gbest = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long cand = sc1 + evalAdd(sol.board, aid);\n            if (cand > localBest) {\n                localBest = cand;\n                gbest = aid;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best1 = f;\n            best2 = gbest;\n        }\n\n        if (f >= 0) applySub(sol.board, f);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        sol.slot[i] = best1;\n        sol.slot[j] = best2;\n\n        if (best1 >= 0) sol.score += applyAdd(sol.board, best1);\n        if (best2 >= 0) sol.score += applyAdd(sol.board, best2);\n\n        return true;\n    } else {\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n\n        return false;\n    }\n}\n\nvoid pairSearchApproxAdaptive(Solution& sol, double timeLimit) {\n    int attempts = 0;\n    int fail = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        int i, j;\n\n        if ((attempts & 7) == 0) {\n            vector<int> none;\n            for (int t = 0; t < K; t++) {\n                if (sol.slot[t] == -1) none.push_back(t);\n            }\n\n            if ((int)none.size() >= 2) {\n                int a = rng.nextInt((int)none.size());\n                int b = rng.nextInt((int)none.size() - 1);\n                if (b >= a) b++;\n                i = none[a];\n                j = none[b];\n            } else {\n                i = rng.nextInt(K);\n                do {\n                    j = rng.nextInt(K);\n                } while (j == i);\n            }\n        } else {\n            i = rng.nextInt(K);\n            do {\n                j = rng.nextInt(K);\n            } while (j == i);\n        }\n\n        attempts++;\n\n        if (optimizePairApprox(sol, i, j, 22)) {\n            coordinateDescent(sol, 4, timeLimit);\n            fail = 0;\n        } else {\n            fail++;\n        }\n\n        if (timer.elapsed() > 1.82 && fail > 70) break;\n    }\n}\n\nbool optimizePairExact(Solution& sol, int i, int j) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    sol.slot[i] = sol.slot[j] = -1;\n\n    long long base = sol.score;\n    long long oldDelta = oldScore - base;\n    long long bestDelta = oldDelta;\n    int bestA = old1;\n    int bestB = old2;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n\n        if (d[a] > bestDelta) {\n            bestDelta = d[a];\n            bestA = a;\n            bestB = -1;\n        }\n    }\n\n    if (0 > bestDelta) {\n        bestDelta = 0;\n        bestA = bestB = -1;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    for (int ia = 0; ia < A; ia++) {\n        int a = ord[ia];\n        if (d[a] + d[ord[0]] <= bestDelta) break;\n\n        for (int ib = 0; ib < A; ib++) {\n            int b = ord[ib];\n            long long ub = d[a] + d[b];\n            if (ub <= bestDelta) break;\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                bestDelta = ub;\n                bestA = a;\n                bestB = b;\n                break;\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        if (delta > bestDelta) {\n            bestDelta = delta;\n            bestA = pi.a;\n            bestB = pi.b;\n        }\n    }\n\n    sol.score = base;\n\n    if (bestDelta > oldDelta) {\n        sol.slot[i] = bestA;\n        sol.slot[j] = bestB;\n\n        if (bestA >= 0) sol.score += applyAdd(sol.board, bestA);\n        if (bestB >= 0) sol.score += applyAdd(sol.board, bestB);\n\n        return true;\n    } else {\n        sol.slot[i] = old1;\n        sol.slot[j] = old2;\n\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n\n        return false;\n    }\n}\n\nvoid exactPairSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 18);\n        vector<pair<int, int>> pairs;\n        pairs.reserve(R * R);\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                pairs.push_back({loss[a].second, loss[b].second});\n            }\n        }\n\n        for (int i = (int)pairs.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n        int maxTries = stagnant == 0 ? 38 : 26;\n\n        for (auto [a, b] : pairs) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizePairExact(sol, a, b)) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= maxTries) break;\n        }\n\n        if (!improved) {\n            int randomTries = 14;\n\n            for (int t = 0; t < randomTries && timer.elapsed() < timeLimit; t++) {\n                int a, b;\n\n                if (rng.nextInt(100) < 75) {\n                    a = loss[rng.nextInt(R)].second;\n                } else {\n                    a = rng.nextInt(K);\n                }\n\n                do {\n                    if (rng.nextInt(100) < 75) {\n                        b = loss[rng.nextInt(R)].second;\n                    } else {\n                        b = rng.nextInt(K);\n                    }\n                } while (a == b);\n\n                if (optimizePairExact(sol, a, b)) {\n                    coordinateDescent(sol, 3, timeLimit);\n                    anchorGroupOptimize(sol, 1, timeLimit);\n                    improved = true;\n                    break;\n                }\n            }\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 3) break;\n        }\n    }\n}\n\nstruct PairCand {\n    long long delta;\n    int a, b;\n};\n\nstruct PairCandMinCmp {\n    bool operator()(const PairCand& x, const PairCand& y) const {\n        return x.delta > y.delta;\n    }\n};\n\nbool optimizeTripleApprox(Solution& sol, int i, int j, int k) {\n    if (i == j || i == k || j == k) return false;\n\n    int old[3] = {sol.slot[i], sol.slot[j], sol.slot[k]};\n    int pos[3] = {i, j, k};\n    long long oldScore = sol.score;\n\n    for (int t = 0; t < 3; t++) {\n        if (old[t] >= 0) sol.score += applySub(sol.board, old[t]);\n        sol.slot[pos[t]] = -1;\n    }\n\n    long long base = sol.score;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    const int CAND = 80;\n    priority_queue<PairCand, vector<PairCand>, PairCandMinCmp> pq;\n\n    auto pushCand = [&](long long delta, int a, int b) {\n        PairCand pc{delta, a, b};\n\n        if ((int)pq.size() < CAND) {\n            pq.push(pc);\n        } else if (delta > pq.top().delta) {\n            pq.pop();\n            pq.push(pc);\n        }\n    };\n\n    pushCand(0, -1, -1);\n\n    int singleT = min(A, 120);\n    for (int t = 0; t < singleT; t++) {\n        int a = ord[t];\n        pushCand(d[a], a, -1);\n    }\n\n    int topT = min(A, 80);\n    for (int x = 0; x < topT; x++) {\n        int a = ord[x];\n        for (int y = x + 1; y < topT; y++) {\n            int b = ord[y];\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                pushCand(d[a] + d[b], a, b);\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        pushCand(delta, pi.a, pi.b);\n    }\n\n    vector<PairCand> cands;\n    while (!pq.empty()) {\n        cands.push_back(pq.top());\n        pq.pop();\n    }\n\n    long long bestScore = oldScore;\n    int best[3] = {old[0], old[1], old[2]};\n\n    for (const PairCand& pc : cands) {\n        long long curScore = base;\n\n        if (pc.a >= 0) curScore += applyAdd(sol.board, pc.a);\n        if (pc.b >= 0) curScore += applyAdd(sol.board, pc.b);\n\n        int third = -1;\n        long long localBest = curScore;\n\n        for (int a = 0; a < A; a++) {\n            long long cand = curScore + evalAdd(sol.board, a);\n            if (cand > localBest) {\n                localBest = cand;\n                third = a;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best[0] = pc.a;\n            best[1] = pc.b;\n            best[2] = third;\n        }\n\n        if (pc.b >= 0) applySub(sol.board, pc.b);\n        if (pc.a >= 0) applySub(sol.board, pc.a);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = best[t];\n            if (best[t] >= 0) sol.score += applyAdd(sol.board, best[t]);\n        }\n        return true;\n    } else {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = old[t];\n            if (old[t] >= 0) sol.score += applyAdd(sol.board, old[t]);\n        }\n        return false;\n    }\n}\n\nvoid tripleSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 12);\n        vector<array<int, 3>> triples;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                for (int c = b + 1; c < R; c++) {\n                    triples.push_back({loss[a].second, loss[b].second, loss[c].second});\n                }\n            }\n        }\n\n        for (int i = (int)triples.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(triples[i], triples[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n\n        for (auto tr : triples) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizeTripleApprox(sol, tr[0], tr[1], tr[2])) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= 7) break;\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 2) break;\n        }\n    }\n}\n\nvoid targetedCellExactSearch(Solution& sol, double timeLimit) {\n    int rounds = 0;\n\n    while (timer.elapsed() < timeLimit && rounds < 2) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n        long long lossSlot[KMAX];\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            lossSlot[i] = ls;\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        vector<int> cells(81);\n        iota(cells.begin(), cells.end(), 0);\n        sort(cells.begin(), cells.end(), [&](int x, int y) {\n            return sol.board[x] < sol.board[y];\n        });\n\n        bool seen[KMAX][KMAX] = {};\n        vector<pair<int, int>> pairs;\n\n        auto addPair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            if (!seen[a][b]) {\n                seen[a][b] = true;\n                pairs.push_back({a, b});\n            }\n        };\n\n        int weakR = min(K, 10);\n        for (int a = 0; a < weakR; a++) {\n            for (int b = a + 1; b < weakR; b++) {\n                addPair(loss[a].second, loss[b].second);\n            }\n        }\n\n        int cellLim = 14;\n        for (int ci = 0; ci < cellLim; ci++) {\n            int cell = cells[ci];\n\n            vector<int> coverSlots;\n            for (int s = 0; s < K; s++) {\n                int aid = sol.slot[s];\n                if (aid >= 0 && actionCoversCell(aid, cell)) {\n                    coverSlots.push_back(s);\n                }\n            }\n\n            sort(coverSlots.begin(), coverSlots.end(), [&](int x, int y) {\n                return lossSlot[x] < lossSlot[y];\n            });\n\n            if ((int)coverSlots.size() > 18) coverSlots.resize(18);\n\n            for (int u : coverSlots) {\n                int lim = min(K, 14);\n                for (int t = 0; t < lim; t++) {\n                    addPair(u, loss[t].second);\n                }\n            }\n\n            for (int a = 0; a < (int)coverSlots.size(); a++) {\n                for (int b = a + 1; b < (int)coverSlots.size(); b++) {\n                    addPair(coverSlots[a], coverSlots[b]);\n                }\n            }\n        }\n\n        sort(pairs.begin(), pairs.end(), [&](const auto& x, const auto& y) {\n            long long sx = lossSlot[x.first] + lossSlot[x.second];\n            long long sy = lossSlot[y.first] + lossSlot[y.second];\n            return sx < sy;\n        });\n\n        bool improved = false;\n        int tries = 0;\n        int maxTries = 10;\n\n        for (auto [a, b] : pairs) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizePairExact(sol, a, b)) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= maxTries) break;\n        }\n\n        if (!improved) break;\n        rounds++;\n    }\n}\n\nstruct AddSeed {\n    long long key;\n    int a, b;\n};\n\nstruct AddSeedMinCmp {\n    bool operator()(const AddSeed& x, const AddSeed& y) const {\n        return x.key > y.key;\n    }\n};\n\nvector<pair<int, int>> buildGlobalAddPairs(const array<int, KMAX>& board, int cap, double timeLimit) {\n    const int A = (int)actions.size();\n    long long d[1000];\n\n    for (int a = 0; a < A; a++) d[a] = evalAdd(board, a);\n\n    priority_queue<AddSeed, vector<AddSeed>, AddSeedMinCmp> pq;\n\n    auto pushSeed = [&](long long key, int a, int b) {\n        if ((int)pq.size() < cap) {\n            pq.push({key, a, b});\n        } else if (key > pq.top().key) {\n            pq.pop();\n            pq.push({key, a, b});\n        }\n    };\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long v = evalPairInfo(board, pi);\n        pushSeed(v, pi.a, pi.b);\n    }\n\n    for (int a = 0; a < A; a++) {\n        if ((a & 15) == 0 && timer.elapsed() > timeLimit) break;\n\n        for (int b = a + 1; b < A; b++) {\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                pushSeed(d[a] + d[b], a, b);\n            }\n        }\n    }\n\n    vector<pair<int, int>> res;\n    res.reserve(pq.size());\n\n    while (!pq.empty()) {\n        res.push_back({pq.top().a, pq.top().b});\n        pq.pop();\n    }\n\n    return res;\n}\n\nint selectTopActionsD(const array<int, KMAX>& board, int topC, int ids[], long long ds[]) {\n    int sz = 0;\n\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        long long d = evalAdd(board, aid);\n\n        if (sz < topC) {\n            int pos = sz++;\n            while (pos > 0 && d > ds[pos - 1]) {\n                ds[pos] = ds[pos - 1];\n                ids[pos] = ids[pos - 1];\n                pos--;\n            }\n            ds[pos] = d;\n            ids[pos] = aid;\n        } else if (d > ds[topC - 1]) {\n            int pos = topC - 1;\n            while (pos > 0 && d > ds[pos - 1]) {\n                ds[pos] = ds[pos - 1];\n                ids[pos] = ids[pos - 1];\n                pos--;\n            }\n            ds[pos] = d;\n            ids[pos] = aid;\n        }\n    }\n\n    return sz;\n}\n\nvector<pair<int, int>> buildRemovalPairsForBroad(const Solution& sol, int maxPairs) {\n    vector<pair<long long, int>> loss;\n    loss.reserve(K);\n    long long lossSlot[KMAX];\n\n    for (int i = 0; i < K; i++) {\n        long long ls = 0;\n        if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n        lossSlot[i] = ls;\n        loss.push_back({ls, i});\n    }\n\n    sort(loss.begin(), loss.end());\n\n    bool seen[KMAX][KMAX] = {};\n    vector<pair<int, int>> pairs;\n    pairs.reserve(maxPairs + 2048);\n\n    auto addPair = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        if (!seen[a][b]) {\n            seen[a][b] = true;\n            pairs.push_back({a, b});\n        }\n    };\n\n    int R = min(K, 24);\n    for (int a = 0; a < R; a++) {\n        for (int b = a + 1; b < R; b++) {\n            addPair(loss[a].second, loss[b].second);\n        }\n    }\n\n    vector<int> cells(81);\n    iota(cells.begin(), cells.end(), 0);\n    sort(cells.begin(), cells.end(), [&](int x, int y) {\n        return sol.board[x] < sol.board[y];\n    });\n\n    for (int ci = 0; ci < 12; ci++) {\n        int cell = cells[ci];\n\n        vector<int> cover;\n        for (int s = 0; s < K; s++) {\n            int aid = sol.slot[s];\n            if (aid >= 0 && actionCoversCell(aid, cell)) cover.push_back(s);\n        }\n\n        sort(cover.begin(), cover.end(), [&](int x, int y) {\n            return lossSlot[x] < lossSlot[y];\n        });\n\n        if ((int)cover.size() > 16) cover.resize(16);\n\n        for (int u : cover) {\n            for (int t = 0; t < min(K, 10); t++) {\n                addPair(u, loss[t].second);\n            }\n        }\n\n        for (int a = 0; a < (int)cover.size(); a++) {\n            for (int b = a + 1; b < (int)cover.size(); b++) {\n                addPair(cover[a], cover[b]);\n            }\n        }\n    }\n\n    // Add extra random diversity after the deterministic prefix.\n    // The first 620 pairs remain identical to the previous broad search.\n    for (int guard = 0; guard < 2500; guard++) {\n        addPair(rng.nextInt(K), rng.nextInt(K));\n    }\n\n    if ((int)pairs.size() > maxPairs) {\n        int keep = min({(int)pairs.size(), maxPairs, 620});\n        vector<pair<int, int>> res;\n        res.reserve(maxPairs);\n\n        for (int i = 0; i < keep; i++) res.push_back(pairs[i]);\n\n        int need = maxPairs - keep;\n        int rest = (int)pairs.size() - keep;\n\n        for (int t = 0; t < need && t < rest; t++) {\n            int j = keep + t + rng.nextInt(rest - t);\n            swap(pairs[keep + t], pairs[j]);\n            res.push_back(pairs[keep + t]);\n        }\n\n        pairs.swap(res);\n    }\n\n    return pairs;\n}\n\nbool broadPairApproxPass(Solution& sol, double timeLimit) {\n    if (timer.elapsed() > timeLimit) return false;\n\n    const int TOP_SINGLE = 26;\n    const int GLOBAL_PAIR = 180;\n    const int MAX_REM = 1200;\n\n    vector<pair<int, int>> globalPairs = buildGlobalAddPairs(sol.board, GLOBAL_PAIR, timeLimit);\n    vector<pair<int, int>> remPairs = buildRemovalPairsForBroad(sol, MAX_REM);\n\n    long long origScore = sol.score;\n    long long bestScore = origScore;\n    int bestI = -1, bestJ = -1;\n    int bestA = -1, bestB = -1;\n\n    int ids[40];\n    long long ds[40];\n\n    auto updateBest = [&](long long cand, int i, int j, int a, int b) {\n        if (cand > bestScore) {\n            bestScore = cand;\n            bestI = i;\n            bestJ = j;\n            bestA = a;\n            bestB = b;\n        }\n    };\n\n    for (int ri = 0; ri < (int)remPairs.size(); ri++) {\n        if ((ri & 7) == 0) {\n            double now = timer.elapsed();\n            if (now > timeLimit) break;\n            if (bestScore > origScore && now + 0.008 > timeLimit) break;\n        }\n\n        int i = remPairs[ri].first;\n        int j = remPairs[ri].second;\n        int old1 = sol.slot[i];\n        int old2 = sol.slot[j];\n\n        long long savedScore = sol.score;\n\n        if (old1 >= 0) sol.score += applySub(sol.board, old1);\n        if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n        long long base = sol.score;\n\n        updateBest(base, i, j, -1, -1);\n\n        int sz = selectTopActionsD(sol.board, TOP_SINGLE, ids, ds);\n\n        for (int x = 0; x < sz; x++) {\n            updateBest(base + ds[x], i, j, ids[x], -1);\n        }\n\n        for (int x = 0; x < sz; x++) {\n            int a = ids[x];\n            for (int y = x; y < sz; y++) {\n                int b = ids[y];\n                long long add;\n                if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                    add = ds[x] + ds[y];\n                } else {\n                    add = evalAdd2(sol.board, a, b);\n                }\n                updateBest(base + add, i, j, a, b);\n            }\n        }\n\n        for (auto [a, b] : globalPairs) {\n            long long add = evalAdd2(sol.board, a, b);\n            updateBest(base + add, i, j, a, b);\n        }\n\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n        sol.score = savedScore;\n    }\n\n    if (bestScore <= origScore || bestI < 0) return false;\n\n    // New: polish the best broad candidate with the exact 2-slot optimizer.\n    if (timer.elapsed() + 0.006 < timeLimit) {\n        if (optimizePairExact(sol, bestI, bestJ)) return true;\n    }\n\n    // Fallback: apply the approximate best move found.\n    int old1 = sol.slot[bestI];\n    int old2 = sol.slot[bestJ];\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    sol.slot[bestI] = bestA;\n    sol.slot[bestJ] = bestB;\n\n    if (bestA >= 0) sol.score += applyAdd(sol.board, bestA);\n    if (bestB >= 0) sol.score += applyAdd(sol.board, bestB);\n\n    return true;\n}\n\nvoid broadPairApproxSearch(Solution& sol, double timeLimit) {\n    int pass = 0;\n\n    while (timer.elapsed() < timeLimit && pass < 4) {\n        bool improved = broadPairApproxPass(sol, timeLimit);\n        if (!improved) break;\n\n        coordinateDescent(sol, 3, timeLimit);\n        anchorGroupOptimize(sol, 1, timeLimit);\n\n        pass++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> K;\n\n    for (int i = 0; i < BN; i++) {\n        for (int j = 0; j < BN; j++) {\n            int x;\n            cin >> x;\n            initBoard[i * BN + j] = x;\n            initScore += x;\n        }\n    }\n\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                cin >> stampVal[m][i * 3 + j];\n            }\n        }\n    }\n\n    timer.reset();\n\n    precompute();\n\n    Solution best = greedySolution();\n\n    coordinateDescent(best, 25, 1.86);\n\n    vector<int> order = findBalancedOrder();\n\n    if (timer.elapsed() < 1.20) {\n        vector<int> ops = beamSearch(order, 6, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 18, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    vector<int> revOrder = order;\n    reverse(revOrder.begin(), revOrder.end());\n\n    if (timer.elapsed() < 1.45) {\n        vector<int> ops = beamSearch(revOrder, 4, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 14, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    pairSearchApproxAdaptive(best, 1.86);\n\n    anchorGroupOptimize(best, 2, 1.875);\n    coordinateDescent(best, 5, 1.885);\n\n    exactPairSearch(best, 1.910);\n    tripleSearch(best, 1.925);\n\n    targetedCellExactSearch(best, 1.945);\n\n    // More time and broader/removal-diverse pair search.\n    broadPairApproxSearch(best, 1.985);\n\n    anchorGroupOptimize(best, 1, 1.990);\n    coordinateDescent(best, 2, 1.990);\n\n    vector<int> out;\n    for (int i = 0; i < K; i++) {\n        if (best.slot[i] >= 0) out.push_back(best.slot[i]);\n    }\n\n    cout << out.size() << '\\n';\n\n    for (int id : out) {\n        const Action& a = actions[id];\n        cout << a.m << ' ' << a.p << ' ' << a.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 TOT = 25;\nstatic constexpr int BASE = 6;\nstatic constexpr int PBASE = 7776;\nstatic constexpr int TOTAL_STATES = PBASE * PBASE;\nstatic constexpr int INF = 1e9;\n\nint A[N][N];\nint srcOf[TOT], idxOf[TOT];\nint pow6_[N + 1];\n\nuint8_t dig[PBASE][N];\nuint8_t sumCode[PBASE];\nuint8_t exhCode[PBASE];\n\nvector<signed char> memoBlock;\n\ninline int manhattan(int r1, int c1, int r2, int c2) {\n    return abs(r1 - r2) + abs(c1 - c2);\n}\n\nstruct TransCode {\n    int npcode, nqcode, code, k;\n};\n\nbool makeTransCodes(int pcode, int qcode, int d, TransCode &tr) {\n    int qd = dig[qcode][d];\n    if (qd >= N) return false;\n\n    int x = N * d + qd;\n    int s = srcOf[x];\n    int idx = idxOf[x];\n    int ps = dig[pcode][s];\n\n    int nq = qcode + pow6_[d];\n    int np = pcode;\n    int k = 0;\n\n    if (idx < ps) {\n        k = 0;\n    } else {\n        k = idx - ps;\n        int buffer = (int)sumCode[pcode] - (int)sumCode[qcode];\n        int capacity = 15 + (int)exhCode[pcode];\n        if (buffer + k > capacity) return false;\n        np = pcode + (idx + 1 - ps) * pow6_[s];\n    }\n\n    tr = {np, nq, np * PBASE + nq, k};\n    return true;\n}\n\nint dfsBlock(int code) {\n    signed char m = memoBlock[code];\n    if (m != -1) {\n        if (m >= 100) return INF;\n        return (int)m;\n    }\n\n    int pcode = code / PBASE;\n    int qcode = code % PBASE;\n\n    if (sumCode[qcode] == TOT) {\n        memoBlock[code] = 0;\n        return 0;\n    }\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(pcode, qcode, d, tr)) continue;\n        int sub = dfsBlock(tr.code);\n        if (sub >= INF) continue;\n        best = min(best, tr.k + sub);\n    }\n\n    memoBlock[code] = (best >= INF ? 100 : (signed char)best);\n    return best;\n}\n\nstruct RowOption {\n    vector<int> cols;\n    string act;\n    int len = 0;\n    int finalCol = 0;\n};\n\nvector<RowOption> smallOpts, bigOpts, hSmallOpts;\n\nRowOption makeRowOption(const vector<int> &cols) {\n    RowOption ro;\n    ro.cols = cols;\n\n    int pos = 0;\n    for (int t = 0; t < (int)cols.size(); t++) {\n        if (t > 0) {\n            while (pos > 0) {\n                ro.act.push_back('L');\n                pos--;\n            }\n        }\n\n        ro.act.push_back('P');\n\n        while (pos < cols[t]) {\n            ro.act.push_back('R');\n            pos++;\n        }\n\n        ro.act.push_back('Q');\n    }\n\n    ro.len = (int)ro.act.size();\n    ro.finalCol = cols.empty() ? 0 : cols.back();\n    return ro;\n}\n\nvoid initRowOptions() {\n    vector<vector<int>> smallDefs = {\n        {},\n        {1},\n        {2},\n        {3},\n        {2, 1},\n        {3, 1},\n        {3, 2},\n        {3, 2, 1},\n    };\n    for (auto &v : smallDefs) smallOpts.push_back(makeRowOption(v));\n\n    bigOpts.push_back(makeRowOption({}));\n\n    vector<int> cur;\n    bool used[4] = {};\n    function<void(int, int)> dfs = [&](int dep, int len) {\n        if (dep == len) {\n            bigOpts.push_back(makeRowOption(cur));\n            return;\n        }\n        for (int c = 1; c <= 3; c++) {\n            if (used[c]) continue;\n            used[c] = true;\n            cur.push_back(c);\n            dfs(dep + 1, len);\n            cur.pop_back();\n            used[c] = false;\n        }\n    };\n\n    for (int len = 1; len <= 3; len++) {\n        memset(used, 0, sizeof(used));\n        cur.clear();\n        dfs(0, len);\n    }\n\n    vector<vector<int>> hDefs = {\n        {},\n        {1},\n        {2},\n        {2, 1},\n    };\n    for (auto &v : hDefs) hSmallOpts.push_back(makeRowOption(v));\n}\n\nstring directScript(int row, int d) {\n    string s;\n    s.push_back('P');\n    s.append(4, 'R');\n    if (row < d) s.append(d - row, 'D');\n    else s.append(row - d, 'U');\n    s.push_back('Q');\n    return s;\n}\n\nstring returnScript(int d, int row) {\n    string s;\n    if (d < row) s.append(row - d, 'D');\n    else s.append(d - row, 'U');\n    s.append(4, 'L');\n    return s;\n}\n\n/*** standard one-large-crane continuation mode ***/\n\nstruct Pattern {\n    array<int, N> opt{};\n    int directRow = -1;\n    int directD = -1;\n    int directAfter = -1;\n    int T = 0;\n    int repR = -1, repC = -1;\n};\n\nint initialLenRow(const Pattern &p, int row) {\n    if (p.directRow == row) {\n        int len = 6 + abs(row - p.directD);\n        if (p.directAfter >= 0) {\n            len += abs(row - p.directD) + 4;\n            len += (row == 0 ? bigOpts[p.directAfter].len : smallOpts[p.directAfter].len);\n        }\n        return len;\n    }\n    return row == 0 ? bigOpts[p.opt[0]].len : smallOpts[p.opt[row]].len;\n}\n\nvoid computeT(Pattern &p) {\n    p.T = 0;\n    for (int i = 0; i < N; i++) {\n        p.T = max(p.T, initialLenRow(p, i));\n    }\n}\n\npair<int, int> baseBigFinal(const Pattern &p) {\n    if (p.directRow == 0) {\n        if (p.directAfter >= 0) return {0, bigOpts[p.directAfter].finalCol};\n        return {p.directD, 4};\n    }\n    return {0, bigOpts[p.opt[0]].finalCol};\n}\n\npair<int, int> finalBigPos(const Pattern &p) {\n    if (p.repR >= 0) return {p.repR, p.repC};\n    return baseBigFinal(p);\n}\n\nstring baseBigScript(const Pattern &p) {\n    if (p.directRow == 0) {\n        string s = directScript(0, p.directD);\n        if (p.directAfter >= 0) {\n            s += returnScript(p.directD, 0);\n            s += bigOpts[p.directAfter].act;\n        }\n        return s;\n    }\n    return bigOpts[p.opt[0]].act;\n}\n\nint safeDist(pair<int, int> a, pair<int, int> b) {\n    auto [r, c] = a;\n    auto [tr, tc] = b;\n\n    if (c == 4) {\n        if (tc == 4) return abs(r - tr);\n        if (tr == 0) return r + abs(4 - tc);\n        return INF;\n    } else {\n        if (r != 0) return INF;\n        if (tr == 0) return abs(c - tc);\n        if (tc == 4) return abs(4 - c) + tr;\n        return INF;\n    }\n}\n\nstring repositionScript(pair<int, int> a, pair<int, int> b) {\n    auto [r, c] = a;\n    auto [tr, tc] = b;\n    string s;\n\n    auto moveV = [&](int from, int to) {\n        if (from < to) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    };\n    auto moveH = [&](int from, int to) {\n        if (from < to) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    };\n\n    if (c == 4) {\n        if (tc == 4) {\n            moveV(r, tr);\n        } else {\n            moveV(r, 0);\n            moveH(4, tc);\n        }\n    } else {\n        if (tr == 0) {\n            moveH(c, tc);\n        } else {\n            moveH(c, 4);\n            moveV(0, tr);\n        }\n    }\n\n    return s;\n}\n\nstring bigInitScript(const Pattern &p) {\n    string s = baseBigScript(p);\n    if (p.repR >= 0) {\n        s += repositionScript(baseBigFinal(p), {p.repR, p.repC});\n    }\n    return s;\n}\n\nstring smallInitScript(const Pattern &p, int row) {\n    string s;\n    if (p.directRow == row) {\n        s = directScript(row, p.directD);\n        if (p.directAfter >= 0) {\n            s += returnScript(p.directD, row);\n            s += smallOpts[p.directAfter].act;\n        }\n        s.push_back('B');\n    } else {\n        s = smallOpts[p.opt[row]].act;\n        s.push_back('B');\n    }\n    return s;\n}\n\nbool samePattern(const Pattern &a, const Pattern &b) {\n    return a.opt == b.opt\n        && a.directRow == b.directRow\n        && a.directD == b.directD\n        && a.directAfter == b.directAfter\n        && a.T == b.T\n        && a.repR == b.repR\n        && a.repC == b.repC;\n}\n\nvector<Pattern> reachableVariants(const Pattern &p) {\n    vector<Pattern> res;\n    res.push_back(p);\n\n    if (p.directRow > 0) return res;\n\n    int bigLen = initialLenRow(p, 0);\n    int slack = p.T - bigLen;\n    if (slack <= 0) return res;\n\n    pair<int, int> base = baseBigFinal(p);\n    vector<pair<int, int>> targets;\n    for (int c = 0; c < N; c++) targets.push_back({0, c});\n    for (int r = 1; r < N; r++) targets.push_back({r, 4});\n\n    for (auto tg : targets) {\n        if (tg == base) continue;\n        int d = safeDist(base, tg);\n        if (d <= slack) {\n            Pattern q = p;\n            q.repR = tg.first;\n            q.repC = tg.second;\n            res.push_back(q);\n        }\n    }\n\n    return res;\n}\n\nstruct State {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) occ[i][j] = -1;\n        }\n        r = c = 0;\n        act.clear();\n        eval = 0;\n    }\n\n    int code() const {\n        return pcode * PBASE + qcode;\n    }\n\n    int delivered() const {\n        return sumCode[qcode];\n    }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveTo(int tr, int tc) {\n        while (r < tr) add('D');\n        while (r > tr) add('U');\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    vector<pair<int, int>> storageOptions(int b, int srcRow, double storageW, int maxOpt) const {\n        vector<tuple<double, int, int, int>> cand;\n        int bd = b / N;\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n                cand.emplace_back(sc, tie, rr, cc);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        vector<pair<int, int>> res;\n        for (int i = 0; i < (int)cand.size() && i < maxOpt; i++) {\n            res.push_back({get<2>(cand[i]), get<3>(cand[i])});\n        }\n        return res;\n    }\n};\n\ntemplate<class S>\nvoid setupInitial(S &st, const Pattern &pat) {\n    st.clear();\n\n    if (pat.directRow >= 0) {\n        st.q[pat.directD] = 1;\n        st.qcode += pow6_[pat.directD];\n    }\n\n    for (int i = 0; i < N; i++) {\n        const vector<int> *cols = nullptr;\n        int offset = 0;\n        int cnt = 0;\n\n        if (pat.directRow == i) {\n            offset = 1;\n            cnt = 1;\n            if (pat.directAfter >= 0) {\n                const RowOption &ro = (i == 0 ? bigOpts[pat.directAfter] : smallOpts[pat.directAfter]);\n                cols = &ro.cols;\n                cnt += (int)ro.cols.size();\n            }\n        } else {\n            const RowOption &ro = (i == 0 ? bigOpts[pat.opt[0]] : smallOpts[pat.opt[i]]);\n            cols = &ro.cols;\n            offset = 0;\n            cnt = (int)ro.cols.size();\n        }\n\n        st.p[i] = cnt;\n        st.pcode += cnt * pow6_[i];\n\n        if (cols != nullptr) {\n            for (int t = 0; t < (int)cols->size(); t++) {\n                int b = A[i][offset + t];\n                int cc = (*cols)[t];\n                st.occ[i][cc] = b;\n                st.lr[b] = i;\n                st.lc[b] = cc;\n            }\n        }\n\n        if (cnt < N) {\n            st.occ[i][0] = A[i][cnt];\n        }\n    }\n\n    auto pos = finalBigPos(pat);\n    st.r = pos.first;\n    st.c = pos.second;\n}\n\nState makeInitialState(const Pattern &pat) {\n    State st;\n    setupInitial(st, pat);\n    st.act.reserve(512);\n    return st;\n}\n\nbool doDispatchBuffered(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int rr = ns.lr[x], cc = ns.lc[x];\n    if (rr < 0 || ns.occ[rr][cc] != x) return false;\n\n    ns.moveTo(rr, cc);\n    ns.add('P');\n    ns.occ[rr][cc] = -1;\n    ns.lr[x] = ns.lc[x] = -1;\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nbool doDispatchSource(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int s = srcOf[x];\n\n    if (ns.p[s] >= N) return false;\n    if (A[s][ns.p[s]] != x) return false;\n    if (ns.occ[s][0] != x) return false;\n\n    ns.moveTo(s, 0);\n    ns.add('P');\n    ns.occ[s][0] = -1;\n    ns.incP(s);\n    if (ns.p[s] < N) ns.occ[s][0] = A[s][ns.p[s]];\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nvoid expandBlockers(\n    const State &cur,\n    int s,\n    int idx,\n    int d,\n    double storageW,\n    int optLimit,\n    vector<State> &out\n) {\n    if (cur.p[s] == idx) {\n        State ns = cur;\n        if (doDispatchSource(ns, d)) out.push_back(std::move(ns));\n        return;\n    }\n\n    if (cur.p[s] > idx) return;\n\n    int b = A[s][cur.p[s]];\n    if (cur.occ[s][0] != b) return;\n\n    State base = cur;\n    base.moveTo(s, 0);\n    base.add('P');\n    base.occ[s][0] = -1;\n    base.incP(s);\n    if (base.p[s] < N) base.occ[s][0] = A[s][base.p[s]];\n\n    auto opts = base.storageOptions(b, s, storageW, optLimit);\n    for (auto [rr, cc] : opts) {\n        if (base.occ[rr][cc] != -1) continue;\n\n        State ns = base;\n        ns.moveTo(rr, cc);\n        ns.add('Q');\n        ns.occ[rr][cc] = b;\n        ns.lr[b] = rr;\n        ns.lc[b] = cc;\n\n        expandBlockers(ns, s, idx, d, storageW, optLimit, out);\n    }\n}\n\nvector<State> expandExecuteTarget(\n    const State &st,\n    int d,\n    double storageW,\n    int optLimit,\n    int perTransLimit\n) {\n    vector<State> res;\n\n    int x = N * d + st.q[d];\n    int s = srcOf[x];\n    int idx = idxOf[x];\n\n    if (idx < st.p[s]) {\n        State ns = st;\n        if (doDispatchBuffered(ns, d)) res.push_back(std::move(ns));\n    } else {\n        expandBlockers(st, s, idx, d, storageW, optLimit, res);\n    }\n\n    if ((int)res.size() > perTransLimit) {\n        sort(res.begin(), res.end(), [](const State &a, const State &b) {\n            return a.act.size() < b.act.size();\n        });\n        res.resize(perTransLimit);\n    }\n\n    return res;\n}\n\nint nearestHeuristic(const State &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct PlanResult {\n    bool ok = false;\n    string act;\n};\n\nPlanResult buildBeam(const State &init, double storageW, int width, int hcoef, int optLimit) {\n    if (dfsBlock(init.code()) >= INF) return {false, \"\"};\n\n    vector<State> beam;\n    beam.push_back(init);\n\n    auto comp = [](const State &a, const State &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.act.size() < b.act.size();\n    };\n\n    int perTransLimit = (optLimit <= 1 ? 1 : (optLimit == 2 ? 8 : 12));\n\n    for (int step = init.delivered(); step < TOT; step++) {\n        vector<State> cand;\n        cand.reserve((size_t)width * N * perTransLimit);\n\n        for (const State &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                vector<State> nsList = expandExecuteTarget(st, d, storageW, optLimit, perTransLimit);\n                for (State &ns : nsList) {\n                    if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n                    int near = nearestHeuristic(ns);\n                    ns.eval = (int)ns.act.size() + hcoef * remAfter + near;\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return {false, \"\"};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    string best;\n    int bestLen = INF;\n    for (const State &st : beam) {\n        if (st.delivered() == TOT && (int)st.act.size() < bestLen) {\n            bestLen = (int)st.act.size();\n            best = st.act;\n        }\n    }\n\n    if (best.empty()) return {false, \"\"};\n    return {true, best};\n}\n\nstruct LiteState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n    int r = 0, c = 0, len = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = len = 0;\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void moveTo(int tr, int tc) {\n        len += abs(r - tr) + abs(c - tc);\n        r = tr;\n        c = tc;\n    }\n\n    pair<int, int> chooseStorage(int b, int srcRow, double storageW) const {\n        int bd = b / N;\n        double best = 1e100;\n        int bestTie = INF;\n        pair<int, int> res = {-1, -1};\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n\n                if (sc + 1e-9 < best || (fabs(sc - best) <= 1e-9 && tie < bestTie)) {\n                    best = sc;\n                    bestTie = tie;\n                    res = {rr, cc};\n                }\n            }\n        }\n\n        return res;\n    }\n\n    bool dispatchBuffered(int d) {\n        int x = N * d + q[d];\n        int rr = lr[x], cc = lc[x];\n        if (rr < 0 || occ[rr][cc] != x) return false;\n\n        moveTo(rr, cc);\n        len++;\n        occ[rr][cc] = -1;\n        lr[x] = lc[x] = -1;\n\n        moveTo(d, N - 1);\n        len++;\n        incQ(d);\n        return true;\n    }\n\n    bool dispatchSource(int d) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n\n        if (p[s] >= N) return false;\n        if (A[s][p[s]] != x) return false;\n        if (occ[s][0] != x) return false;\n\n        moveTo(s, 0);\n        len++;\n        occ[s][0] = -1;\n        incP(s);\n        if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n        moveTo(d, N - 1);\n        len++;\n        incQ(d);\n        return true;\n    }\n\n    bool executeTarget(int d, double storageW) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        if (idx < p[s]) {\n            return dispatchBuffered(d);\n        }\n\n        while (p[s] < idx) {\n            int b = A[s][p[s]];\n            if (occ[s][0] != b) return false;\n\n            moveTo(s, 0);\n            len++;\n            occ[s][0] = -1;\n            incP(s);\n            if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n            auto cell = chooseStorage(b, s, storageW);\n            if (cell.first < 0) return false;\n\n            moveTo(cell.first, cell.second);\n            len++;\n            occ[cell.first][cell.second] = b;\n            lr[b] = cell.first;\n            lc[b] = cell.second;\n        }\n\n        return dispatchSource(d);\n    }\n};\n\nLiteState makeLiteInitialState(const Pattern &pat) {\n    LiteState st;\n    setupInitial(st, pat);\n    return st;\n}\n\nint nearestLite(const LiteState &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nint greedyLength(const Pattern &pat, double storageW, int hcoef) {\n    string bs = bigInitScript(pat);\n    if ((int)bs.size() > pat.T) return INF;\n\n    LiteState st = makeLiteInitialState(pat);\n    if (dfsBlock(st.code()) >= INF) return INF;\n\n    for (int step = st.delivered(); step < TOT; step++) {\n        int bestEval = INF;\n        int bestLen = INF;\n        bool found = false;\n        LiteState bestSt;\n\n        for (int d = 0; d < N; d++) {\n            TransCode tr;\n            if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n            int remAfter = dfsBlock(tr.code);\n            if (remAfter >= INF) continue;\n\n            LiteState ns = st;\n            if (!ns.executeTarget(d, storageW)) continue;\n            if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n\n            int eval = ns.len + hcoef * remAfter + nearestLite(ns);\n            if (eval < bestEval || (eval == bestEval && ns.len < bestLen)) {\n                bestEval = eval;\n                bestLen = ns.len;\n                bestSt = ns;\n                found = true;\n            }\n        }\n\n        if (!found) return INF;\n        st = bestSt;\n    }\n\n    return pat.T + st.len;\n}\n\nvector<Pattern> generateCandidates() {\n    vector<Pattern> res;\n    int B = (int)bigOpts.size();\n    int S = (int)smallOpts.size();\n    int smallCodeMax = 1;\n    for (int i = 1; i < N; i++) smallCodeMax *= S;\n\n    for (int b = 0; b < B; b++) {\n        for (int code = 0; code < smallCodeMax; code++) {\n            Pattern p;\n            p.opt.fill(0);\n            p.opt[0] = b;\n            int tmp = code;\n            for (int i = 1; i < N; i++) {\n                p.opt[i] = tmp % S;\n                tmp /= S;\n            }\n            computeT(p);\n            res.push_back(p);\n        }\n    }\n\n    vector<int> oneSmall;\n    for (int i = 0; i < S; i++) {\n        if (smallOpts[i].cols.size() == 1) oneSmall.push_back(i);\n    }\n\n    for (int dr = 0; dr < N; dr++) {\n        if (A[dr][0] % N != 0) continue;\n        int d = A[dr][0] / N;\n\n        if (dr == 0) {\n            for (int after = -1; after < B; after++) {\n                for (int code = 0; code < smallCodeMax; code++) {\n                    Pattern p;\n                    p.opt.fill(0);\n                    p.opt[0] = -1;\n                    int tmp = code;\n                    for (int i = 1; i < N; i++) {\n                        p.opt[i] = tmp % S;\n                        tmp /= S;\n                    }\n                    p.directRow = 0;\n                    p.directD = d;\n                    p.directAfter = after;\n                    computeT(p);\n                    res.push_back(p);\n                }\n            }\n        } else {\n            vector<int> afters;\n            afters.push_back(-1);\n            for (int x : oneSmall) afters.push_back(x);\n\n            int codeMax = 1;\n            for (int i = 1; i < N; i++) if (i != dr) codeMax *= S;\n\n            for (int after : afters) {\n                for (int b = 0; b < B; b++) {\n                    for (int code = 0; code < codeMax; code++) {\n                        Pattern p;\n                        p.opt.fill(0);\n                        p.opt[0] = b;\n                        int tmp = code;\n                        for (int i = 1; i < N; i++) {\n                            if (i == dr) {\n                                p.opt[i] = -1;\n                            } else {\n                                p.opt[i] = tmp % S;\n                                tmp /= S;\n                            }\n                        }\n                        p.directRow = dr;\n                        p.directD = d;\n                        p.directAfter = after;\n                        computeT(p);\n                        res.push_back(p);\n                    }\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\narray<string, N> makeSortedOutput(const Pattern &pat, const string &cont) {\n    array<string, N> out;\n\n    string big = bigInitScript(pat);\n    if ((int)big.size() < pat.T) big += string(pat.T - (int)big.size(), '.');\n    big += cont;\n    out[0] = big;\n\n    for (int i = 1; i < N; i++) {\n        out[i] = smallInitScript(pat, i);\n    }\n\n    return out;\n}\n\n/*** handoff mode ***/\n\nint hDirectCode() {\n    return (int)hSmallOpts.size();\n}\n\nbool isHDirectSmall(int row, int opt) {\n    return opt == hDirectCode() && A[row][0] == row * N;\n}\n\nint hSmallInitLenBase(int opt) {\n    const RowOption &ro = hSmallOpts[opt];\n    return ro.len + (4 - ro.finalCol);\n}\n\nstring hSmallInitScriptBase(int opt) {\n    const RowOption &ro = hSmallOpts[opt];\n    string s = ro.act;\n    s.append(4 - ro.finalCol, 'R');\n    return s;\n}\n\nint hSmallInitLenRow(int row, int opt) {\n    if (isHDirectSmall(row, opt)) return 6;\n    return hSmallInitLenBase(opt);\n}\n\nstring hSmallInitScriptRow(int row, int opt) {\n    if (isHDirectSmall(row, opt)) {\n        return string(\"PRRRRQ\");\n    }\n    return hSmallInitScriptBase(opt);\n}\n\nstruct HPattern {\n    int bopt = 0;\n    // -2: no initial direct dispatch by large crane.\n    // -1: direct-dispatch container 0 and stay/reposition from col 4.\n    // >=0: direct-dispatch container 0, return to row-0 receiving gate, then use bigOpts[bdirectAfter].\n    int bdirectAfter = -2;\n    array<int, N> sopt{};\n    int T = 0;\n    int repC = 0;\n};\n\nint hBigBaseLen(const HPattern &p) {\n    if (p.bdirectAfter == -2) {\n        return bigOpts[p.bopt].len;\n    }\n    int len = 6;\n    if (p.bdirectAfter >= 0) {\n        len += 4 + bigOpts[p.bdirectAfter].len;\n    }\n    return len;\n}\n\nint hBigBaseFinalC(const HPattern &p) {\n    if (p.bdirectAfter == -2) {\n        return bigOpts[p.bopt].finalCol;\n    }\n    if (p.bdirectAfter >= 0) {\n        return bigOpts[p.bdirectAfter].finalCol;\n    }\n    return 4;\n}\n\nstring hBigBaseScript(const HPattern &p) {\n    if (p.bdirectAfter == -2) {\n        return bigOpts[p.bopt].act;\n    }\n\n    string s = \"PRRRRQ\";\n    if (p.bdirectAfter >= 0) {\n        s.append(4, 'L');\n        s += bigOpts[p.bdirectAfter].act;\n    }\n    return s;\n}\n\nstring hBigInitScript(const HPattern &p) {\n    string s = hBigBaseScript(p);\n    int c = hBigBaseFinalC(p);\n\n    while (c < p.repC) {\n        s.push_back('R');\n        c++;\n    }\n    while (c > p.repC) {\n        s.push_back('L');\n        c--;\n    }\n    return s;\n}\n\nvoid computeHT(HPattern &p) {\n    p.T = hBigBaseLen(p);\n    for (int i = 1; i < N; i++) p.T = max(p.T, hSmallInitLenRow(i, p.sopt[i]));\n}\n\nstruct HState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    int nextFree[N];\n    int smallLenRel = 0;\n    uint8_t hcnt[N];\n    short htime[N][N];\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = 0;\n        act.clear();\n        eval = 0;\n        smallLenRel = 0;\n        for (int i = 0; i < N; i++) {\n            nextFree[i] = 0;\n            hcnt[i] = 0;\n            for (int j = 0; j < N; j++) htime[i][j] = 0;\n        }\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveSafe(int tr, int tc) {\n        if (r > 0 && c == 3 && !(r == tr && c == tc)) {\n            add('L');\n        }\n\n        if (r != tr) {\n            while (c > 2) add('L');\n            while (r < tr) add('D');\n            while (r > tr) add('U');\n        }\n\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    void placeHandoff(int d) {\n        moveSafe(d, 2);\n        while ((int)act.size() + 1 < nextFree[d]) add('.');\n        add('R');\n\n        int qtime = (int)act.size();\n        add('Q');\n\n        htime[d][hcnt[d]++] = (short)qtime;\n        smallLenRel = max(smallLenRel, qtime + 5);\n        nextFree[d] = qtime + 4;\n        incQ(d);\n    }\n\n    vector<pair<int, int>> storageOptions(int b, int srcRow, double storageW, int maxOpt) const {\n        vector<tuple<double, int, int, int>> cand;\n        int bd = b / N;\n        int endC = (bd == 0 ? 4 : 3);\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (rr > 0 && cc == 3) continue;\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + abs(endC - cc);\n\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n                cand.emplace_back(sc, tie, rr, cc);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        vector<pair<int, int>> res;\n        for (int i = 0; i < (int)cand.size() && i < maxOpt; i++) {\n            res.push_back({get<2>(cand[i]), get<3>(cand[i])});\n        }\n        return res;\n    }\n};\n\ntemplate<class S>\nvoid setupHInitial(S &st, const HPattern &pat) {\n    st.clear();\n\n    if (pat.bdirectAfter == -2) {\n        const RowOption &ro = bigOpts[pat.bopt];\n        int cnt = (int)ro.cols.size();\n        st.p[0] = cnt;\n        st.pcode += cnt * pow6_[0];\n\n        for (int t = 0; t < cnt; t++) {\n            int b = A[0][t];\n            int cc = ro.cols[t];\n            st.occ[0][cc] = b;\n            st.lr[b] = 0;\n            st.lc[b] = cc;\n        }\n        if (cnt < N) st.occ[0][0] = A[0][cnt];\n    } else {\n        st.q[0] = 1;\n        st.qcode += pow6_[0];\n\n        int cnt = 1;\n        if (pat.bdirectAfter >= 0) {\n            const RowOption &ro = bigOpts[pat.bdirectAfter];\n            for (int t = 0; t < (int)ro.cols.size(); t++) {\n                int b = A[0][1 + t];\n                int cc = ro.cols[t];\n                st.occ[0][cc] = b;\n                st.lr[b] = 0;\n                st.lc[b] = cc;\n            }\n            cnt += (int)ro.cols.size();\n        }\n\n        st.p[0] = cnt;\n        st.pcode += cnt * pow6_[0];\n        if (cnt < N) st.occ[0][0] = A[0][cnt];\n    }\n\n    for (int i = 1; i < N; i++) {\n        int opt = pat.sopt[i];\n\n        if (isHDirectSmall(i, opt)) {\n            st.q[i] = 1;\n            st.qcode += pow6_[i];\n\n            st.p[i] = 1;\n            st.pcode += pow6_[i];\n            if (1 < N) st.occ[i][0] = A[i][1];\n            continue;\n        }\n\n        const RowOption &ro = hSmallOpts[opt];\n        int cnt = (int)ro.cols.size();\n        st.p[i] = cnt;\n        st.pcode += cnt * pow6_[i];\n\n        for (int t = 0; t < cnt; t++) {\n            int b = A[i][t];\n            int cc = ro.cols[t];\n            st.occ[i][cc] = b;\n            st.lr[b] = i;\n            st.lc[b] = cc;\n        }\n        if (cnt < N) st.occ[i][0] = A[i][cnt];\n    }\n\n    st.r = 0;\n    st.c = pat.repC;\n}\n\nHState makeHInitialState(const HPattern &pat) {\n    HState st;\n    setupHInitial(st, pat);\n    st.act.reserve(512);\n    return st;\n}\n\nbool hPlaceOutput(HState &ns, int d) {\n    if (d == 0) {\n        ns.moveSafe(0, 4);\n        ns.add('Q');\n        ns.incQ(0);\n    } else {\n        ns.placeHandoff(d);\n    }\n    return true;\n}\n\nbool doHDispatchBuffered(HState &ns, int d) {\n    int x = N * d + ns.q[d];\n    int rr = ns.lr[x], cc = ns.lc[x];\n    if (rr < 0 || ns.occ[rr][cc] != x) return false;\n\n    ns.moveSafe(rr, cc);\n    ns.add('P');\n    ns.occ[rr][cc] = -1;\n    ns.lr[x] = ns.lc[x] = -1;\n\n    return hPlaceOutput(ns, d);\n}\n\nbool doHDispatchSource(HState &ns, int d) {\n    int x = N * d + ns.q[d];\n    int s = srcOf[x];\n\n    if (ns.p[s] >= N) return false;\n    if (A[s][ns.p[s]] != x) return false;\n    if (ns.occ[s][0] != x) return false;\n\n    ns.moveSafe(s, 0);\n    ns.add('P');\n    ns.occ[s][0] = -1;\n    ns.incP(s);\n    if (ns.p[s] < N) ns.occ[s][0] = A[s][ns.p[s]];\n\n    return hPlaceOutput(ns, d);\n}\n\nvoid expandHBlockers(\n    const HState &cur,\n    int s,\n    int idx,\n    int d,\n    double storageW,\n    int optLimit,\n    vector<HState> &out\n) {\n    if (cur.p[s] == idx) {\n        HState ns = cur;\n        if (doHDispatchSource(ns, d)) out.push_back(std::move(ns));\n        return;\n    }\n\n    if (cur.p[s] > idx) return;\n\n    int b = A[s][cur.p[s]];\n    if (cur.occ[s][0] != b) return;\n\n    HState base = cur;\n    base.moveSafe(s, 0);\n    base.add('P');\n    base.occ[s][0] = -1;\n    base.incP(s);\n    if (base.p[s] < N) base.occ[s][0] = A[s][base.p[s]];\n\n    auto opts = base.storageOptions(b, s, storageW, optLimit);\n    for (auto [rr, cc] : opts) {\n        if (base.occ[rr][cc] != -1) continue;\n\n        HState ns = base;\n        ns.moveSafe(rr, cc);\n        ns.add('Q');\n        ns.occ[rr][cc] = b;\n        ns.lr[b] = rr;\n        ns.lc[b] = cc;\n\n        expandHBlockers(ns, s, idx, d, storageW, optLimit, out);\n    }\n}\n\nvector<HState> expandHExecuteTarget(\n    const HState &st,\n    int d,\n    double storageW,\n    int optLimit,\n    int perTransLimit\n) {\n    vector<HState> res;\n\n    int x = N * d + st.q[d];\n    int s = srcOf[x];\n    int idx = idxOf[x];\n\n    if (idx < st.p[s]) {\n        HState ns = st;\n        if (doHDispatchBuffered(ns, d)) res.push_back(std::move(ns));\n    } else {\n        expandHBlockers(st, s, idx, d, storageW, optLimit, res);\n    }\n\n    if ((int)res.size() > perTransLimit) {\n        sort(res.begin(), res.end(), [](const HState &a, const HState &b) {\n            return max((int)a.act.size(), a.smallLenRel) < max((int)b.act.size(), b.smallLenRel);\n        });\n        res.resize(perTransLimit);\n    }\n\n    return res;\n}\n\ntemplate<class S>\nint nearestHGeneric(const S &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n        int endC = (d == 0 ? 4 : 3);\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, endC) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, endC) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct HPlanResult {\n    bool ok = false;\n    string act;\n    int smallLenRel = 0;\n    array<uint8_t, N> hcnt{};\n    array<array<short, N>, N> htime{};\n};\n\nHPlanResult buildHBeam(const HState &init, double storageW, int width, int hcoef, int optLimit) {\n    if (dfsBlock(init.code()) >= INF) return {false, \"\", 0, {}, {}};\n\n    vector<HState> beam;\n    beam.push_back(init);\n\n    auto comp = [](const HState &a, const HState &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return max((int)a.act.size(), a.smallLenRel) < max((int)b.act.size(), b.smallLenRel);\n    };\n\n    int perTransLimit = (optLimit <= 1 ? 1 : 8);\n\n    for (int step = init.delivered(); step < TOT; step++) {\n        vector<HState> cand;\n        cand.reserve((size_t)width * N * perTransLimit);\n\n        for (const HState &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                vector<HState> nsList = expandHExecuteTarget(st, d, storageW, optLimit, perTransLimit);\n                for (HState &ns : nsList) {\n                    if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n                    int near = nearestHGeneric(ns);\n                    ns.eval = max((int)ns.act.size(), ns.smallLenRel) + hcoef * remAfter + near;\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return {false, \"\", 0, {}, {}};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    int bestLen = INF;\n    HState bestState;\n    bool found = false;\n\n    for (const HState &st0 : beam) {\n        HState st = st0;\n        if (st.r > 0 && st.c == 3) st.add('L');\n        int len = max((int)st.act.size(), st.smallLenRel);\n        if (len < bestLen) {\n            bestLen = len;\n            bestState = std::move(st);\n            found = true;\n        }\n    }\n\n    if (!found) return {false, \"\", 0, {}, {}};\n\n    HPlanResult res;\n    res.ok = true;\n    res.act = bestState.act;\n    res.smallLenRel = bestState.smallLenRel;\n    for (int i = 0; i < N; i++) {\n        res.hcnt[i] = bestState.hcnt[i];\n        for (int j = 0; j < N; j++) res.htime[i][j] = bestState.htime[i][j];\n    }\n    return res;\n}\n\nstruct HLiteState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n    int r = 0, c = 0, len = 0;\n    int nextFree[N];\n    int smallLenRel = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = len = 0;\n        smallLenRel = 0;\n        for (int i = 0; i < N; i++) nextFree[i] = 0;\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) {\n        p[s]++;\n        pcode += pow6_[s];\n    }\n\n    void incQ(int d) {\n        q[d]++;\n        qcode += pow6_[d];\n    }\n\n    void moveSafe(int tr, int tc) {\n        if (r > 0 && c == 3 && !(r == tr && c == tc)) {\n            len++;\n            c = 2;\n        }\n\n        if (r != tr) {\n            if (c > 2) {\n                len += c - 2;\n                c = 2;\n            }\n            len += abs(r - tr);\n            r = tr;\n        }\n\n        len += abs(c - tc);\n        c = tc;\n    }\n\n    void placeHandoff(int d) {\n        moveSafe(d, 2);\n        while (len + 1 < nextFree[d]) len++;\n        len++;\n        c = 3;\n\n        int qtime = len;\n        len++;\n        smallLenRel = max(smallLenRel, qtime + 5);\n        nextFree[d] = qtime + 4;\n        incQ(d);\n    }\n\n    pair<int, int> chooseStorage(int b, int srcRow, double storageW) const {\n        int bd = b / N;\n        int endC = (bd == 0 ? 4 : 3);\n        double best = 1e100;\n        int bestTie = INF;\n        pair<int, int> res = {-1, -1};\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (rr > 0 && cc == 3) continue;\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + abs(endC - cc);\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n\n                if (sc + 1e-9 < best || (fabs(sc - best) <= 1e-9 && tie < bestTie)) {\n                    best = sc;\n                    bestTie = tie;\n                    res = {rr, cc};\n                }\n            }\n        }\n\n        return res;\n    }\n\n    bool placeOutput(int d) {\n        if (d == 0) {\n            moveSafe(0, 4);\n            len++;\n            incQ(0);\n        } else {\n            placeHandoff(d);\n        }\n        return true;\n    }\n\n    bool dispatchBuffered(int d) {\n        int x = N * d + q[d];\n        int rr = lr[x], cc = lc[x];\n        if (rr < 0 || occ[rr][cc] != x) return false;\n\n        moveSafe(rr, cc);\n        len++;\n        occ[rr][cc] = -1;\n        lr[x] = lc[x] = -1;\n\n        return placeOutput(d);\n    }\n\n    bool dispatchSource(int d) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n\n        if (p[s] >= N) return false;\n        if (A[s][p[s]] != x) return false;\n        if (occ[s][0] != x) return false;\n\n        moveSafe(s, 0);\n        len++;\n        occ[s][0] = -1;\n        incP(s);\n        if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n        return placeOutput(d);\n    }\n\n    bool executeTarget(int d, double storageW) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        if (idx < p[s]) {\n            return dispatchBuffered(d);\n        }\n\n        while (p[s] < idx) {\n            int b = A[s][p[s]];\n            if (occ[s][0] != b) return false;\n\n            moveSafe(s, 0);\n            len++;\n            occ[s][0] = -1;\n            incP(s);\n            if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n            auto cell = chooseStorage(b, s, storageW);\n            if (cell.first < 0) return false;\n\n            moveSafe(cell.first, cell.second);\n            len++;\n            occ[cell.first][cell.second] = b;\n            lr[b] = cell.first;\n            lc[b] = cell.second;\n        }\n\n        return dispatchSource(d);\n    }\n};\n\nHLiteState makeHLiteInitialState(const HPattern &pat) {\n    HLiteState st;\n    setupHInitial(st, pat);\n    return st;\n}\n\nint hGreedyLength(const HPattern &pat, double storageW, int hcoef) {\n    string bs = hBigInitScript(pat);\n    if ((int)bs.size() > pat.T) return INF;\n\n    HLiteState st = makeHLiteInitialState(pat);\n    if (dfsBlock(st.code()) >= INF) return INF;\n\n    for (int step = st.delivered(); step < TOT; step++) {\n        int bestEval = INF;\n        int bestLen = INF;\n        bool found = false;\n        HLiteState bestSt;\n\n        for (int d = 0; d < N; d++) {\n            TransCode tr;\n            if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n            int remAfter = dfsBlock(tr.code);\n            if (remAfter >= INF) continue;\n\n            HLiteState ns = st;\n            if (!ns.executeTarget(d, storageW)) continue;\n            if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n\n            int curLen = max(ns.len, ns.smallLenRel);\n            int eval = curLen + hcoef * remAfter + nearestHGeneric(ns);\n            if (eval < bestEval || (eval == bestEval && curLen < bestLen)) {\n                bestEval = eval;\n                bestLen = curLen;\n                bestSt = ns;\n                found = true;\n            }\n        }\n\n        if (!found) return INF;\n        st = bestSt;\n    }\n\n    if (st.r > 0 && st.c == 3) st.len++;\n    return pat.T + max(st.len, st.smallLenRel);\n}\n\nvector<HPattern> generateHPatterns() {\n    vector<HPattern> res;\n\n    int B = (int)bigOpts.size();\n    int S = (int)hSmallOpts.size();\n\n    vector<pair<int, int>> bigVars; // {bdirectAfter, bopt}\n\n    if (A[0][0] == 0) {\n        bigVars.push_back({-1, 0});\n        for (int after = 0; after < B; after++) {\n            bigVars.push_back({after, 0});\n        }\n    }\n    for (int b = 0; b < B; b++) {\n        bigVars.push_back({-2, b});\n    }\n\n    vector<int> optList[N];\n    for (int i = 1; i < N; i++) {\n        if (A[i][0] == i * N) optList[i].push_back(hDirectCode());\n        for (int o = 0; o < S; o++) optList[i].push_back(o);\n    }\n\n    for (auto [bdirectAfter, bopt] : bigVars) {\n        int sizes[5] = {};\n        int total = 1;\n        for (int i = 1; i < N; i++) {\n            sizes[i] = (int)optList[i].size();\n            total *= sizes[i];\n        }\n\n        for (int code = 0; code < total; code++) {\n            HPattern base;\n            base.bopt = bopt;\n            base.bdirectAfter = bdirectAfter;\n            base.sopt.fill(0);\n\n            int tmp = code;\n            for (int i = 1; i < N; i++) {\n                int id = tmp % sizes[i];\n                tmp /= sizes[i];\n                base.sopt[i] = optList[i][id];\n            }\n\n            computeHT(base);\n            int finalC = hBigBaseFinalC(base);\n            int slack = base.T - hBigBaseLen(base);\n\n            for (int c = 0; c < N; c++) {\n                if (abs(c - finalC) <= slack) {\n                    HPattern p = base;\n                    p.repC = c;\n                    res.push_back(p);\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\narray<string, N> makeHOutput(const HPattern &pat, const HPlanResult &pr) {\n    array<string, N> out;\n\n    string big = hBigInitScript(pat);\n    if ((int)big.size() < pat.T) big += string(pat.T - (int)big.size(), '.');\n    big += pr.act;\n    out[0] = big;\n\n    for (int i = 1; i < N; i++) {\n        string s = hSmallInitScriptRow(i, pat.sopt[i]);\n        int need = pat.T + pr.smallLenRel;\n        if ((int)s.size() < need) s.resize(need, '.');\n\n        for (int k = 0; k < pr.hcnt[i]; k++) {\n            int t = pat.T + pr.htime[i][k];\n            if ((int)s.size() <= t + 4) s.resize(t + 5, '.');\n            s[t + 1] = 'L';\n            s[t + 2] = 'P';\n            s[t + 3] = 'R';\n            s[t + 4] = 'Q';\n        }\n        out[i] = s;\n    }\n\n    return out;\n}\n\n/*** fallback direct ***/\n\nstring buildDirectPlan() {\n    State st;\n    st.clear();\n    for (int i = 0; i < N; i++) st.occ[i][0] = A[i][0];\n\n    for (int s = 0; s < N; s++) {\n        while (st.p[s] < N) {\n            int x = A[s][st.p[s]];\n            int d = x / N;\n\n            st.moveTo(s, 0);\n            st.add('P');\n            st.occ[s][0] = -1;\n            st.incP(s);\n            if (st.p[s] < N) st.occ[s][0] = A[s][st.p[s]];\n\n            st.moveTo(d, N - 1);\n            st.add('Q');\n        }\n    }\n\n    return st.act;\n}\n\nint directInversions() {\n    vector<int> seq[N];\n    int inv = 0;\n\n    for (int s = 0; s < N; s++) {\n        for (int k = 0; k < N; k++) {\n            int x = A[s][k];\n            int d = x / N;\n            for (int y : seq[d]) {\n                if (y > x) inv++;\n            }\n            seq[d].push_back(x);\n        }\n    }\n\n    return inv;\n}\n\nvoid initTables() {\n    pow6_[0] = 1;\n    for (int i = 0; i < N; i++) pow6_[i + 1] = pow6_[i] * BASE;\n\n    for (int code = 0; code < PBASE; code++) {\n        int tmp = code;\n        int sm = 0, ex = 0;\n        for (int i = 0; i < N; i++) {\n            int v = tmp % BASE;\n            tmp /= BASE;\n            dig[code][i] = (uint8_t)v;\n            sm += v;\n            if (v == N) ex++;\n        }\n        sumCode[code] = (uint8_t)sm;\n        exhCode[code] = (uint8_t)ex;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initTables();\n    initRowOptions();\n\n    int Nin;\n    cin >> Nin;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> A[i][j];\n            srcOf[A[i][j]] = i;\n            idxOf[A[i][j]] = j;\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsedMs = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    };\n\n    memoBlock.assign(TOTAL_STATES, -1);\n\n    array<string, N> bestOut;\n    long long bestScore = (long long)4e18;\n\n    {\n        string directAct = buildDirectPlan();\n        int inv = directInversions();\n        long long directScore = (long long)directAct.size() + 100LL * inv;\n\n        bestOut[0] = directAct.empty() ? \".\" : directAct;\n        for (int i = 1; i < N; i++) bestOut[i] = \"B\";\n        bestScore = directScore;\n    }\n\n    auto tryUpdateSorted = [&](const Pattern &pat, const string &cont) {\n        if (cont.empty()) return;\n\n        string bs = bigInitScript(pat);\n        if ((int)bs.size() > pat.T) return;\n\n        auto out = makeSortedOutput(pat, cont);\n        int m0 = 0;\n        for (int i = 0; i < N; i++) m0 = max(m0, (int)out[i].size());\n        if (m0 <= 0 || m0 > 10000) return;\n\n        if ((long long)m0 < bestScore) {\n            bestScore = m0;\n            bestOut = out;\n        }\n    };\n\n    auto tryUpdateH = [&](const HPattern &pat, const HPlanResult &pr) {\n        if (!pr.ok) return;\n\n        string bs = hBigInitScript(pat);\n        if ((int)bs.size() > pat.T) return;\n\n        int m0 = max(pat.T + (int)pr.act.size(), pat.T + pr.smallLenRel);\n        if (m0 <= 0 || m0 > 10000) return;\n\n        if ((long long)m0 < bestScore) {\n            bestScore = m0;\n            bestOut = makeHOutput(pat, pr);\n        }\n    };\n\n    vector<Pattern> candidates = generateCandidates();\n\n    vector<pair<int, int>> estimates;\n    estimates.reserve(candidates.size());\n\n    for (int idx = 0; idx < (int)candidates.size(); idx++) {\n        if ((idx & 255) == 0 && elapsedMs() > 1450 && (int)estimates.size() > 80) break;\n\n        int gl = greedyLength(candidates[idx], 1.0, 8);\n        if (gl < INF) estimates.push_back({gl, idx});\n    }\n\n    sort(estimates.begin(), estimates.end());\n\n    vector<Pattern> baseSelected;\n\n    auto addUnique = [&](vector<Pattern> &v, const Pattern &p) {\n        for (const Pattern &q : v) {\n            if (samePattern(p, q)) return;\n        }\n        v.push_back(p);\n    };\n\n    for (int i = 0; i < (int)estimates.size() && i < 60; i++) {\n        addUnique(baseSelected, candidates[estimates[i].second]);\n    }\n\n    for (int so = 0; so < (int)smallOpts.size(); so++) {\n        int bo = -1;\n        for (int b = 0; b < (int)bigOpts.size(); b++) {\n            if (bigOpts[b].cols == smallOpts[so].cols) {\n                bo = b;\n                break;\n            }\n        }\n        if (bo < 0) continue;\n\n        Pattern p;\n        p.opt.fill(so);\n        p.opt[0] = bo;\n        computeT(p);\n        addUnique(baseSelected, p);\n    }\n\n    vector<Pattern> variants;\n    for (const Pattern &p : baseSelected) {\n        for (const Pattern &v : reachableVariants(p)) {\n            addUnique(variants, v);\n        }\n    }\n\n    vector<pair<int, int>> variantEst;\n    for (int i = 0; i < (int)variants.size(); i++) {\n        if ((i & 63) == 0 && elapsedMs() > 1800 && (int)variantEst.size() > 30) break;\n        int gl = greedyLength(variants[i], 1.0, 8);\n        if (gl < INF) variantEst.push_back({gl, i});\n    }\n\n    sort(variantEst.begin(), variantEst.end());\n\n    vector<Pattern> finalPatterns;\n    for (int i = 0; i < (int)variantEst.size() && i < 42; i++) {\n        addUnique(finalPatterns, variants[variantEst[i].second]);\n    }\n    for (int i = 0; i < (int)baseSelected.size() && i < 10; i++) {\n        addUnique(finalPatterns, baseSelected[i]);\n    }\n\n    if (finalPatterns.empty()) {\n        Pattern p;\n        p.opt.fill(0);\n        p.opt[0] = 0;\n        computeT(p);\n        finalPatterns.push_back(p);\n    }\n\n    for (int rank = 0; rank < (int)finalPatterns.size(); rank++) {\n        if (elapsedMs() > 2480) break;\n\n        const Pattern &pat = finalPatterns[rank];\n        State init = makeInitialState(pat);\n\n        if (dfsBlock(init.code()) >= INF) continue;\n\n        {\n            PlanResult pr = buildBeam(init, 1.0, 1, 8, 1);\n            if (pr.ok) tryUpdateSorted(pat, pr.act);\n        }\n\n        vector<double> weights;\n        vector<int> hs;\n        int width;\n\n        if (rank < 6) {\n            weights = {0.0, 0.4, 0.9, 1.8, 4.0};\n            hs = {0, 8};\n            width = 240;\n        } else if (rank < 20) {\n            weights = {0.4, 0.9, 1.8, 3.5};\n            hs = {8};\n            width = 145;\n        } else {\n            weights = {0.9, 2.5};\n            hs = {8};\n            width = 80;\n        }\n\n        for (int h : hs) {\n            for (double w : weights) {\n                if (elapsedMs() > 2520) break;\n\n                PlanResult pr = buildBeam(init, w, width, h, 1);\n                if (pr.ok) tryUpdateSorted(pat, pr.act);\n            }\n        }\n    }\n\n    // Handoff mode: small cranes in rows 1..4 act as dispatch assistants.\n    if (elapsedMs() < 2820) {\n        vector<HPattern> hpats = generateHPatterns();\n\n        vector<pair<int, int>> hEst;\n        hEst.reserve(hpats.size());\n\n        for (int idx = 0; idx < (int)hpats.size(); idx++) {\n            if ((idx & 127) == 0 && elapsedMs() > 2630 && (int)hEst.size() > 30) break;\n            int gl = hGreedyLength(hpats[idx], 1.0, 8);\n            if (gl < INF) hEst.push_back({gl, idx});\n        }\n\n        sort(hEst.begin(), hEst.end());\n\n        vector<int> hSel;\n        vector<char> used(hpats.size(), 0);\n        auto addHSel = [&](int idx) {\n            if (0 <= idx && idx < (int)hpats.size() && !used[idx]) {\n                used[idx] = 1;\n                hSel.push_back(idx);\n            }\n        };\n\n        for (int i = 0; i < (int)hEst.size() && i < 30; i++) addHSel(hEst[i].second);\n\n        for (int rank = 0; rank < (int)hSel.size(); rank++) {\n            if (elapsedMs() > 2860) break;\n\n            const HPattern &pat = hpats[hSel[rank]];\n            HState init = makeHInitialState(pat);\n\n            if (dfsBlock(init.code()) >= INF) continue;\n\n            {\n                HPlanResult pr = buildHBeam(init, 1.0, 1, 8, 1);\n                tryUpdateH(pat, pr);\n            }\n\n            vector<double> weights;\n            int width;\n\n            if (rank < 5) {\n                weights = {0.4, 0.9, 1.8, 3.5};\n                width = 150;\n            } else if (rank < 14) {\n                weights = {0.8, 1.8, 3.0};\n                width = 90;\n            } else {\n                weights = {1.2};\n                width = 55;\n            }\n\n            for (double w : weights) {\n                if (elapsedMs() > 2870) break;\n                HPlanResult pr = buildHBeam(init, w, width, 8, 1);\n                tryUpdateH(pat, pr);\n            }\n\n            if (rank < 3 && elapsedMs() < 2800) {\n                for (double w : {0.8, 2.0}) {\n                    if (elapsedMs() > 2840) break;\n                    HPlanResult pr = buildHBeam(init, w, 65, 8, 2);\n                    tryUpdateH(pat, pr);\n                }\n            }\n        }\n    }\n\n    // Small final branching for the standard mode if time remains.\n    for (int rank = 0; rank < (int)finalPatterns.size() && rank < 4; rank++) {\n        if (elapsedMs() > 2820) break;\n\n        const Pattern &pat = finalPatterns[rank];\n        State init = makeInitialState(pat);\n\n        for (double w : {0.7, 1.5, 3.0}) {\n            if (elapsedMs() > 2910) break;\n            PlanResult pr = buildBeam(init, w, 65, 8, 2);\n            if (pr.ok) tryUpdateSorted(pat, pr.act);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (bestOut[i].empty()) bestOut[i] = \".\";\n        cout << bestOut[i] << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 20;\nstatic const int V = N * N;\nstatic const long long INFLL = (1LL << 60);\nstatic const int INF = 1e9;\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    bool ok(double lim) const {\n        return elapsed() < lim;\n    }\n};\n\nTimer TIMER;\n\nint H[V];\nint DIST[V][V];\nlong long BASE_COST = 0;\n\nint cell_id(int r, int c) {\n    return r * N + c;\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 Op {\n    char c;\n    int d;\n};\n\nstruct Solution {\n    vector<Op> ops;\n    long long cost = 0;\n    long long load = 0;\n    int pos = 0;\n    bool valid = true;\n\n    Solution() {\n        ops.reserve(4096);\n    }\n\n    void moveOne(char ch) {\n        ops.push_back({ch, 0});\n        cost += 100 + load;\n\n        int r = pos / N;\n        int c = pos % N;\n        if (ch == 'U') --r;\n        if (ch == 'D') ++r;\n        if (ch == 'L') --c;\n        if (ch == 'R') ++c;\n        if (r < 0 || r >= N || c < 0 || c >= N) valid = false;\n        pos = cell_id(r, c);\n    }\n\n    void moveTo(int target) {\n        int tr = target / N;\n        int tc = target % N;\n        while (pos / N < tr) moveOne('D');\n        while (pos / N > tr) moveOne('U');\n        while (pos % N < tc) moveOne('R');\n        while (pos % N > tc) moveOne('L');\n    }\n\n    void addLoad(long long d) {\n        while (d > 0) {\n            int x = (int)min<long long>(d, 1000000);\n            ops.push_back({'+', x});\n            cost += x;\n            load += x;\n            d -= x;\n        }\n    }\n\n    void addUnload(long long d) {\n        while (d > 0) {\n            int x = (int)min<long long>(d, 1000000);\n            if (load < x) valid = false;\n            ops.push_back({'-', x});\n            cost += x;\n            load -= x;\n            d -= x;\n        }\n    }\n};\n\narray<int, V> nearestDist(const vector<int>& rem, bool positive, bool& has) {\n    array<int, V> dist;\n    dist.fill(INF);\n    queue<int> q;\n    has = false;\n\n    for (int i = 0; i < V; ++i) {\n        if ((positive && rem[i] > 0) || (!positive && rem[i] < 0)) {\n            dist[i] = 0;\n            q.push(i);\n            has = true;\n        }\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        int r = v / N;\n        int c = v % N;\n        const int dr[4] = {-1, 1, 0, 0};\n        const int dc[4] = {0, 0, -1, 1};\n\n        for (int k = 0; k < 4; ++k) {\n            int nr = r + dr[k];\n            int nc = c + dc[k];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int to = cell_id(nr, nc);\n            if (dist[to] > dist[v] + 1) {\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n    }\n\n    return dist;\n}\n\nint selectSource(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearNeg,\n    int mode,\n    int maxAmount\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] <= 0) continue;\n        if (maxAmount >= 0 && rem[i] > maxAmount) continue;\n\n        int d = DIST[cur][i];\n        int nd = nearNeg[i] >= INF ? 0 : nearNeg[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * rem[i];\n        } else if (mode == 1) {\n            score = 10000LL * d - 200LL * rem[i];\n        } else {\n            score = 8000LL * d + 3000LL * nd - 50LL * rem[i];\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nint selectDemand(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearPos,\n    bool hasPos,\n    long long load,\n    int mode\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] >= 0) continue;\n\n        int demand = -rem[i];\n        int del = (int)min<long long>(load, demand);\n        if (del <= 0) continue;\n\n        int d = DIST[cur][i];\n        int future = 0;\n        if (load == del && hasPos && nearPos[i] < INF) future = nearPos[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * del + 1000LL * future;\n        } else if (mode == 1) {\n            score = 1000LL * d * (100 + load) / (del + 10) + 500LL * future;\n        } else {\n            score = 10000LL * d - 200LL * del + 1000LL * future;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nSolution makeGreedySolution(int maxLoad, int ratioNum, int ratioDen, int sourceMode, int demandMode) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 10000; ++iter) {\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            sol.moveTo(p);\n            int a = rem[p];\n            sol.addLoad(a);\n            rem[p] = 0;\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (maxLoad > 0 && hasPos) {\n                int maxAmount = maxLoad - (int)sol.load;\n                if (maxAmount > 0) {\n                    p = selectSource(sol.pos, rem, nearNeg, sourceMode, maxAmount);\n                    if (p >= 0) {\n                        int nearestDemand = nearNeg[sol.pos];\n                        int dp = DIST[sol.pos][p];\n\n                        if (nearestDemand > 0 &&\n                            1LL * dp * ratioDen <= 1LL * nearestDemand * ratioNum) {\n                            takePos = true;\n                        }\n                    }\n                }\n            }\n\n            if (takePos) {\n                sol.moveTo(p);\n                int a = rem[p];\n                sol.addLoad(a);\n                rem[p] = 0;\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                sol.moveTo(q);\n                int x = (int)min<long long>(sol.load, -rem[q]);\n                sol.addUnload(x);\n                rem[q] += x;\n            }\n        }\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nvoid serviceCell(Solution& sol, vector<int>& rem, int cap) {\n    int v = sol.pos;\n\n    if (rem[v] < 0 && sol.load > 0) {\n        long long x = min<long long>(sol.load, -rem[v]);\n        sol.addUnload(x);\n        rem[v] += (int)x;\n    }\n\n    if (rem[v] > 0 && sol.load < cap) {\n        long long x = min<long long>(rem[v], (long long)cap - sol.load);\n        sol.addLoad(x);\n        rem[v] -= (int)x;\n    }\n}\n\nlong long stepScoreForService(int nxt, int target, const vector<int>& rem, long long load, int cap) {\n    long long score = 0;\n\n    if (rem[nxt] < 0 && load > 0) {\n        long long x = min<long long>(load, -rem[nxt]);\n        score -= 100000LL * x;\n        score -= 3000LL * x * DIST[nxt][target];\n    }\n\n    if (rem[nxt] > 0 && load < cap) {\n        long long x = min<long long>(rem[nxt], (long long)cap - load);\n        score -= 20000LL * x;\n        score += 700LL * x * DIST[nxt][target];\n    }\n\n    return score;\n}\n\nvoid moveToService(Solution& sol, int target, vector<int>& rem, int cap, int pathMode) {\n    serviceCell(sol, rem, cap);\n\n    while (sol.pos != target) {\n        int r = sol.pos / N;\n        int c = sol.pos % N;\n        int tr = target / N;\n        int tc = target % N;\n\n        char chosen = 0;\n\n        if (pathMode == 0) {\n            if (r < tr) chosen = 'D';\n            else if (r > tr) chosen = 'U';\n            else if (c < tc) chosen = 'R';\n            else chosen = 'L';\n        } else if (pathMode == 1) {\n            if (c < tc) chosen = 'R';\n            else if (c > tc) chosen = 'L';\n            else if (r < tr) chosen = 'D';\n            else chosen = 'U';\n        } else {\n            vector<pair<char, int>> cand;\n            if (r < tr) cand.push_back({'D', cell_id(r + 1, c)});\n            if (r > tr) cand.push_back({'U', cell_id(r - 1, c)});\n            if (c < tc) cand.push_back({'R', cell_id(r, c + 1)});\n            if (c > tc) cand.push_back({'L', cell_id(r, c - 1)});\n\n            long long best = INFLL;\n            for (auto [ch, id] : cand) {\n                long long sc = stepScoreForService(id, target, rem, sol.load, cap);\n                if (sc < best) {\n                    best = sc;\n                    chosen = ch;\n                }\n            }\n        }\n\n        sol.moveOne(chosen);\n        serviceCell(sol, rem, cap);\n    }\n}\n\nSolution makeGreedyServiceSolution(\n    int cap,\n    int ratioNum,\n    int ratioDen,\n    int sourceMode,\n    int demandMode,\n    int pathMode\n) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 20000; ++iter) {\n        serviceCell(sol, rem, cap);\n\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            moveToService(sol, p, rem, cap, pathMode);\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (sol.load < cap && hasPos) {\n                p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n                if (p >= 0) {\n                    int direct = nearNeg[sol.pos];\n                    int via = DIST[sol.pos][p] + nearNeg[p];\n\n                    if (direct >= INF) direct = 1000;\n                    if (via * ratioDen <= direct * ratioNum + 2 * ratioDen) {\n                        takePos = true;\n                    }\n\n                    if (DIST[sol.pos][p] <= 2 && sol.load < cap * 3LL / 4) {\n                        takePos = true;\n                    }\n                }\n            }\n\n            if (takePos) {\n                moveToService(sol, p, rem, cap, pathMode);\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                moveToService(sol, q, rem, cap, pathMode);\n            }\n        }\n    }\n\n    serviceCell(sol, rem, cap);\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev;\n        long long cap, cost;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow(int n_) : n(n_), g(n_) {}\n\n    int addEdge(int fr, int to, long long cap, long long cost) {\n        Edge f{to, (int)g[to].size(), cap, cost};\n        Edge r{fr, (int)g[fr].size(), 0, -cost};\n        g[fr].push_back(f);\n        g[to].push_back(r);\n        return (int)g[fr].size() - 1;\n    }\n\n    pair<long long, long long> minCostFlow(int s, int t, long long maxf) {\n        long long flow = 0;\n        long long cost = 0;\n\n        vector<long long> pot(n, 0), dist(n);\n        vector<int> pv(n), pe(n);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INFLL);\n            dist[s] = 0;\n\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != d) continue;\n\n                for (int i = 0; i < (int)g[v].size(); ++i) {\n                    Edge& e = g[v][i];\n                    if (e.cap <= 0) continue;\n\n                    long long nd = d + e.cost + pot[v] - pot[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INFLL) break;\n\n            for (int v = 0; v < n; ++v) {\n                if (dist[v] < INFLL) pot[v] += dist[v];\n            }\n\n            long long add = maxf - flow;\n            for (int v = t; v != s; v = pv[v]) {\n                add = min(add, g[pv[v]][pe[v]].cap);\n            }\n\n            for (int v = t; v != s; v = pv[v]) {\n                Edge& e = g[pv[v]][pe[v]];\n                e.cap -= add;\n                g[v][e.rev].cap += add;\n                cost += add * e.cost;\n            }\n\n            flow += add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nstruct Flow {\n    int s, t, amount;\n};\n\nvector<Flow> computeMinCostFlows(int variant) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n            total += H[i];\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n    if (total == 0) return {};\n\n    int SRC = 0;\n    int posBase = 1;\n    int negBase = 1 + P;\n    int SNK = 1 + P + Q;\n    int nodes = SNK + 1;\n\n    MinCostFlow mf(nodes);\n\n    for (int i = 0; i < P; ++i) {\n        mf.addEdge(SRC, posBase + i, posAmt[i], 0);\n    }\n\n    for (int j = 0; j < Q; ++j) {\n        mf.addEdge(negBase + j, SNK, negAmt[j], 0);\n    }\n\n    struct Ref {\n        int node, edgeIndex, pi, qi;\n    };\n    vector<Ref> refs;\n\n    const long long CAP = 1e9;\n    const long long W = 100000000LL;\n\n    for (int i = 0; i < P; ++i) {\n        for (int j = 0; j < Q; ++j) {\n            long long tie = 0;\n\n            if (variant != 0) {\n                uint64_t seed = ((uint64_t)variant << 48) ^ ((uint64_t)posCells[i] << 24) ^ (uint64_t)negCells[j];\n                tie = splitmix64(seed) % 1000;\n            }\n\n            long long c = 1LL * DIST[posCells[i]][negCells[j]] * W + tie;\n            int idx = mf.addEdge(posBase + i, negBase + j, CAP, c);\n            refs.push_back({posBase + i, idx, i, j});\n        }\n    }\n\n    mf.minCostFlow(SRC, SNK, total);\n\n    vector<Flow> flows;\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            flows.push_back({posCells[ref.pi], negCells[ref.qi], (int)used});\n        }\n    }\n\n    return flows;\n}\n\nvector<Flow> computeGreedyFlows(int mode) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n\n    vector<Flow> flows;\n\n    for (int step = 0; step < P + Q + 5; ++step) {\n        long long bestScore = INFLL;\n        int bi = -1, bj = -1;\n\n        for (int i = 0; i < P; ++i) {\n            if (posAmt[i] <= 0) continue;\n\n            for (int j = 0; j < Q; ++j) {\n                if (negAmt[j] <= 0) continue;\n\n                int a = min(posAmt[i], negAmt[j]);\n                int d = DIST[posCells[i]][negCells[j]];\n\n                long long score;\n                if (mode == 0) {\n                    score = 100000LL * d - 700LL * a;\n                } else if (mode == 1) {\n                    score = 100000LL * d\n                          + 150LL * (DIST[0][posCells[i]] + DIST[0][negCells[j]])\n                          - 500LL * a;\n                } else {\n                    score = 100000LL * d\n                          - 1200LL * a\n                          + 20LL * abs(posAmt[i] - negAmt[j]);\n                }\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi < 0) break;\n\n        int a = min(posAmt[bi], negAmt[bj]);\n        flows.push_back({posCells[bi], negCells[bj], a});\n        posAmt[bi] -= a;\n        negAmt[bj] -= a;\n    }\n\n    return flows;\n}\n\nvector<int> optimizeOrder(const vector<int>& starts, const vector<int>& ends) {\n    int m = (int)starts.size();\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    vector<int> startLink(m);\n    vector<vector<int>> link(m, vector<int>(m));\n\n    for (int i = 0; i < m; ++i) {\n        startLink[i] = DIST[0][starts[i]];\n    }\n\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < m; ++j) {\n            link[i][j] = DIST[ends[i]][starts[j]];\n        }\n    }\n\n    auto L = [&](int prev, int cur) -> int {\n        if (prev < 0) return startLink[cur];\n        return link[prev][cur];\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n\n    for (int cnt = 0; cnt < m; ++cnt) {\n        int bestG = -1, bestPos = 0;\n        int bestInc = INF;\n\n        for (int g = 0; g < m; ++g) {\n            if (used[g]) continue;\n\n            for (int p = 0; p <= (int)order.size(); ++p) {\n                int prev = (p == 0 ? -1 : order[p - 1]);\n                int nxt = (p == (int)order.size() ? -2 : order[p]);\n\n                int inc = L(prev, g);\n                if (nxt != -2) inc += L(g, nxt) - L(prev, nxt);\n\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestG = g;\n                    bestPos = p;\n                }\n            }\n        }\n\n        order.insert(order.begin() + bestPos, bestG);\n        used[bestG] = true;\n    }\n\n    for (int pass = 0; pass < 30; ++pass) {\n        int bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prev = (i == 0 ? -1 : order[i - 1]);\n            int nxt = (i + 1 == m ? -2 : order[i + 1]);\n\n            int oldRemove = L(prev, x);\n            if (nxt != -2) oldRemove += L(x, nxt);\n\n            int newRemove = 0;\n            if (nxt != -2) newRemove += L(prev, nxt);\n\n            int removeDelta = newRemove - oldRemove;\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int oldInsert = 0;\n                if (after != -2) oldInsert += L(before, after);\n\n                int newInsert = L(before, x);\n                if (after != -2) newInsert += L(x, after);\n\n                int delta = removeDelta + newInsert - oldInsert;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            int oldInternal = 0;\n            int newInternal = 0;\n            int prev = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += L(order[r - 1], order[r]);\n                newInternal += L(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                int oldCost = L(prev, order[l]) + oldInternal;\n                if (after != -2) oldCost += L(order[r], after);\n\n                int newCost = L(prev, order[r]) + newInternal;\n                if (after != -2) newCost += L(order[l], after);\n\n                int delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else if (bestType == 2) {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nstruct SourceGroup {\n    int source = -1;\n    int total = 0;\n    int end = -1;\n    vector<int> dest, amt, order;\n};\n\nvoid computeSourceOrder(SourceGroup& g, int target) {\n    int k = (int)g.dest.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            dp[idx(mask, j)] = 1LL * DIST[g.source][g.dest[j]] * (100 + total);\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = total - sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.dest[last]][g.dest[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)];\n            if (target >= 0) c += 100LL * DIST[g.dest[last]][target];\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = g.source;\n        int load = total;\n\n        for (int left = k; left > 0; --left) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score = 1LL * DIST[cur][g.dest[j]] * (100 + load);\n                if (left == 1 && target >= 0) {\n                    score += 100LL * DIST[g.dest[j]][target];\n                }\n\n                score -= 5LL * g.amt[j];\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.dest[bj];\n            load -= g.amt[bj];\n        }\n    }\n\n    g.end = g.dest[g.order.back()];\n}\n\nvector<SourceGroup> buildSourceGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.s].push_back({f.t, f.amount});\n    }\n\n    vector<SourceGroup> groups;\n\n    for (int s = 0; s < V; ++s) {\n        if (mp[s].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [t, a] : mp[s]) comb[t] += a;\n\n        SourceGroup g;\n        g.source = s;\n\n        for (auto [t, a] : comb) {\n            g.dest.push_back(t);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeSourceOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeSourceGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildSourceGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].source;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n            computeSourceOrder(groups[gi], target);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].source;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n        computeSourceOrder(groups[gi], target);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        sol.moveTo(g.source);\n        sol.addLoad(g.total);\n\n        for (int idx : g.order) {\n            sol.moveTo(g.dest[idx]);\n            sol.addUnload(g.amt[idx]);\n        }\n    }\n\n    return sol;\n}\n\nSolution makePairSolution(const vector<Flow>& flows) {\n    Solution sol;\n    int m = (int)flows.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = flows[i].s;\n        ends[i] = flows[i].t;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int idx : order) {\n        const auto& f = flows[idx];\n\n        sol.moveTo(f.s);\n        sol.addLoad(f.amount);\n        sol.moveTo(f.t);\n        sol.addUnload(f.amount);\n    }\n\n    return sol;\n}\n\nstruct DemandGroup {\n    int demand = -1;\n    int total = 0;\n    int start = -1;\n    int end = -1;\n    vector<int> src, amt, order;\n};\n\nvoid computeDemandOrder(DemandGroup& g, int prevCell) {\n    int k = (int)g.src.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            long long entry = 0;\n            if (prevCell >= 0) entry = 100LL * DIST[prevCell][g.src[j]];\n\n            dp[idx(mask, j)] = entry;\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.src[last]][g.src[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)] + 1LL * DIST[g.src[last]][g.demand] * (100 + total);\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = -1;\n        int load = 0;\n\n        for (int step = 0; step < k; ++step) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score;\n\n                if (step == 0) {\n                    score = 0;\n                    if (prevCell >= 0) score += 100LL * DIST[prevCell][g.src[j]];\n                    score -= 50LL * DIST[g.src[j]][g.demand];\n                } else {\n                    score = 1LL * DIST[cur][g.src[j]] * (100 + load)\n                          + 10LL * DIST[g.src[j]][g.demand];\n                }\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.src[bj];\n            load += g.amt[bj];\n        }\n    }\n\n    g.start = g.src[g.order.front()];\n    g.end = g.demand;\n}\n\nvector<DemandGroup> buildDemandGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.t].push_back({f.s, f.amount});\n    }\n\n    vector<DemandGroup> groups;\n\n    for (int t = 0; t < V; ++t) {\n        if (mp[t].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [s, a] : mp[t]) comb[s] += a;\n\n        DemandGroup g;\n        g.demand = t;\n\n        for (auto [s, a] : comb) {\n            g.src.push_back(s);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeDemandOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeDemandGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildDemandGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].start;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n            computeDemandOrder(groups[gi], prev);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].start;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n        computeDemandOrder(groups[gi], prev);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        for (int idx : g.order) {\n            sol.moveTo(g.src[idx]);\n            sol.addLoad(g.amt[idx]);\n        }\n\n        sol.moveTo(g.demand);\n        sol.addUnload(g.total);\n    }\n\n    return sol;\n}\n\nstruct EdgeJob {\n    int s, t, amount;\n};\n\nlong long edgeTieCost(int variant, int u, int v) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    int ar2 = r1 + r2;\n    int ac2 = c1 + c2;\n\n    if (variant == 0) return 0;\n\n    if (variant == 1) {\n        return ar2 + ac2;\n    }\n\n    if (variant == 2) {\n        return (2 * (N - 1) - ar2) + (2 * (N - 1) - ac2);\n    }\n\n    if (variant == 3) {\n        return abs(ar2 - (N - 1)) + abs(ac2 - (N - 1));\n    }\n\n    uint64_t seed = ((uint64_t)variant << 40) ^ ((uint64_t)u << 20) ^ (uint64_t)v;\n    return splitmix64(seed) % 50;\n}\n\nvoid addSignedEdgeFlow(vector<long long>& right, vector<long long>& down, int u, int v, long long a) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    if (r1 == r2) {\n        if (c2 == c1 + 1) {\n            right[r1 * (N - 1) + c1] += a;\n        } else if (c2 == c1 - 1) {\n            right[r1 * (N - 1) + c2] -= a;\n        }\n    } else if (c1 == c2) {\n        if (r2 == r1 + 1) {\n            down[r1 * N + c1] += a;\n        } else if (r2 == r1 - 1) {\n            down[r2 * N + c1] -= a;\n        }\n    }\n}\n\nvector<EdgeJob> computeGridEdgeJobs(int variant) {\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) total += H[i];\n    }\n\n    if (total == 0) return {};\n\n    int SRC = V;\n    int SNK = V + 1;\n    MinCostFlow mf(V + 2);\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) mf.addEdge(SRC, i, H[i], 0);\n        if (H[i] < 0) mf.addEdge(i, SNK, -H[i], 0);\n    }\n\n    struct Ref {\n        int u, v, node, edgeIndex;\n    };\n\n    vector<Ref> refs;\n\n    const long long CAP = 1000000000LL;\n    const long long W = 100000LL;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int u = cell_id(r, c);\n\n            if (r + 1 < N) {\n                int v = cell_id(r + 1, c);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n\n            if (c + 1 < N) {\n                int v = cell_id(r, c + 1);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n        }\n    }\n\n    auto [flow, cost] = mf.minCostFlow(SRC, SNK, total);\n    if (flow != total) return {};\n\n    vector<long long> right(N * (N - 1), 0), down((N - 1) * N, 0);\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            addSignedEdgeFlow(right, down, ref.u, ref.v, used);\n        }\n    }\n\n    vector<EdgeJob> jobs;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c + 1 < N; ++c) {\n            long long f = right[r * (N - 1) + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r, c + 1), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r, c + 1), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    for (int r = 0; r + 1 < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            long long f = down[r * N + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r + 1, c), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r + 1, c), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    return jobs;\n}\n\nvector<int> optimizeEdgeOrder(const vector<EdgeJob>& jobs) {\n    int m = (int)jobs.size();\n\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    auto link = [&](int a, int b) -> long long {\n        if (b == -2) {\n            if (a == -1) return 0;\n            return jobs[a].amount;\n        }\n\n        if (a == -1) {\n            return 100LL * DIST[0][jobs[b].s] + jobs[b].amount;\n        }\n\n        if (jobs[a].t == jobs[b].s) {\n            return llabs((long long)jobs[a].amount - jobs[b].amount);\n        }\n\n        return jobs[a].amount\n             + 100LL * DIST[jobs[a].t][jobs[b].s]\n             + jobs[b].amount;\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n    int prev = -1;\n\n    for (int k = 0; k < m; ++k) {\n        long long best = INFLL;\n        int bj = -1;\n\n        for (int j = 0; j < m; ++j) {\n            if (used[j]) continue;\n\n            long long sc = link(prev, j);\n            if (sc < best) {\n                best = sc;\n                bj = j;\n            }\n        }\n\n        used[bj] = true;\n        order.push_back(bj);\n        prev = bj;\n    }\n\n    int maxPass = (m > 500 ? 5 : 10);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        long long bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prevNode = (i == 0 ? -1 : order[i - 1]);\n            int nextNode = (i + 1 == m ? -2 : order[i + 1]);\n\n            long long removeDelta = link(prevNode, nextNode) - link(prevNode, x) - link(x, nextNode);\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                long long delta = removeDelta\n                                + link(before, x)\n                                + link(x, after)\n                                - link(before, after);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            long long oldInternal = 0;\n            long long newInternal = 0;\n            int before = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += link(order[r - 1], order[r]);\n                newInternal += link(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                long long oldCost = link(before, order[l]) + oldInternal + link(order[r], after);\n                long long newCost = link(before, order[r]) + newInternal + link(order[l], after);\n\n                long long delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nSolution makeEdgeRelaySolution(const vector<EdgeJob>& jobs) {\n    Solution sol;\n\n    vector<long long> delta(V, 0);\n\n    for (auto& e : jobs) {\n        if (DIST[e.s][e.t] != 1 || e.amount <= 0) {\n            sol.valid = false;\n            return sol;\n        }\n\n        delta[e.s] -= e.amount;\n        delta[e.t] += e.amount;\n    }\n\n    for (int i = 0; i < V; ++i) {\n        if (delta[i] != -H[i]) {\n            sol.valid = false;\n            return sol;\n        }\n    }\n\n    if (jobs.empty()) return sol;\n\n    vector<int> order = optimizeEdgeOrder(jobs);\n\n    for (int idx : order) {\n        const auto& e = jobs[idx];\n\n        if (sol.pos != e.s) {\n            if (sol.load > 0) sol.addUnload(sol.load);\n            sol.moveTo(e.s);\n        }\n\n        if (sol.load < e.amount) {\n            sol.addLoad(e.amount - sol.load);\n        } else if (sol.load > e.amount) {\n            sol.addUnload(sol.load - e.amount);\n        }\n\n        sol.moveTo(e.t);\n    }\n\n    if (sol.load > 0) sol.addUnload(sol.load);\n\n    return sol;\n}\n\nSolution makeGridRelaySolution(int variant) {\n    vector<EdgeJob> jobs = computeGridEdgeJobs(variant);\n    return makeEdgeRelaySolution(jobs);\n}\n\npair<int, int> transformCoord(int r, int c, int type) {\n    if (type == 0) return {r, c};\n    if (type == 1) return {c, N - 1 - r};\n    if (type == 2) return {N - 1 - r, N - 1 - c};\n    if (type == 3) return {N - 1 - c, r};\n    if (type == 4) return {r, N - 1 - c};\n    if (type == 5) return {N - 1 - r, c};\n    if (type == 6) return {c, r};\n    return {N - 1 - c, N - 1 - r};\n}\n\nSolution makeCycleSolution() {\n    vector<pair<int, int>> base;\n\n    for (int i = 0; i < N; ++i) base.push_back({i, 0});\n\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) base.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) base.push_back({i, j});\n        }\n    }\n\n    for (int j = N - 1; j >= 1; --j) base.push_back({0, j});\n\n    long long bestCost = INFLL;\n    vector<int> bestCycle;\n    int bestStart = -1;\n\n    for (int type = 0; type < 8; ++type) {\n        vector<int> cyc;\n        cyc.reserve(V);\n\n        for (auto [r, c] : base) {\n            auto [nr, nc] = transformCoord(r, c, type);\n            cyc.push_back(cell_id(nr, nc));\n        }\n\n        for (int rev = 0; rev < 2; ++rev) {\n            if (rev) reverse(cyc.begin(), cyc.end());\n\n            for (int s = 0; s < V; ++s) {\n                long long load = 0;\n                long long cost = BASE_COST + 100LL * DIST[0][cyc[s]];\n                bool ok = true;\n\n                for (int k = 0; k < V; ++k) {\n                    int id = cyc[(s + k) % V];\n                    load += H[id];\n\n                    if (load < 0) {\n                        ok = false;\n                        break;\n                    }\n\n                    if (k + 1 < V) {\n                        int nxt = cyc[(s + k + 1) % V];\n                        cost += 1LL * DIST[id][nxt] * (100 + load);\n                    }\n                }\n\n                if (ok && cost < bestCost) {\n                    bestCost = cost;\n                    bestCycle = cyc;\n                    bestStart = s;\n                }\n            }\n\n            if (rev) reverse(cyc.begin(), cyc.end());\n        }\n    }\n\n    Solution sol;\n\n    if (bestStart < 0) {\n        sol.valid = false;\n        return sol;\n    }\n\n    sol.moveTo(bestCycle[bestStart]);\n\n    for (int k = 0; k < V; ++k) {\n        int id = bestCycle[(bestStart + k) % V];\n\n        if (H[id] > 0) sol.addLoad(H[id]);\n        else if (H[id] < 0) sol.addUnload(-H[id]);\n\n        if (k + 1 < V) {\n            int nxt = bestCycle[(bestStart + k + 1) % V];\n            sol.moveTo(nxt);\n        }\n    }\n\n    return sol;\n}\n\n// Cheap cyclic event-sequence candidates.\nstruct Event {\n    int cell;\n    int delta; // positive: load, negative: unload\n};\n\nstruct EventEval {\n    long long cost;\n    int rot;\n};\n\nEventEval evalEventOrder(const vector<Event>& ev) {\n    int m = (int)ev.size();\n    if (m == 0) return {BASE_COST == 0 ? 0 : INFLL, -1};\n\n    vector<long long> cum(m + 1, 0);\n    long long handling = 0;\n\n    for (int i = 0; i < m; ++i) {\n        cum[i + 1] = cum[i] + ev[i].delta;\n        handling += llabs((long long)ev[i].delta);\n    }\n\n    if (cum[m] != 0) return {INFLL, -1};\n\n    long long mn = cum[0];\n    for (int i = 1; i < m; ++i) mn = min(mn, cum[i]);\n\n    long long cyclicMove = 0;\n    for (int i = 0; i < m; ++i) {\n        int j = (i + 1) % m;\n        long long loadAfter = cum[i + 1] - mn;\n        if (loadAfter < 0) return {INFLL, -1};\n        cyclicMove += 1LL * DIST[ev[i].cell][ev[j].cell] * (100 + loadAfter);\n    }\n\n    long long best = INFLL;\n    int bestRot = -1;\n\n    for (int r = 0; r < m; ++r) {\n        if (cum[r] != mn) continue;\n\n        int pred = (r + m - 1) % m;\n        long long omitted = 100LL * DIST[ev[pred].cell][ev[r].cell];\n        long long c = handling + cyclicMove - omitted + 100LL * DIST[0][ev[r].cell];\n\n        if (c < best) {\n            best = c;\n            bestRot = r;\n        }\n    }\n\n    return {best, bestRot};\n}\n\nSolution makeEventSequenceSolution(const vector<Event>& ev) {\n    Solution sol;\n\n    if (ev.empty()) {\n        if (BASE_COST != 0) sol.valid = false;\n        return sol;\n    }\n\n    vector<long long> sum(V, 0);\n    for (auto& e : ev) sum[e.cell] += e.delta;\n\n    for (int i = 0; i < V; ++i) {\n        if (sum[i] != H[i]) {\n            sol.valid = false;\n            return sol;\n        }\n    }\n\n    EventEval ee = evalEventOrder(ev);\n    if (ee.rot < 0 || ee.cost >= INFLL / 2) {\n        sol.valid = false;\n        return sol;\n    }\n\n    int m = (int)ev.size();\n    int step = 0;\n\n    while (step < m) {\n        int idx = (ee.rot + step) % m;\n        int cell = ev[idx].cell;\n        long long d = ev[idx].delta;\n        ++step;\n\n        while (step < m) {\n            int idx2 = (ee.rot + step) % m;\n            if (ev[idx2].cell != cell) break;\n\n            if ((d > 0 && ev[idx2].delta > 0) || (d < 0 && ev[idx2].delta < 0)) {\n                d += ev[idx2].delta;\n                ++step;\n            } else {\n                break;\n            }\n        }\n\n        sol.moveTo(cell);\n        if (d > 0) sol.addLoad(d);\n        else sol.addUnload(-d);\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    return sol;\n}\n\nuint64_t hashEvents(const vector<Event>& ev) {\n    uint64_t h = ev.size() + 1234567;\n    for (auto& e : ev) {\n        uint64_t key = ((uint64_t)e.cell << 32) ^ (uint32_t)(e.delta + 1000007);\n        h = splitmix64(h ^ key);\n    }\n    return h;\n}\n\nvector<Event> eventsFromCellOrder(const vector<int>& cells, int chunk) {\n    vector<Event> ev;\n\n    for (int id : cells) {\n        int x = H[id];\n        if (x == 0) continue;\n\n        int sign = (x > 0 ? 1 : -1);\n        int rem = abs(x);\n\n        while (rem > 0) {\n            int a = (chunk >= 1000000 ? rem : min(chunk, rem));\n            ev.push_back({id, sign * a});\n            rem -= a;\n        }\n    }\n\n    return ev;\n}\n\nint hilbertIndex(int x, int y) {\n    int n = 32;\n    int d = 0;\n\n    for (int s = n / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n\n        d += s * s * ((3 * rx) ^ ry);\n\n        if (ry == 0) {\n            if (rx == 1) {\n                x = s - 1 - x;\n                y = s - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    return d;\n}\n\nint mortonIndex(int x, int y) {\n    int d = 0;\n    for (int b = 0; b < 5; ++b) {\n        d |= ((y >> b) & 1) << (2 * b);\n        d |= ((x >> b) & 1) << (2 * b + 1);\n    }\n    return d;\n}\n\nvector<int> makeGreedyCellOrder(int mode) {\n    vector<char> used(V, false);\n    int remCnt = 0;\n    for (int i = 0; i < V; ++i) if (H[i] != 0) ++remCnt;\n\n    vector<int> order;\n    order.reserve(remCnt);\n\n    long long load = 0;\n    int cur = 0;\n\n    for (int step = 0; step < remCnt; ++step) {\n        long long bestScore = INFLL;\n        int best = -1;\n\n        for (int i = 0; i < V; ++i) {\n            if (H[i] == 0 || used[i]) continue;\n            if (H[i] < 0 && load < -H[i]) continue;\n\n            long long d = DIST[cur][i];\n            long long a = abs(H[i]);\n            long long nh = load + H[i];\n\n            long long score;\n            if (mode == 0) {\n                score = d * (100 + load) + (H[i] > 0 ? 2000 + 50 * a : -1000 * a);\n            } else if (mode == 1) {\n                long long target = 150;\n                score = d * (100 + load) + llabs(nh - target) * 80 + (H[i] > 0 ? 500 : 0);\n            } else if (mode == 2) {\n                long long target = 350;\n                score = d * (100 + load) + llabs(nh - target) * 40 + (H[i] > 0 ? 200 : 0);\n            } else if (mode == 3) {\n                score = 10000LL * d - (H[i] < 0 ? 500LL * a : 100LL * a) + 20LL * nh;\n            } else if (mode == 4) {\n                if (load < 200) {\n                    score = d * (100 + load) + (H[i] > 0 ? -200LL * a : 5000LL - 100LL * a);\n                } else {\n                    score = d * (100 + load) + (H[i] > 0 ? 1500LL : -800LL * a);\n                }\n            } else {\n                score = d * (100 + load) / (a + 5) + (H[i] > 0 ? 200 : -300);\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best = i;\n            }\n        }\n\n        if (best < 0) {\n            for (int i = 0; i < V; ++i) {\n                if (H[i] > 0 && !used[i]) {\n                    int d = DIST[cur][i];\n                    if (d < bestScore) {\n                        bestScore = d;\n                        best = i;\n                    }\n                }\n            }\n        }\n\n        if (best < 0) break;\n\n        used[best] = true;\n        order.push_back(best);\n        load += H[best];\n        cur = best;\n\n        if (load < 0) break;\n    }\n\n    return order;\n}\n\ntemplate<class F>\nvoid generateEventCandidates(F&& considerEvent) {\n    unordered_set<uint64_t> seen;\n\n    auto addEventOrder = [&](const vector<Event>& ev) {\n        if (ev.empty()) return;\n\n        vector<long long> sum(V, 0);\n        long long total = 0;\n\n        for (auto& e : ev) {\n            if (e.delta == 0) return;\n            if (e.cell < 0 || e.cell >= V) return;\n            sum[e.cell] += e.delta;\n            total += e.delta;\n        }\n\n        if (total != 0) return;\n\n        for (int i = 0; i < V; ++i) {\n            if (sum[i] != H[i]) return;\n        }\n\n        uint64_t h = hashEvents(ev);\n        if (seen.insert(h).second) {\n            considerEvent(ev);\n        }\n    };\n\n    vector<int> chunks = {1000000, 50, 25};\n\n    auto addCells = [&](const vector<int>& cells) {\n        for (int ch : chunks) {\n            addEventOrder(eventsFromCellOrder(cells, ch));\n        }\n    };\n\n    vector<vector<pair<int, int>>> bases;\n\n    vector<pair<int, int>> rowSnake;\n    for (int r = 0; r < N; ++r) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < N; ++c) rowSnake.push_back({r, c});\n        } else {\n            for (int c = N - 1; c >= 0; --c) rowSnake.push_back({r, c});\n        }\n    }\n    bases.push_back(rowSnake);\n\n    vector<pair<int, int>> colSnake;\n    for (int c = 0; c < N; ++c) {\n        if (c % 2 == 0) {\n            for (int r = 0; r < N; ++r) colSnake.push_back({r, c});\n        } else {\n            for (int r = N - 1; r >= 0; --r) colSnake.push_back({r, c});\n        }\n    }\n    bases.push_back(colSnake);\n\n    vector<pair<int, int>> cycleBase;\n    for (int i = 0; i < N; ++i) cycleBase.push_back({i, 0});\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) cycleBase.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) cycleBase.push_back({i, j});\n        }\n    }\n    for (int j = N - 1; j >= 1; --j) cycleBase.push_back({0, j});\n    bases.push_back(cycleBase);\n\n    vector<pair<int, int>> spiral;\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) spiral.push_back({top, c});\n        ++top;\n        for (int r = top; r <= bottom; ++r) spiral.push_back({r, right});\n        --right;\n        if (top <= bottom) {\n            for (int c = right; c >= left; --c) spiral.push_back({bottom, c});\n            --bottom;\n        }\n        if (left <= right) {\n            for (int r = bottom; r >= top; --r) spiral.push_back({r, left});\n            ++left;\n        }\n    }\n    bases.push_back(spiral);\n\n    for (auto& base : bases) {\n        for (int type = 0; type < 8; ++type) {\n            vector<int> cells;\n            cells.reserve(V);\n\n            for (auto [r, c] : base) {\n                auto [nr, nc] = transformCoord(r, c, type);\n                cells.push_back(cell_id(nr, nc));\n            }\n\n            addCells(cells);\n            reverse(cells.begin(), cells.end());\n            addCells(cells);\n        }\n    }\n\n    for (int curve = 0; curve < 2; ++curve) {\n        for (int type = 0; type < 8; ++type) {\n            vector<pair<int, int>> arr;\n            arr.reserve(V);\n\n            for (int id = 0; id < V; ++id) {\n                int r = id / N;\n                int c = id % N;\n                auto [tr, tc] = transformCoord(r, c, type);\n\n                int key = (curve == 0 ? hilbertIndex(tr, tc) : mortonIndex(tr, tc));\n                arr.push_back({key, id});\n            }\n\n            sort(arr.begin(), arr.end());\n\n            vector<int> cells;\n            cells.reserve(V);\n            for (auto [key, id] : arr) cells.push_back(id);\n\n            addCells(cells);\n            reverse(cells.begin(), cells.end());\n            addCells(cells);\n        }\n    }\n\n    int nonzero = 0;\n    for (int i = 0; i < V; ++i) if (H[i] != 0) ++nonzero;\n\n    for (int mode = 0; mode < 6; ++mode) {\n        vector<int> cells = makeGreedyCellOrder(mode);\n        if ((int)cells.size() == nonzero) {\n            addCells(cells);\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int inputN;\n    cin >> inputN;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> H[cell_id(i, j)];\n        }\n    }\n\n    for (int a = 0; a < V; ++a) {\n        int ar = a / N;\n        int ac = a % N;\n\n        for (int b = 0; b < V; ++b) {\n            int br = b / N;\n            int bc = b % N;\n            DIST[a][b] = abs(ar - br) + abs(ac - bc);\n        }\n    }\n\n    for (int i = 0; i < V; ++i) BASE_COST += abs(H[i]);\n\n    if (BASE_COST == 0) {\n        return 0;\n    }\n\n    Solution best;\n    best.cost = INFLL;\n    best.valid = false;\n\n    auto consider = [&](Solution&& sol) {\n        if (!sol.valid) return;\n        if (sol.load != 0) return;\n        if (sol.ops.size() > 100000) return;\n\n        if (!best.valid || sol.cost < best.cost) {\n            best = std::move(sol);\n        }\n    };\n\n    // Safe exact fallback.\n    consider(makeCycleSolution());\n\n    // Cheap event-order candidates.\n    auto considerEvent = [&](const vector<Event>& ev) {\n        EventEval ee = evalEventOrder(ev);\n        if (ee.rot < 0 || ee.cost >= INFLL / 2) return;\n        if (best.valid && ee.cost >= best.cost) return;\n        consider(makeEventSequenceSolution(ev));\n    };\n    generateEventCandidates(considerEvent);\n\n    // Greedy candidates.\n    vector<int> maxLoads = {0, 120, 250, 500};\n    vector<pair<int, int>> ratios = {{1, 1}, {3, 2}, {2, 1}};\n    vector<int> sourceModes = {0, 2};\n    vector<int> demandModes = {0, 1, 2};\n\n    for (int ml : maxLoads) {\n        for (auto [rn, rd] : ratios) {\n            if (ml == 0 && !(rn == 1 && rd == 1)) continue;\n\n            for (int sm : sourceModes) {\n                for (int dm : demandModes) {\n                    consider(makeGreedySolution(ml, rn, rd, sm, dm));\n                }\n            }\n        }\n    }\n\n    // Opportunistic path-servicing greedy candidates.\n    vector<int> caps = {120, 250, 500, 1000000000};\n\n    for (int cap : caps) {\n        for (auto [rn, rd] : ratios) {\n            for (int sm : sourceModes) {\n                for (int dm : {0, 1}) {\n                    consider(makeGreedyServiceSolution(cap, rn, rd, sm, dm, 2));\n                }\n            }\n        }\n    }\n\n    for (int pm : {0, 1}) {\n        consider(makeGreedyServiceSolution(250, 3, 2, 2, 1, pm));\n        consider(makeGreedyServiceSolution(500, 3, 2, 2, 1, pm));\n    }\n\n    // Transportation-flow based candidates.\n    for (int variant = 0; variant < 3; ++variant) {\n        vector<Flow> flows = computeMinCostFlows(variant);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // Greedy transportation variants.\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<Flow> flows = computeGreedyFlows(mode);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    // Aggregated adjacent-edge min-cost flow with chained execution.\n    for (int variant = 0; variant < 5; ++variant) {\n        consider(makeGridRelaySolution(variant));\n    }\n\n    // A few optional extra grid-flow tie variants if there is comfortable time left.\n    for (int variant = 5; variant < 8; ++variant) {\n        if (!TIMER.ok(1.86)) break;\n        consider(makeGridRelaySolution(variant));\n    }\n\n    for (const Op& op : best.ops) {\n        if (op.c == '+' || op.c == '-') {\n            cout << op.c << op.d << '\\n';\n        } else {\n            cout << op.c << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, T;\n    int S, G;\n    int SUM_MAXV;\n    int APPROX_MAXV;\n\n    vector<vector<int>> X;\n    vector<int> initMax;\n\n    vector<vector<int>> neigh;\n    vector<int> degSlot;\n    vector<pair<int,int>> gridEdges;\n    vector<unsigned long long> incidentMask;\n    vector<int> posOrder;\n\n    mt19937 rng;\n\n    Solver(int N_, int M_, int T_, const vector<vector<int>>& X_)\n        : N(N_), M(M_), T(T_), X(X_), rng(123456789) {\n        S = 2 * N * (N - 1);\n        G = N * N;\n        APPROX_MAXV = M * 100;\n\n        initMax.assign(M, 1);\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n            initMax[l] = max(1, mx);\n        }\n\n        SUM_MAXV = 0;\n        for (int v : initMax) SUM_MAXV += v;\n        SUM_MAXV = max(1, SUM_MAXV);\n\n        build_grid_info();\n    }\n\n    void build_grid_info() {\n        neigh.assign(S, {});\n        degSlot.assign(S, 0);\n        gridEdges.clear();\n        incidentMask.assign(S, 0ULL);\n\n        auto add_edge = [&](int p, int q) {\n            int eid = (int)gridEdges.size();\n            gridEdges.push_back({p, q});\n            neigh[p].push_back(q);\n            neigh[q].push_back(p);\n            incidentMask[p] |= (1ULL << eid);\n            incidentMask[q] |= (1ULL << eid);\n        };\n\n        auto id = [&](int i, int j) {\n            return i * N + j;\n        };\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = id(i, j);\n                if (j + 1 < N) add_edge(p, id(i, j + 1));\n                if (i + 1 < N) add_edge(p, id(i + 1, j));\n            }\n        }\n\n        for (int p = 0; p < S; p++) degSlot[p] = (int)neigh[p].size();\n\n        posOrder.resize(G);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            if (degSlot[a] != degSlot[b]) return degSlot[a] > degSlot[b];\n\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            double ca = (ai - (N - 1) / 2.0) * (ai - (N - 1) / 2.0)\n                      + (aj - (N - 1) / 2.0) * (aj - (N - 1) / 2.0);\n            double cb = (bi - (N - 1) / 2.0) * (bi - (N - 1) / 2.0)\n                      + (bj - (N - 1) / 2.0) * (bj - (N - 1) / 2.0);\n\n            return ca < cb;\n        });\n    }\n\n    inline double PW(const vector<double>& pairW, int a, int b) const {\n        return pairW[a * S + b];\n    }\n\n    double objective(\n        const vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        double ret = 0.0;\n\n        for (int p = 0; p < G; p++) {\n            ret += nodeCoef * degSlot[p] * nodeW[slotSeed[p]];\n        }\n\n        for (auto [p, q] : gridEdges) {\n            ret += PW(pairW, slotSeed[p], slotSeed[q]);\n        }\n\n        return ret;\n    }\n\n    double swap_delta(\n        const vector<int>& slotSeed,\n        int p,\n        int q,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        if (p == q) return 0.0;\n\n        int a = slotSeed[p];\n        int b = slotSeed[q];\n\n        double delta = 0.0;\n\n        delta += nodeCoef * degSlot[p] * (nodeW[b] - nodeW[a]);\n        delta += nodeCoef * degSlot[q] * (nodeW[a] - nodeW[b]);\n\n        for (int r : neigh[p]) {\n            if (r == q) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, b, c) - PW(pairW, a, c);\n        }\n\n        for (int r : neigh[q]) {\n            if (r == p) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, a, c) - PW(pairW, b, c);\n        }\n\n        return delta;\n    }\n\n    double local_search(\n        vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        int maxIter\n    ) const {\n        double cur = objective(slotSeed, pairW, nodeW, nodeCoef);\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            double bestD = 1e-9;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < S; p++) {\n                for (int q = p + 1; q < S; q++) {\n                    if (degSlot[p] == 0 && degSlot[q] == 0) continue;\n\n                    double d = swap_delta(slotSeed, p, q, pairW, nodeW, nodeCoef);\n                    if (d > bestD) {\n                        bestD = d;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur += bestD;\n        }\n\n        return cur;\n    }\n\n    vector<int> make_sorted_initial(const vector<double>& key, bool shuffleGrid) {\n        vector<int> seeds(S);\n        iota(seeds.begin(), seeds.end(), 0);\n\n        sort(seeds.begin(), seeds.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> slotSeed(S, -1);\n\n        for (int k = 0; k < G; k++) {\n            slotSeed[posOrder[k]] = seeds[k];\n        }\n        for (int k = G; k < S; k++) {\n            slotSeed[k] = seeds[k];\n        }\n\n        if (shuffleGrid) {\n            vector<int> planted;\n            for (int p = 0; p < G; p++) planted.push_back(slotSeed[p]);\n            shuffle(planted.begin(), planted.end(), rng);\n            for (int p = 0; p < G; p++) slotSeed[p] = planted[p];\n        }\n\n        return slotSeed;\n    }\n\n    vector<int> make_greedy_initial(\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        double noiseAmp\n    ) {\n        vector<int> slotSeed(S, -1);\n        vector<char> used(S, 0);\n\n        uniform_real_distribution<double> dist(-noiseAmp, noiseAmp);\n\n        for (int p : posOrder) {\n            int best = -1;\n            double bestScore = -1e100;\n\n            for (int s = 0; s < S; s++) {\n                if (used[s]) continue;\n\n                double sc = nodeCoef * degSlot[p] * nodeW[s];\n\n                for (int r : neigh[p]) {\n                    if (r < G && slotSeed[r] != -1) {\n                        sc += PW(pairW, s, slotSeed[r]);\n                    }\n                }\n\n                if (noiseAmp > 0) sc += dist(rng);\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = s;\n                }\n            }\n\n            slotSeed[p] = best;\n            used[best] = 1;\n        }\n\n        int out = G;\n        for (int s = 0; s < S; s++) {\n            if (!used[s]) slotSeed[out++] = s;\n        }\n\n        return slotSeed;\n    }\n\n    void compute_node_info(\n        int turn,\n        vector<int>& val,\n        vector<double>& nodeW,\n        vector<double>& criticalKey\n    ) const {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n\n        val.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) val[i] += X[i][l];\n        }\n\n        vector<double> rankBonus(S, 0.0);\n        vector<int> curMax(M, 1);\n\n        static const double rw[10] = {\n            260.0, 160.0, 100.0, 60.0, 36.0,\n            22.0, 14.0, 9.0, 6.0, 4.0\n        };\n\n        double rankScale = 1.15 - 0.25 * prog;\n\n        for (int l = 0; l < M; l++) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                return a < b;\n            });\n\n            curMax[l] = max(1, X[ids[0]][l]);\n\n            for (int r = 0; r < min(10, S); r++) {\n                int id = ids[r];\n                double frac0 = (double)X[id][l] / initMax[l];\n                double frac1 = (double)X[id][l] / curMax[l];\n                double frac = 0.6 * frac0 + 0.4 * frac1;\n                rankBonus[id] += rankScale * rw[r] * frac;\n            }\n\n            int second = X[ids[min(1, S - 1)]][l];\n            int gap = X[ids[0]][l] - second;\n            rankBonus[ids[0]] += (1.0 - 0.3 * prog) * 3.0 * gap;\n        }\n\n        nodeW.assign(S, 0.0);\n        criticalKey.assign(S, 0.0);\n\n        double quadCoef = 0.85 - 0.30 * prog;\n\n        for (int i = 0; i < S; i++) {\n            double quad = 0.0;\n            for (int l = 0; l < M; l++) {\n                quad += (double)X[i][l] * X[i][l] / initMax[l];\n            }\n\n            nodeW[i] = val[i] + quadCoef * quad + rankBonus[i];\n            criticalKey[i] = nodeW[i] + 0.75 * rankBonus[i];\n        }\n    }\n\n    vector<double> build_pair_quantile(double beta, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double mean = 0.5 * (ysum[i] + ysum[j]);\n                double var = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double d = a - b;\n                    var += 0.25 * d * d;\n                    pot += max(a, b);\n                }\n\n                double sd = sqrt(max(0.0, var));\n                double w = (1.0 - potCoef) * (mean + beta * sd) + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    vector<double> build_pair_ce(double tau, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double ce = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double mx = max(a, b);\n                    double diff = fabs(a - b);\n\n                    ce += mx + tau * log(0.5 * (1.0 + exp(-diff / tau)));\n                    pot += mx;\n                }\n\n                double w = (1.0 - potCoef) * ce + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    void build_raw_pair_stats(\n        const vector<int>& val,\n        vector<double>& mu,\n        vector<double>& sd\n    ) const {\n        mu.assign(S * S, 0.0);\n        sd.assign(S * S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            mu[i * S + i] = val[i];\n            sd[i * S + i] = 0.0;\n\n            for (int j = i + 1; j < S; j++) {\n                double m = 0.5 * (val[i] + val[j]);\n                double var = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double d = X[i][l] - X[j][l];\n                    var += 0.25 * d * d;\n                }\n\n                double s = sqrt(max(0.0, var));\n\n                mu[i * S + j] = mu[j * S + i] = m;\n                sd[i * S + j] = sd[j * S + i] = s;\n            }\n        }\n    }\n\n    static inline double normal_cdf(double z) {\n        if (z < -8.0) return 0.0;\n        if (z > 8.0) return 1.0;\n        return 0.5 * erfc(-z * 0.70710678118654752440);\n    }\n\n    double approx_expected_max_normal(\n        const vector<int>& slotSeed,\n        const vector<double>& mu,\n        const vector<double>& sd\n    ) const {\n        const int STEP = 5;\n        double ret = 0.0;\n\n        for (int s = 0; s < APPROX_MAXV; s += STEP) {\n            double prod = 1.0;\n\n            for (auto [p, q] : gridEdges) {\n                int a = slotSeed[p];\n                int b = slotSeed[q];\n\n                double m = mu[a * S + b];\n                double sig = sd[a * S + b];\n\n                double cdf;\n                if (sig < 1e-9) {\n                    cdf = (m <= s ? 1.0 : 0.0);\n                } else {\n                    cdf = normal_cdf((s + 0.5 - m) / sig);\n                }\n\n                prod *= cdf;\n                if (prod <= 1e-15) {\n                    prod = 0.0;\n                    break;\n                }\n            }\n\n            ret += (1.0 - prod) * STEP;\n        }\n\n        return ret;\n    }\n\n    double coord_max_expectation(const vector<int>& slotSeed) const {\n        double total = 0.0;\n\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n\n            for (int th = 1; th <= mx; th++) {\n                double prod = 1.0;\n\n                for (auto [p, q] : gridEdges) {\n                    int a = X[slotSeed[p]][l];\n                    int b = X[slotSeed[q]][l];\n\n                    int ge = 0;\n                    if (a >= th) ge++;\n                    if (b >= th) ge++;\n\n                    double pLess = 1.0 - 0.5 * ge;\n\n                    if (pLess <= 0.0) {\n                        prod = 0.0;\n                        break;\n                    }\n\n                    prod *= pLess;\n                    if (prod <= 1e-15) {\n                        prod = 0.0;\n                        break;\n                    }\n                }\n\n                total += 1.0 - prod;\n            }\n        }\n\n        return total;\n    }\n\n    vector<float> build_pair_cdf() const {\n        int L = SUM_MAXV + 1;\n        vector<float> cdf(S * S * L, 0.0f);\n\n        vector<double> dp(L, 0.0), ndp(L, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i; j < S; j++) {\n                fill(dp.begin(), dp.end(), 0.0);\n                dp[0] = 1.0;\n\n                int curMaxSum = 0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = X[i][l];\n                    int b = X[j][l];\n                    int nxtMaxSum = min(SUM_MAXV, curMaxSum + max(a, b));\n\n                    fill(ndp.begin(), ndp.begin() + nxtMaxSum + 1, 0.0);\n\n                    if (a == b) {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            if (s + a <= SUM_MAXV) ndp[s + a] += dp[s];\n                        }\n                    } else {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            double p = 0.5 * dp[s];\n                            if (s + a <= SUM_MAXV) ndp[s + a] += p;\n                            if (s + b <= SUM_MAXV) ndp[s + b] += p;\n                        }\n                    }\n\n                    dp.swap(ndp);\n                    curMaxSum = nxtMaxSum;\n                }\n\n                int idx1 = (i * S + j) * L;\n                int idx2 = (j * S + i) * L;\n\n                double cum = 0.0;\n                for (int s = 0; s <= SUM_MAXV; s++) {\n                    if (s <= curMaxSum) cum += dp[s];\n                    if (cum < 0.0) cum = 0.0;\n                    if (cum > 1.0) cum = 1.0;\n\n                    float v = (float)cum;\n                    cdf[idx1 + s] = v;\n                    cdf[idx2 + s] = v;\n                }\n            }\n        }\n\n        return cdf;\n    }\n\n    vector<float> build_pair_logcdf(const vector<float>& cdf) const {\n        vector<float> logcdf(cdf.size());\n\n        for (size_t i = 0; i < cdf.size(); i++) {\n            float f = cdf[i];\n\n            if (f <= 0.0f) logcdf[i] = -80.0f;\n            else if (f >= 1.0f) logcdf[i] = 0.0f;\n            else logcdf[i] = (float)log((double)f);\n        }\n\n        return logcdf;\n    }\n\n    vector<double> build_pair_tail(\n        const vector<float>& cdf,\n        int threshold,\n        double scale\n    ) const {\n        int L = SUM_MAXV + 1;\n        vector<double> pairW(S * S, 0.0);\n\n        int start = max(0, threshold - 1);\n        if (start >= SUM_MAXV) return pairW;\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                int idx = (i * S + j) * L;\n\n                double tail = 0.0;\n                for (int s = start; s < SUM_MAXV; s++) {\n                    double f = cdf[idx + s];\n                    if (f < 0.0) f = 0.0;\n                    if (f > 1.0) f = 1.0;\n                    tail += 1.0 - f;\n                }\n\n                tail *= scale;\n                pairW[i * S + j] = pairW[j * S + i] = tail;\n            }\n        }\n\n        return pairW;\n    }\n\n    double exact_expected_max(\n        const vector<int>& slotSeed,\n        const vector<float>& cdf\n    ) const {\n        int L = SUM_MAXV + 1;\n        vector<double> prod(SUM_MAXV, 1.0);\n\n        for (auto [p, q] : gridEdges) {\n            int a = slotSeed[p];\n            int b = slotSeed[q];\n            int idx = (a * S + b) * L;\n\n            for (int s = 0; s < SUM_MAXV; s++) {\n                double f = cdf[idx + s];\n                if (f < 0.0) f = 0.0;\n                if (f > 1.0) f = 1.0;\n                prod[s] *= f;\n            }\n        }\n\n        double ret = 0.0;\n        for (int s = 0; s < SUM_MAXV; s++) {\n            ret += 1.0 - prod[s];\n        }\n\n        return ret;\n    }\n\n    double score_from_logprod(const vector<double>& logProd) const {\n        double ret = 0.0;\n\n        for (int s = 0; s < SUM_MAXV; s++) {\n            double x = logProd[s];\n\n            if (x < -50.0) {\n                ret += 1.0;\n            } else {\n                if (x > 0.0) x = 0.0;\n                ret += 1.0 - exp(x);\n            }\n        }\n\n        return ret;\n    }\n\n    double exact_final_local_search_all(\n        vector<int>& slotSeed,\n        const vector<float>& logcdf,\n        int maxIter\n    ) const {\n        int L = SUM_MAXV + 1;\n\n        vector<double> logProd(SUM_MAXV, 0.0);\n\n        for (auto [p, q] : gridEdges) {\n            int a = slotSeed[p];\n            int b = slotSeed[q];\n            int base = (a * S + b) * L;\n\n            for (int s = 0; s < SUM_MAXV; s++) {\n                logProd[s] += logcdf[base + s];\n            }\n        }\n\n        double cur = score_from_logprod(logProd);\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            double bestScore = cur + 1e-8;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < S; p++) {\n                for (int q = p + 1; q < S; q++) {\n                    unsigned long long mask = incidentMask[p] | incidentMask[q];\n                    if (mask == 0ULL) continue;\n\n                    int seedP = slotSeed[p];\n                    int seedQ = slotSeed[q];\n\n                    int oldBase[8], newBase[8], cnt = 0;\n\n                    unsigned long long m = mask;\n                    while (m) {\n                        int eid = __builtin_ctzll(m);\n                        m &= m - 1;\n\n                        auto [u, v] = gridEdges[eid];\n\n                        int oldA = slotSeed[u];\n                        int oldB = slotSeed[v];\n\n                        int newA = oldA;\n                        int newB = oldB;\n\n                        if (u == p) newA = seedQ;\n                        else if (u == q) newA = seedP;\n\n                        if (v == p) newB = seedQ;\n                        else if (v == q) newB = seedP;\n\n                        int ob = (oldA * S + oldB) * L;\n                        int nb = (newA * S + newB) * L;\n\n                        if (ob != nb) {\n                            oldBase[cnt] = ob;\n                            newBase[cnt] = nb;\n                            cnt++;\n                        }\n                    }\n\n                    if (cnt == 0) continue;\n\n                    double sc = 0.0;\n\n                    for (int s = 0; s < SUM_MAXV; s++) {\n                        double nl = logProd[s];\n\n                        for (int k = 0; k < cnt; k++) {\n                            nl += logcdf[newBase[k] + s] - logcdf[oldBase[k] + s];\n                        }\n\n                        if (nl < -50.0) {\n                            sc += 1.0;\n                        } else {\n                            if (nl > 0.0) nl = 0.0;\n                            sc += 1.0 - exp(nl);\n                        }\n                    }\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            int seedP = slotSeed[bp];\n            int seedQ = slotSeed[bq];\n\n            unsigned long long mask = incidentMask[bp] | incidentMask[bq];\n            unsigned long long m = mask;\n\n            while (m) {\n                int eid = __builtin_ctzll(m);\n                m &= m - 1;\n\n                auto [u, v] = gridEdges[eid];\n\n                int oldA = slotSeed[u];\n                int oldB = slotSeed[v];\n\n                int newA = oldA;\n                int newB = oldB;\n\n                if (u == bp) newA = seedQ;\n                else if (u == bq) newA = seedP;\n\n                if (v == bp) newB = seedQ;\n                else if (v == bq) newB = seedP;\n\n                int ob = (oldA * S + oldB) * L;\n                int nb = (newA * S + newB) * L;\n\n                if (ob != nb) {\n                    for (int s = 0; s < SUM_MAXV; s++) {\n                        logProd[s] += logcdf[nb + s] - logcdf[ob + s];\n                    }\n                }\n            }\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur = bestScore;\n        }\n\n        return cur;\n    }\n\n    vector<vector<int>> solve_turn(int turn) {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n        bool isFinal = (turn == T - 1);\n\n        vector<int> val;\n        vector<double> nodeW, criticalKey;\n        compute_node_info(turn, val, nodeW, criticalKey);\n\n        vector<double> valKey(S);\n        for (int i = 0; i < S; i++) valKey[i] = val[i];\n\n        vector<double> rawMu, rawSd;\n        build_raw_pair_stats(val, rawMu, rawSd);\n\n        double masterNodeCoef = max(0.09, 0.19 - 0.07 * prog);\n        if (isFinal) masterNodeCoef *= 0.55;\n\n        vector<double> masterPairW =\n            build_pair_quantile(\n                1.55 + 0.45 * prog,\n                0.12 + 0.10 * prog,\n                0.16 * (1.0 - prog)\n            );\n\n        vector<float> finalCDF;\n        vector<float> finalLogCDF;\n\n        if (isFinal) {\n            finalCDF = build_pair_cdf();\n            finalLogCDF = build_pair_logcdf(finalCDF);\n        }\n\n        struct Work {\n            vector<double> pairW;\n            double nodeCoef;\n            int iter;\n        };\n\n        vector<Work> works;\n\n        works.push_back(Work{\n            masterPairW,\n            masterNodeCoef,\n            isFinal ? 90 : 105\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                50.0 - 20.0 * prog,\n                0.06 + 0.17 * prog,\n                0.0\n            ),\n            (isFinal ? 0.07 : max(0.11, 0.22 - 0.07 * prog)),\n            isFinal ? 75 : 85\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                2.00 + 0.45 * prog,\n                0.18 + 0.12 * prog,\n                0.10 * (1.0 - prog)\n            ),\n            (isFinal ? 0.055 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 80\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                1.05 + 0.25 * prog,\n                0.38,\n                0.20 * (1.0 - prog)\n            ),\n            (isFinal ? 0.06 : max(0.09, 0.18 - 0.05 * prog)),\n            isFinal ? 70 : 75\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                24.0 - 10.0 * prog,\n                0.08 + 0.12 * prog,\n                0.15 * (1.0 - prog)\n            ),\n            (isFinal ? 0.05 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 75\n        });\n\n        if (turn >= T - 3) {\n            works.push_back(Work{\n                build_pair_quantile(\n                    2.35 + 0.35 * prog,\n                    0.26,\n                    0.0\n                ),\n                isFinal ? 0.04 : 0.08,\n                isFinal ? 80 : 70\n            });\n        }\n\n        if (isFinal) {\n            works.push_back(Work{\n                build_pair_ce(14.0, 0.18, 0.0),\n                0.04,\n                80\n            });\n            works.push_back(Work{\n                build_pair_ce(9.0, 0.24, 0.0),\n                0.035,\n                80\n            });\n\n            int bestNow = 0;\n            for (int v : val) bestNow = max(bestNow, v);\n\n            vector<int> thresholds = {\n                bestNow - 30,\n                bestNow,\n                bestNow + 25,\n                bestNow + 50\n            };\n\n            for (int th : thresholds) {\n                works.push_back(Work{\n                    build_pair_tail(finalCDF, th, 10.0),\n                    0.02,\n                    85\n                });\n            }\n        }\n\n        double bestScore = -1e100;\n        vector<int> bestSlotSeed;\n\n        vector<pair<double, vector<int>>> finalTop;\n\n        auto add_final_top = [&](double sc, const vector<int>& cand) {\n            if (!isFinal) return;\n\n            finalTop.push_back({sc, cand});\n            sort(finalTop.begin(), finalTop.end(), [&](const auto& a, const auto& b) {\n                return a.first > b.first;\n            });\n\n            if ((int)finalTop.size() > 5) finalTop.pop_back();\n        };\n\n        auto eval_candidate = [&](const vector<int>& slotSeed) -> double {\n            if (isFinal) {\n                return exact_expected_max(slotSeed, finalCDF);\n            } else {\n                double edgeObj = objective(slotSeed, masterPairW, nodeW, masterNodeCoef);\n                double geneObj = coord_max_expectation(slotSeed);\n                double maxObj = approx_expected_max_normal(slotSeed, rawMu, rawSd);\n\n                double geneLambda = 22.0 - 10.0 * prog;\n                double maxLambda = 13.0 + 10.0 * prog;\n\n                return edgeObj + geneLambda * geneObj + maxLambda * maxObj;\n            }\n        };\n\n        auto process = [&](vector<int> start, const Work& w) {\n            local_search(start, w.pairW, nodeW, w.nodeCoef, w.iter);\n            double sc = eval_candidate(start);\n\n            add_final_top(sc, start);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestSlotSeed = start;\n            }\n        };\n\n        uniform_real_distribution<double> noise(-1.0, 1.0);\n\n        for (int wi = 0; wi < (int)works.size(); wi++) {\n            const Work& w = works[wi];\n\n            if (wi == 0) {\n                process(make_sorted_initial(nodeW, false), w);\n                process(make_sorted_initial(valKey, false), w);\n                process(make_sorted_initial(criticalKey, false), w);\n                process(make_sorted_initial(criticalKey, true), w);\n            }\n\n            if (wi == 1) {\n                process(make_sorted_initial(nodeW, false), w);\n            }\n\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 0.0), w);\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 38.0 + 13.0 * wi), w);\n\n            if (wi < 5) {\n                vector<double> key = criticalKey;\n                double amp = 55.0 + 25.0 * wi;\n                for (int i = 0; i < S; i++) key[i] += amp * noise(rng);\n                process(make_sorted_initial(key, wi % 2), w);\n            }\n        }\n\n        if (isFinal && !finalTop.empty()) {\n            sort(finalTop.begin(), finalTop.end(), [&](const auto& a, const auto& b) {\n                return a.first > b.first;\n            });\n\n            vector<vector<int>> starts;\n\n            for (auto& pr : finalTop) {\n                bool same = false;\n                for (auto& v : starts) {\n                    if (v == pr.second) {\n                        same = true;\n                        break;\n                    }\n                }\n\n                if (!same) starts.push_back(pr.second);\n                if ((int)starts.size() >= 3) break;\n            }\n\n            for (auto cand : starts) {\n                exact_final_local_search_all(cand, finalLogCDF, 4);\n                double sc = exact_expected_max(cand, finalCDF);\n\n                if (sc > bestScore + 1e-7) {\n                    bestScore = sc;\n                    bestSlotSeed = cand;\n                }\n            }\n        }\n\n        if (bestSlotSeed.empty()) {\n            bestSlotSeed = make_sorted_initial(valKey, false);\n        }\n\n        vector<vector<int>> A(N, vector<int>(N));\n\n        for (int p = 0; p < G; p++) {\n            A[p / N][p % N] = bestSlotSeed[p];\n        }\n\n        return A;\n    }\n\n    void update_X(const vector<vector<int>>& nx) {\n        X = nx;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n\n    int S = 2 * N * (N - 1);\n    vector<vector<int>> X(S, vector<int>(M));\n\n    for (int i = 0; i < S; i++) {\n        for (int l = 0; l < M; l++) {\n            cin >> X[i][l];\n        }\n    }\n\n    Solver solver(N, M, T, X);\n\n    for (int t = 0; t < T; t++) {\n        auto A = solver.solve_turn(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << A[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        vector<vector<int>> nx(S, vector<int>(M));\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                if (!(cin >> nx[i][l])) return 0;\n            }\n        }\n\n        solver.update_X(nx);\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\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 Assignment {\n    int f;\n    int dir;\n    int cell;\n};\n\nstruct Estimate {\n    int cnt = 0;\n    int maxrot = 0;\n    int pairCnt = 0;\n};\n\nstruct Choice {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct NextMove {\n    bool exists = false;\n    int x = 0, y = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nstruct PlanResult {\n    int Vp = 0;\n    vector<int> parent;\n    vector<int> edgeLen;\n    int initX = 0, initY = 0;\n    vector<string> ops;\n    long long score = (1LL << 60);\n    bool complete = false;\n    bool valid = false;\n    int remT = 0;\n};\n\nstruct MEdge {\n    int cellIdx;\n    int dir;\n    int rot;\n};\n\nstatic int oldMatching(const vector<vector<MEdge>>& edges, int R,\n                       vector<int>& matchCell, vector<int>& matchDir) {\n    int L = (int)edges.size();\n    matchCell.assign(R, -1);\n    matchDir.assign(R, -1);\n\n    vector<int> order(L);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return edges[a].size() < edges[b].size();\n    });\n\n    vector<unsigned char> seen(R);\n\n    function<bool(int)> dfs = [&](int li) -> bool {\n        for (const auto& e : edges[li]) {\n            int ci = e.cellIdx;\n            if (seen[ci]) continue;\n            seen[ci] = 1;\n\n            if (matchCell[ci] == -1 || dfs(matchCell[ci])) {\n                matchCell[ci] = li;\n                matchDir[ci] = e.dir;\n                return true;\n            }\n        }\n        return false;\n    };\n\n    int cnt = 0;\n    for (int li : order) {\n        if (edges[li].empty()) continue;\n        fill(seen.begin(), seen.end(), 0);\n        if (dfs(li)) cnt++;\n    }\n    return cnt;\n}\n\nstatic int limitedMatching(const vector<vector<MEdge>>& edges, int R, int limit,\n                           vector<int>& matchCell, vector<int>& matchDir) {\n    int L = (int)edges.size();\n    matchCell.assign(R, -1);\n    matchDir.assign(R, -1);\n\n    vector<int> order(L), deg(L, 0);\n    iota(order.begin(), order.end(), 0);\n\n    for (int i = 0; i < L; i++) {\n        for (const auto& e : edges[i]) {\n            if (e.rot <= limit) deg[i]++;\n        }\n    }\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    vector<unsigned char> seen(R);\n\n    function<bool(int)> dfs = [&](int li) -> bool {\n        for (const auto& e : edges[li]) {\n            if (e.rot > limit) continue;\n            int ci = e.cellIdx;\n            if (seen[ci]) continue;\n            seen[ci] = 1;\n\n            if (matchCell[ci] == -1 || dfs(matchCell[ci])) {\n                matchCell[ci] = li;\n                matchDir[ci] = e.dir;\n                return true;\n            }\n        }\n        return false;\n    };\n\n    int cnt = 0;\n    for (int li : order) {\n        if (deg[li] == 0) continue;\n        fill(seen.begin(), seen.end(), 0);\n        if (dfs(li)) cnt++;\n    }\n    return cnt;\n}\n\nstatic vector<Assignment> makeAssignments(const vector<int>& fingers,\n                                          const vector<int>& cells,\n                                          const vector<int>& matchCell,\n                                          const vector<int>& matchDir) {\n    vector<Assignment> assigns;\n    for (int ci = 0; ci < (int)cells.size(); ci++) {\n        if (matchCell[ci] == -1) continue;\n        int li = matchCell[ci];\n        assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n    }\n\n    sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n        return a.f < b.f;\n    });\n\n    return assigns;\n}\n\nclass StarPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    vector<int> outLen;\n    vector<int> len;\n    vector<int> dir;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus;\n    bool routeAware;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    StarPlanner(int N_, int V_,\n                const vector<unsigned char>& src0,\n                const vector<unsigned char>& tgt0,\n                const vector<int>& lengths,\n                int scoreMode_,\n                int strategy_,\n                double pairBonus_,\n                bool routeAware_ = true)\n        : N(N_), Vp(V_), k(V_ - 1), C(N_ * N_),\n          outLen(lengths),\n          len(V_, 0), dir(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_), pairBonus(pairBonus_),\n          routeAware(routeAware_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 1; i <= k; i++) len[i] = lengths[i - 1];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else runHybrid();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n        for (int i = 1; i < Vp; i++) {\n            res.parent[i] = 0;\n            res.edgeLen[i] = outLen[i - 1];\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int f, int d) const {\n        int x = rootX + DX[d] * len[f];\n        int y = rootY + DY[d] * len[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        return cellAt(rx, ry, f, dir[f]);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    int maxRotOf(const vector<Assignment>& assigns) const {\n        int mx = 0;\n        for (const auto& a : assigns) {\n            mx = max(mx, rotDist(dir[a.f], a.dir));\n        }\n        return mx;\n    }\n\n    Estimate estimateAtRoot(int x, int y, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int r = rotDist(dir[f], d);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) {\n            return (travel + 0.3) / cnt + 0.002 * dist;\n        } else {\n            return travel - 1.5 * (cnt - 1) + 0.01 * dist;\n        }\n    }\n\n    Choice findBestRoot(int mode) {\n        Choice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, mode);\n                if (e.cnt == 0) continue;\n\n                int dist = abs(rx - x) + abs(ry - y);\n                int travel = max(dist, max(e.maxrot, 1));\n                double sc = rootScore(travel, e.cnt, dist);\n                sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                if (!best.exists ||\n                    sc < best.score - 1e-12 ||\n                    (fabs(sc - best.score) < 1e-12 &&\n                     (e.cnt > best.cnt ||\n                      (e.cnt == best.cnt && travel < best.travel)))) {\n                    best.exists = true;\n                    best.x = x;\n                    best.y = y;\n                    best.score = sc;\n                    best.cnt = e.cnt;\n                    best.travel = travel;\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                Estimate e = estimateAtRoot(x, y, PICK);\n                if (e.cnt == 0) continue;\n\n                int travel = max(e.maxrot, 1);\n                int center = abs(x - N / 2) + abs(y - N / 2);\n                double sc = (travel + 0.3) / e.cnt\n                            - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                            + 0.0005 * center;\n\n                if (sc < bestScore - 1e-12 ||\n                    (fabs(sc - bestScore) < 1e-12 &&\n                     (e.cnt > bestCnt ||\n                      (e.cnt == bestCnt && center < bestCenter)))) {\n                    bestScore = sc;\n                    bestCnt = e.cnt;\n                    bestCenter = center;\n                    rx = x;\n                    ry = y;\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int mode) {\n        vector<int> fingers;\n        vector<vector<MEdge>> edges;\n        vector<int> cells;\n\n        for (int f = 1; f <= k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int d = 0; d < 4; d++) {\n                int cid = cellAt(x, y, f, d);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                edges[li].push_back({tmpIndex[cid], d, rotDist(dir[f], d)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const MEdge& a, const MEdge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> curMatch, curDir;\n        int curCnt = oldMatching(edges, R, curMatch, curDir);\n        vector<Assignment> cur = makeAssignments(fingers, cells, curMatch, curDir);\n        if (cur.empty()) return {};\n\n        vector<int> fullMatch, fullDir;\n        int fullCnt = limitedMatching(edges, R, 2, fullMatch, fullDir);\n\n        if (fullCnt >= curCnt && fullCnt > 0) {\n            vector<int> bestMatch = fullMatch, bestDir = fullDir;\n\n            for (int lim = 0; lim <= 2; lim++) {\n                vector<int> m, d;\n                int c = limitedMatching(edges, R, lim, m, d);\n                if (c == fullCnt) {\n                    bestMatch = std::move(m);\n                    bestDir = std::move(d);\n                    break;\n                }\n            }\n\n            vector<Assignment> opt = makeAssignments(fingers, cells, bestMatch, bestDir);\n\n            if ((int)opt.size() > (int)cur.size()) return opt;\n\n            if (opt.size() == cur.size()) {\n                int base = abs(rx - x) + abs(ry - y);\n                int curMax = maxRotOf(cur);\n                int optMax = maxRotOf(opt);\n                int curTurns = max({base, curMax, 1});\n                int optTurns = max({base, optMax, 1});\n\n                if (optTurns < curTurns) return opt;\n            }\n        }\n\n        return cur;\n    }\n\n    NextMove fallbackNext(int mode) {\n        NextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 1; f <= k; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int d = 0; d < 4; d++) {\n                    int tx = cx - DX[d] * len[f];\n                    int ty = cy - DY[d] * len[f];\n                    if (!inside(tx, ty)) continue;\n\n                    int md = abs(rx - tx) + abs(ry - ty);\n                    int travel = max(md, max(rotDist(dir[f], d), 1));\n                    double sc = travel;\n\n                    if (!best.exists || sc < best.score) {\n                        best.exists = true;\n                        best.x = tx;\n                        best.y = ty;\n                        best.score = sc;\n                        best.assigns = {Assignment{f, d, cid}};\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    NextMove makeNext(int mode, const Choice& ch) {\n        NextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    NextMove chooseNext(int mode) {\n        return makeNext(mode, findBestRoot(mode));\n    }\n\n    int potentialForRoot(int nx, int ny,\n                         const vector<unsigned char>& selected,\n                         const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        int cnt = 0;\n\n        static const int DELTA[3] = {0, 1, 3};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(nx, ny, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                mark[cid] = st;\n                cnt++;\n                break;\n            }\n        }\n\n        return cnt;\n    }\n\n    char chooseMoveChar(int tx, int ty,\n                        const vector<unsigned char>& selected,\n                        const vector<unsigned char>& reserved) {\n        vector<pair<char, pair<int, int>>> cand;\n\n        if (rx < tx) cand.push_back({'D', {rx + 1, ry}});\n        if (rx > tx) cand.push_back({'U', {rx - 1, ry}});\n        if (ry < ty) cand.push_back({'R', {rx, ry + 1}});\n        if (ry > ty) cand.push_back({'L', {rx, ry - 1}});\n\n        if (cand.empty()) return '.';\n        if (cand.size() == 1 || !routeAware) return cand[0].first;\n\n        int bestPot = -1;\n        char bestChar = cand[0].first;\n        int bestDimRemain = -1;\n\n        for (auto& c : cand) {\n            int pot = potentialForRoot(c.second.first, c.second.second, selected, reserved);\n            bool vertical = (c.first == 'U' || c.first == 'D');\n            int dimRemain = vertical ? abs(tx - rx) : abs(ty - ry);\n\n            if (pot > bestPot || (pot == bestPot && dimRemain > bestDimRemain)) {\n                bestPot = pot;\n                bestChar = c.first;\n                bestDimRemain = dimRemain;\n            }\n        }\n\n        return bestChar;\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 1; f <= k; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenDir = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nd = (dir[f] + DELTA[oi]) & 3;\n                int cid = cellAt(rx, ry, f, nd);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenDir = nd;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                dir[f] = chosenDir;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 1; f <= k; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetDir(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxrot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetDir[a.f] = a.dir;\n            reserved[a.cell] = 1;\n            maxrot = max(maxrot, rotDist(dir[a.f], a.dir));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max(md, max(maxrot, 1));\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty, selected, reserved);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (dir[f] != targetDir[f]) {\n                    char rc = rotateStep(dir[f], targetDir[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (dir[a.f] != a.dir) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                NextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                NextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) {\n                mode = PICK;\n            } else {\n                mode = DROP;\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBestRoot(PICK);\n            if (canDrop) cd = findBestRoot(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n};\n\nstruct PChoice {\n    bool exists = false;\n    int x = 0, y = 0, sdir = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct PNextMove {\n    bool exists = false;\n    int x = 0, y = 0, sdir = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nclass PalmPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    int N, Vp, k, C;\n    int A;\n    vector<int> leafLen;\n\n    int sd = 0;\n    vector<int> rel;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus;\n    bool pathAware;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    PalmPlanner(int N_, int V_,\n                const vector<unsigned char>& src0,\n                const vector<unsigned char>& tgt0,\n                int A_,\n                const vector<int>& lengths,\n                int scoreMode_,\n                int strategy_,\n                double pairBonus_,\n                bool pathAware_ = false)\n        : N(N_), Vp(V_), k(V_ - 2), C(N_ * N_),\n          A(A_), leafLen(V_, 0), rel(V_, 0), holding(V_, 0),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_), pairBonus(pairBonus_),\n          pathAware(pathAware_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1)\n    {\n        for (int i = 0; i < k; i++) leafLen[i + 2] = lengths[i];\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else runHybrid();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n\n        res.parent[1] = 0;\n        res.edgeLen[1] = A;\n        for (int f = 2; f < Vp; f++) {\n            res.parent[f] = 1;\n            res.edgeLen[f] = leafLen[f];\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.remT = remT;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    int previewRotateDir(int cur, int target) const {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return cur;\n        if (diff == 1 || diff == 2) return (cur + 1) % 4;\n        return (cur + 3) % 4;\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) % 4;\n            return 'R';\n        } else {\n            cur = (cur + 3) % 4;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int shoulderDir, int f, int absDir) const {\n        int x = rootX + DX[shoulderDir] * A + DX[absDir] * leafLen[f];\n        int y = rootY + DY[shoulderDir] * A + DY[absDir] * leafLen[f];\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCell(int f) const {\n        int ad = (sd + rel[f]) & 3;\n        return cellAt(rx, ry, sd, f, ad);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        else return holding[f] && remT > 0;\n    }\n\n    int maxRotOf(const vector<Assignment>& assigns, int sdir) const {\n        int mx = 0;\n        for (const auto& a : assigns) {\n            int targetRel = (a.dir - sdir + 4) & 3;\n            mx = max(mx, rotDist(rel[a.f], targetRel));\n        }\n        return mx;\n    }\n\n    Estimate estimateAtState(int x, int y, int sdir, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 2; f < Vp; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int ad = 0; ad < 4; ad++) {\n                int cid = cellAt(x, y, sdir, f, ad);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int tr = (ad - sdir + 4) & 3;\n                int r = rotDist(rel[f], tr);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) return (travel + 0.3) / cnt + 0.002 * dist;\n        return travel - 1.4 * (cnt - 1) + 0.01 * dist;\n    }\n\n    PChoice findBestState(int mode) {\n        PChoice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    Estimate e = estimateAtState(x, y, sdir, mode);\n                    if (e.cnt == 0) continue;\n\n                    int dist = abs(rx - x) + abs(ry - y);\n                    int travel = max({dist, rotDist(sd, sdir), e.maxrot, 1});\n                    double sc = rootScore(travel, e.cnt, dist + rotDist(sd, sdir));\n                    sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                    if (!best.exists ||\n                        sc < best.score - 1e-12 ||\n                        (fabs(sc - best.score) < 1e-12 &&\n                         (e.cnt > best.cnt ||\n                          (e.cnt == best.cnt && travel < best.travel)))) {\n                        best.exists = true;\n                        best.x = x;\n                        best.y = y;\n                        best.sdir = sdir;\n                        best.score = sc;\n                        best.cnt = e.cnt;\n                        best.travel = travel;\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    Estimate e = estimateAtState(x, y, sdir, PICK);\n                    if (e.cnt == 0) continue;\n\n                    int travel = max({rotDist(0, sdir), e.maxrot, 1});\n                    int center = abs(x - N / 2) + abs(y - N / 2);\n                    double sc = (travel + 0.3) / e.cnt\n                                - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                                + 0.0005 * center;\n\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) < 1e-12 &&\n                         (e.cnt > bestCnt ||\n                          (e.cnt == bestCnt && center < bestCenter)))) {\n                        bestScore = sc;\n                        bestCnt = e.cnt;\n                        bestCenter = center;\n                        rx = x;\n                        ry = y;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int sdir, int mode) {\n        vector<int> fingers;\n        vector<vector<MEdge>> edges;\n        vector<int> cells;\n\n        for (int f = 2; f < Vp; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n\n            int li = (int)fingers.size() - 1;\n            for (int ad = 0; ad < 4; ad++) {\n                int cid = cellAt(x, y, sdir, f, ad);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                int tr = (ad - sdir + 4) & 3;\n                edges[li].push_back({tmpIndex[cid], ad, rotDist(rel[f], tr)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const MEdge& a, const MEdge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int L = (int)fingers.size();\n        int R = (int)cells.size();\n        if (L == 0 || R == 0) return {};\n\n        vector<int> curMatch, curDir;\n        int curCnt = oldMatching(edges, R, curMatch, curDir);\n        vector<Assignment> cur = makeAssignments(fingers, cells, curMatch, curDir);\n        if (cur.empty()) return {};\n\n        vector<int> fullMatch, fullDir;\n        int fullCnt = limitedMatching(edges, R, 2, fullMatch, fullDir);\n\n        if (fullCnt >= curCnt && fullCnt > 0) {\n            vector<int> bestMatch = fullMatch, bestDir = fullDir;\n\n            for (int lim = 0; lim <= 2; lim++) {\n                vector<int> m, d;\n                int c = limitedMatching(edges, R, lim, m, d);\n                if (c == fullCnt) {\n                    bestMatch = std::move(m);\n                    bestDir = std::move(d);\n                    break;\n                }\n            }\n\n            vector<Assignment> opt = makeAssignments(fingers, cells, bestMatch, bestDir);\n\n            if ((int)opt.size() > (int)cur.size()) return opt;\n\n            if (opt.size() == cur.size()) {\n                int base = max(abs(rx - x) + abs(ry - y), rotDist(sd, sdir));\n                int curMax = maxRotOf(cur, sdir);\n                int optMax = maxRotOf(opt, sdir);\n                int curTurns = max({base, curMax, 1});\n                int optTurns = max({base, optMax, 1});\n\n                if (optTurns < curTurns) return opt;\n            }\n        }\n\n        return cur;\n    }\n\n    PNextMove fallbackNext(int mode) {\n        PNextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 2; f < Vp; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int sdir = 0; sdir < 4; sdir++) {\n                    for (int ad = 0; ad < 4; ad++) {\n                        int tx = cx - DX[sdir] * A - DX[ad] * leafLen[f];\n                        int ty = cy - DY[sdir] * A - DY[ad] * leafLen[f];\n                        if (!inside(tx, ty)) continue;\n\n                        int tr = (ad - sdir + 4) & 3;\n                        int travel = max({abs(rx - tx) + abs(ry - ty),\n                                          rotDist(sd, sdir),\n                                          rotDist(rel[f], tr),\n                                          1});\n                        double sc = travel;\n\n                        if (!best.exists || sc < best.score) {\n                            best.exists = true;\n                            best.x = tx;\n                            best.y = ty;\n                            best.sdir = sdir;\n                            best.score = sc;\n                            best.assigns = {Assignment{f, ad, cid}};\n                        }\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    PNextMove makeNext(int mode, const PChoice& ch) {\n        PNextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, ch.sdir, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.sdir = ch.sdir;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    PNextMove chooseNext(int mode) {\n        return makeNext(mode, findBestState(mode));\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    int potentialForRoot(int nx, int ny, int sdirAfter,\n                         const vector<unsigned char>& selected,\n                         const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        int cnt = 0;\n\n        static const int DELTA[3] = {0, 1, 3};\n\n        for (int f = 2; f < Vp; f++) {\n            if (selected[f]) continue;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nr = (rel[f] + DELTA[oi]) & 3;\n                int ad = (sdirAfter + nr) & 3;\n                int cid = cellAt(nx, ny, sdirAfter, f, ad);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                mark[cid] = st;\n                cnt++;\n                break;\n            }\n        }\n\n        return cnt;\n    }\n\n    char chooseMoveChar(int tx, int ty,\n                        const vector<unsigned char>& selected,\n                        const vector<unsigned char>& reserved,\n                        int sdirAfter) {\n        vector<pair<char, pair<int, int>>> cand;\n\n        if (rx < tx) cand.push_back({'D', {rx + 1, ry}});\n        if (rx > tx) cand.push_back({'U', {rx - 1, ry}});\n        if (ry < ty) cand.push_back({'R', {rx, ry + 1}});\n        if (ry > ty) cand.push_back({'L', {rx, ry - 1}});\n\n        if (cand.empty()) return '.';\n        if (cand.size() == 1 || !pathAware) return cand[0].first;\n\n        int bestPot = -1;\n        char bestChar = cand[0].first;\n        int bestDimRemain = -1;\n\n        for (auto& c : cand) {\n            int pot = potentialForRoot(c.second.first, c.second.second,\n                                       sdirAfter, selected, reserved);\n            bool vertical = (c.first == 'U' || c.first == 'D');\n            int dimRemain = vertical ? abs(tx - rx) : abs(ty - ry);\n\n            if (pot > bestPot || (pot == bestPot && dimRemain > bestDimRemain)) {\n                bestPot = pot;\n                bestChar = c.first;\n                bestDimRemain = dimRemain;\n            }\n        }\n\n        return bestChar;\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        for (int f = 2; f < Vp; f++) {\n            if (selected[f]) continue;\n            if (cmd[f] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenRel = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int nr = (rel[f] + DELTA[oi]) & 3;\n                int ad = (sd + nr) & 3;\n                int cid = cellAt(rx, ry, sd, f, ad);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenRel = nr;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[f] = RCHAR[chosen];\n                rel[f] = chosenRel;\n                cmd[Vp + f] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 2; f < Vp; f++) {\n            if (cmd[Vp + f] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, int tsd, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(Vp, 0);\n        vector<int> targetRel(Vp, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxLeafRot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetRel[a.f] = (a.dir - tsd + 4) & 3;\n            reserved[a.cell] = 1;\n            maxLeafRot = max(maxLeafRot, rotDist(rel[a.f], targetRel[a.f]));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int total = max({md, rotDist(sd, tsd), maxLeafRot, 1});\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            if (rx != tx || ry != ty) {\n                int futureSd = previewRotateDir(sd, tsd);\n                char mv = chooseMoveChar(tx, ty, selected, reserved, futureSd);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            if (sd != tsd) {\n                char rc = rotateStep(sd, tsd);\n                cmd[1] = rc;\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                if (rel[f] != targetRel[f]) {\n                    char rc = rotateStep(rel[f], targetRel[f]);\n                    cmd[f] = rc;\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty || sd != tsd) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    if (rel[a.f] != targetRel[a.f]) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(a.f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + a.f] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                PNextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                PNextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            PChoice cp, cd;\n            if (canPick) cp = findBestState(PICK);\n            if (canDrop) cd = findBestState(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) mode = PICK;\n            else mode = DROP;\n\n            PNextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            PChoice cp, cd;\n            if (canPick) cp = findBestState(PICK);\n            if (canDrop) cd = findBestState(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            PNextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.sdir, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\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\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    int C = N * N;\n    vector<unsigned char> src(C, 0), tgt(C, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int cid = i * N + j;\n            if (s[i][j] == '1' && t[i][j] == '0') src[cid] = 1;\n            if (s[i][j] == '0' && t[i][j] == '1') tgt[cid] = 1;\n        }\n    }\n\n    int maxL = max(1, N / 2);\n\n    auto buildLengthSets = [&](int K) {\n        vector<vector<int>> sets;\n\n        auto clampLen = [&](int x) {\n            return max(1, min(maxL, x));\n        };\n\n        auto addSet = [&](vector<int> a) {\n            if ((int)a.size() != K) return;\n            for (int& x : a) x = clampLen(x);\n            for (auto& b : sets) {\n                if (a == b) return;\n            }\n            sets.push_back(a);\n        };\n\n        if (K <= 0) return sets;\n\n        auto cycleSet = [&](int L) {\n            L = max(1, min(L, maxL));\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = 1 + (i % L);\n            return a;\n        };\n\n        auto repeatVals = [&](vector<int> vals) {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = vals[i % vals.size()];\n            return a;\n        };\n\n        addSet(cycleSet(maxL));\n        addSet(cycleSet(6));\n        addSet(cycleSet(4));\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    a[i] = (int)llround(1.0 + (double)i * (maxL - 1) / (K - 1));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                a[i] = (int)llround((i + 0.5) * maxL / K);\n                if (a[i] < 1) a[i] = 1;\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    double r = (double)i / (K - 1);\n                    a[i] = (int)llround(pow((double)maxL, r));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                if (i % 2 == 0) a[i] = 1 + (i / 2) % maxL;\n                else a[i] = maxL - (i / 2) % maxL;\n            }\n            addSet(a);\n        }\n\n        addSet(vector<int>(K, 1));\n        addSet(vector<int>(K, maxL));\n        addSet(vector<int>(K, max(1, maxL / 2)));\n\n        addSet(repeatVals(vector<int>{1, maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 2), maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 3), max(1, 2 * maxL / 3), maxL}));\n        addSet(repeatVals(vector<int>{max(1, maxL / 4), max(1, maxL / 2), max(1, 3 * maxL / 4), maxL}));\n\n        return sets;\n    };\n\n    vector<vector<int>> starLengthSets = buildLengthSets(V - 1);\n\n    auto startTime = chrono::steady_clock::now();\n\n    auto elapsedMs = [&]() {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration_cast<chrono::milliseconds>(now - startTime).count();\n    };\n\n    PlanResult best;\n\n    auto consider = [&](PlanResult&& res) {\n        if (res.valid &&\n            (res.score < best.score ||\n             (res.score == best.score && res.ops.size() < best.ops.size()))) {\n            best = std::move(res);\n        }\n    };\n\n    struct StarParam {\n        int li;\n        int sm;\n        int st;\n        double pb;\n    };\n\n    vector<StarParam> starParams;\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.0});\n\n    int split = (int)starParams.size();\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 1, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 1, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.30});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.30});\n\n    auto runStarRange = [&](int l, int r) {\n        for (int idx = l; idx < r; idx++) {\n            if (idx > l && elapsedMs() > 2760) break;\n\n            auto p = starParams[idx];\n            StarPlanner planner(N, V, src, tgt, starLengthSets[p.li], p.sm, p.st, p.pb);\n            PlanResult res = planner.run();\n            consider(std::move(res));\n        }\n    };\n\n    runStarRange(0, split);\n\n    vector<vector<int>> palmLengthSets;\n    vector<int> As;\n\n    if (V >= 5) {\n        int kp = V - 2;\n        palmLengthSets = buildLengthSets(kp);\n        As = {\n            maxL,\n            max(1, (2 * maxL + 1) / 3),\n            max(1, maxL / 2)\n        };\n        sort(As.begin(), As.end());\n        As.erase(unique(As.begin(), As.end()), As.end());\n        reverse(As.begin(), As.end());\n    }\n\n    auto runPalm = [&](double pb, int limSets, bool pathAware) {\n        if (V < 5) return;\n        limSets = min(limSets, (int)palmLengthSets.size());\n        vector<int> palmStrategies = {0, 2, 1};\n\n        for (int A : As) {\n            for (int li = 0; li < limSets; li++) {\n                for (int stg : palmStrategies) {\n                    if (elapsedMs() > 2760) return;\n\n                    PalmPlanner planner(N, V, src, tgt, A, palmLengthSets[li], 0, stg, pb, pathAware);\n                    PlanResult res = planner.run();\n                    consider(std::move(res));\n                }\n            }\n        }\n    };\n\n    if (elapsedMs() < 2300 && V >= 5) {\n        runPalm(0.25, 5, false);\n    }\n\n    if (elapsedMs() < 2760) {\n        runStarRange(split, (int)starParams.size());\n    }\n\n    if (elapsedMs() < 2650 && V >= 5) {\n        runPalm(0.0, 3, false);\n    }\n\n    // Extra safe variants: only if the known-good candidates finished early.\n    if (elapsedMs() < 2700 && V >= 5) {\n        runPalm(0.25, 2, true);\n    }\n\n    if (elapsedMs() < 2700) {\n        int lim = min(5, (int)starLengthSets.size());\n        vector<int> stgs = {0, 2};\n        for (int i = 0; i < lim; i++) {\n            for (int stg : stgs) {\n                if (elapsedMs() > 2760) break;\n                StarPlanner planner(N, V, src, tgt, starLengthSets[i], 0, stg, 0.0, false);\n                PlanResult res = planner.run();\n                consider(std::move(res));\n            }\n        }\n    }\n\n    if (!best.valid) {\n        best.valid = true;\n        best.Vp = V;\n        best.parent.assign(V, -1);\n        best.edgeLen.assign(V, 0);\n        vector<int> lens = starLengthSets.empty() ? vector<int>(V - 1, 1) : starLengthSets[0];\n\n        for (int i = 1; i < V; i++) {\n            best.parent[i] = 0;\n            best.edgeLen[i] = lens[i - 1];\n        }\n        best.initX = 0;\n        best.initY = 0;\n        best.ops.clear();\n    }\n\n    cout << best.Vp << '\\n';\n    for (int i = 1; i < best.Vp; i++) {\n        cout << best.parent[i] << ' ' << best.edgeLen[i] << '\\n';\n    }\n    cout << best.initX << ' ' << best.initY << '\\n';\n\n    for (const string& op : best.ops) {\n        cout << op << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing ll = long long;\nusing uchar = unsigned char;\n\nconstexpr int CMAX = 100000;\nconstexpr int MAXLEN = 400000;\nconstexpr int MAXV = 1000;\nconstexpr int INF = 1e9;\n\nstruct Fish {\n    int x, y, w;\n};\n\nstruct Candidate {\n    int approx;\n    int cat;\n    vector<pair<int,int>> poly;\n};\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nvector<Fish> fishes;\nvector<int> fishOrderY;\nvector<Candidate> candidates;\n\nvector<pair<int,int>> bestPoly;\nvector<pair<int,int>> bestSafePoly;\nint bestApprox = -1;\nint bestSafeApprox = -1;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nvector<pair<int,int>> square_poly() {\n    return {{0,0}, {CMAX,0}, {CMAX,CMAX}, {0,CMAX}};\n}\n\nuint64_t poly_hash(const vector<pair<int,int>>& p) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)p.size();\n    h *= 1099511628211ULL;\n    for (auto [x, y] : p) {\n        h ^= (uint64_t)(x + 1000003LL * y);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvoid record_candidate(const vector<pair<int,int>>& poly, int approx, int cat) {\n    if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return;\n    if (approx < 0) return;\n    if (approx == 0 && bestApprox >= 0 && !candidates.empty()) return;\n\n    if (approx > bestApprox) {\n        bestApprox = approx;\n        bestPoly = poly;\n    }\n\n    if ((cat == 0 || cat == 3) && approx > bestSafeApprox) {\n        bestSafeApprox = approx;\n        bestSafePoly = poly;\n    }\n\n    candidates.push_back({approx, cat, poly});\n\n    if (candidates.size() > 900) {\n        nth_element(candidates.begin(), candidates.begin() + 650, candidates.end(),\n                    [](const Candidate& a, const Candidate& b) {\n                        return a.approx > b.approx;\n                    });\n        candidates.resize(650);\n    }\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 <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sum(int idx) const {\n        int r = 0;\n        for (; idx > 0; idx -= idx & -idx) r += bit[idx];\n        return r;\n    }\n    int all() const {\n        return sum(n);\n    }\n};\n\nint exact_score(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n\n    int minx = CMAX, maxx = 0, miny = CMAX, maxy = 0;\n    for (auto [x, y] : poly) {\n        minx = min(minx, x);\n        maxx = max(maxx, x);\n        miny = min(miny, y);\n        maxy = max(maxy, y);\n    }\n\n    struct VEdge {\n        int x, y1, y2;\n    };\n\n    struct Event {\n        int y, xi, delta;\n        bool operator<(const Event& other) const {\n            return y < other.y;\n        }\n    };\n\n    vector<VEdge> vedges;\n    vector<int> xs;\n    unordered_map<int, vector<pair<int,int>>> vmap;\n    unordered_map<int, vector<pair<int,int>>> hmap;\n    vmap.reserve(m * 2 + 10);\n    hmap.reserve(m * 2 + 10);\n\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            if (y1 == y2) continue;\n            vedges.push_back({x1, y1, y2});\n            xs.push_back(x1);\n            vmap[x1].push_back({y1, y2});\n        } else {\n            if (x1 > x2) swap(x1, x2);\n            if (x1 == x2) continue;\n            hmap[y1].push_back({x1, x2});\n        }\n    }\n\n    for (auto& kv : vmap) sort(kv.second.begin(), kv.second.end());\n    for (auto& kv : hmap) sort(kv.second.begin(), kv.second.end());\n\n    sort(xs.begin(), xs.end());\n    xs.erase(unique(xs.begin(), xs.end()), xs.end());\n\n    vector<Event> events;\n    events.reserve(vedges.size() * 2);\n\n    for (const auto& e : vedges) {\n        int xi = lower_bound(xs.begin(), xs.end(), e.x) - xs.begin();\n        events.push_back({e.y1, xi, +1});\n        events.push_back({e.y2, xi, -1});\n    }\n\n    sort(events.begin(), events.end());\n\n    Fenwick fw((int)xs.size());\n    int ep = 0;\n    int score = 0;\n\n    auto on_boundary = [&](int px, int py) -> bool {\n        auto itv = vmap.find(px);\n        if (itv != vmap.end()) {\n            for (auto [a, b] : itv->second) {\n                if (a <= py && py <= b) return true;\n            }\n        }\n\n        auto ith = hmap.find(py);\n        if (ith != hmap.end()) {\n            for (auto [a, b] : ith->second) {\n                if (a <= px && px <= b) return true;\n            }\n        }\n\n        return false;\n    };\n\n    for (int id : fishOrderY) {\n        const auto& f = fishes[id];\n\n        if (f.y < miny) continue;\n        if (f.y > maxy) break;\n\n        while (ep < (int)events.size() && events[ep].y <= f.y) {\n            fw.add(events[ep].xi + 1, events[ep].delta);\n            ep++;\n        }\n\n        if (f.x < minx || f.x > maxx) continue;\n\n        if (on_boundary(f.x, f.y)) {\n            score += f.w;\n            continue;\n        }\n\n        int pos = upper_bound(xs.begin(), xs.end(), f.x) - xs.begin();\n        int crossings = fw.all() - fw.sum(pos);\n        if (crossings & 1) score += f.w;\n    }\n\n    return score;\n}\n\nint rect_score(int x1, int y1, int x2, int y2) {\n    if (x1 >= x2 || y1 >= y2) return -INF;\n    int s = 0;\n    for (const auto& f : fishes) {\n        if (x1 <= f.x && f.x <= x2 && y1 <= f.y && f.y <= y2) s += f.w;\n    }\n    return s;\n}\n\nvoid refine_and_record_rectangle(int x1, int y1, int x2, int y2) {\n    if (elapsed_sec() > 1.75) return;\n\n    x1 = max(0, min(CMAX, x1));\n    x2 = max(0, min(CMAX, x2));\n    y1 = max(0, min(CMAX, y1));\n    y2 = max(0, min(CMAX, y2));\n\n    if (x1 >= x2 || y1 >= y2) return;\n\n    auto opt_left = [&]() -> int {\n        int lo = 0, hi = max(0, x2 - 1);\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (y1 <= f.y && f.y <= y2 && f.x <= x2) {\n                pts.push_back({f.x, f.w});\n                if (lo <= f.x && f.x <= hi) cand.push_back(f.x);\n                if (lo <= f.x + 1 && f.x + 1 <= hi) cand.push_back(f.x + 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end(), greater<pair<int,int>>());\n        sort(cand.begin(), cand.end(), greater<int>());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = x1;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first >= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_right = [&]() -> int {\n        int lo = min(CMAX, x1 + 1), hi = CMAX;\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (y1 <= f.y && f.y <= y2 && f.x >= x1) {\n                pts.push_back({f.x, f.w});\n                if (lo <= f.x && f.x <= hi) cand.push_back(f.x);\n                if (lo <= f.x - 1 && f.x - 1 <= hi) cand.push_back(f.x - 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = x2;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first <= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_bottom = [&]() -> int {\n        int lo = 0, hi = max(0, y2 - 1);\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (x1 <= f.x && f.x <= x2 && f.y <= y2) {\n                pts.push_back({f.y, f.w});\n                if (lo <= f.y && f.y <= hi) cand.push_back(f.y);\n                if (lo <= f.y + 1 && f.y + 1 <= hi) cand.push_back(f.y + 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end(), greater<pair<int,int>>());\n        sort(cand.begin(), cand.end(), greater<int>());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = y1;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first >= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_top = [&]() -> int {\n        int lo = min(CMAX, y1 + 1), hi = CMAX;\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (x1 <= f.x && f.x <= x2 && f.y >= y1) {\n                pts.push_back({f.y, f.w});\n                if (lo <= f.y && f.y <= hi) cand.push_back(f.y);\n                if (lo <= f.y - 1 && f.y - 1 <= hi) cand.push_back(f.y - 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = y2;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first <= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    for (int it = 0; it < 4; it++) {\n        x1 = opt_left();\n        x2 = opt_right();\n        y1 = opt_bottom();\n        y2 = opt_top();\n        if (x1 >= x2 || y1 >= y2) return;\n    }\n\n    int sc = rect_score(x1, y1, x2, y2);\n    if (sc <= 0) return;\n\n    vector<pair<int,int>> poly = {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}};\n    record_candidate(poly, sc, 3);\n}\n\nstruct GridSolver {\n    int D, G, maxEdges, ncell;\n    vector<int> w;\n\n    struct Comp {\n        vector<int> cells;\n        int score = 0;\n        int perim = 0;\n    };\n\n    struct Eval {\n        int score;\n        int len;\n    };\n\n    struct Corridor {\n        int a, b;\n        bool xFirst;\n    };\n\n    GridSolver(int d) : D(d), G(CMAX / d), maxEdges(MAXLEN / d), ncell(G * G), w(ncell, 0) {\n        for (const auto& f : fishes) {\n            int x = f.x / D;\n            int y = f.y / D;\n            if (x >= G) x = G - 1;\n            if (y >= G) y = G - 1;\n            w[idx(x, y)] += f.w;\n        }\n    }\n\n    inline int idx(int x, int y) const {\n        return y * G + x;\n    }\n\n    inline bool in_grid(int x, int y) const {\n        return 0 <= x && x < G && 0 <= y && y < G;\n    }\n\n    int mask_score(const vector<uchar>& mask) const {\n        int s = 0;\n        for (int i = 0; i < ncell; i++) if (mask[i]) s += w[i];\n        return s;\n    }\n\n    int selected_neighbor_count(const vector<uchar>& mask, int x, int y) const {\n        int c = 0;\n        if (x > 0 && mask[idx(x - 1, y)]) c++;\n        if (x + 1 < G && mask[idx(x + 1, y)]) c++;\n        if (y > 0 && mask[idx(x, y - 1)]) c++;\n        if (y + 1 < G && mask[idx(x, y + 1)]) c++;\n        return c;\n    }\n\n    int selected_neighbor_count_id(const vector<uchar>& mask, int v) const {\n        return selected_neighbor_count(mask, v % G, v / G);\n    }\n\n    int boundary_edges(const vector<uchar>& mask) const {\n        int p = 0;\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n                if (x == 0 || !mask[idx(x - 1, y)]) p++;\n                if (x + 1 == G || !mask[idx(x + 1, y)]) p++;\n                if (y == 0 || !mask[idx(x, y - 1)]) p++;\n                if (y + 1 == G || !mask[idx(x, y + 1)]) p++;\n            }\n        }\n        return p;\n    }\n\n    void fix_diagonal(vector<uchar>& mask) const {\n        for (int it = 0; it < 30; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < G; y++) {\n                for (int x = 0; x + 1 < G; x++) {\n                    int a = idx(x, y);\n                    int b = idx(x + 1, y);\n                    int c = idx(x, y + 1);\n                    int d = idx(x + 1, y + 1);\n\n                    bool A = mask[a], B = mask[b], C = mask[c], DD = mask[d];\n\n                    if (A && DD && !B && !C) {\n                        int choose = (w[b] >= w[c] ? b : c);\n                        mask[choose] = 1;\n                        changed = true;\n                    } else if (B && C && !A && !DD) {\n                        int choose = (w[a] >= w[d] ? a : d);\n                        mask[choose] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void fill_holes(vector<uchar>& mask) const {\n        vector<uchar> out(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto push = [&](int x, int y) {\n            int id = idx(x, y);\n            if (!mask[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < G; x++) {\n            push(x, 0);\n            push(x, G - 1);\n        }\n        for (int y = 0; y < G; y++) {\n            push(0, y);\n            push(G - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % G, y = v / G;\n            const int dx[4] = {1, -1, 0, 0};\n            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 (!in_grid(nx, ny)) continue;\n                int ni = idx(nx, ny);\n                if (!mask[ni] && !out[ni]) {\n                    out[ni] = 1;\n                    q.push_back(ni);\n                }\n            }\n        }\n\n        for (int i = 0; i < ncell; i++) {\n            if (!mask[i] && !out[i]) mask[i] = 1;\n        }\n    }\n\n    vector<Comp> find_components(const vector<uchar>& mask, vector<int>* compIdOut = nullptr) const {\n        vector<int> compId(ncell, -1);\n        vector<Comp> comps;\n        vector<int> q;\n        q.reserve(ncell);\n\n        for (int s = 0; s < ncell; s++) {\n            if (!mask[s] || compId[s] != -1) continue;\n\n            int cid = (int)comps.size();\n            comps.push_back(Comp{});\n            compId[s] = cid;\n            q.clear();\n            q.push_back(s);\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                comps[cid].cells.push_back(v);\n                comps[cid].score += w[v];\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) {\n                        comps[cid].perim++;\n                        continue;\n                    }\n\n                    int ni = idx(nx, ny);\n                    if (!mask[ni]) {\n                        comps[cid].perim++;\n                    } else if (compId[ni] == -1) {\n                        compId[ni] = cid;\n                        q.push_back(ni);\n                    }\n                }\n            }\n        }\n\n        if (compIdOut) *compIdOut = move(compId);\n        return comps;\n    }\n\n    void trim_leaves(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        vector<uchar> inq(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto maybe_push = [&](int id) {\n            if (!mask[id] || w[id] > 0 || inq[id]) return;\n            if (selected_neighbor_count_id(mask, id) <= 1) {\n                inq[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < ncell; i++) maybe_push(i);\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            inq[v] = 0;\n            if (!mask[v] || w[v] > 0) continue;\n            if (sel <= 1) continue;\n\n            int k = selected_neighbor_count_id(mask, v);\n            if (k <= 1) {\n                mask[v] = 0;\n                sel--;\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (in_grid(nx, ny)) maybe_push(idx(nx, ny));\n                }\n            }\n        }\n    }\n\n    void add_positive_boundary(vector<uchar>& mask) const {\n        int P = boundary_edges(mask);\n\n        for (int it = 0; it < 4; it++) {\n            bool changed = false;\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool simple_removable(const vector<uchar>& mask, int v) const {\n        int x = v % G, y = v / G;\n        bool occ[3][3] = {};\n        bool vis[3][3] = {};\n        int cnt = 0;\n\n        for (int dy = -1; dy <= 1; dy++) {\n            for (int dx = -1; dx <= 1; dx++) {\n                if (dx == 0 && dy == 0) continue;\n                int nx = x + dx, ny = y + dy;\n                if (in_grid(nx, ny) && mask[idx(nx, ny)]) {\n                    occ[dy + 1][dx + 1] = true;\n                    cnt++;\n                }\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int comps = 0;\n        const int ddx[4] = {1, -1, 0, 0};\n        const int ddy[4] = {0, 0, 1, -1};\n\n        for (int sy = 0; sy < 3; sy++) {\n            for (int sx = 0; sx < 3; sx++) {\n                if (!occ[sy][sx] || vis[sy][sx]) continue;\n\n                comps++;\n                int qx[9], qy[9], h = 0, t = 0;\n                qx[t] = sx;\n                qy[t] = sy;\n                t++;\n                vis[sy][sx] = true;\n\n                while (h < t) {\n                    int cx = qx[h], cy = qy[h];\n                    h++;\n\n                    for (int dir = 0; dir < 4; dir++) {\n                        int nx = cx + ddx[dir], ny = cy + ddy[dir];\n                        if (0 <= nx && nx < 3 && 0 <= ny && ny < 3 &&\n                            occ[ny][nx] && !vis[ny][nx]) {\n                            vis[ny][nx] = true;\n                            qx[t] = nx;\n                            qy[t] = ny;\n                            t++;\n                        }\n                    }\n                }\n            }\n        }\n\n        return comps == 1;\n    }\n\n    void polish_mask(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        int P = boundary_edges(mask);\n\n        for (int pass = 0; pass < 3; pass++) {\n            if (elapsed_sec() > 1.86) break;\n\n            bool changed = false;\n\n            for (int id = 0; id < ncell; id++) {\n                if (!mask[id] || sel <= 1) continue;\n\n                int k = selected_neighbor_count_id(mask, id);\n                if (k == 4) continue;\n\n                int delta = 2 * k - 4;\n                bool ok = false;\n\n                if (w[id] < 0) {\n                    if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                } else if (w[id] == 0 && delta < 0) {\n                    ok = true;\n                }\n\n                if (ok && simple_removable(mask, id)) {\n                    mask[id] = 0;\n                    sel--;\n                    P += delta;\n                    changed = true;\n                }\n            }\n\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        sel++;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    bool extract_polygon(const vector<uchar>& mask, vector<pair<int,int>>& poly) const {\n        int V = (G + 1) * (G + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (G + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n        };\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n\n                if (y == 0 || !mask[idx(x, y - 1)]) set_edge(x, y, x + 1, y);\n                if (x + 1 == G || !mask[idx(x + 1, y)]) set_edge(x + 1, y, x + 1, y + 1);\n                if (y + 1 == G || !mask[idx(x, y + 1)]) set_edge(x + 1, y + 1, x, y + 1);\n                if (x == 0 || !mask[idx(x - 1, y)]) set_edge(x, y + 1, x, y);\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (1LL * edges * D > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n        int cur = start;\n\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int px = pv % (G + 1), py = pv / (G + 1);\n            int cx = cv % (G + 1), cy = cv / (G + 1);\n            int nx = nv % (G + 1), ny = nv / (G + 1);\n\n            if ((px == cx && cx == nx) || (py == cy && cy == ny)) continue;\n\n            poly.push_back({cx * D, cy * D});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    bool extract_rect_union(const vector<Rect>& inRects, vector<pair<int,int>>& poly) const {\n        vector<Rect> rects;\n        vector<int> xs, ys;\n        rects.reserve(inRects.size());\n        xs.reserve(inRects.size() * 2 + 4);\n        ys.reserve(inRects.size() * 2 + 4);\n\n        for (auto r : inRects) {\n            if (r.x1 > r.x2) swap(r.x1, r.x2);\n            if (r.y1 > r.y2) swap(r.y1, r.y2);\n\n            r.x1 = max(0, min(CMAX, r.x1));\n            r.x2 = max(0, min(CMAX, r.x2));\n            r.y1 = max(0, min(CMAX, r.y1));\n            r.y2 = max(0, min(CMAX, r.y2));\n\n            if (r.x1 >= r.x2 || r.y1 >= r.y2) continue;\n\n            rects.push_back(r);\n            xs.push_back(r.x1);\n            xs.push_back(r.x2);\n            ys.push_back(r.y1);\n            ys.push_back(r.y2);\n        }\n\n        if (rects.empty()) return false;\n\n        sort(xs.begin(), xs.end());\n        xs.erase(unique(xs.begin(), xs.end()), xs.end());\n        sort(ys.begin(), ys.end());\n        ys.erase(unique(ys.begin(), ys.end()), ys.end());\n\n        int NX = (int)xs.size() - 1;\n        int NY = (int)ys.size() - 1;\n        if (NX <= 0 || NY <= 0) return false;\n\n        int Wd = NX + 1;\n        vector<int> diff((NX + 1) * (NY + 1), 0);\n\n        auto did = [&](int x, int y) {\n            return y * Wd + x;\n        };\n\n        for (auto r : rects) {\n            int x1 = lower_bound(xs.begin(), xs.end(), r.x1) - xs.begin();\n            int x2 = lower_bound(xs.begin(), xs.end(), r.x2) - xs.begin();\n            int y1 = lower_bound(ys.begin(), ys.end(), r.y1) - ys.begin();\n            int y2 = lower_bound(ys.begin(), ys.end(), r.y2) - ys.begin();\n\n            diff[did(x1, y1)]++;\n            diff[did(x2, y1)]--;\n            diff[did(x1, y2)]--;\n            diff[did(x2, y2)]++;\n        }\n\n        for (int y = 0; y <= NY; y++) {\n            for (int x = 1; x <= NX; x++) {\n                diff[did(x, y)] += diff[did(x - 1, y)];\n            }\n        }\n        for (int y = 1; y <= NY; y++) {\n            for (int x = 0; x <= NX; x++) {\n                diff[did(x, y)] += diff[did(x, y - 1)];\n            }\n        }\n\n        vector<uchar> cov(NX * NY, 0);\n        for (int y = 0; y < NY; y++) {\n            for (int x = 0; x < NX; x++) {\n                if (diff[did(x, y)] > 0) cov[y * NX + x] = 1;\n            }\n        }\n\n        vector<uchar> out(NX * NY, 0);\n        vector<int> q;\n        q.reserve(NX * NY);\n\n        auto push = [&](int x, int y) {\n            if (x < 0 || x >= NX || y < 0 || y >= NY) return;\n            int id = y * NX + x;\n            if (!cov[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < NX; x++) {\n            push(x, 0);\n            push(x, NY - 1);\n        }\n        for (int y = 0; y < NY; y++) {\n            push(0, y);\n            push(NX - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % NX, y = v / NX;\n\n            const int dx[4] = {1, -1, 0, 0};\n            const int dy[4] = {0, 0, 1, -1};\n\n            for (int dir = 0; dir < 4; dir++) {\n                push(x + dx[dir], y + dy[dir]);\n            }\n        }\n\n        for (int i = 0; i < NX * NY; i++) {\n            if (!cov[i] && !out[i]) cov[i] = 1;\n        }\n\n        int V = (NX + 1) * (NY + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        long long totalLen = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (NX + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty, int len) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n            totalLen += len;\n        };\n\n        for (int y = 0; y < NY; y++) {\n            for (int x = 0; x < NX; x++) {\n                if (!cov[y * NX + x]) continue;\n\n                if (y == 0 || !cov[(y - 1) * NX + x]) {\n                    set_edge(x, y, x + 1, y, xs[x + 1] - xs[x]);\n                }\n                if (x + 1 == NX || !cov[y * NX + (x + 1)]) {\n                    set_edge(x + 1, y, x + 1, y + 1, ys[y + 1] - ys[y]);\n                }\n                if (y + 1 == NY || !cov[(y + 1) * NX + x]) {\n                    set_edge(x + 1, y + 1, x, y + 1, xs[x + 1] - xs[x]);\n                }\n                if (x == 0 || !cov[y * NX + (x - 1)]) {\n                    set_edge(x, y + 1, x, y, ys[y + 1] - ys[y]);\n                }\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (totalLen > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n\n        int cur = start;\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int pxi = pv % (NX + 1), pyi = pv / (NX + 1);\n            int cxi = cv % (NX + 1), cyi = cv / (NX + 1);\n            int nxi = nv % (NX + 1), nyi = nv / (NX + 1);\n\n            int px = xs[pxi], py = ys[pyi];\n            int cx = xs[cxi], cy = ys[cyi];\n            int nx = xs[nxi], ny = ys[nyi];\n\n            if ((px == cx && cx == nx) || (py == cy && cy == ny)) continue;\n\n            poly.push_back({cx, cy});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    void finalize_original(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.90) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        trim_leaves(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        add_positive_boundary(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc, 0);\n    }\n\n    void finalize_polish(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.88) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        polish_mask(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        polish_mask(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc, 1);\n    }\n\n    void finalize_candidate(vector<uchar> mask, int variants = 1) const {\n        if (variants & 1) {\n            auto m = mask;\n            finalize_original(move(m));\n        }\n        if ((variants & 2) && elapsed_sec() < 1.50) {\n            auto m = mask;\n            finalize_polish(move(m));\n        }\n    }\n\n    void finalize_thin(const vector<int>& selectedIds,\n                       const vector<Corridor>& corridors,\n                       const vector<Comp>& comps,\n                       int approx) const {\n        if (elapsed_sec() > 1.88) return;\n        if (selectedIds.empty()) return;\n\n        size_t rcnt = corridors.size() * 2;\n        for (int cid : selectedIds) rcnt += comps[cid].cells.size();\n\n        vector<Rect> rects;\n        rects.reserve(rcnt);\n\n        auto add_rect = [&](int x1, int y1, int x2, int y2) {\n            if (x1 > x2) swap(x1, x2);\n            if (y1 > y2) swap(y1, y2);\n\n            x1 = max(0, min(CMAX, x1));\n            x2 = max(0, min(CMAX, x2));\n            y1 = max(0, min(CMAX, y1));\n            y2 = max(0, min(CMAX, y2));\n\n            if (x1 < x2 && y1 < y2) rects.push_back({x1, y1, x2, y2});\n        };\n\n        for (int cid : selectedIds) {\n            for (int cell : comps[cid].cells) {\n                int x = cell % G;\n                int y = cell / G;\n                add_rect(x * D, y * D, (x + 1) * D, (y + 1) * D);\n            }\n        }\n\n        const int half = 1;\n\n        auto center = [&](int cell) {\n            int x = cell % G;\n            int y = cell / G;\n            return pair<int,int>{x * D + D / 2, y * D + D / 2};\n        };\n\n        auto add_h = [&](int x1, int x2, int y) {\n            if (x1 == x2) return;\n            if (x1 > x2) swap(x1, x2);\n            add_rect(x1, y - half, x2, y + half);\n        };\n\n        auto add_v = [&](int x, int y1, int y2) {\n            if (y1 == y2) return;\n            if (y1 > y2) swap(y1, y2);\n            add_rect(x - half, y1, x + half, y2);\n        };\n\n        for (const auto& c : corridors) {\n            auto [sx, sy] = center(c.a);\n            auto [tx, ty] = center(c.b);\n\n            if (c.xFirst) {\n                add_h(sx, tx, sy);\n                add_v(tx, sy, ty);\n            } else {\n                add_v(sx, sy, ty);\n                add_h(sx, tx, ty);\n            }\n        }\n\n        vector<pair<int,int>> poly;\n        if (!extract_rect_union(rects, poly)) return;\n\n        record_candidate(poly, approx, 2);\n    }\n\n    Eval eval_l_path(int src, int dst, bool xFirst,\n                     const vector<uchar>& cur,\n                     int targetCid,\n                     const vector<int>& compId) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        int score = 0, len = 0;\n\n        auto visit = [&](int x, int y) {\n            int id = idx(x, y);\n            len++;\n            if (!cur[id] && compId[id] != targetCid) score += w[id];\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, ty);\n                }\n            }\n        }\n\n        return {score, len};\n    }\n\n    vector<int> build_l_path(int src, int dst, bool xFirst) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        vector<int> res;\n        res.reserve(abs(tx - sx) + abs(ty - sy) + 1);\n\n        auto add = [&](int x, int y) {\n            res.push_back(idx(x, y));\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, ty);\n                }\n            }\n        }\n\n        return res;\n    }\n\n    void greedy_connect(const vector<Comp>& comps,\n                        const vector<int>& compId,\n                        const vector<int>& ids,\n                        int maxAdd,\n                        int compLimit,\n                        int variants) const {\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> cur(ncell, 0);\n        vector<int> curCells;\n        curCells.reserve(ncell / 4);\n\n        auto add_cell = [&](int cell) {\n            if (!cur[cell]) {\n                cur[cell] = 1;\n                curCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            for (int cell : comps[cid].cells) add_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0])) addedConsidered++;\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c == 1 || c == 2 || c == 3 || c == 5 || c == 8 ||\n                   c == 13 || c == 21 || c == 34;\n        };\n\n        finalize_candidate(cur, variants);\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : curCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                bool xFirst = true;\n                int gain = 0;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1) continue;\n                int src = root[bestCell];\n                if (src < 0) continue;\n\n                Eval e1 = eval_l_path(src, bestCell, true, cur, cid, compId);\n                Eval e2 = eval_l_path(src, bestCell, false, cur, cid, compId);\n\n                bool xf = true;\n                Eval e = e1;\n\n                if (e2.score > e1.score || (e2.score == e1.score && e2.len < e1.len)) {\n                    e = e2;\n                    xf = false;\n                }\n\n                int gain = comps[cid].score + e.score;\n                if (gain <= 0) continue;\n\n                double metric = (double)gain / (e.len + 5.0) + 0.03 * gain;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = src;\n                    best.dst = bestCell;\n                    best.xFirst = xf;\n                    best.gain = gain;\n                    best.len = e.len;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path = build_l_path(best.src, best.dst, best.xFirst);\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cell : path) add_cell(cell);\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            if (snapshot(addedConsidered)) finalize_candidate(cur, variants);\n\n            if (iter % 3 == 0 && boundary_edges(cur) > maxEdges * 3 / 2) break;\n        }\n\n        finalize_candidate(cur, variants);\n    }\n\n    void thin_greedy_connect(const vector<Comp>& comps,\n                             const vector<int>& compId,\n                             const vector<int>& ids,\n                             int maxAdd,\n                             int compLimit) const {\n        if (elapsed_sec() > 1.78) return;\n\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> network(ncell, 0);\n        vector<int> networkCells;\n        vector<int> selectedIds;\n        vector<Corridor> corridors;\n\n        int approx = 0;\n        long long roughLen = 0;\n\n        auto add_network_cell = [&](int cell) {\n            if (!network[cell]) {\n                network[cell] = 1;\n                networkCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            selectedIds.push_back(cid);\n            approx += comps[cid].score;\n            roughLen += 1LL * comps[cid].perim * D;\n            for (int cell : comps[cid].cells) add_network_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0]) && considered[ids[0]]) addedConsidered++;\n\n        finalize_thin(selectedIds, corridors, comps, approx);\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c <= 5 || c == 8 || c == 13 || c == 21 ||\n                   c == 34 || c == 55 || c == 89 || (c > 20 && c % 5 == 0);\n        };\n\n        auto path_bonus = [&](const vector<int>& path) {\n            vector<int> cs;\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && considered[cid] && comps[cid].score > 0) {\n                    cs.push_back(cid);\n                }\n            }\n\n            sort(cs.begin(), cs.end());\n            cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n            int s = 0;\n            for (int cid : cs) s += comps[cid].score;\n            return s;\n        };\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : networkCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1 || bestDist <= 0) continue;\n\n                long long addCost = 2LL * bestDist * D + 1LL * comps[cid].perim * D;\n                if (roughLen + addCost > 700000LL) continue;\n\n                double costK = addCost / 1000.0;\n                double metric = (double)comps[cid].score / (costK + 2.0) + 0.025 * comps[cid].score;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = root[bestCell];\n                    best.dst = bestCell;\n                    best.len = bestDist;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path1 = build_l_path(best.src, best.dst, true);\n            vector<int> path2 = build_l_path(best.src, best.dst, false);\n\n            int b1 = path_bonus(path1);\n            int b2 = path_bonus(path2);\n\n            bool xf = true;\n            vector<int> path;\n\n            if (b2 > b1) {\n                xf = false;\n                path = move(path2);\n            } else {\n                path = move(path1);\n            }\n\n            corridors.push_back({best.src, best.dst, xf});\n            roughLen += 2LL * (int)path.size() * D + 8;\n\n            for (int cell : path) add_network_cell(cell);\n\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && considered[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            int cnum = (int)selectedIds.size();\n            if (snapshot(cnum) || (roughLen > 300000 && cnum % 3 == 0)) {\n                finalize_thin(selectedIds, corridors, comps, approx);\n            }\n\n            if (roughLen > 620000LL) break;\n        }\n\n        finalize_thin(selectedIds, corridors, comps, approx);\n    }\n\n    void process_mask(vector<uchar> mask, int maxAdd, int compLimit, int mode = 3, int variants = 1) const {\n        if (elapsed_sec() > 1.82) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        vector<int> compId;\n        vector<Comp> comps = find_components(mask, &compId);\n        if (comps.empty()) return;\n\n        vector<int> ids;\n        for (int i = 0; i < (int)comps.size(); i++) {\n            if (comps[i].score > 0) ids.push_back(i);\n        }\n        if (ids.empty()) return;\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return comps[a].score > comps[b].score;\n        });\n\n        if (mode & 1) {\n            int alone = min(3, (int)ids.size());\n\n            for (int k = 0; k < alone; k++) {\n                vector<uchar> cur(ncell, 0);\n                for (int cell : comps[ids[k]].cells) cur[cell] = 1;\n                finalize_candidate(cur, variants);\n            }\n\n            if ((int)ids.size() >= 2) {\n                greedy_connect(comps, compId, ids, maxAdd, compLimit, variants);\n            }\n        }\n\n        if ((mode & 2) && elapsed_sec() < 1.78) {\n            int tMax = max(maxAdd, D <= 250 ? 100 : 45);\n            int tLimit = min(compLimit, D <= 250 ? 350 : 140);\n\n            thin_greedy_connect(comps, compId, ids, tMax, tLimit);\n\n            if (D <= 250 && elapsed_sec() < 1.78) {\n                vector<int> ids2 = ids;\n                sort(ids2.begin(), ids2.end(), [&](int a, int b) {\n                    long long lhs = 1LL * comps[a].score * (comps[b].perim + 1);\n                    long long rhs = 1LL * comps[b].score * (comps[a].perim + 1);\n                    if (lhs != rhs) return lhs > rhs;\n                    return comps[a].score > comps[b].score;\n                });\n\n                thin_greedy_connect(comps, compId, ids2, max(60, maxAdd / 2), min(tLimit, 180));\n            }\n        }\n    }\n\n    void run_best_rectangle(int variants = 1) const {\n        if (elapsed_sec() > 1.80) return;\n\n        int best = INT_MIN;\n        int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0;\n\n        vector<int> col(G, 0);\n\n        for (int x1 = 0; x1 < G; x1++) {\n            fill(col.begin(), col.end(), 0);\n\n            for (int x2 = x1; x2 < G; x2++) {\n                for (int y = 0; y < G; y++) col[y] += w[idx(x2, y)];\n\n                int cur = 0, st = 0;\n                for (int y = 0; y < G; y++) {\n                    if (y == 0 || cur <= 0) {\n                        cur = col[y];\n                        st = y;\n                    } else {\n                        cur += col[y];\n                    }\n\n                    if (cur > best) {\n                        best = cur;\n                        bx1 = x1;\n                        bx2 = x2;\n                        by1 = st;\n                        by2 = y;\n                    }\n                }\n            }\n        }\n\n        if (best <= 0) return;\n\n        vector<uchar> mask(ncell, 0);\n        for (int y = by1; y <= by2; y++) {\n            for (int x = bx1; x <= bx2; x++) {\n                mask[idx(x, y)] = 1;\n            }\n        }\n\n        finalize_candidate(mask, variants);\n\n        refine_and_record_rectangle(bx1 * D, by1 * D, (bx2 + 1) * D, (by2 + 1) * D);\n    }\n\n    vector<double> gaussian_blur(double sigma) const {\n        int r = max(1, (int)ceil(3.0 * sigma));\n        vector<double> ker(2 * r + 1);\n        double sum = 0.0;\n\n        for (int d = -r; d <= r; d++) {\n            double v = exp(-(double)d * d / (2.0 * sigma * sigma));\n            ker[d + r] = v;\n            sum += v;\n        }\n        for (double& v : ker) v /= sum;\n\n        vector<double> src(ncell), tmp(ncell), out(ncell);\n        for (int i = 0; i < ncell; i++) src[i] = (double)w[i];\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int nx = x + d;\n                    if (0 <= nx && nx < G) s += src[idx(nx, y)] * ker[d + r];\n                }\n                tmp[idx(x, y)] = s;\n            }\n        }\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int ny = y + d;\n                    if (0 <= ny && ny < G) s += tmp[idx(x, ny)] * ker[d + r];\n                }\n                out[idx(x, y)] = s;\n            }\n        }\n\n        return out;\n    }\n\n    void run_smoothing(const vector<double>& sigmas,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime,\n                       int mode = 1,\n                       int variants = 1) const {\n        vector<double> ratios = {-0.05, -0.02, 0.0, 0.02, 0.05, 0.10, 0.18, 0.30};\n\n        for (double sigma : sigmas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<double> blur = gaussian_blur(sigma);\n            double mx = *max_element(blur.begin(), blur.end());\n            if (mx <= 1e-12) continue;\n\n            for (double r : ratios) {\n                if (elapsed_sec() > stopTime) return;\n\n                double th = mx * r;\n                vector<uchar> mask(ncell, 0);\n                int cnt = 0;\n\n                for (int i = 0; i < ncell; i++) {\n                    if (blur[i] > th) {\n                        mask[i] = 1;\n                        cnt++;\n                    }\n                }\n\n                if (cnt == 0 || cnt == ncell) continue;\n                process_mask(move(mask), maxAdd, compLimit, mode, variants);\n            }\n        }\n    }\n\n    void run_weight_thresholds(const vector<int>& thresholds,\n                               int maxAdd,\n                               int compLimit,\n                               double stopTime,\n                               int mode = 3,\n                               int variants = 1) const {\n        for (int th : thresholds) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask(ncell, 0);\n            int cnt = 0;\n\n            for (int i = 0; i < ncell; i++) {\n                if (w[i] >= th) {\n                    mask[i] = 1;\n                    cnt++;\n                }\n            }\n\n            if (cnt == 0) continue;\n            process_mask(move(mask), maxAdd, compLimit, mode, variants);\n        }\n    }\n\n    vector<uchar> graph_cut_mask(int lam, int scale) const {\n        int S = ncell;\n        int T = ncell + 1;\n        atcoder::mf_graph<ll> g(ncell + 2);\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int v = idx(x, y);\n                ll profit = (ll)w[v] * scale;\n\n                if (profit > 0) g.add_edge(S, v, profit);\n                else if (profit < 0) g.add_edge(v, T, -profit);\n\n                int bs = 0;\n                if (x == 0) bs++;\n                if (x + 1 == G) bs++;\n                if (y == 0) bs++;\n                if (y + 1 == G) bs++;\n\n                if (bs) g.add_edge(v, T, (ll)lam * bs);\n\n                if (x + 1 < G) {\n                    int u = idx(x + 1, y);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n                if (y + 1 < G) {\n                    int u = idx(x, y + 1);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n            }\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n\n        vector<uchar> mask(ncell, 0);\n        for (int i = 0; i < ncell; i++) mask[i] = cut[i] ? 1 : 0;\n        return mask;\n    }\n\n    void run_graph_cut(const vector<int>& lambdas,\n                       int scale,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime,\n                       int mode = 3,\n                       int variants = 1) const {\n        for (int lam : lambdas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask = graph_cut_mask(lam, scale);\n            process_mask(move(mask), maxAdd, compLimit, mode, variants);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int N;\n    cin >> N;\n\n    fishes.reserve(2 * N);\n\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n\n        int w = (i < N ? 1 : -1);\n        fishes.push_back({x, y, w});\n    }\n\n    fishOrderY.resize(fishes.size());\n    iota(fishOrderY.begin(), fishOrderY.end(), 0);\n    sort(fishOrderY.begin(), fishOrderY.end(), [&](int a, int b) {\n        if (fishes[a].y != fishes[b].y) return fishes[a].y < fishes[b].y;\n        return fishes[a].x < fishes[b].x;\n    });\n\n    bestApprox = -1;\n    bestSafeApprox = -1;\n\n    record_candidate(square_poly(), 0, 0);\n\n    GridSolver g500(500);\n\n    g500.run_best_rectangle(1);\n\n    // Keep thin-corridor candidates, but skip expensive polished variants here.\n    g500.run_weight_thresholds(vector<int>{1, 2, 3}, 32, 140, 0.56, 3, 1);\n\n    g500.run_smoothing(vector<double>{2.0, 3.5, 5.5, 8.0, 12.0}, 18, 90, 1.00, 1, 1);\n\n    if (elapsed_sec() < 1.25) {\n        g500.run_graph_cut(vector<int>{10, 16, 25, 40, 70, 120}, 100, 24, 120, 1.40, 3, 1);\n    }\n\n    if (elapsed_sec() < 1.62) {\n        GridSolver g400(400);\n        g400.run_best_rectangle(1);\n        g400.run_smoothing(vector<double>{2.5, 4.0, 6.5, 10.0, 14.0}, 14, 80, 1.72, 1, 1);\n    }\n\n    if (elapsed_sec() < 1.76) {\n        GridSolver g250(250);\n        g250.run_weight_thresholds(vector<int>{1, 2, 3}, 100, 350, 1.86, 2, 0);\n    }\n\n    vector<pair<int,int>> output;\n    if (!bestSafePoly.empty()) output = bestSafePoly;\n    else if (!bestPoly.empty()) output = bestPoly;\n    else output = square_poly();\n\n    if (bestApprox >= 0 && !bestPoly.empty()) {\n        candidates.push_back({bestApprox, 2, bestPoly});\n    }\n    if (bestSafeApprox >= 0 && !bestSafePoly.empty()) {\n        candidates.push_back({bestSafeApprox, 0, bestSafePoly});\n    }\n\n    if (elapsed_sec() < 1.84) {\n        int bestExact = exact_score(output);\n        vector<pair<int,int>> exactBest = output;\n\n        if (bestExact < 0) {\n            bestExact = 0;\n            exactBest = square_poly();\n        }\n\n        vector<int> order;\n        vector<char> usedIdx(candidates.size(), 0);\n\n        auto add_idx = [&](int id) {\n            if (id < 0 || id >= (int)candidates.size()) return;\n            if (usedIdx[id]) return;\n            usedIdx[id] = 1;\n            order.push_back(id);\n        };\n\n        vector<int> all(candidates.size());\n        iota(all.begin(), all.end(), 0);\n        sort(all.begin(), all.end(), [&](int a, int b) {\n            return candidates[a].approx > candidates[b].approx;\n        });\n\n        if ((int)candidates.size() <= 260) {\n            for (int id : all) add_idx(id);\n        } else {\n            for (int i = 0; i < min(120, (int)all.size()); i++) add_idx(all[i]);\n\n            for (int cat = 0; cat <= 3; cat++) {\n                vector<int> v;\n                for (int i = 0; i < (int)candidates.size(); i++) {\n                    if (candidates[i].cat == cat) v.push_back(i);\n                }\n\n                sort(v.begin(), v.end(), [&](int a, int b) {\n                    return candidates[a].approx > candidates[b].approx;\n                });\n\n                for (int i = 0; i < min(60, (int)v.size()); i++) add_idx(v[i]);\n            }\n        }\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(order.size() * 2 + 10);\n        seen.insert(poly_hash(output));\n\n        for (int id : order) {\n            if (elapsed_sec() > 1.965) break;\n\n            uint64_t h = poly_hash(candidates[id].poly);\n            if (seen.find(h) != seen.end()) continue;\n            seen.insert(h);\n\n            int sc = exact_score(candidates[id].poly);\n            if (sc > bestExact) {\n                bestExact = sc;\n                exactBest = candidates[id].poly;\n            }\n        }\n\n        output = exactBest;\n    }\n\n    cout << output.size() << '\\n';\n    for (auto [x, y] : output) {\n        cout << x << ' ' << y << '\\n';\n    }\n\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectD {\n    double w, h;\n};\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    double estScore = 1e100;\n    double baseW = 0, baseH = 0;\n    uint64_t hash = 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};\n\nstatic constexpr double TRUE_U = 100000.0;\nstatic constexpr double TRUE_L_MIN = 10000.0;\nstatic constexpr double TRUE_L_MAX = 50000.0;\nstatic constexpr double INF = 1e100;\n\nint N, T;\ndouble SIGMA;\nvector<double> sumWObs, sumHObs;\nvector<int> cntWObs, cntHObs;\n\nmt19937_64 rng(123456789);\n\ndouble normal_pdf(double x) {\n    static const double INV_SQRT_2PI = 0.39894228040143267794;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble normal_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble clamp_double(double x, double lo, double hi) {\n    return max(lo, min(hi, x));\n}\n\ndouble truncated_normal_mean(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    double a = (L - obsMean) / sd;\n    double b = (U - obsMean) / sd;\n    double Z = normal_cdf(b) - normal_cdf(a);\n    if (Z < 1e-12) return clamp_double(obsMean, L, U);\n    double m = obsMean + sd * (normal_pdf(a) - normal_pdf(b)) / Z;\n    return clamp_double(m, L, U);\n}\n\ndouble sample_truncated_normal(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    normal_distribution<double> nd(obsMean, sd);\n    for (int t = 0; t < 200; t++) {\n        double x = nd(rng);\n        if (L <= x && x <= U) return x;\n    }\n    return clamp_double(obsMean, L, U);\n}\n\ndouble estimate_L_from_current_observations() {\n    vector<double> vals;\n    vector<double> noiseVars;\n    vals.reserve(2 * N);\n    noiseVars.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        vals.push_back(sumWObs[i] / cntWObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntWObs[i]);\n        vals.push_back(sumHObs[i] / cntHObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntHObs[i]);\n    }\n\n    double mean = accumulate(vals.begin(), vals.end(), 0.0) / vals.size();\n    double L1 = 2.0 * mean - TRUE_U;\n\n    double var = 0.0;\n    for (double x : vals) var += (x - mean) * (x - mean);\n    var /= vals.size();\n\n    double avgNoise = accumulate(noiseVars.begin(), noiseVars.end(), 0.0) / noiseVars.size();\n    double trueVar = max(0.0, var - avgNoise);\n    double L2 = TRUE_U - sqrt(max(0.0, 12.0 * trueVar));\n\n    double L = 0.72 * L1 + 0.28 * L2;\n    return clamp_double(L, TRUE_L_MIN, TRUE_L_MAX);\n}\n\nstruct LPosterior {\n    vector<double> Ls;\n    vector<double> ws;\n    double meanL = 30000.0;\n    double mapL = 30000.0;\n};\n\nLPosterior compute_L_posterior_grid() {\n    const int G = 161;\n    LPosterior post;\n    post.Ls.resize(G);\n    post.ws.resize(G);\n\n    vector<double> logw(G, 0.0);\n\n    for (int g = 0; g < G; g++) {\n        double L = TRUE_L_MIN + (TRUE_L_MAX - TRUE_L_MIN) * g / (G - 1);\n        post.Ls[g] = L;\n\n        double ll = 0.0;\n        double len = TRUE_U - L;\n\n        for (int i = 0; i < N; i++) {\n            {\n                double m = sumWObs[i] / cntWObs[i];\n                double sd = SIGMA / sqrt((double)cntWObs[i]);\n                double a = (L - m) / sd;\n                double b = (TRUE_U - m) / sd;\n                double p = normal_cdf(b) - normal_cdf(a);\n                p = max(p, 1e-300);\n                ll += log(p) - log(len);\n            }\n            {\n                double m = sumHObs[i] / cntHObs[i];\n                double sd = SIGMA / sqrt((double)cntHObs[i]);\n                double a = (L - m) / sd;\n                double b = (TRUE_U - m) / sd;\n                double p = normal_cdf(b) - normal_cdf(a);\n                p = max(p, 1e-300);\n                ll += log(p) - log(len);\n            }\n        }\n\n        logw[g] = ll;\n    }\n\n    double mx = *max_element(logw.begin(), logw.end());\n    double sm = 0.0;\n\n    int mapId = 0;\n    for (int g = 0; g < G; g++) {\n        if (logw[g] > logw[mapId]) mapId = g;\n        post.ws[g] = exp(logw[g] - mx);\n        sm += post.ws[g];\n    }\n\n    if (sm <= 0.0 || !isfinite(sm)) {\n        fill(post.ws.begin(), post.ws.end(), 1.0 / G);\n    } else {\n        for (double& x : post.ws) x /= sm;\n    }\n\n    post.meanL = 0.0;\n    for (int g = 0; g < G; g++) post.meanL += post.ws[g] * post.Ls[g];\n\n    post.mapL = post.Ls[mapId];\n    return post;\n}\n\ndouble posterior_L_quantile(const LPosterior& post, double q) {\n    double acc = 0.0;\n    for (int i = 0; i < (int)post.Ls.size(); i++) {\n        acc += post.ws[i];\n        if (acc >= q) return post.Ls[i];\n    }\n    return post.Ls.back();\n}\n\nvector<RectD> posterior_mean_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = truncated_normal_mean(mw, sw, L, TRUE_U);\n        res[i].h = truncated_normal_mean(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> posterior_bayes_mean_rects(const LPosterior& post) {\n    vector<RectD> res(N);\n\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n\n        double ew = 0.0, eh = 0.0;\n        for (int g = 0; g < (int)post.Ls.size(); g++) {\n            double L = post.Ls[g];\n            double wg = post.ws[g];\n            ew += wg * truncated_normal_mean(mw, sw, L, TRUE_U);\n            eh += wg * truncated_normal_mean(mh, sh, L, TRUE_U);\n        }\n\n        res[i].w = ew;\n        res[i].h = eh;\n    }\n\n    return res;\n}\n\nvector<RectD> posterior_sample_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = sample_truncated_normal(mw, sw, L, TRUE_U);\n        res[i].h = sample_truncated_normal(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> blend_rects(const vector<RectD>& a, const vector<RectD>& b, double t) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        res[i].w = (1.0 - t) * a[i].w + t * b[i].w;\n        res[i].h = (1.0 - t) * a[i].h + t * b[i].h;\n    }\n    return res;\n}\n\nstatic inline bool overlap_interval(double l1, double r1, double l2, double r2) {\n    return max(l1, l2) < min(r1, r2) - 1e-9;\n}\n\npair<double, double> simulate_ops(const vector<Op>& ops, const vector<RectD>& rects) {\n    vector<double> x(N, 0), y(N, 0), w(N, 0), h(N, 0);\n    vector<int> placed;\n    placed.reserve(ops.size());\n\n    double W = 0, H = 0;\n\n    for (const Op& op : ops) {\n        int p = op.p;\n        double rw = op.r ? rects[p].h : rects[p].w;\n        double rh = op.r ? rects[p].w : rects[p].h;\n\n        double nx = 0, ny = 0;\n        if (op.d == 'U') {\n            nx = (op.b == -1 ? 0.0 : x[op.b] + w[op.b]);\n            ny = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(nx, nx + rw, x[q], x[q] + w[q])) {\n                    ny = max(ny, y[q] + h[q]);\n                }\n            }\n        } else {\n            ny = (op.b == -1 ? 0.0 : y[op.b] + h[op.b]);\n            nx = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(ny, ny + rh, y[q], y[q] + h[q])) {\n                    nx = max(nx, x[q] + w[q]);\n                }\n            }\n        }\n\n        x[p] = nx;\n        y[p] = ny;\n        w[p] = rw;\n        h[p] = rh;\n        placed.push_back(p);\n        W = max(W, nx + rw);\n        H = max(H, ny + rh);\n    }\n    return {W, H};\n}\n\nuint64_t splitmix64_u(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\nuint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (const Op& op : ops) {\n        uint64_t v = (uint64_t)(op.p + 1);\n        v = v * 1315423911ULL + (uint64_t)(op.r + 3);\n        v = v * 1315423911ULL + (uint64_t)(op.d == 'L' ? 7 : 11);\n        v = v * 1315423911ULL + (uint64_t)(op.b + 2);\n        h ^= splitmix64_u(v + h);\n    }\n    return h;\n}\n\nvoid add_candidate(vector<Candidate>& pool,\n                   unordered_set<uint64_t>& seen,\n                   const vector<Op>& ops,\n                   const vector<RectD>& baseRects) {\n    if ((int)ops.size() != N) return;\n\n    uint64_t hv = hash_ops(ops);\n    if (seen.find(hv) != seen.end()) return;\n    seen.insert(hv);\n\n    auto [W, H] = simulate_ops(ops, baseRects);\n    if (!isfinite(W) || !isfinite(H)) return;\n\n    Candidate c;\n    c.ops = ops;\n    c.baseW = W;\n    c.baseH = H;\n    c.estScore = W + H;\n    c.hash = hv;\n    pool.push_back(std::move(c));\n}\n\nstruct ShelfResult {\n    bool ok = false;\n    vector<Op> ops;\n};\n\n// mode 0: vertical columns using U\n// mode 1: horizontal rows using L\nShelfResult make_shelf_layout(const vector<RectD>& planRects, int mode, double cap) {\n    vector<array<double, 2>> cross(N), len(N);\n\n    for (int i = 0; i < N; i++) {\n        double w = planRects[i].w;\n        double h = planRects[i].h;\n        if (mode == 0) {\n            cross[i][0] = w; len[i][0] = h;\n            cross[i][1] = h; len[i][1] = w;\n        } else {\n            cross[i][0] = h; len[i][0] = w;\n            cross[i][1] = w; len[i][1] = h;\n        }\n    }\n\n    vector<double> vals;\n    vals.reserve(2 * N);\n    for (int i = 0; i < N; i++) {\n        vals.push_back(cross[i][0]);\n        vals.push_back(cross[i][1]);\n    }\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end(), [](double a, double b) {\n        return fabs(a - b) <= 1e-7 * max(1.0, max(fabs(a), fabs(b)));\n    }), vals.end());\n\n    int C = vals.size();\n\n    vector<vector<double>> pref(C, vector<double>(N + 1, 0.0));\n    for (int m = 0; m < C; m++) {\n        double M = vals[m];\n        for (int i = 0; i < N; i++) {\n            double bestLen = INF;\n            if (cross[i][0] <= M + 1e-7) bestLen = min(bestLen, len[i][0]);\n            if (cross[i][1] <= M + 1e-7) bestLen = min(bestLen, len[i][1]);\n            if (bestLen >= INF / 2 || pref[m][i] >= INF / 2) pref[m][i + 1] = INF;\n            else pref[m][i + 1] = min(INF, pref[m][i] + bestLen);\n        }\n    }\n\n    auto get_cost_idx = [&](int l, int r) -> int {\n        int lo = 0, hi = C;\n        while (lo < hi) {\n            int mid = (lo + hi) >> 1;\n            double s = pref[mid][r] - pref[mid][l];\n            if (s <= cap + 1e-7) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo == C) return -1;\n        return lo;\n    };\n\n    vector<double> dp(N + 1, INF);\n    vector<int> prv(N + 1, -1), prvM(N + 1, -1);\n    dp[0] = 0.0;\n\n    for (int r = 1; r <= N; r++) {\n        for (int l = 0; l < r; l++) {\n            if (dp[l] >= INF / 2) continue;\n            int mi = get_cost_idx(l, r);\n            if (mi < 0) continue;\n            double ndp = dp[l] + vals[mi];\n            if (ndp < dp[r]) {\n                dp[r] = ndp;\n                prv[r] = l;\n                prvM[r] = mi;\n            }\n        }\n    }\n\n    if (prv[N] < 0) return {};\n\n    vector<pair<int, int>> segs;\n    for (int r = N; r > 0; r = prv[r]) {\n        segs.push_back({prv[r], r});\n    }\n    reverse(segs.begin(), segs.end());\n\n    vector<int> orient(N, 0);\n    vector<int> anchorOfSeg(segs.size(), -1);\n\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        int mi = get_cost_idx(l, r);\n        double M = vals[mi];\n\n        int anchor = l;\n        double bestCross = -1.0;\n\n        for (int i = l; i < r; i++) {\n            int chosen = 0;\n            double bestLen = INF, bestCr = INF;\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (cross[i][rr] <= M + 1e-7) {\n                    if (len[i][rr] < bestLen - 1e-7 ||\n                        (fabs(len[i][rr] - bestLen) <= 1e-7 && cross[i][rr] < bestCr)) {\n                        bestLen = len[i][rr];\n                        bestCr = cross[i][rr];\n                        chosen = rr;\n                    }\n                }\n            }\n            orient[i] = chosen;\n\n            double cr = cross[i][chosen];\n            if (cr > bestCross) {\n                bestCross = cr;\n                anchor = i;\n            }\n        }\n        anchorOfSeg[si] = anchor;\n    }\n\n    vector<Op> ops;\n    ops.reserve(N);\n\n    int boundaryRef = -1;\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        for (int i = l; i < r; i++) {\n            Op op;\n            op.p = i;\n            op.r = orient[i];\n            op.d = (mode == 0 ? 'U' : 'L');\n            op.b = boundaryRef;\n            ops.push_back(op);\n        }\n        boundaryRef = anchorOfSeg[si];\n    }\n\n    ShelfResult res;\n    res.ok = true;\n    res.ops = std::move(ops);\n    return res;\n}\n\nvector<double> make_caps(const vector<RectD>& rects, int mode, int cnt) {\n    (void)mode;\n\n    double area = 0.0;\n    double minCap = 0.0;\n    for (int i = 0; i < N; i++) {\n        area += rects[i].w * rects[i].h;\n        minCap = max(minCap, min(rects[i].w, rects[i].h));\n    }\n\n    double S = sqrt(max(1.0, area));\n    vector<double> caps;\n\n    double loF = 0.52, hiF = 2.35;\n    for (int k = 0; k < cnt; k++) {\n        double u = (cnt == 1 ? 0.5 : (double)k / (cnt - 1));\n        double f = exp(log(loF) + u * (log(hiF) - log(loF)));\n        caps.push_back(max(minCap, S * f));\n    }\n\n    for (double f : {0.72, 0.80, 0.88, 0.96, 1.04, 1.12, 1.20, 1.32, 1.48}) {\n        caps.push_back(max(minCap, S * f));\n    }\n\n    sort(caps.begin(), caps.end());\n    vector<double> uniq;\n    for (double x : caps) {\n        if (uniq.empty() || fabs(x - uniq.back()) > 1e-6 * max(1.0, x)) uniq.push_back(x);\n    }\n    return uniq;\n}\n\ndouble min_final_perimeter_lb(double W, double H, double A) {\n    double S = sqrt(max(1.0, A));\n    double ans = INF;\n\n    if (W <= S && H <= S) ans = min(ans, 2.0 * S);\n    ans = min(ans, W + max(H, A / max(W, 1.0)));\n    ans = min(ans, H + max(W, A / max(H, 1.0)));\n    ans = max(ans, W + H);\n    return ans;\n}\n\nvector<Op> make_greedy_layout(const vector<RectD>& planRects,\n                              double aspect,\n                              double scale,\n                              double wOverflow,\n                              double wWaste,\n                              double wBal,\n                              double wLB,\n                              double jitter) {\n    vector<Op> ops;\n    ops.reserve(N);\n\n    vector<double> x(N), y(N), ww(N), hh(N);\n    double W = 0.0, H = 0.0;\n    double totalArea = 0.0;\n    for (auto& r : planRects) totalArea += r.w * r.h;\n\n    double S = sqrt(max(1.0, totalArea)) * scale;\n    double Wlim = S * sqrt(aspect);\n    double Hlim = S / sqrt(aspect);\n\n    double usedArea = 0.0;\n    uniform_real_distribution<double> ud(0.0, 1.0);\n\n    for (int i = 0; i < N; i++) {\n        double itemArea = planRects[i].w * planRects[i].h;\n\n        double bestCost = INF;\n        Op bestOp{i, 0, 'U', -1};\n        double bestX = 0, bestY = 0, bestW = 0, bestH = 0;\n        double bestBW = 0, bestBH = 0;\n\n        for (int r = 0; r < 2; r++) {\n            double rw = r ? planRects[i].h : planRects[i].w;\n            double rh = r ? planRects[i].w : planRects[i].h;\n\n            for (int dd = 0; dd < 2; dd++) {\n                char d = (dd == 0 ? 'U' : 'L');\n                for (int b = -1; b < i; b++) {\n                    double nx = 0, ny = 0;\n\n                    if (d == 'U') {\n                        nx = (b == -1 ? 0.0 : x[b] + ww[b]);\n                        ny = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(nx, nx + rw, x[q], x[q] + ww[q])) {\n                                ny = max(ny, y[q] + hh[q]);\n                            }\n                        }\n                    } else {\n                        ny = (b == -1 ? 0.0 : y[b] + hh[b]);\n                        nx = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(ny, ny + rh, y[q], y[q] + hh[q])) {\n                                nx = max(nx, x[q] + ww[q]);\n                            }\n                        }\n                    }\n\n                    double nW = max(W, nx + rw);\n                    double nH = max(H, ny + rh);\n                    double nUsed = usedArea + itemArea;\n\n                    double overflow = max(0.0, nW - Wlim) + max(0.0, nH - Hlim);\n                    double wasteLen = max(0.0, nW * nH - nUsed) / sqrt(max(1.0, nUsed));\n                    double bal = fabs(nW / Wlim - nH / Hlim) * sqrt(totalArea);\n                    double lb = min_final_perimeter_lb(nW, nH, totalArea);\n                    double progress = 0.25 + 0.75 * (double)(i + 1) / N;\n\n                    double cost =\n                        wLB * lb +\n                        progress * (nW + nH) +\n                        wOverflow * overflow +\n                        wWaste * wasteLen +\n                        wBal * bal +\n                        0.0007 * (nx + ny) +\n                        jitter * ud(rng) * sqrt(totalArea);\n\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestOp = {i, r, d, b};\n                        bestX = nx;\n                        bestY = ny;\n                        bestW = rw;\n                        bestH = rh;\n                        bestBW = nW;\n                        bestBH = nH;\n                    }\n                }\n            }\n        }\n\n        ops.push_back(bestOp);\n        x[i] = bestX;\n        y[i] = bestY;\n        ww[i] = bestW;\n        hh[i] = bestH;\n        W = bestBW;\n        H = bestBH;\n        usedArea += itemArea;\n    }\n\n    return ops;\n}\n\nvoid output_query(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const Op& 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    Timer timer;\n\n    cin >> N >> T >> SIGMA;\n\n    sumWObs.assign(N, 0.0);\n    sumHObs.assign(N, 0.0);\n    cntWObs.assign(N, 1);\n    cntHObs.assign(N, 1);\n\n    for (int i = 0; i < N; i++) {\n        long long w, h;\n        cin >> w >> h;\n        sumWObs[i] = (double)w;\n        sumHObs[i] = (double)h;\n    }\n\n    // Improved measurement policy:\n    // Use high-noise extra turns for repeated single-rectangle measurements,\n    // while still leaving at least about 2N turns for full packing trials.\n    double noiseFactor = clamp_double((SIGMA - 3000.0) / 7000.0, 0.0, 1.0);\n    int maxMeasureQ = max(0, T - 2 * N);\n    int measureQ = min(maxMeasureQ, (int)round(maxMeasureQ * noiseFactor));\n\n    if (measureQ > 0) {\n        double L0 = estimate_L_from_current_observations();\n        vector<RectD> base0 = posterior_mean_rects(L0);\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            double ia = base0[a].w * base0[a].h +\n                        0.25 * (base0[a].w + base0[a].h) * sqrt(base0[a].w * base0[a].h);\n            double ib = base0[b].w * base0[b].h +\n                        0.25 * (base0[b].w + base0[b].h) * sqrt(base0[b].w * base0[b].h);\n            return ia > ib;\n        });\n\n        for (int k = 0; k < measureQ; k++) {\n            int i = ids[k % N];\n\n            vector<Op> ops;\n            ops.push_back({i, 0, 'U', -1});\n            output_query(ops);\n\n            long long Wm, Hm;\n            if (!(cin >> Wm >> Hm)) return 0;\n\n            sumWObs[i] += (double)Wm;\n            sumHObs[i] += (double)Hm;\n            cntWObs[i]++;\n            cntHObs[i]++;\n        }\n    }\n\n    int remainingTurns = T - measureQ;\n    if (remainingTurns <= 0) return 0;\n\n    double Lest = estimate_L_from_current_observations();\n    vector<RectD> baseRects = posterior_mean_rects(Lest);\n\n    LPosterior lpost = compute_L_posterior_grid();\n    vector<RectD> bayesRects = posterior_bayes_mean_rects(lpost);\n\n    double avgBayesDiff = 0.0;\n    for (int i = 0; i < N; i++) {\n        avgBayesDiff += fabs(baseRects[i].w - bayesRects[i].w);\n        avgBayesDiff += fabs(baseRects[i].h - bayesRects[i].h);\n    }\n    avgBayesDiff /= (2.0 * N);\n\n    bool useBayes = (avgBayesDiff > 120.0);\n\n    int randomScenarioCount = (N <= 50 ? 10 : 8);\n    if (remainingTurns <= 30) randomScenarioCount = min(randomScenarioCount, 6);\n\n    vector<vector<RectD>> scenarios;\n    scenarios.push_back(baseRects);\n    for (int s = 0; s < randomScenarioCount; s++) {\n        scenarios.push_back(posterior_sample_rects(Lest));\n    }\n\n    int originalScenarioCount = scenarios.size();\n\n    if (useBayes) {\n        scenarios.push_back(bayesRects);\n    }\n\n    int S = scenarios.size();\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(8192);\n\n    int targetPool = max(450, min(1300, remainingTurns * 3));\n\n    int planScenarios = min(originalScenarioCount, 5);\n\n    // Original stable shelf candidates.\n    for (int ps = 0; ps < planScenarios; ps++) {\n        const auto& plan = scenarios[ps];\n        int capCnt = (ps == 0 ? 82 : 42);\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(plan, mode, capCnt);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Original randomized greedy candidates.\n    uniform_real_distribution<double> ud(0.0, 1.0);\n    int greedyAttempts = 0;\n    while ((int)pool.size() < targetPool && timer.elapsed() < 2.12) {\n        int ps = greedyAttempts % planScenarios;\n        const auto& plan = scenarios[ps];\n\n        double aspect = exp(log(0.48) + ud(rng) * (log(2.10) - log(0.48)));\n        double scale = 1.00 + 0.42 * ud(rng);\n\n        double wOverflow = 2.0 + 18.0 * ud(rng);\n        double wWaste = 0.05 + 2.50 * ud(rng);\n        double wBal = 0.02 + 1.10 * ud(rng);\n        double wLB = 1.0 + 6.0 * ud(rng);\n        double jitter = 0.000 + 0.035 * ud(rng);\n\n        vector<Op> ops = make_greedy_layout(plan, aspect, scale, wOverflow, wWaste, wBal, wLB, jitter);\n        add_candidate(pool, seen, ops, baseRects);\n        greedyAttempts++;\n    }\n\n    // Conservative extra candidates from Bayesian-estimated rectangles.\n    if (useBayes && timer.elapsed() < 2.32) {\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(bayesRects, mode, 56);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(bayesRects, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Alternative posterior-L planning rectangles.\n    if (useBayes && avgBayesDiff > 180.0 && timer.elapsed() < 2.45) {\n        vector<vector<RectD>> altPlans;\n\n        altPlans.push_back(blend_rects(baseRects, bayesRects, 0.50));\n        altPlans.push_back(blend_rects(baseRects, bayesRects, 0.25));\n        altPlans.push_back(blend_rects(baseRects, bayesRects, 0.75));\n\n        double q25 = posterior_L_quantile(lpost, 0.25);\n        double q75 = posterior_L_quantile(lpost, 0.75);\n\n        if (fabs(lpost.mapL - Lest) > 400.0) {\n            altPlans.push_back(posterior_mean_rects(lpost.mapL));\n        }\n        if (fabs(q25 - Lest) > 700.0) {\n            altPlans.push_back(posterior_mean_rects(q25));\n        }\n        if (fabs(q75 - Lest) > 700.0) {\n            altPlans.push_back(posterior_mean_rects(q75));\n        }\n\n        int addedPlan = 0;\n        for (const auto& plan : altPlans) {\n            if (timer.elapsed() > 2.50) break;\n\n            int capCnt = (addedPlan < 3 ? 44 : 32);\n            for (int mode = 0; mode < 2; mode++) {\n                vector<double> caps = make_caps(plan, mode, capCnt);\n                for (double cap : caps) {\n                    ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                    if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n                }\n            }\n            addedPlan++;\n        }\n    }\n\n    if (pool.empty()) {\n        vector<Op> ops;\n        for (int i = 0; i < N; i++) ops.push_back({i, 0, 'U', -1});\n        add_candidate(pool, seen, ops, baseRects);\n    }\n\n    // Slightly favor candidates that are good under both moment and Bayesian estimates.\n    if (useBayes) {\n        for (Candidate& c : pool) {\n            auto [bW, bH] = simulate_ops(c.ops, bayesRects);\n            double baseScore = c.baseW + c.baseH;\n            double bayesScore = bW + bH;\n            c.estScore = 0.86 * baseScore + 0.14 * bayesScore;\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.estScore < b.estScore;\n    });\n\n    int maxKeep = max(remainingTurns, min((int)pool.size(), 1350));\n    if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n\n    int C = pool.size();\n\n    vector<float> predW(C * S), predH(C * S), predScore(C * S);\n\n    for (int c = 0; c < C; c++) {\n        for (int s = 0; s < S; s++) {\n            pair<double, double> wh;\n            if (s == 0) wh = {pool[c].baseW, pool[c].baseH};\n            else wh = simulate_ops(pool[c].ops, scenarios[s]);\n            predW[c * S + s] = (float)wh.first;\n            predH[c * S + s] = (float)wh.second;\n            predScore[c * S + s] = (float)(wh.first + wh.second);\n        }\n    }\n\n    vector<double> logWeight(S, 0.0);\n    vector<double> weight(S, 1.0 / S);\n    vector<double> bestScenarioScore(S, INF);\n    vector<char> used(C, 0);\n\n    int bestBaseIdx = 0;\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        int chosen = -1;\n        double bestVal = INF;\n\n        for (int c = 0; c < C; c++) {\n            if (used[c]) continue;\n            double val = 0.0;\n            for (int s = 0; s < S; s++) {\n                double sc = predScore[c * S + s];\n                val += weight[s] * min(bestScenarioScore[s], sc);\n            }\n            val += 1e-9 * pool[c].estScore;\n            if (val < bestVal) {\n                bestVal = val;\n                chosen = c;\n            }\n        }\n\n        if (chosen < 0) chosen = bestBaseIdx;\n\n        output_query(pool[chosen].ops);\n\n        long long Wobs, Hobs;\n        if (!(cin >> Wobs >> Hobs)) return 0;\n\n        if (chosen >= 0 && chosen < C) {\n            used[chosen] = 1;\n\n            for (int s = 0; s < S; s++) {\n                bestScenarioScore[s] = min(bestScenarioScore[s], (double)predScore[chosen * S + s]);\n            }\n\n            double effSigma = max(2500.0, 2.25 * SIGMA);\n            for (int s = 0; s < S; s++) {\n                double dw = (double)Wobs - predW[chosen * S + s];\n                double dh = (double)Hobs - predH[chosen * S + s];\n                logWeight[s] += -0.5 * (dw * dw + dh * dh) / (effSigma * effSigma);\n            }\n\n            double mx = *max_element(logWeight.begin(), logWeight.end());\n            double sm = 0.0;\n            for (int s = 0; s < S; s++) {\n                weight[s] = exp(logWeight[s] - mx);\n                sm += weight[s];\n            }\n            if (sm <= 0 || !isfinite(sm)) {\n                fill(weight.begin(), weight.end(), 1.0 / S);\n            } else {\n                for (int s = 0; s < S; s++) {\n                    weight[s] = weight[s] / sm;\n                    weight[s] = 0.965 * weight[s] + 0.035 / S;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc041":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nint N, M, HH;\nvector<int> A;\nvector<vector<int>> adj;\nvector<int> highOrder, lowOrder;\nvector<vector<int>> dpCost;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ULL;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct State {\n    vector<int> d;\n    vector<int> cnt;\n    long long val = 0;\n};\n\nbool hasNeighborDepth(const vector<int>& d, int v, int dep) {\n    for (int u : adj[v]) if (d[u] == dep) return true;\n    return false;\n}\n\nvoid initState(State& s, const vector<int>& depth) {\n    s.d = depth;\n    s.cnt.assign(N, 0);\n    s.val = 0;\n\n    for (int v = 0; v < N; v++) {\n        s.val += 1LL * s.d[v] * A[v];\n\n        if (s.d[v] > 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) s.cnt[v]++;\n            }\n        }\n    }\n}\n\nbool verifyState(const State& s) {\n    if ((int)s.d.size() != N) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (s.d[v] < 0 || s.d[v] > HH) return false;\n\n        if (s.d[v] > 0) {\n            bool ok = false;\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n    }\n\n    return true;\n}\n\nbool canMove(const State& s, int v, int nd) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n\n    return true;\n}\n\nbool canMoveExcept(const State& s, int v, int nd, int exceptChild) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (w == exceptChild) continue;\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n\n    return true;\n}\n\nvoid applyMove(State& s, int v, int nd) {\n    int od = s.d[v];\n    if (od == nd) return;\n\n    for (int w : adj[v]) {\n        if (s.d[w] > 0) {\n            if (s.d[w] - 1 == od) s.cnt[w]--;\n            if (s.d[w] - 1 == nd) s.cnt[w]++;\n        }\n    }\n\n    s.val += 1LL * (nd - od) * A[v];\n    s.d[v] = nd;\n\n    int c = 0;\n    if (nd > 0) {\n        for (int u : adj[v]) if (s.d[u] == nd - 1) c++;\n    }\n    s.cnt[v] = c;\n}\n\nbool tryRaise(State& s, int v) {\n    int od = s.d[v];\n\n    for (int nd = HH; nd > od; nd--) {\n        if (canMove(s, v, nd)) {\n            applyMove(s, v, nd);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool greedyImprove(State& s, int maxPass = 10) {\n    bool any = false;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool moved = false;\n\n        for (int v : highOrder) {\n            if (tryRaise(s, v)) {\n                moved = true;\n                any = true;\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nvector<int> aroundMark;\nint aroundStamp = 1;\n\nvoid greedyAround(State& s, int v) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n\n    auto add = [&](int x) {\n        if (aroundMark[x] != aroundStamp) {\n            aroundMark[x] = aroundStamp;\n            list.push_back(x);\n        }\n    };\n\n    add(v);\n    for (int u : adj[v]) {\n        add(u);\n        for (int w : adj[u]) add(w);\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        for (int x : list) tryRaise(s, x);\n    }\n}\n\nvoid greedyRegion(State& s, int start, int radius, int passes) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n    queue<pair<int, int>> q;\n\n    aroundMark[start] = aroundStamp;\n    q.push({start, 0});\n    list.push_back(start);\n\n    while (!q.empty()) {\n        auto [v, dist] = q.front();\n        q.pop();\n\n        if (dist >= radius) continue;\n\n        for (int u : adj[v]) {\n            if (aroundMark[u] == aroundStamp) continue;\n\n            aroundMark[u] = aroundStamp;\n            list.push_back(u);\n            q.push({u, dist + 1});\n        }\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int p = 0; p < passes; p++) {\n        for (int v : list) tryRaise(s, v);\n    }\n}\n\nvoid computeDPCost() {\n    const int INF = 1e9;\n    dpCost.assign(HH, vector<int>(N, INF));\n    if (HH <= 0) return;\n\n    for (int v = 0; v < N; v++) {\n        dpCost[0][v] = HH * A[v];\n    }\n\n    for (int k = 1; k < HH; k++) {\n        for (int v = 0; v < N; v++) {\n            int best = INF;\n            for (int u : adj[v]) best = min(best, dpCost[k - 1][u]);\n            dpCost[k][v] = best + (HH - k) * A[v];\n        }\n    }\n}\n\nstruct Mode {\n    bool indepTop;\n    bool indepLower;\n    bool lookahead;\n    int kind;\n    double noise;\n    double dpWeight;\n};\n\ndouble coverScore(int cov, double cost, int future, int kind, double noise) {\n    double c = (double)cov;\n    double score;\n\n    if ((kind & 3) == 0) {\n        score = c / cost;\n    } else if ((kind & 3) == 1) {\n        score = c * c / cost;\n    } else if ((kind & 3) == 2) {\n        score = c / sqrt(cost);\n    } else {\n        score = c * sqrt(c) / cost;\n    }\n\n    score *= (1.0 + 0.025 * future);\n\n    if (noise > 0) {\n        score *= (1.0 + noise * (rng.nextDouble() - 0.5));\n    }\n\n    return score;\n}\n\nbool selectCoverLevel(\n    int k,\n    const vector<int>& target,\n    vector<int>& depth,\n    vector<char>& used,\n    bool independent,\n    const Mode& mode\n) {\n    vector<char> targetMark(N, 0), covered(N, 0), banned(N, 0);\n\n    for (int t : target) targetMark[t] = 1;\n\n    int rem = (int)target.size();\n    vector<int> selected;\n\n    auto candidateCost = [&](int c) -> double {\n        double base = (double)(HH - k) * A[c];\n\n        if (mode.dpWeight > 0 && k >= 0 && k < HH && !dpCost.empty()) {\n            double extra = max(0, dpCost[k][c] - (HH - k) * A[c]);\n            base += mode.dpWeight * extra;\n        }\n\n        return max(1.0, base);\n    };\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (used[c]) continue;\n            if (independent && banned[c]) continue;\n\n            int future = 0;\n            if (k > 0) {\n                for (int u : adj[c]) if (!used[u]) future++;\n                if (mode.lookahead && future == 0) continue;\n            }\n\n            int cov = 0;\n            if (k == HH - 1 && targetMark[c] && !covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (targetMark[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = coverScore(cov, candidateCost(c), future, mode.kind, mode.noise);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        used[best] = 1;\n        depth[best] = k;\n        selected.push_back(best);\n\n        if (independent) {\n            banned[best] = 1;\n            for (int u : adj[best]) banned[u] = 1;\n        }\n\n        auto mark = [&](int x) {\n            if (targetMark[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        if (k == HH - 1) mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    auto addCover = [&](int c, int delta) {\n        if (k == HH - 1) {\n            coverCnt[c] += delta;\n            for (int u : adj[c]) coverCnt[u] += delta;\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u]) coverCnt[u] += delta;\n            }\n        }\n    };\n\n    for (int c : selected) {\n        if (used[c] && depth[c] == k) addCover(c, 1);\n    }\n\n    for (int t : target) {\n        if (coverCnt[t] <= 0) return false;\n    }\n\n    sort(selected.begin(), selected.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selected) {\n        if (!used[c] || depth[c] != k) continue;\n\n        if (k < HH - 1 && !hasNeighborDepth(depth, c, HH - 1)) continue;\n\n        bool ok = true;\n\n        if (k == HH - 1) {\n            if (coverCnt[c] <= 1) ok = false;\n\n            if (ok) {\n                for (int u : adj[c]) {\n                    if (coverCnt[u] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u] && coverCnt[u] <= 1) {\n                    ok = false;\n                    break;\n                }\n            }\n        }\n\n        if (ok) {\n            addCover(c, -1);\n            used[c] = 0;\n            depth[c] = HH;\n        }\n    }\n\n    return true;\n}\n\nbool buildChain(vector<int>& outDepth, const Mode& mode) {\n    vector<int> depth(N, HH);\n    vector<char> used(N, 0);\n\n    for (int k = HH - 1; k >= 0; k--) {\n        vector<int> target;\n\n        if (k == HH - 1) {\n            target.resize(N);\n            iota(target.begin(), target.end(), 0);\n        } else {\n            for (int v = 0; v < N; v++) {\n                if (depth[v] == k + 1) target.push_back(v);\n            }\n        }\n\n        if (target.empty()) continue;\n\n        bool independent = (k == HH - 1 ? mode.indepTop : mode.indepLower);\n\n        if (!selectCoverLevel(k, target, depth, used, independent, mode)) {\n            return false;\n        }\n    }\n\n    State s;\n    initState(s, depth);\n\n    if (!verifyState(s)) return false;\n\n    outDepth = depth;\n    return true;\n}\n\nbool localImproveCover(\n    const vector<char>& targetMark,\n    const vector<char>& candidate,\n    vector<char>& selected,\n    const vector<char>& forced,\n    const vector<double>& cost,\n    bool topClosed,\n    int maxLoops\n) {\n    vector<vector<int>> cover(N);\n\n    for (int c = 0; c < N; c++) {\n        if (!candidate[c] && !selected[c]) continue;\n\n        if (topClosed && targetMark[c]) cover[c].push_back(c);\n\n        for (int u : adj[c]) {\n            if (targetMark[u]) cover[c].push_back(u);\n        }\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    for (int c = 0; c < N; c++) {\n        if (!selected[c]) continue;\n        for (int t : cover[c]) coverCnt[t]++;\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    vector<int> candList;\n    for (int c = 0; c < N; c++) {\n        if (candidate[c]) candList.push_back(c);\n    }\n\n    auto removableActual = [&](int c) -> bool {\n        if (forced[c]) return false;\n        if (cost[c] <= 1e-9 || cost[c] > 1e17) return false;\n\n        for (int t : cover[c]) {\n            if (coverCnt[t] <= 1) return false;\n        }\n\n        return true;\n    };\n\n    auto pruneActual = [&]() {\n        vector<int> sels;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c]) sels.push_back(c);\n        }\n\n        sort(sels.begin(), sels.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        for (int c : sels) {\n            if (!selected[c]) continue;\n            if (!removableActual(c)) continue;\n\n            selected[c] = 0;\n            for (int t : cover[c]) coverCnt[t]--;\n        }\n    };\n\n    pruneActual();\n\n    if (maxLoops <= 0) {\n        for (int t = 0; t < N; t++) {\n            if (targetMark[t] && coverCnt[t] <= 0) return false;\n        }\n        return true;\n    }\n\n    vector<int> tmpCnt(N);\n\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                selOrder.push_back(c);\n            }\n        }\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        double bestGain = 1e-6;\n        int bestC = -1;\n        vector<int> bestRem;\n\n        for (int c : candList) {\n            if (selected[c]) continue;\n            if (cover[c].empty()) continue;\n            if (cost[c] <= 1e-9 || cost[c] > 1e17) continue;\n\n            copy(coverCnt.begin(), coverCnt.end(), tmpCnt.begin());\n\n            for (int t : cover[c]) tmpCnt[t]++;\n\n            double gain = -cost[c];\n            vector<int> rems;\n\n            for (int s : selOrder) {\n                bool ok = true;\n\n                for (int t : cover[s]) {\n                    if (tmpCnt[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    for (int t : cover[s]) tmpCnt[t]--;\n                    gain += cost[s];\n                    rems.push_back(s);\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestC = c;\n                bestRem.swap(rems);\n            }\n        }\n\n        if (bestC == -1) break;\n\n        selected[bestC] = 1;\n        for (int t : cover[bestC]) coverCnt[t]++;\n\n        for (int r : bestRem) {\n            if (!selected[r]) continue;\n\n            selected[r] = 0;\n            for (int t : cover[r]) coverCnt[t]--;\n        }\n\n        pruneActual();\n    }\n\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                selOrder.push_back(c);\n            }\n        }\n\n        if (selOrder.empty()) break;\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        int trialLimit = min((int)selOrder.size(), 80 + 20 * maxLoops);\n\n        double bestGain = 1e-6;\n        vector<char> bestSel;\n        vector<int> bestCnt;\n\n        for (int ii = 0; ii < trialLimit; ii++) {\n            int r = selOrder[ii];\n\n            vector<char> tmpSel = selected;\n            vector<int> tc = coverCnt;\n\n            tmpSel[r] = 0;\n            for (int t : cover[r]) tc[t]--;\n\n            vector<char> need(N, 0);\n            int rem = 0;\n\n            for (int t : cover[r]) {\n                if (tc[t] == 0 && !need[t]) {\n                    need[t] = 1;\n                    rem++;\n                }\n            }\n\n            double addCost = 0.0;\n            bool fail = false;\n            int steps = 0;\n\n            while (rem > 0 && steps < 12) {\n                int bestA = -1;\n                int bestCov = 0;\n                double bestScore = -1;\n\n                for (int c : candList) {\n                    if (tmpSel[c]) continue;\n                    if (cost[c] <= 1e-9 || cost[c] > 1e17) continue;\n\n                    int cov = 0;\n                    for (int t : cover[c]) {\n                        if (need[t]) cov++;\n                    }\n\n                    if (cov == 0) continue;\n\n                    double sc = (double)cov * cov / cost[c];\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestA = c;\n                        bestCov = cov;\n                    }\n                }\n\n                if (bestA == -1 || bestCov == 0) {\n                    fail = true;\n                    break;\n                }\n\n                tmpSel[bestA] = 1;\n                addCost += cost[bestA];\n\n                for (int t : cover[bestA]) {\n                    tc[t]++;\n                    if (need[t]) {\n                        need[t] = 0;\n                        rem--;\n                    }\n                }\n\n                steps++;\n            }\n\n            if (fail || rem > 0) continue;\n\n            double gain = cost[r] - addCost;\n\n            vector<int> tmpOrder;\n            for (int c = 0; c < N; c++) {\n                if (tmpSel[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                    tmpOrder.push_back(c);\n                }\n            }\n\n            sort(tmpOrder.begin(), tmpOrder.end(), [&](int a, int b) {\n                return cost[a] > cost[b];\n            });\n\n            for (int c : tmpOrder) {\n                if (!tmpSel[c]) continue;\n\n                bool ok = true;\n                for (int t : cover[c]) {\n                    if (tc[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    tmpSel[c] = 0;\n                    for (int t : cover[c]) tc[t]--;\n                    gain += cost[c];\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestSel.swap(tmpSel);\n                bestCnt.swap(tc);\n            }\n        }\n\n        if (bestGain > 1e-6) {\n            selected.swap(bestSel);\n            coverCnt.swap(bestCnt);\n            pruneActual();\n        } else {\n            break;\n        }\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    return true;\n}\n\nbool reoptTop(State& s, int improveLoops) {\n    if (HH == 0) return false;\n\n    int k = HH - 1;\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0), candidate(N, 0), selected(N, 0), covered(N, 0), forced(N, 0);\n    vector<double> cost(N, 1e18);\n\n    int rem = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] >= k) {\n            target[v] = 1;\n            rem++;\n        }\n    }\n\n    if (rem == 0) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (!target[v]) continue;\n\n        if (k == 0 || hasNeighborDepth(d, v, k - 1)) {\n            candidate[v] = 1;\n            cost[v] = A[v];\n        }\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            if (target[c] && !covered[c]) cov++;\n\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = (double)cov / A[c];\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n\n        auto mark = [&](int x) {\n            if (target[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, true, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n\n    for (int v = 0; v < N; v++) {\n        if (target[v]) nd[v] = HH;\n    }\n\n    for (int v = 0; v < N; v++) {\n        if (selected[v]) nd[v] = k;\n    }\n\n    State ns;\n    initState(ns, nd);\n\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n\n    return false;\n}\n\nbool reoptLevel(State& s, int k, int improveLoops) {\n    if (k < 0 || k >= HH - 1) return false;\n\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0);\n    int targetCount = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k + 1) {\n            target[v] = 1;\n            targetCount++;\n        }\n    }\n\n    if (targetCount == 0) return false;\n\n    vector<char> candidate(N, 0), selected(N, 0), forced(N, 0), covered(N, 0);\n    vector<char> demoteTarget(N, 0), lowerLeaf(N, 0);\n    vector<double> cost(N, 1e18);\n    vector<int> retireDepth(N, -1);\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            candidate[v] = 1;\n            selected[v] = 0;\n\n            int bestRetire = -1;\n\n            for (int dep = HH; dep >= k + 2; dep--) {\n                if (hasNeighborDepth(d, v, dep - 1)) {\n                    bestRetire = dep;\n                    break;\n                }\n            }\n\n            if (bestRetire == -1) {\n                forced[v] = 1;\n                selected[v] = 1;\n                retireDepth[v] = k;\n                cost[v] = 0;\n            } else {\n                retireDepth[v] = bestRetire;\n                cost[v] = (bestRetire - k) * A[v];\n            }\n        } else if (d[v] == HH) {\n            bool supp = (k == 0) || hasNeighborDepth(d, v, k - 1);\n\n            if (supp) {\n                candidate[v] = 1;\n                cost[v] = (HH - k) * A[v];\n            }\n        } else if (improveLoops >= 5 && d[v] == k + 1) {\n            bool noHigherChild = true;\n            if (k + 2 <= HH) {\n                for (int u : adj[v]) {\n                    if (d[u] == k + 2) {\n                        noHigherChild = false;\n                        break;\n                    }\n                }\n            }\n\n            if (noHigherChild && canMove(s, v, k)) {\n                candidate[v] = 1;\n                demoteTarget[v] = 1;\n                cost[v] = A[v];\n            }\n        } else if (improveLoops >= 6 && d[v] > k + 1 && d[v] < HH) {\n            bool noHigherChild = true;\n            if (d[v] + 1 <= HH) {\n                for (int u : adj[v]) {\n                    if (d[u] == d[v] + 1) {\n                        noHigherChild = false;\n                        break;\n                    }\n                }\n            }\n\n            if (noHigherChild && canMove(s, v, k)) {\n                candidate[v] = 1;\n                lowerLeaf[v] = 1;\n                cost[v] = (d[v] - k) * A[v];\n            }\n        }\n    }\n\n    int rem = targetCount;\n\n    auto markBy = [&](int c) {\n        if (demoteTarget[c] && target[c] && !covered[c]) {\n            covered[c] = 1;\n            rem--;\n        }\n\n        for (int u : adj[c]) {\n            if (target[u] && !covered[u]) {\n                covered[u] = 1;\n                rem--;\n            }\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (forced[v]) markBy(v);\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n\n            if (demoteTarget[c] && target[c] && !covered[c]) cov++;\n\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = (double)cov / max(1.0, cost[c]);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n        markBy(best);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, true, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            if (selected[v]) {\n                nd[v] = k;\n            } else {\n                if (retireDepth[v] == -1) return false;\n                nd[v] = retireDepth[v];\n            }\n        } else if (d[v] == HH && selected[v]) {\n            nd[v] = k;\n        } else if (d[v] == k + 1 && demoteTarget[v] && selected[v]) {\n            nd[v] = k;\n        } else if (lowerLeaf[v] && selected[v]) {\n            nd[v] = k;\n        }\n    }\n\n    State ns;\n    initState(ns, nd);\n\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n\n    return false;\n}\n\nbool supportReplaceImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    vector<int> childIndex(N, -1);\n    vector<int> candMark(N, 0);\n    int stamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n\n        for (int p : highOrder) {\n            if ((chk++ & 15) == 0 && elapsed() > stopTime) return any;\n\n            int k = s.d[p];\n            if (k >= HH) continue;\n\n            vector<int> childs;\n\n            for (int w : adj[p]) {\n                if (s.d[w] == k + 1 && s.cnt[w] <= 1) {\n                    childs.push_back(w);\n                }\n            }\n\n            if (childs.empty()) {\n                if (tryRaise(s, p)) {\n                    moved = true;\n                    any = true;\n                }\n                continue;\n            }\n\n            int C = (int)childs.size();\n            if (C > 8) continue;\n\n            for (int i = 0; i < C; i++) childIndex[childs[i]] = i;\n\n            if (++stamp == INT_MAX) {\n                fill(candMark.begin(), candMark.end(), 0);\n                stamp = 1;\n            }\n\n            vector<int> raw;\n\n            auto addRaw = [&](int u) {\n                if (u == p) return;\n                if (candMark[u] != stamp) {\n                    candMark[u] = stamp;\n                    raw.push_back(u);\n                }\n            };\n\n            for (int w : childs) addRaw(w);\n\n            for (int w : childs) {\n                for (int u : adj[w]) {\n                    addRaw(u);\n                }\n            }\n\n            vector<int> cands, masks, deltas;\n\n            for (int u : raw) {\n                if (s.d[u] == k) continue;\n\n                int mask = 0;\n\n                int selfIdx = childIndex[u];\n                if (selfIdx >= 0) mask |= 1 << selfIdx;\n\n                for (int x : adj[u]) {\n                    int idx = childIndex[x];\n                    if (idx >= 0) mask |= 1 << idx;\n                }\n\n                if (mask == 0) continue;\n                if (!canMove(s, u, k)) continue;\n\n                cands.push_back(u);\n                masks.push_back(mask);\n                deltas.push_back((k - s.d[u]) * A[u]);\n            }\n\n            for (int x : childs) childIndex[x] = -1;\n\n            int K = (int)cands.size();\n            if (K == 0) continue;\n\n            if (K > 90) {\n                vector<int> ord(K);\n                iota(ord.begin(), ord.end(), 0);\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    int pa = __builtin_popcount((unsigned)masks[a]);\n                    int pb = __builtin_popcount((unsigned)masks[b]);\n                    return deltas[a] + 18 * pa > deltas[b] + 18 * pb;\n                });\n\n                vector<int> nc, nm, ndlt;\n                for (int i = 0; i < 90; i++) {\n                    int id = ord[i];\n                    nc.push_back(cands[id]);\n                    nm.push_back(masks[id]);\n                    ndlt.push_back(deltas[id]);\n                }\n                cands.swap(nc);\n                masks.swap(nm);\n                deltas.swap(ndlt);\n                K = 90;\n            }\n\n            int S = 1 << C;\n            int FULL = S - 1;\n            const int NEG = -1000000000;\n\n            vector<vector<int>> dp(K + 1, vector<int>(S, NEG));\n            vector<vector<unsigned char>> take(K + 1, vector<unsigned char>(S, 0));\n            vector<vector<int>> pre(K + 1, vector<int>(S, -1));\n\n            dp[0][0] = 0;\n\n            for (int i = 0; i < K; i++) {\n                for (int m = 0; m < S; m++) {\n                    if (dp[i][m] <= NEG / 2) continue;\n\n                    if (dp[i][m] > dp[i + 1][m]) {\n                        dp[i + 1][m] = dp[i][m];\n                    }\n\n                    int nm = m | masks[i];\n                    if (nm == m) continue;\n\n                    int nv = dp[i][m] + deltas[i];\n                    if (nv > dp[i + 1][nm]) {\n                        dp[i + 1][nm] = nv;\n                        take[i + 1][nm] = 1;\n                        pre[i + 1][nm] = m;\n                    }\n                }\n            }\n\n            if (dp[K][FULL] <= NEG / 2) continue;\n\n            vector<int> chosen;\n            int mask = FULL;\n\n            for (int i = K; i >= 1; i--) {\n                if (take[i][mask]) {\n                    chosen.push_back(cands[i - 1]);\n                    mask = pre[i][mask];\n                }\n            }\n\n            vector<pair<int, int>> oldDepth;\n            bool ok = true;\n            int altDelta = 0;\n\n            for (int u : chosen) {\n                int od = s.d[u];\n                oldDepth.push_back({u, od});\n\n                if (!canMove(s, u, k)) {\n                    ok = false;\n                    break;\n                }\n\n                applyMove(s, u, k);\n                altDelta += (k - od) * A[u];\n            }\n\n            int bestNd = -1;\n\n            if (ok) {\n                for (int nd = HH; nd > k; nd--) {\n                    if (canMove(s, p, nd)) {\n                        bestNd = nd;\n                        break;\n                    }\n                }\n            }\n\n            bool accepted = false;\n\n            if (bestNd != -1) {\n                int net = altDelta + (bestNd - k) * A[p];\n\n                if (net > 0) {\n                    applyMove(s, p, bestNd);\n                    greedyAround(s, p);\n                    moved = true;\n                    any = true;\n                    accepted = true;\n                }\n            }\n\n            if (!accepted) {\n                for (int i = (int)oldDepth.size() - 1; i >= 0; i--) {\n                    applyMove(s, oldDepth[i].first, oldDepth[i].second);\n                }\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\n// New compound move:\n// provide alternative supports for p's children, optionally create p's new parent,\n// then raise p.\nbool combinedSupportParentImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    vector<int> childIndex(N, -1);\n    vector<int> candMark(N, 0);\n    vector<int> changedMark(N, 0);\n    int candStamp = 1;\n    int changedStamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool movedPass = false;\n        int chk = 0;\n\n        for (int p : highOrder) {\n            if ((chk++ & 15) == 0 && elapsed() > stopTime) return any;\n\n            int k = s.d[p];\n            if (k >= HH) continue;\n\n            vector<int> childs;\n            for (int w : adj[p]) {\n                if (s.d[w] == k + 1 && s.cnt[w] <= 1) {\n                    childs.push_back(w);\n                }\n            }\n\n            int C = (int)childs.size();\n            if (C == 0 || C > 7) continue;\n\n            for (int i = 0; i < C; i++) childIndex[childs[i]] = i;\n\n            if (++candStamp == INT_MAX) {\n                fill(candMark.begin(), candMark.end(), 0);\n                candStamp = 1;\n            }\n\n            vector<int> raw;\n\n            auto addRaw = [&](int u) {\n                if (u == p) return;\n                if (candMark[u] != candStamp) {\n                    candMark[u] = candStamp;\n                    raw.push_back(u);\n                }\n            };\n\n            for (int w : childs) addRaw(w);\n            for (int w : childs) {\n                for (int u : adj[w]) addRaw(u);\n            }\n\n            vector<int> cands, masks, deltas;\n\n            for (int u : raw) {\n                if (s.d[u] == k) continue;\n\n                int mask = 0;\n\n                int selfIdx = childIndex[u];\n                if (selfIdx >= 0) mask |= 1 << selfIdx;\n\n                for (int x : adj[u]) {\n                    int idx = childIndex[x];\n                    if (idx >= 0) mask |= 1 << idx;\n                }\n\n                if (mask == 0) continue;\n                if (!canMove(s, u, k)) continue;\n\n                cands.push_back(u);\n                masks.push_back(mask);\n                deltas.push_back((k - s.d[u]) * A[u]);\n            }\n\n            for (int x : childs) childIndex[x] = -1;\n\n            int K = (int)cands.size();\n            if (K == 0) continue;\n\n            if (K > 80) {\n                vector<int> ord(K);\n                iota(ord.begin(), ord.end(), 0);\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    int pa = __builtin_popcount((unsigned)masks[a]);\n                    int pb = __builtin_popcount((unsigned)masks[b]);\n                    return deltas[a] + 20 * pa > deltas[b] + 20 * pb;\n                });\n\n                vector<int> nc, nm, ndlt;\n                for (int i = 0; i < 80; i++) {\n                    int id = ord[i];\n                    nc.push_back(cands[id]);\n                    nm.push_back(masks[id]);\n                    ndlt.push_back(deltas[id]);\n                }\n                cands.swap(nc);\n                masks.swap(nm);\n                deltas.swap(ndlt);\n                K = 80;\n            }\n\n            int S = 1 << C;\n            int FULL = S - 1;\n            const int NEG = -1000000000;\n\n            vector<vector<int>> dp(K + 1, vector<int>(S, NEG));\n            vector<vector<unsigned char>> take(K + 1, vector<unsigned char>(S, 0));\n            vector<vector<int>> pre(K + 1, vector<int>(S, -1));\n\n            dp[0][0] = 0;\n\n            for (int i = 0; i < K; i++) {\n                for (int m = 0; m < S; m++) {\n                    if (dp[i][m] <= NEG / 2) continue;\n\n                    if (dp[i][m] > dp[i + 1][m]) {\n                        dp[i + 1][m] = dp[i][m];\n                        take[i + 1][m] = 0;\n                    }\n\n                    int nm = m | masks[i];\n                    if (nm == m) continue;\n\n                    int nv = dp[i][m] + deltas[i];\n                    if (nv > dp[i + 1][nm]) {\n                        dp[i + 1][nm] = nv;\n                        take[i + 1][nm] = 1;\n                        pre[i + 1][nm] = m;\n                    }\n                }\n            }\n\n            if (dp[K][FULL] <= NEG / 2) continue;\n\n            vector<int> chosen;\n            int mask = FULL;\n\n            for (int i = K; i >= 1; i--) {\n                if (take[i][mask]) {\n                    chosen.push_back(i - 1);\n                    mask = pre[i][mask];\n                }\n            }\n\n            State tmp = s;\n            long long before = s.val;\n\n            if (++changedStamp == INT_MAX) {\n                fill(changedMark.begin(), changedMark.end(), 0);\n                changedStamp = 1;\n            }\n\n            bool ok = true;\n\n            for (int id : chosen) {\n                int u = cands[id];\n\n                if (changedMark[u] == changedStamp) continue;\n                if (!canMove(tmp, u, k)) {\n                    ok = false;\n                    break;\n                }\n\n                changedMark[u] = changedStamp;\n                applyMove(tmp, u, k);\n            }\n\n            if (!ok) continue;\n\n            long long bestNet = 0;\n            int bestNd = -1;\n            int bestQ = -1;\n            int bestNeed = -1;\n\n            for (int nd = HH; nd > k; nd--) {\n                if (canMove(tmp, p, nd)) {\n                    long long net = tmp.val - before + 1LL * (nd - k) * A[p];\n\n                    if (net > bestNet) {\n                        bestNet = net;\n                        bestNd = nd;\n                        bestQ = -1;\n                        bestNeed = -1;\n                    }\n                }\n\n                int need = nd - 1;\n\n                for (int q : adj[p]) {\n                    if (q == p) continue;\n                    if (changedMark[q] == changedStamp) continue;\n                    if (tmp.d[q] == need) continue;\n\n                    if (!canMoveExcept(tmp, q, need, p)) continue;\n\n                    int oldq = tmp.d[q];\n\n                    applyMove(tmp, q, need);\n                    if (canMove(tmp, p, nd)) {\n                        long long net = tmp.val - before + 1LL * (nd - k) * A[p];\n\n                        if (net > bestNet) {\n                            bestNet = net;\n                            bestNd = nd;\n                            bestQ = q;\n                            bestNeed = need;\n                        }\n                    }\n                    applyMove(tmp, q, oldq);\n                }\n            }\n\n            if (bestNd == -1 || bestNet <= 0) continue;\n\n            if (bestQ != -1) {\n                if (!canMoveExcept(tmp, bestQ, bestNeed, p)) continue;\n                applyMove(tmp, bestQ, bestNeed);\n            }\n\n            if (!canMove(tmp, p, bestNd)) continue;\n            applyMove(tmp, p, bestNd);\n\n            if (tmp.val > before && verifyState(tmp)) {\n                s = std::move(tmp);\n                greedyAround(s, p);\n                any = true;\n                movedPass = true;\n            }\n        }\n\n        if (!movedPass) break;\n    }\n\n    return any;\n}\n\nbool pairRaiseImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n\n        for (int v : highOrder) {\n            if ((chk++ & 31) == 0 && elapsed() > stopTime) return any;\n\n            int dv = s.d[v];\n            if (dv >= HH) continue;\n\n            int bestNet = 0;\n            int bestNd = -1;\n            int bestU = -1;\n            int bestNeed = -1;\n\n            for (int nd = dv + 1; nd <= HH; nd++) {\n                int directNet = (nd - dv) * A[v];\n\n                if (canMove(s, v, nd)) {\n                    if (directNet > bestNet) {\n                        bestNet = directNet;\n                        bestNd = nd;\n                        bestU = -1;\n                    }\n                    continue;\n                }\n\n                int need = nd - 1;\n\n                for (int u : adj[v]) {\n                    if (s.d[u] == need) continue;\n                    if (!canMoveExcept(s, u, need, v)) continue;\n\n                    int oldu = s.d[u];\n                    int deltaU = (need - oldu) * A[u];\n                    int net = directNet + deltaU;\n\n                    if (net <= bestNet) continue;\n\n                    applyMove(s, u, need);\n                    bool ok = canMove(s, v, nd);\n                    applyMove(s, u, oldu);\n\n                    if (ok) {\n                        bestNet = net;\n                        bestNd = nd;\n                        bestU = u;\n                        bestNeed = need;\n                    }\n                }\n            }\n\n            if (bestNd == -1 || bestNet <= 0) continue;\n\n            if (bestU == -1) {\n                if (canMove(s, v, bestNd)) {\n                    applyMove(s, v, bestNd);\n                    moved = true;\n                    any = true;\n                }\n            } else {\n                long long before = s.val;\n                int oldu = s.d[bestU];\n                int oldv = s.d[v];\n\n                applyMove(s, bestU, bestNeed);\n\n                if (canMove(s, v, bestNd)) {\n                    applyMove(s, v, bestNd);\n\n                    if (verifyState(s) && s.val > before) {\n                        moved = true;\n                        any = true;\n                    } else {\n                        applyMove(s, v, oldv);\n                        applyMove(s, bestU, oldu);\n                    }\n                } else {\n                    applyMove(s, bestU, oldu);\n                }\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nbool liftClosureImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    vector<int> mark(N, 0), suppIn(N, 0);\n    int stamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool movedPass = false;\n        int chk = 0;\n\n        for (int seed : highOrder) {\n            if ((chk++ & 15) == 0 && elapsed() > stopTime) return any;\n\n            int base = s.d[seed];\n            if (base >= HH) continue;\n\n            if (++stamp == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                stamp = 1;\n            }\n\n            vector<int> nodes;\n            vector<int> touched;\n            bool fail = false;\n\n            auto addNode = [&](int x) {\n                if (mark[x] == stamp) return;\n                if (s.d[x] >= HH) {\n                    fail = true;\n                    return;\n                }\n                mark[x] = stamp;\n                nodes.push_back(x);\n            };\n\n            addNode(seed);\n\n            for (int qi = 0; qi < (int)nodes.size() && !fail; qi++) {\n                int x = nodes[qi];\n                int t = s.d[x];\n\n                for (int y : adj[x]) {\n                    if (s.d[y] != t + 1) continue;\n\n                    if (suppIn[y] == 0) touched.push_back(y);\n                    suppIn[y]++;\n\n                    if (mark[y] != stamp && suppIn[y] >= s.cnt[y]) {\n                        addNode(y);\n                        if (fail) break;\n                    }\n                }\n            }\n\n            for (int x : touched) suppIn[x] = 0;\n\n            if (fail || nodes.empty()) continue;\n\n            long long gain = 0;\n            for (int x : nodes) gain += A[x];\n\n            bool hasSameSupport = false;\n            for (int u : adj[seed]) {\n                if (s.d[u] == base && mark[u] != stamp) {\n                    hasSameSupport = true;\n                    break;\n                }\n            }\n\n            vector<pair<int, int>> options;\n\n            if (hasSameSupport) {\n                options.push_back({-1, 0});\n            } else {\n                for (int q : adj[seed]) {\n                    if (mark[q] == stamp) continue;\n                    if (s.d[q] == base) continue;\n                    if (!canMove(s, q, base)) continue;\n\n                    int delta = (base - s.d[q]) * A[q];\n                    if (gain + delta > 0) {\n                        options.push_back({q, delta});\n                    }\n                }\n\n                sort(options.begin(), options.end(), [&](auto a, auto b) {\n                    return a.second > b.second;\n                });\n            }\n\n            if (options.empty()) continue;\n\n            sort(nodes.begin(), nodes.end(), [&](int a, int b) {\n                if (s.d[a] != s.d[b]) return s.d[a] < s.d[b];\n                return a < b;\n            });\n\n            bool acceptedAny = false;\n\n            for (auto [supportVertex, delta] : options) {\n                long long before = s.val;\n                vector<pair<int, int>> changed;\n\n                auto doMove = [&](int x, int nd) {\n                    if (s.d[x] == nd) return;\n                    changed.push_back({x, s.d[x]});\n                    applyMove(s, x, nd);\n                };\n\n                auto revert = [&]() {\n                    for (int i = (int)changed.size() - 1; i >= 0; i--) {\n                        applyMove(s, changed[i].first, changed[i].second);\n                    }\n                };\n\n                if (supportVertex != -1) {\n                    doMove(supportVertex, base);\n                }\n\n                for (int x : nodes) {\n                    doMove(x, s.d[x] + 1);\n                }\n\n                if (verifyState(s) && s.val > before) {\n                    movedPass = true;\n                    any = true;\n                    acceptedAny = true;\n                    break;\n                } else {\n                    revert();\n                }\n            }\n\n            if (acceptedAny) {\n                continue;\n            }\n        }\n\n        if (!movedPass) break;\n    }\n\n    return any;\n}\n\nbool addSupportImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n\n        for (int u : lowOrder) {\n            if ((chk++ & 7) == 0 && elapsed() > stopTime) return any;\n\n            int old = s.d[u];\n            if (old <= 0) continue;\n\n            int limit = (A[u] <= 15 ? 8 : 5);\n            vector<int> tries;\n            vector<char> seen(HH + 1, 0);\n\n            for (int nd = old - 1; nd >= 0 && (int)tries.size() < limit; nd--) {\n                if (!seen[nd]) {\n                    seen[nd] = 1;\n                    tries.push_back(nd);\n                }\n            }\n\n            State bestTmp;\n            long long bestVal = s.val;\n            bool found = false;\n\n            for (int nd : tries) {\n                if (elapsed() > stopTime) return any;\n                if (!canMove(s, u, nd)) continue;\n\n                State tmp = s;\n                applyMove(tmp, u, nd);\n                greedyRegion(tmp, u, 3, 3);\n\n                if (tmp.val > bestVal && verifyState(tmp)) {\n                    bestVal = tmp.val;\n                    bestTmp = std::move(tmp);\n                    found = true;\n                }\n            }\n\n            if (found) {\n                s = std::move(bestTmp);\n                moved = true;\n                any = true;\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nvoid polish(State& s, int passes, int improveLoops, double stopTime) {\n    for (int p = 0; p < passes; p++) {\n        if (elapsed() > stopTime) return;\n\n        reoptTop(s, improveLoops);\n\n        for (int k = HH - 2; k >= 0; k--) {\n            if (elapsed() > stopTime) return;\n            reoptLevel(s, k, improveLoops);\n        }\n\n        greedyImprove(s, 8);\n\n        if (improveLoops > 0 && elapsed() < stopTime) {\n            supportReplaceImprove(s, 1, stopTime);\n            greedyImprove(s, 4);\n        }\n    }\n}\n\nState makeFallback() {\n    vector<int> dist(N, -1);\n    queue<int> q;\n\n    dist[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u : adj[v]) {\n            if (dist[u] == -1) {\n                dist[u] = dist[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    vector<int> depth(N, 0);\n\n    for (int v = 0; v < N; v++) {\n        if (dist[v] < 0) depth[v] = 0;\n        else depth[v] = dist[v] % (HH + 1);\n    }\n\n    State s;\n    initState(s, depth);\n\n    if (!verifyState(s)) {\n        fill(depth.begin(), depth.end(), 0);\n        initState(s, depth);\n    }\n\n    greedyImprove(s, 12);\n    return s;\n}\n\nvoid anneal(State& best, double endTime) {\n    State cur = best;\n\n    double st = elapsed();\n    double duration = max(0.001, endTime - st);\n\n    double T0 = 120.0;\n    double T1 = 0.8;\n    double T = T0;\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 4095) == 0) {\n            double now = elapsed();\n\n            if (now >= endTime) break;\n\n            double prog = min(1.0, (now - st) / duration);\n            T = T0 * pow(T1 / T0, prog);\n\n            if ((iter & 65535) == 0 && iter > 0) {\n                greedyImprove(cur, 3);\n                if (cur.val > best.val) best = cur;\n                if (cur.val + 7000 < best.val) cur = best;\n            }\n        }\n\n        iter++;\n\n        int v = -1, nd = -1;\n        bool prechecked = false;\n\n        int type = rng.nextInt(100);\n\n        if (type < 30) {\n            int w = -1;\n\n            for (int t = 0; t < 6; t++) {\n                int cand = rng.nextInt(N);\n\n                if (cur.d[cand] > 0 && cur.cnt[cand] <= 1) {\n                    w = cand;\n                    break;\n                }\n            }\n\n            if (w == -1) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] == 0) continue;\n                w = cand;\n            }\n\n            nd = cur.d[w] - 1;\n\n            int bestU = -1;\n            int bestDelta = INT_MIN;\n\n            for (int u : adj[w]) {\n                if (cur.d[u] == nd) continue;\n                if (!canMove(cur, u, nd)) continue;\n\n                int delta = (nd - cur.d[u]) * A[u];\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestU = u;\n                }\n            }\n\n            if (bestU == -1) continue;\n\n            v = bestU;\n            prechecked = true;\n        } else if (type < 55) {\n            int K = min(N, 450);\n            v = lowOrder[rng.nextInt(K)];\n            if (cur.d[v] == 0) continue;\n            nd = rng.nextInt(cur.d[v]);\n        } else if (type < 85) {\n            int K = min(N, 750);\n            v = highOrder[rng.nextInt(K)];\n\n            if (cur.d[v] == HH) continue;\n\n            nd = -1;\n\n            for (int x = HH; x > cur.d[v]; x--) {\n                if (canMove(cur, v, x)) {\n                    nd = x;\n                    break;\n                }\n            }\n\n            if (nd == -1) continue;\n            prechecked = true;\n        } else {\n            v = rng.nextInt(N);\n            nd = rng.nextInt(HH + 1);\n            if (nd == cur.d[v]) continue;\n        }\n\n        if (!prechecked && !canMove(cur, v, nd)) continue;\n\n        int delta = (nd - cur.d[v]) * A[v];\n\n        bool accept = false;\n\n        if (delta >= 0) {\n            accept = true;\n        } else {\n            if (delta > -30.0 * T) {\n                double prob = exp(delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n        }\n\n        if (!accept) continue;\n\n        applyMove(cur, v, nd);\n\n        if (delta < 0) {\n            greedyAround(cur, v);\n        }\n\n        if (cur.val > best.val) {\n            best = cur;\n        }\n    }\n\n    greedyImprove(best, 10);\n}\n\nbool isBad(const State& s, int v) {\n    return s.d[v] > 0 && s.cnt[v] <= 0;\n}\n\nvoid repairState(State& s) {\n    deque<int> q;\n    vector<char> inq(N, 0);\n\n    auto push = [&](int v) {\n        if (!inq[v]) {\n            inq[v] = 1;\n            q.push_back(v);\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (isBad(s, v)) push(v);\n    }\n\n    int guard = 0;\n\n    while (!q.empty() && guard < 50000) {\n        int v = q.front();\n        q.pop_front();\n        inq[v] = 0;\n\n        if (!isBad(s, v)) continue;\n\n        int old = s.d[v];\n        int need = old - 1;\n\n        int bestU = -1;\n        int bestDelta = INT_MIN;\n\n        if (need >= 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == need) continue;\n\n                if (canMove(s, u, need)) {\n                    int delta = (need - s.d[u]) * A[u];\n                    if (delta > bestDelta) {\n                        bestDelta = delta;\n                        bestU = u;\n                    }\n                }\n            }\n        }\n\n        int nd = 0;\n\n        for (int x = old - 1; x >= 1; x--) {\n            bool ok = false;\n\n            for (int u : adj[v]) {\n                if (s.d[u] == x - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n\n            if (ok) {\n                nd = x;\n                break;\n            }\n        }\n\n        int lowerDelta = (nd - old) * A[v];\n\n        if (bestU != -1 && bestDelta > lowerDelta) {\n            applyMove(s, bestU, need);\n\n            push(v);\n            push(bestU);\n            for (int u : adj[bestU]) push(u);\n            for (int u : adj[v]) push(u);\n        } else {\n            applyMove(s, v, nd);\n\n            push(v);\n            for (int u : adj[v]) push(u);\n        }\n\n        guard++;\n    }\n\n    if (!verifyState(s)) {\n        vector<int> zero(N, 0);\n        initState(s, zero);\n    }\n}\n\nbool forceRaiseRepairImprove(State& s, int maxTrials, double stopTime) {\n    bool any = false;\n    int trials = 0;\n    int chk = 0;\n\n    for (int p : highOrder) {\n        if ((chk++ & 1) == 0 && elapsed() > stopTime) return any;\n        if (trials >= maxTrials) break;\n\n        if (s.d[p] >= HH) continue;\n\n        int potential = (HH - s.d[p]) * A[p];\n        if (potential <= 0) continue;\n\n        trials++;\n\n        State tmp = s;\n        long long before = s.val;\n\n        applyMove(tmp, p, HH);\n        repairState(tmp);\n\n        if (!verifyState(tmp)) continue;\n\n        greedyRegion(tmp, p, 3, 3);\n        greedyImprove(tmp, 2);\n\n        if (tmp.val > before && verifyState(tmp)) {\n            s = std::move(tmp);\n            any = true;\n        }\n    }\n\n    return any;\n}\n\nvoid lns(State& best, double endTime) {\n    State base = best;\n\n    while (elapsed() < endTime) {\n        State s = (rng.nextInt(100) < 85 ? best : base);\n\n        int remCnt = 2 + rng.nextInt(12);\n        if (rng.nextInt(100) < 15) remCnt += rng.nextInt(20);\n\n        for (int i = 0; i < remCnt; i++) {\n            int v = -1;\n\n            for (int t = 0; t < 60; t++) {\n                int cand;\n\n                if (rng.nextInt(100) < 65) {\n                    cand = highOrder[rng.nextInt(min(N, 800))];\n                } else {\n                    cand = rng.nextInt(N);\n                }\n\n                if (s.d[cand] < HH) {\n                    v = cand;\n                    break;\n                }\n            }\n\n            if (v != -1) {\n                applyMove(s, v, HH);\n            }\n        }\n\n        int addCnt = 4 + rng.nextInt(24);\n\n        for (int i = 0; i < addCnt; i++) {\n            int K = min(N, 250 + rng.nextInt(550));\n            int v = lowOrder[rng.nextInt(K)];\n\n            int nd;\n\n            if (rng.nextInt(100) < 70) {\n                nd = rng.nextInt(HH);\n            } else {\n                nd = max(0, s.d[v] - 1 - rng.nextInt(3));\n            }\n\n            if (nd < 0) nd = 0;\n            if (nd > HH) nd = HH;\n\n            applyMove(s, v, nd);\n        }\n\n        for (int t = 0; t < 35; t++) {\n            int v = rng.nextInt(N);\n\n            if (!isBad(s, v)) continue;\n\n            int need = s.d[v] - 1;\n            if (need < 0) continue;\n\n            int bu = -1;\n            int bestCost = INT_MAX;\n\n            for (int u : adj[v]) {\n                int c = abs(s.d[u] - need) * A[u] + A[u];\n\n                if (c < bestCost) {\n                    bestCost = c;\n                    bu = u;\n                }\n            }\n\n            if (bu != -1) {\n                applyMove(s, bu, need);\n            }\n        }\n\n        repairState(s);\n\n        if (!verifyState(s)) continue;\n\n        greedyImprove(s, 5);\n\n        if (s.val > best.val - 3000 && elapsed() < endTime - 0.03) {\n            polish(s, 1, 1, endTime);\n        }\n\n        if (s.val > best.val) {\n            best = s;\n            base = s;\n        } else if (s.val > base.val || rng.nextInt(100) < 5) {\n            base = s;\n        }\n    }\n\n    greedyImprove(best, 8);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> HH;\n\n    A.resize(N);\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        cin >> A[i];\n        seed = seed * 1000003ULL + A[i] + 97;\n    }\n\n    adj.assign(N, {});\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n\n        seed ^= (uint64_t)(u + 1) * 1000000007ULL + (uint64_t)(v + 1) * 1000003ULL;\n    }\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n\n        seed ^= ((uint64_t)x << 32) ^ (uint64_t)y ^ ((uint64_t)i * 11995408973635179863ULL);\n    }\n\n    if (seed == 0) seed = 88172645463325252ULL;\n    rng.x = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    highOrder.resize(N);\n    lowOrder.resize(N);\n\n    iota(highOrder.begin(), highOrder.end(), 0);\n    iota(lowOrder.begin(), lowOrder.end(), 0);\n\n    sort(highOrder.begin(), highOrder.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    sort(lowOrder.begin(), lowOrder.end(), [&](int a, int b) {\n        return A[a] < A[b];\n    });\n\n    aroundMark.assign(N, 0);\n\n    computeDPCost();\n\n    State best = makeFallback();\n    polish(best, 1, 0, 0.20);\n\n    vector<State> pool;\n\n    auto addPool = [&](const State& s) {\n        if (!verifyState(s)) return;\n\n        const int POOL_SIZE = 4;\n\n        if ((int)pool.size() < POOL_SIZE) {\n            pool.push_back(s);\n            return;\n        }\n\n        int worst = 0;\n        for (int i = 1; i < POOL_SIZE; i++) {\n            if (pool[i].val < pool[worst].val) worst = i;\n        }\n\n        if (s.val > pool[worst].val) {\n            pool[worst] = s;\n        }\n    };\n\n    addPool(best);\n\n    const double CONSTRUCT_LIMIT = 0.70;\n    int attempt = 0;\n\n    double dpWs[] = {0.0, 0.0, 0.015, 0.03, 0.06, 0.10};\n\n    while (attempt < 220 && elapsed() < CONSTRUCT_LIMIT) {\n        Mode mode;\n\n        if (attempt < 24) {\n            mode.indepTop = (attempt & 1);\n            mode.indepLower = (attempt & 2);\n            mode.kind = (attempt / 6) & 3;\n            mode.noise = 0.0;\n            mode.dpWeight = dpWs[(attempt / 4) % 6];\n        } else {\n            mode.indepTop = (rng.nextInt(100) < 45);\n            mode.indepLower = (rng.nextInt(100) < 25);\n            mode.kind = rng.nextInt(4);\n            mode.noise = 0.20 + 0.70 * rng.nextDouble();\n            mode.dpWeight = dpWs[rng.nextInt(6)] * (0.7 + 0.8 * rng.nextDouble());\n        }\n\n        mode.lookahead = true;\n\n        vector<int> depth;\n\n        if (buildChain(depth, mode)) {\n            State s;\n            initState(s, depth);\n\n            polish(s, 1, 0, CONSTRUCT_LIMIT);\n\n            if (s.val > best.val) best = s;\n            addPool(s);\n        }\n\n        attempt++;\n    }\n\n    for (State s : pool) {\n        if (elapsed() > 0.95) break;\n\n        polish(s, 1, 4, 0.98);\n\n        if (s.val > best.val) best = s;\n    }\n\n    polish(best, 1, 5, 1.08);\n\n    anneal(best, 1.56);\n\n    polish(best, 1, 4, 1.67);\n\n    lns(best, 1.83);\n\n    polish(best, 1, 6, 1.875);\n    supportReplaceImprove(best, 1, 1.888);\n\n    combinedSupportParentImprove(best, 1, 1.900);\n    pairRaiseImprove(best, 1, 1.912);\n    liftClosureImprove(best, 2, 1.928);\n    pairRaiseImprove(best, 1, 1.938);\n\n    addSupportImprove(best, 1, 1.950);\n    forceRaiseRepairImprove(best, 140, 1.966);\n    pairRaiseImprove(best, 1, 1.974);\n\n    greedyImprove(best, 10);\n\n    if (!verifyState(best)) {\n        best = makeFallback();\n    }\n\n    vector<int> parent(N, -1);\n    bool ok = true;\n\n    for (int v = 0; v < N; v++) {\n        if (best.d[v] == 0) {\n            parent[v] = -1;\n        } else {\n            int p = -1;\n\n            for (int u : adj[v]) {\n                if (best.d[u] == best.d[v] - 1) {\n                    p = u;\n                    break;\n                }\n            }\n\n            if (p == -1) {\n                ok = false;\n                break;\n            }\n\n            parent[v] = p;\n        }\n    }\n\n    if (!ok) {\n        for (int i = 0; i < N; i++) parent[i] = -1;\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N;\nuint32_t FULL;\nconst int MAXN = 20;\n\nstruct Op {\n    char d;\n    int p;\n};\n\nstruct GAct {\n    char d;\n    int p;\n    int k;\n};\n\nstruct State {\n    array<uint32_t, MAXN> x{}, o{};\n    int xcnt = 0;\n};\n\nState INIT;\nvector<pair<int,int>> initialXs;\nint idxAt[MAXN][MAXN];\n\nchrono::steady_clock::time_point START;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nint popc(uint32_t v) {\n    return __builtin_popcount(v);\n}\n\nint firstBit(uint32_t m) {\n    return m ? __builtin_ctz(m) : N;\n}\n\nint lastBit(uint32_t m) {\n    return m ? 31 - __builtin_clz(m) : -1;\n}\n\nchar invDir(char d) {\n    if (d == 'L') return 'R';\n    if (d == 'R') return 'L';\n    if (d == 'U') return 'D';\n    return 'U';\n}\n\nvoid appendOps(vector<Op>& ops, char d, int p, int k) {\n    for (int i = 0; i < k; i++) ops.push_back({d, p});\n}\n\nbool edgeO(const State& s, const Op& op) {\n    int p = op.p;\n    uint32_t bit = 1u << p;\n    if (op.d == 'L') return s.o[p] & 1u;\n    if (op.d == 'R') return s.o[p] & (1u << (N - 1));\n    if (op.d == 'U') return s.o[0] & bit;\n    return s.o[N - 1] & bit;\n}\n\ninline void setBit(uint32_t& m, uint32_t bit, bool v) {\n    if (v) m |= bit;\n    else m &= ~bit;\n}\n\nvoid applyOp(State& s, const Op& op) {\n    int p = op.p;\n    if (op.d == 'L') {\n        if (s.x[p] & 1u) s.xcnt--;\n        s.x[p] >>= 1;\n        s.o[p] >>= 1;\n    } else if (op.d == 'R') {\n        if (s.x[p] & (1u << (N - 1))) s.xcnt--;\n        s.x[p] = (s.x[p] << 1) & FULL;\n        s.o[p] = (s.o[p] << 1) & FULL;\n    } else if (op.d == 'U') {\n        uint32_t bit = 1u << p;\n        if (s.x[0] & bit) s.xcnt--;\n        for (int i = 0; i < N - 1; i++) {\n            bool xb = s.x[i + 1] & bit;\n            bool ob = s.o[i + 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[N - 1] &= ~bit;\n        s.o[N - 1] &= ~bit;\n    } else {\n        uint32_t bit = 1u << p;\n        if (s.x[N - 1] & bit) s.xcnt--;\n        for (int i = N - 1; i >= 1; i--) {\n            bool xb = s.x[i - 1] & bit;\n            bool ob = s.o[i - 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[0] &= ~bit;\n        s.o[0] &= ~bit;\n    }\n}\n\nvoid applyGAct(State& s, const GAct& a) {\n    Op op{a.d, a.p};\n    for (int i = 0; i < a.k; i++) applyOp(s, op);\n}\n\nvector<Op> expandGSeq(const vector<GAct>& gs) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& g : gs) total += g.k;\n    ops.reserve(total);\n    for (auto& g : gs) appendOps(ops, g.d, g.p, g.k);\n    return ops;\n}\n\nbool isPerfectFull(const vector<Op>& ops) {\n    if ((int)ops.size() > 4 * N * N) return false;\n    State s = INIT;\n    for (auto& op : ops) {\n        if (edgeO(s, op)) return false;\n        applyOp(s, op);\n    }\n    return s.xcnt == 0;\n}\n\nbool truncateToPerfectPrefix(vector<Op>& ops) {\n    if (INIT.xcnt == 0) {\n        ops.clear();\n        return true;\n    }\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) {\n            ops.resize(t + 1);\n            return true;\n        }\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkip(const vector<Op>& ops, int l, int r) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (l <= t && t < r) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkipTwo(const vector<Op>& ops, int a, int b) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (t == a || t == b) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkipSet(const vector<Op>& ops, const vector<int>& ids) {\n    vector<char> skip(ops.size(), 0);\n    for (int id : ids) {\n        if (0 <= id && id < (int)ops.size()) skip[id] = 1;\n    }\n\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (skip[t]) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nvoid pruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n\n        int maxLen = min(55, (int)seq.size());\n        for (int len = maxLen; len >= 2 && elapsed() < until; len--) {\n            for (int i = 0; i + len <= (int)seq.size() && elapsed() < until; ) {\n                if (canPerfectSkip(seq, i, i + len)) {\n                    seq.erase(seq.begin() + i, seq.begin() + i + len);\n                    truncateToPerfectPrefix(seq);\n                    changed = true;\n                    i = max(0, i - len);\n                } else {\n                    i++;\n                }\n            }\n        }\n\n        for (int i = 0; i < (int)seq.size() && elapsed() < until; ) {\n            if (canPerfectSkip(seq, i, i + 1)) {\n                seq.erase(seq.begin() + i);\n                truncateToPerfectPrefix(seq);\n                changed = true;\n                if (i > 0) i--;\n            } else {\n                i++;\n            }\n        }\n    }\n}\n\nvoid pairPruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n        int n = (int)seq.size();\n\n        for (int pass = 0; pass < 2 && !changed && elapsed() < until; pass++) {\n            for (int i = 0; i < n && !changed && elapsed() < until; i++) {\n                for (int j = n - 1; j > i && elapsed() < until; j--) {\n                    bool invSameLine = (seq[i].p == seq[j].p && invDir(seq[i].d) == seq[j].d);\n                    if (pass == 0 && !invSameLine) continue;\n                    if (pass == 1 && invSameLine) continue;\n\n                    if (canPerfectSkipTwo(seq, i, j)) {\n                        seq.erase(seq.begin() + j);\n                        seq.erase(seq.begin() + i);\n                        truncateToPerfectPrefix(seq);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid randomSubsetPrune(vector<Op>& seq, double until, RNG& rng) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    while (elapsed() < until) {\n        int n = (int)seq.size();\n        if (n < 3) break;\n\n        int m = 3 + rng.nextInt(2);\n        vector<int> ids;\n\n        if (rng.nextInt(2) == 0) {\n            for (int tr = 0; tr < 25 && ids.empty(); tr++) {\n                int a = rng.nextInt(n);\n                int b = rng.nextInt(n);\n                if (a == b) continue;\n                if (seq[a].p == seq[b].p && invDir(seq[a].d) == seq[b].d) {\n                    ids.push_back(a);\n                    ids.push_back(b);\n                }\n            }\n        }\n\n        while ((int)ids.size() < m) {\n            int v = rng.nextInt(n);\n            bool ok = true;\n            for (int u : ids) if (u == v) ok = false;\n            if (ok) ids.push_back(v);\n        }\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if (canPerfectSkipSet(seq, ids)) {\n            sort(ids.rbegin(), ids.rend());\n            for (int id : ids) seq.erase(seq.begin() + id);\n            truncateToPerfectPrefix(seq);\n        }\n    }\n}\n\nstruct OInfo {\n    int firstRow[MAXN], lastRow[MAXN], rowCnt[MAXN];\n    int firstCol[MAXN], lastCol[MAXN], colCnt[MAXN];\n};\n\nvoid computeOInfo(const State& s, OInfo& info) {\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.o[i];\n        info.firstRow[i] = firstBit(m);\n        info.lastRow[i] = lastBit(m);\n        info.rowCnt[i] = popc(m);\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t cm = 0;\n        uint32_t bit = 1u << j;\n        for (int i = 0; i < N; i++) {\n            if (s.o[i] & bit) cm |= 1u << i;\n        }\n        info.firstCol[j] = firstBit(cm);\n        info.lastCol[j] = lastBit(cm);\n        info.colCnt[j] = popc(cm);\n    }\n}\n\nstruct Analysis {\n    int xcnt = 0;\n    int invis = 0;\n    double sumMin = 0;\n};\n\nAnalysis analyzeState(const State& s) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    Analysis a;\n    a.xcnt = s.xcnt;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            int md = 100;\n\n            if (j < info.firstRow[i]) vis++, md = min(md, j + 1);\n            if (j > info.lastRow[i]) vis++, md = min(md, N - j);\n            if (i < info.firstCol[j]) vis++, md = min(md, i + 1);\n            if (i > info.lastCol[j]) vis++, md = min(md, N - i);\n\n            if (vis == 0) {\n                a.invis++;\n                a.sumMin += N;\n            } else {\n                a.sumMin += md;\n            }\n        }\n    }\n    return a;\n}\n\nstruct GenParam {\n    double alpha = 1.0;\n    double critW = 6.0;\n    double twoW = 2.0;\n    double multiW = 1.0;\n    double damageW = 0.0;\n};\n\nstruct Cand {\n    char d;\n    int p, k;\n    int cnt;\n    double benefit;\n    double score;\n};\n\nvector<Cand> genCandidates(const State& s, const GenParam& gp) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    static double w[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) w[i][j] = 0.0;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            if (j < info.firstRow[i]) vis++;\n            if (j > info.lastRow[i]) vis++;\n            if (i < info.firstCol[j]) vis++;\n            if (i > info.lastCol[j]) vis++;\n\n            if (vis == 1) w[i][j] = gp.critW;\n            else if (vis == 2) w[i][j] = gp.twoW;\n            else if (vis >= 3) w[i][j] = gp.multiW;\n        }\n    }\n\n    vector<Cand> res;\n    res.reserve(160);\n\n    auto addCand = [&](char d, int p, int k, int cnt, double benefit, int movedO) {\n        if (cnt <= 0) return;\n        double b = max(1e-9, benefit);\n        double sc = (double)k / pow(b, gp.alpha) + gp.damageW * movedO * k;\n        res.push_back({d, p, k, cnt, benefit, sc});\n    };\n\n    for (int i = 0; i < N; i++) {\n        {\n            int clear = info.firstRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int j = 0; j < clear; j++) {\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('L', i, j + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n        {\n            int clear = N - 1 - info.lastRow[i];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int j = N - 1 - t;\n                if (s.x[i] & (1u << j)) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('R', i, t + 1, cnt, ben, info.rowCnt[i]);\n                }\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n        {\n            int clear = info.firstCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int i = 0; i < clear; i++) {\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('U', j, i + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n        {\n            int clear = N - 1 - info.lastCol[j];\n            int cnt = 0;\n            double ben = 0;\n            for (int t = 0; t < clear; t++) {\n                int i = N - 1 - t;\n                if (s.x[i] & bit) {\n                    cnt++;\n                    ben += w[i][j];\n                    addCand('D', j, t + 1, cnt, ben, info.colCnt[j]);\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\n// ---------- Guaranteed cover construction ----------\n\nstruct CoverCand {\n    char d;\n    int p, k;\n    uint64_t mask;\n};\n\nvector<CoverCand> buildCoverCandidates() {\n    vector<CoverCand> cands;\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        for (int j = 0; j < N; j++) {\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'L', i, j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int j = N - 1 - t;\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'R', i, t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n\n        uint64_t mask = 0;\n        for (int i = 0; i < N; i++) {\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'U', j, i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int i = N - 1 - t;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'D', j, t + 1, mask});\n            }\n        }\n    }\n\n    return cands;\n}\n\nuint64_t unionIds(const vector<int>& ids, const vector<CoverCand>& cands) {\n    uint64_t m = 0;\n    for (int id : ids) m |= cands[id].mask;\n    return m;\n}\n\nint objectiveCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    if (ids.empty()) return 0;\n    int sum = 0, mx = 0;\n    for (int id : ids) {\n        sum += 2 * cands[id].k;\n        mx = max(mx, cands[id].k);\n    }\n    return sum - mx;\n}\n\nint sumKCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    int s = 0;\n    for (int id : ids) s += cands[id].k;\n    return s;\n}\n\nvoid removeRedundant(vector<int>& ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int a = 0; a < (int)ids.size(); a++) {\n            uint64_t u = 0;\n            for (int b = 0; b < (int)ids.size(); b++) if (a != b) {\n                u |= cands[ids[b]].mask;\n            }\n            if (u == ALL) {\n                ids.erase(ids.begin() + a);\n                changed = true;\n                break;\n            }\n        }\n    }\n}\n\ndouble coverScore(const CoverCand& c, int nc, int mode) {\n    int cost = 2 * c.k;\n    if (mode == 0) return cost / (double)nc;\n    if (mode == 1) return cost / pow((double)nc, 1.3);\n    if (mode == 2) return (cost - 0.3 * c.k) / pow((double)nc, 1.1);\n    if (mode == 3) return cost / (double)(nc * nc);\n    return (cost + 0.05 * __builtin_popcountll(c.mask)) / pow((double)nc, 1.5);\n}\n\nvector<int> greedyCoverMulti(vector<int> ids, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    uint64_t covered = unionIds(ids, cands);\n\n    while (covered != ALL) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            uint64_t nm = cands[i].mask & ~covered;\n            if (!nm) continue;\n\n            int nc = __builtin_popcountll(nm);\n            double sc = coverScore(cands[i], nc, mode);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) break;\n        ids.push_back(best);\n        covered |= cands[best].mask;\n    }\n\n    removeRedundant(ids, cands, ALL);\n    return ids;\n}\n\nvector<int> greedyCover(int pre, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    vector<int> ids;\n    if (pre >= 0) ids.push_back(pre);\n    return greedyCoverMulti(ids, mode, cands, ALL);\n}\n\nvector<int> improveCoverPlan(vector<int> ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    removeRedundant(ids, cands, ALL);\n\n    for (int iter = 0; iter < 6; iter++) {\n        int curObj = objectiveCover(ids, cands);\n        vector<int> bestIds = ids;\n        int bestObj = curObj;\n\n        vector<char> in(cands.size(), 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int c = 0; c < (int)cands.size(); c++) {\n            if (in[c]) continue;\n            vector<int> tmp = ids;\n            tmp.push_back(c);\n            removeRedundant(tmp, cands, ALL);\n            if (unionIds(tmp, cands) != ALL) continue;\n\n            int obj = objectiveCover(tmp, cands);\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestIds = tmp;\n            }\n        }\n\n        for (int r = 0; r < (int)ids.size(); r++) {\n            vector<int> base = ids;\n            base.erase(base.begin() + r);\n\n            for (int mode = 0; mode < 5; mode++) {\n                vector<int> tmp = greedyCoverMulti(base, mode, cands, ALL);\n                if (unionIds(tmp, cands) != ALL) continue;\n\n                int obj = objectiveCover(tmp, cands);\n                if (obj < bestObj) {\n                    bestObj = obj;\n                    bestIds = tmp;\n                }\n            }\n        }\n\n        if (bestObj < curObj) ids = bestIds;\n        else break;\n    }\n\n    return ids;\n}\n\nstruct Plan {\n    vector<int> ids;\n    int obj;\n};\n\nstring keyIds(vector<int> ids) {\n    sort(ids.begin(), ids.end());\n    string s;\n    for (int id : ids) {\n        s += to_string(id);\n        s += ',';\n    }\n    return s;\n}\n\nvector<Plan> generateCoverPlans(const vector<CoverCand>& cands) {\n    int M = (int)initialXs.size();\n    uint64_t ALL = ((1ULL << M) - 1);\n\n    vector<Plan> plans;\n    unordered_set<string> seen;\n\n    auto addPlan = [&](vector<int> ids) {\n        if (ids.empty()) return;\n        removeRedundant(ids, cands, ALL);\n        if (unionIds(ids, cands) != ALL) return;\n        string key = keyIds(ids);\n        if (seen.insert(key).second) {\n            plans.push_back({ids, objectiveCover(ids, cands)});\n        }\n    };\n\n    for (int mode = 0; mode < 5; mode++) {\n        addPlan(greedyCover(-1, mode, cands, ALL));\n        for (int pre = 0; pre < (int)cands.size(); pre++) {\n            addPlan(greedyCover(pre, mode, cands, ALL));\n        }\n    }\n\n    vector<pair<double,int>> rank;\n    for (int i = 0; i < (int)cands.size(); i++) {\n        int pc = max(1, __builtin_popcountll(cands[i].mask));\n        double sc = (2.0 * cands[i].k) / pow((double)pc, 1.25) - 0.05 * cands[i].k;\n        rank.push_back({sc, i});\n    }\n    sort(rank.begin(), rank.end());\n\n    int P = min(22, (int)rank.size());\n    for (int mode = 0; mode < 4; mode++) {\n        for (int a = 0; a < P; a++) {\n            for (int b = a + 1; b < P; b++) {\n                addPlan(greedyCoverMulti({rank[a].second, rank[b].second}, mode, cands, ALL));\n            }\n        }\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    int top = min(25, (int)plans.size());\n    for (int i = 0; i < top; i++) {\n        addPlan(improveCoverPlan(plans[i].ids, cands, ALL));\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    if ((int)plans.size() > 80) plans.resize(80);\n    return plans;\n}\n\nvector<int> orderedIds(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = plan.ids;\n\n    if (variant == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k > cands[b].k;\n        });\n    } else if (variant == 3) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (cands[a].d != cands[b].d) return cands[a].d < cands[b].d;\n            if (cands[a].p != cands[b].p) return cands[a].p < cands[b].p;\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant >= 4) {\n        for (int i = (int)ids.size() - 1; i >= 1; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ids[i], ids[j]);\n        }\n    }\n\n    return ids;\n}\n\nvector<Op> buildRoundTripOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n    if (ids.empty()) return ops;\n\n    int maxK = -1;\n    vector<int> finals;\n    for (int id : ids) {\n        if (cands[id].k > maxK) {\n            maxK = cands[id].k;\n            finals.clear();\n            finals.push_back(id);\n        } else if (cands[id].k == maxK) {\n            finals.push_back(id);\n        }\n    }\n\n    int finalId = finals[variant % finals.size()];\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += 2 * cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        if (id == finalId) continue;\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n        appendOps(ops, invDir(c.d), c.p, c.k);\n    }\n\n    auto& f = cands[finalId];\n    appendOps(ops, f.d, f.p, f.k);\n    return ops;\n}\n\nvector<Op> buildOneWayOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n\n    int reserveSize = 0;\n    for (int id : ids) reserveSize += cands[id].k;\n    ops.reserve(reserveSize);\n\n    for (int id : ids) {\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n    }\n    return ops;\n}\n\nvector<Op> makeHintSequence() {\n    vector<Op> ops;\n\n    for (auto [i, j] : initialXs) {\n        int bestK = 1e9;\n        char bestD = 'L';\n\n        auto upd = [&](char d, int k) {\n            if (k < bestK) {\n                bestK = k;\n                bestD = d;\n            }\n        };\n\n        uint32_t leftMask = (j == 0 ? 0u : ((1u << j) - 1));\n        if ((INIT.o[i] & leftMask) == 0) upd('L', j + 1);\n\n        uint32_t rightMask = FULL & ~((1u << (j + 1)) - 1);\n        if ((INIT.o[i] & rightMask) == 0) upd('R', N - j);\n\n        uint32_t bit = 1u << j;\n\n        bool ok = true;\n        for (int r = 0; r < i; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('U', i + 1);\n\n        ok = true;\n        for (int r = i + 1; r < N; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('D', N - i);\n\n        if (bestK < 1e9) {\n            appendOps(ops, bestD, (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n            appendOps(ops, invDir(bestD), (bestD == 'L' || bestD == 'R') ? i : j, bestK);\n        }\n    }\n\n    return ops;\n}\n\n// ---------- Direct search ----------\n\nuint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nuint64_t hashState(const State& s) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (int i = 0; i < N; i++) {\n        uint64_t v = ((uint64_t)s.x[i] << 32) ^ s.o[i] ^ (uint64_t)i * 0x9e3779b97f4a7c15ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\ndouble stateHeuristic(const State& s) {\n    Analysis a = analyzeState(s);\n    return 0.32 * a.sumMin + 4.5 * a.invis + 0.15 * a.xcnt;\n}\n\nstruct EstCand {\n    int cost;\n    uint64_t mask;\n};\n\nunordered_map<uint64_t, float> ESTCACHE;\n\ndouble staticGreedyEstimateRaw(const State& s) {\n    if (s.xcnt == 0) return 0;\n\n    int id[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) id[i][j] = -1;\n\n    int M = 0;\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n            id[i][j] = M++;\n        }\n    }\n\n    OInfo info;\n    computeOInfo(s, info);\n\n    vector<EstCand> cs;\n    cs.reserve(180);\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        int clear = info.firstRow[i];\n        for (int j = 0; j < clear; j++) {\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        clear = N - 1 - info.lastRow[i];\n        for (int t = 0; t < clear; t++) {\n            int j = N - 1 - t;\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint64_t mask = 0;\n        int clear = info.firstCol[j];\n        for (int i = 0; i < clear; i++) {\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        clear = N - 1 - info.lastCol[j];\n        for (int t = 0; t < clear; t++) {\n            int i = N - 1 - t;\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({t + 1, mask});\n            }\n        }\n    }\n\n    uint64_t ALL = (1ULL << M) - 1;\n    uint64_t covered = 0;\n    double total = 0;\n\n    for (int iter = 0; iter < M && covered != ALL; iter++) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cs.size(); i++) {\n            uint64_t nm = cs[i].mask & ~covered;\n            if (!nm) continue;\n            int nc = __builtin_popcountll(nm);\n            double sc = cs[i].cost / pow((double)nc, 1.25);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) {\n            Analysis a = analyzeState(s);\n            int rem = M - __builtin_popcountll(covered);\n            return total + 230.0 + 15.0 * rem + 6.0 * a.invis + 0.20 * a.sumMin;\n        }\n\n        total += cs[best].cost;\n        covered |= cs[best].mask;\n    }\n\n    return total;\n}\n\ndouble staticGreedyEstimateCached(const State& s) {\n    if (s.xcnt == 0) return 0;\n    uint64_t key = hashState(s) ^ 0x9ddfea08eb382d69ULL;\n    auto it = ESTCACHE.find(key);\n    if (it != ESTCACHE.end()) return it->second;\n\n    double v = staticGreedyEstimateRaw(s);\n    if ((int)ESTCACHE.size() < 200000) ESTCACHE.emplace(key, (float)v);\n    return v;\n}\n\nstruct TrialParam {\n    GenParam gen;\n    double noise = 0.0;\n    int topK = 1;\n    double topBias = 2.0;\n    double lookInvW = 0.0;\n    double lookSumW = 0.0;\n};\n\nTrialParam makeTrialParam(int t, RNG& rng) {\n    TrialParam p;\n\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.lookInvW = 4.0;\n        p.lookSumW = 0.015;\n    } else if (t == 1) {\n        p.gen = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.lookInvW = 3.0;\n        p.lookSumW = 0.010;\n    } else if (t == 2) {\n        p.gen = {1.5, 4.0, 1.8, 1.0, 0.02};\n    } else if (t == 3) {\n        p.gen = {0.85, 10.0, 2.5, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.15;\n        p.lookInvW = 2.0;\n    } else if (t == 4) {\n        p.gen = {1.2, 8.0, 3.0, 1.0, 0.03};\n        p.topK = 2;\n    } else if (t == 5) {\n        p.gen = {0.55, 5.0, 1.5, 1.0, 0.00};\n    } else if (t == 6) {\n        p.gen = {1.75, 5.0, 1.7, 1.0, 0.02};\n        p.lookInvW = 2.5;\n    } else if (t == 7) {\n        p.gen = {0.70, 12.0, 3.2, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.12;\n        p.lookInvW = 1.5;\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.9;\n        p.gen.critW = 3.0 + rng.nextDouble() * 8.0;\n        p.gen.twoW = 1.2 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.04;\n        p.noise = 0.15 + rng.nextDouble() * 0.9;\n        p.topK = 1 + rng.nextInt(8);\n        p.topBias = 1.5 + rng.nextDouble() * 3.0;\n\n        if (t % 7 == 0) {\n            p.lookInvW = 1.5 + rng.nextDouble() * 3.0;\n            p.lookSumW = 0.004 + rng.nextDouble() * 0.012;\n        }\n    }\n\n    return p;\n}\n\nvector<Op> directTrialFrom(const State& start, const TrialParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n\n        vector<Cand> viable;\n        viable.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            double score = c.score;\n\n            if (tp.lookInvW > 0 || tp.lookSumW > 0) {\n                State tmp = st;\n                applyGAct(tmp, {c.d, c.p, c.k});\n                Analysis a = analyzeState(tmp);\n\n                if (a.xcnt > 0 && a.invis == a.xcnt) score += 1e6;\n                score += tp.lookInvW * a.invis;\n                score += tp.lookSumW * a.sumMin;\n            }\n\n            if (tp.noise > 0) {\n                double z = tp.noise * (2.0 * rng.nextDouble() - 1.0);\n                score *= exp(z);\n            }\n\n            c.score = score;\n            viable.push_back(c);\n        }\n\n        if (viable.empty()) return {};\n\n        sort(viable.begin(), viable.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        int m = min(tp.topK, (int)viable.size());\n        int idx = 0;\n        if (m > 1) {\n            idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.topBias) * m));\n        }\n\n        Cand ch = viable[idx];\n\n        GAct ga{ch.d, ch.p, ch.k};\n        applyGAct(st, ga);\n        seq.push_back(ga);\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nvector<Op> directTrial(const TrialParam& tp, int moveLimit, RNG& rng) {\n    return directTrialFrom(INIT, tp, moveLimit, rng);\n}\n\nstruct LookParam {\n    GenParam gen;\n    double estW = 1.0;\n    double baseW = 0.1;\n    double noise = 0.0;\n    int topK = 1;\n    int preLimit = 45;\n    double bias = 2.0;\n};\n\nLookParam makeLookParam(int t, RNG& rng) {\n    LookParam p;\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.estW = 1.0;\n        p.baseW = 0.10;\n        p.preLimit = 45;\n        p.topK = 1;\n    } else if (t == 1) {\n        p.gen = {1.25, 6.5, 2.2, 1.0, 0.01};\n        p.estW = 0.85;\n        p.baseW = 0.25;\n        p.preLimit = 55;\n        p.topK = 2;\n        p.noise = 0.08;\n    } else if (t == 2) {\n        p.gen = {0.85, 10.0, 2.6, 1.0, 0.015};\n        p.estW = 1.15;\n        p.baseW = 0.05;\n        p.preLimit = 65;\n        p.topK = 3;\n        p.noise = 0.12;\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.8;\n        p.gen.critW = 4.0 + rng.nextDouble() * 7.0;\n        p.gen.twoW = 1.3 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.025;\n        p.estW = 0.75 + rng.nextDouble() * 0.65;\n        p.baseW = rng.nextDouble() * 0.35;\n        p.noise = 0.10 + rng.nextDouble() * 0.35;\n        p.topK = 1 + rng.nextInt(5);\n        p.preLimit = 35 + rng.nextInt(45);\n        p.bias = 1.5 + rng.nextDouble() * 3.0;\n    }\n    return p;\n}\n\nvector<Op> directStaticTrialFrom(const State& start, const LookParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n        if (cands.empty()) return {};\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        if ((int)cands.size() > tp.preLimit) cands.resize(tp.preLimit);\n\n        vector<pair<double, Cand>> scored;\n        scored.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            State tmp = st;\n            applyGAct(tmp, {c.d, c.p, c.k});\n\n            double score = c.k + tp.estW * staticGreedyEstimateCached(tmp) + tp.baseW * c.score;\n\n            if (tmp.xcnt > 0) {\n                Analysis a = analyzeState(tmp);\n                if (a.invis == a.xcnt) score += 10000;\n                score += 1.0 * a.invis;\n            }\n\n            if (tp.noise > 0) {\n                score *= exp(tp.noise * (2.0 * rng.nextDouble() - 1.0));\n            }\n\n            scored.push_back({score, c});\n        }\n\n        if (scored.empty()) return {};\n\n        sort(scored.begin(), scored.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        int m = min(tp.topK, (int)scored.size());\n        int idx = 0;\n        if (m > 1) idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.bias) * m));\n\n        Cand ch = scored[idx].second;\n        applyGAct(st, {ch.d, ch.p, ch.k});\n        seq.push_back({ch.d, ch.p, ch.k});\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nvector<Op> directStaticTrial(const LookParam& tp, int moveLimit, RNG& rng) {\n    return directStaticTrialFrom(INIT, tp, moveLimit, rng);\n}\n\n// ---------- Rollout greedy ----------\n\nstruct RollParam {\n    GenParam mainGp;\n    GenParam finishGp;\n    double lookInvW = 2.0;\n    double lookSumW = 0.006;\n    double baseW = 0.03;\n    double noise = 0.0;\n    int top = 10;\n};\n\nRollParam makeRollParam(int t, RNG& rng) {\n    RollParam p;\n    if (t == 0) {\n        p.mainGp = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.finishGp = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.top = 10;\n        p.lookInvW = 2.5;\n    } else if (t == 1) {\n        p.mainGp = {0.85, 10.0, 2.6, 1.0, 0.015};\n        p.finishGp = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.top = 12;\n        p.lookInvW = 2.0;\n        p.noise = 0.04;\n    } else if (t == 2) {\n        p.mainGp = {1.4, 5.0, 1.8, 1.0, 0.02};\n        p.finishGp = {0.75, 9.0, 2.8, 1.0, 0.01};\n        p.top = 9;\n        p.lookInvW = 3.0;\n    } else {\n        p.mainGp.alpha = 0.75 + rng.nextDouble() * 0.85;\n        p.mainGp.critW = 4.0 + rng.nextDouble() * 8.0;\n        p.mainGp.twoW = 1.3 + rng.nextDouble() * 2.8;\n        p.mainGp.multiW = 1.0;\n        p.mainGp.damageW = rng.nextDouble() * 0.03;\n\n        p.finishGp.alpha = 0.75 + rng.nextDouble() * 0.85;\n        p.finishGp.critW = 4.0 + rng.nextDouble() * 8.0;\n        p.finishGp.twoW = 1.3 + rng.nextDouble() * 2.8;\n        p.finishGp.multiW = 1.0;\n        p.finishGp.damageW = rng.nextDouble() * 0.03;\n\n        p.top = 7 + rng.nextInt(7);\n        p.lookInvW = 1.0 + rng.nextDouble() * 3.5;\n        p.lookSumW = rng.nextDouble() * 0.012;\n        p.noise = rng.nextDouble() * 0.12;\n    }\n    return p;\n}\n\nint greedyFinishCost(State st, int limit, const RollParam& rp, double until) {\n    const int INF = 1e9;\n    int moves = 0;\n\n    for (int step = 0; step < 50 && elapsed() < until; step++) {\n        if (st.xcnt == 0) return moves;\n\n        vector<Cand> cands = genCandidates(st, rp.finishGp);\n        if (cands.empty()) return INF;\n\n        int bestId = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            auto& c = cands[i];\n            if (moves + c.k > limit) continue;\n\n            State tmp = st;\n            applyGAct(tmp, {c.d, c.p, c.k});\n\n            double score = c.score;\n            if (tmp.xcnt > 0) {\n                Analysis a = analyzeState(tmp);\n                if (a.invis == a.xcnt) score += 1e6;\n                score += rp.lookInvW * a.invis + rp.lookSumW * a.sumMin;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestId = i;\n            }\n        }\n\n        if (bestId < 0) return INF;\n\n        Cand ch = cands[bestId];\n        applyGAct(st, {ch.d, ch.p, ch.k});\n        moves += ch.k;\n    }\n\n    return st.xcnt == 0 ? moves : INF;\n}\n\nvector<Op> rolloutTrial(const State& start, int moveLimit, double until, RNG& rng, int mode) {\n    RollParam rp = makeRollParam(mode, rng);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    for (int step = 0; step < 48 && st.xcnt > 0 && elapsed() < until; step++) {\n        vector<Cand> cands = genCandidates(st, rp.mainGp);\n        if (cands.empty()) return {};\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n        if ((int)cands.size() > rp.top) cands.resize(rp.top);\n\n        int bestId = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size() && elapsed() < until; i++) {\n            Cand c = cands[i];\n            if (moves + c.k > moveLimit) continue;\n\n            State tmp = st;\n            applyGAct(tmp, {c.d, c.p, c.k});\n\n            int rest = greedyFinishCost(tmp, moveLimit - moves - c.k, rp, until);\n            if (rest >= 1e9) continue;\n\n            double score = c.k + rest + rp.baseW * c.score;\n            if (rp.noise > 0) {\n                score *= exp(rp.noise * (2.0 * rng.nextDouble() - 1.0));\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestId = i;\n            }\n        }\n\n        if (bestId < 0) return {};\n\n        Cand ch = cands[bestId];\n        applyGAct(st, {ch.d, ch.p, ch.k});\n        seq.push_back({ch.d, ch.p, ch.k});\n        moves += ch.k;\n        if (moves > moveLimit) return {};\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\n// ---------- Beam search ----------\n\nstruct BeamState {\n    State st;\n    int g;\n    vector<GAct> seq;\n    double eval;\n    uint64_t h;\n};\n\nvector<Op> beamSearch(int moveLimit, double until, RNG& rng, bool useSetup) {\n    (void)rng;\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    GenParam gp;\n    gp.alpha = 1.15;\n    gp.critW = 7.5;\n    gp.twoW = 2.4;\n    gp.multiW = 1.0;\n    gp.damageW = 0.015;\n\n    const int WIDTH = 260;\n    const int PER_STATE = 12;\n    const int SETUP_PER_STATE = 3;\n\n    vector<BeamState> beam;\n    beam.push_back({INIT, 0, {}, stateHeuristic(INIT), hashState(INIT)});\n\n    int bestG = INT_MAX;\n    vector<GAct> bestSeq;\n\n    for (int depth = 0; depth < 45 && elapsed() < until; depth++) {\n        vector<BeamState> next;\n        next.reserve(WIDTH * (PER_STATE + SETUP_PER_STATE));\n\n        for (auto& bs : beam) {\n            if (elapsed() >= until) break;\n            if (bs.st.xcnt == 0) {\n                if (bs.g < bestG) {\n                    bestG = bs.g;\n                    bestSeq = bs.seq;\n                }\n                continue;\n            }\n\n            vector<Cand> cands = genCandidates(bs.st, gp);\n            vector<Cand> selected;\n\n            if (!cands.empty()) {\n                sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                    return a.score < b.score;\n                });\n\n                int take = min(PER_STATE, (int)cands.size());\n                for (int ci = 0; ci < take; ci++) selected.push_back(cands[ci]);\n            }\n\n            if (useSetup && depth < 32) {\n                double baseH = stateHeuristic(bs.st);\n                vector<Cand> setups;\n\n                for (int p = 0; p < N; p++) {\n                    Op ops[4] = {{'L', p}, {'R', p}, {'U', p}, {'D', p}};\n                    for (auto op : ops) {\n                        if (edgeO(bs.st, op)) continue;\n\n                        State ns = bs.st;\n                        int before = ns.xcnt;\n                        applyOp(ns, op);\n\n                        if (ns.xcnt != before) continue;\n\n                        double h2 = stateHeuristic(ns);\n                        double gain = baseH - h2;\n\n                        if (gain > 0.35) {\n                            double sc = 0.85 - 0.08 * gain;\n                            setups.push_back({op.d, op.p, 1, 0, gain, sc});\n                        }\n                    }\n                }\n\n                sort(setups.begin(), setups.end(), [](const Cand& a, const Cand& b) {\n                    return a.score < b.score;\n                });\n\n                int take = min(SETUP_PER_STATE, (int)setups.size());\n                for (int i = 0; i < take; i++) selected.push_back(setups[i]);\n            }\n\n            if (selected.empty()) continue;\n\n            for (const Cand& c : selected) {\n                int ng = bs.g + c.k;\n                if (ng > moveLimit) continue;\n\n                State ns = bs.st;\n                applyGAct(ns, {c.d, c.p, c.k});\n\n                BeamState child;\n                child.st = ns;\n                child.g = ng;\n                child.seq = bs.seq;\n                child.seq.push_back({c.d, c.p, c.k});\n                child.h = hashState(ns);\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestG) {\n                        bestG = ng;\n                        bestSeq = child.seq;\n                    }\n                    continue;\n                }\n\n                child.eval = ng + stateHeuristic(ns);\n                next.push_back(std::move(child));\n            }\n        }\n\n        if (next.empty()) break;\n\n        sort(next.begin(), next.end(), [](const BeamState& a, const BeamState& b) {\n            return a.eval < b.eval;\n        });\n\n        vector<BeamState> nb;\n        nb.reserve(WIDTH);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(WIDTH * 2);\n\n        for (auto& s : next) {\n            if (seen.insert(s.h).second) {\n                nb.push_back(std::move(s));\n                if ((int)nb.size() >= WIDTH) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    if (bestG < INT_MAX) return expandGSeq(bestSeq);\n    return {};\n}\n\n// ---------- Tail improvement ----------\n\nstruct MAct {\n    char d;\n    int p;\n    int k;\n    bool rt;\n    int cost;\n    double score;\n};\n\nvoid applyMAct(State& s, const MAct& m) {\n    if (!m.rt) {\n        applyGAct(s, {m.d, m.p, m.k});\n        return;\n    }\n\n    int k = m.k;\n    if (m.d == 'L') {\n        uint32_t mask = (1u << k) - 1;\n        uint32_t rem = s.x[m.p] & mask;\n        s.xcnt -= popc(rem);\n        s.x[m.p] &= ~mask;\n    } else if (m.d == 'R') {\n        uint32_t mask = FULL & ~((1u << (N - k)) - 1);\n        uint32_t rem = s.x[m.p] & mask;\n        s.xcnt -= popc(rem);\n        s.x[m.p] &= ~mask;\n    } else if (m.d == 'U') {\n        uint32_t bit = 1u << m.p;\n        for (int i = 0; i < k; i++) {\n            if (s.x[i] & bit) {\n                s.x[i] &= ~bit;\n                s.xcnt--;\n            }\n        }\n    } else {\n        uint32_t bit = 1u << m.p;\n        for (int i = N - k; i < N; i++) {\n            if (s.x[i] & bit) {\n                s.x[i] &= ~bit;\n                s.xcnt--;\n            }\n        }\n    }\n}\n\nvector<Op> expandMActs(const vector<MAct>& ms) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& m : ms) total += m.cost;\n    ops.reserve(total);\n\n    for (auto& m : ms) {\n        appendOps(ops, m.d, m.p, m.k);\n        if (m.rt) appendOps(ops, invDir(m.d), m.p, m.k);\n    }\n\n    return ops;\n}\n\nint dirId(char d) {\n    if (d == 'L') return 0;\n    if (d == 'R') return 1;\n    if (d == 'U') return 2;\n    return 3;\n}\n\nvector<MAct> genTailMacros(const State& s) {\n    GenParam gp{1.1, 8.0, 2.4, 1.0, 0.012};\n    vector<Cand> cs = genCandidates(s, gp);\n\n    vector<MAct> ms;\n    unordered_set<int> seen;\n    seen.reserve(cs.size() * 2 + 10);\n\n    for (auto& c : cs) {\n        int baseCode = ((dirId(c.d) * N + c.p) * (N + 1) + c.k) * 2;\n\n        if (seen.insert(baseCode).second) {\n            ms.push_back({c.d, c.p, c.k, false, c.k, c.score});\n        }\n\n        if (c.cnt < s.xcnt) {\n            int code = baseCode | 1;\n            if (seen.insert(code).second) {\n                ms.push_back({c.d, c.p, c.k, true, 2 * c.k, c.score * 1.8 + 0.08 * c.k});\n            }\n        }\n    }\n\n    sort(ms.begin(), ms.end(), [](const MAct& a, const MAct& b) {\n        return a.score < b.score;\n    });\n\n    if ((int)ms.size() > 95) ms.resize(95);\n    return ms;\n}\n\nint boardLowerBound(const State& s) {\n    int lb = 0;\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n            int d = min(min(i + 1, N - i), min(j + 1, N - j));\n            lb = max(lb, d);\n        }\n    }\n    return lb;\n}\n\nstruct TailNode {\n    State st;\n    int g;\n    int parent;\n    MAct act;\n    uint64_t key;\n};\n\nstruct TailItem {\n    double f;\n    int idx;\n    bool operator<(const TailItem& other) const {\n        return f > other.f;\n    }\n};\n\nvector<Op> tailMacroSearch(const State& start, int limit, double until) {\n    if (start.xcnt == 0) return {};\n    if (limit <= 0) return {};\n\n    vector<TailNode> nodes;\n    nodes.reserve(30000);\n\n    priority_queue<TailItem> pq;\n    unordered_map<uint64_t, int> dist;\n    dist.reserve(50000);\n\n    uint64_t skey = hashState(start);\n    nodes.push_back({start, 0, -1, MAct(), skey});\n    dist[skey] = 0;\n    pq.push({0.35 * stateHeuristic(start), 0});\n\n    int bestCost = limit + 1;\n    int bestIdx = -1;\n\n    while (!pq.empty() && elapsed() < until && (int)nodes.size() < 36000) {\n        auto it = pq.top();\n        pq.pop();\n\n        int idx = it.idx;\n        TailNode& nd = nodes[idx];\n\n        auto dit = dist.find(nd.key);\n        if (dit == dist.end() || dit->second != nd.g) continue;\n        if (nd.g >= bestCost) continue;\n        if (nd.g + boardLowerBound(nd.st) >= bestCost) continue;\n\n        if (nd.st.xcnt == 0) {\n            if (nd.g < bestCost) {\n                bestCost = nd.g;\n                bestIdx = idx;\n            }\n            continue;\n        }\n\n        vector<MAct> acts = genTailMacros(nd.st);\n        if (acts.empty()) continue;\n\n        for (auto& a : acts) {\n            int ng = nd.g + a.cost;\n            if (ng >= bestCost || ng > limit) continue;\n\n            State ns = nd.st;\n            applyMAct(ns, a);\n\n            int lb = boardLowerBound(ns);\n            if (ng + lb >= bestCost) continue;\n\n            uint64_t key = hashState(ns);\n            auto dit2 = dist.find(key);\n            if (dit2 != dist.end() && dit2->second <= ng) continue;\n\n            int ni = (int)nodes.size();\n            nodes.push_back({ns, ng, idx, a, key});\n            dist[key] = ng;\n\n            if (ns.xcnt == 0) {\n                if (ng < bestCost) {\n                    bestCost = ng;\n                    bestIdx = ni;\n                }\n            } else {\n                double f = ng + 0.35 * stateHeuristic(ns);\n                pq.push({f, ni});\n            }\n        }\n    }\n\n    if (bestIdx < 0) return {};\n\n    vector<MAct> ms;\n    for (int v = bestIdx; nodes[v].parent != -1; v = nodes[v].parent) {\n        ms.push_back(nodes[v].act);\n    }\n    reverse(ms.begin(), ms.end());\n\n    return expandMActs(ms);\n}\n\nstruct SNode {\n    State st;\n    int g;\n    int parent;\n    Op act;\n    uint64_t key;\n};\n\nstruct SItem {\n    double f;\n    int idx;\n    bool operator<(const SItem& other) const {\n        return f > other.f;\n    }\n};\n\nvector<Op> singleTailSearch(const State& start, int limit, double until) {\n    if (start.xcnt == 0) return {};\n    if (limit <= 0) return {};\n\n    vector<SNode> nodes;\n    nodes.reserve(50000);\n\n    priority_queue<SItem> pq;\n    unordered_map<uint64_t, int> dist;\n    dist.reserve(80000);\n\n    uint64_t skey = hashState(start);\n    nodes.push_back({start, 0, -1, Op(), skey});\n    dist[skey] = 0;\n    pq.push({0.40 * stateHeuristic(start), 0});\n\n    int bestCost = limit + 1;\n    int bestIdx = -1;\n\n    while (!pq.empty() && elapsed() < until && (int)nodes.size() < 55000) {\n        auto item = pq.top();\n        pq.pop();\n\n        int idx = item.idx;\n        SNode& nd = nodes[idx];\n\n        auto dit = dist.find(nd.key);\n        if (dit == dist.end() || dit->second != nd.g) continue;\n        if (nd.g >= bestCost) continue;\n        if (nd.g + boardLowerBound(nd.st) >= bestCost) continue;\n\n        if (nd.st.xcnt == 0) {\n            if (nd.g < bestCost) {\n                bestCost = nd.g;\n                bestIdx = idx;\n            }\n            continue;\n        }\n\n        for (int p = 0; p < N; p++) {\n            Op ops[4] = {{'L', p}, {'R', p}, {'U', p}, {'D', p}};\n            for (auto op : ops) {\n                if (edgeO(nd.st, op)) continue;\n\n                int ng = nd.g + 1;\n                if (ng >= bestCost || ng > limit) continue;\n\n                State ns = nd.st;\n                applyOp(ns, op);\n\n                int lb = boardLowerBound(ns);\n                if (ng + lb >= bestCost) continue;\n\n                uint64_t key = hashState(ns);\n                auto dit2 = dist.find(key);\n                if (dit2 != dist.end() && dit2->second <= ng) continue;\n\n                int ni = (int)nodes.size();\n                nodes.push_back({ns, ng, idx, op, key});\n                dist[key] = ng;\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestCost) {\n                        bestCost = ng;\n                        bestIdx = ni;\n                    }\n                } else {\n                    double f = ng + 0.40 * stateHeuristic(ns);\n                    pq.push({f, ni});\n                }\n            }\n        }\n    }\n\n    if (bestIdx < 0) return {};\n\n    vector<Op> ops;\n    for (int v = bestIdx; nodes[v].parent != -1; v = nodes[v].parent) {\n        ops.push_back(nodes[v].act);\n    }\n    reverse(ops.begin(), ops.end());\n    return ops;\n}\n\nvector<State> buildPrefixStates(const vector<Op>& ops) {\n    vector<State> states;\n    states.reserve(ops.size() + 1);\n\n    State s = INIT;\n    states.push_back(s);\n\n    for (auto& op : ops) {\n        if (edgeO(s, op)) break;\n        applyOp(s, op);\n        states.push_back(s);\n        if (s.xcnt == 0) break;\n    }\n\n    return states;\n}\n\nvoid suffixDirectImprove(vector<Op>& best, double until, RNG& rng) {\n    bool improved = true;\n    int globalAttempt = 0;\n\n    while (improved && elapsed() < until) {\n        improved = false;\n\n        vector<State> states = buildPrefixStates(best);\n        if ((int)states.size() <= 1) return;\n\n        vector<int> cuts;\n\n        auto addCut = [&](int t) {\n            if (t <= 0 || t >= (int)states.size()) return;\n            int rem = states[t].xcnt;\n            if (rem <= 0 || rem > 28) return;\n            if ((int)best.size() - t <= 2) return;\n            cuts.push_back(t);\n        };\n\n        int prev = states[0].xcnt;\n        for (int t = 1; t < (int)states.size(); t++) {\n            if (states[t].xcnt < prev) {\n                addCut(t);\n                prev = states[t].xcnt;\n            }\n        }\n\n        int st = max(1, (int)states.size() - 75);\n        for (int t = st; t + 1 < (int)states.size(); t += 4) {\n            addCut(t);\n        }\n\n        sort(cuts.begin(), cuts.end());\n        cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n        sort(cuts.begin(), cuts.end(), [&](int a, int b) {\n            int ra = states[a].xcnt, rb = states[b].xcnt;\n            if (ra != rb) return ra < rb;\n            return a > b;\n        });\n\n        if ((int)cuts.size() > 28) cuts.resize(28);\n\n        for (int cut : cuts) {\n            if (elapsed() >= until) break;\n\n            int limit = (int)best.size() - cut - 1;\n            if (limit <= 0) continue;\n\n            for (int z = 0; z < 5 && elapsed() < until; z++) {\n                vector<Op> comp;\n\n                if (z < 3) {\n                    TrialParam tp = makeTrialParam(z, rng);\n                    comp = directTrialFrom(states[cut], tp, limit, rng);\n                } else if (z == 3) {\n                    LookParam lp = makeLookParam(100 + globalAttempt, rng);\n                    lp.preLimit = min(lp.preLimit, 45);\n                    comp = directStaticTrialFrom(states[cut], lp, limit, rng);\n                } else {\n                    comp = rolloutTrial(states[cut], limit, min(until, elapsed() + 0.020), rng, 100 + globalAttempt);\n                }\n\n                globalAttempt++;\n\n                if (!comp.empty()) {\n                    vector<Op> ops;\n                    ops.reserve(cut + comp.size());\n                    ops.insert(ops.end(), best.begin(), best.begin() + cut);\n                    ops.insert(ops.end(), comp.begin(), comp.end());\n\n                    if (truncateToPerfectPrefix(ops) && isPerfectFull(ops) && ops.size() < best.size()) {\n                        best = std::move(ops);\n                        pruneSequence(best, min(until, elapsed() + 0.012));\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n\n            if (improved) break;\n        }\n    }\n}\n\nvoid tailImprove(vector<Op>& best, double until, RNG& rng) {\n    (void)rng;\n    bool improved = true;\n\n    while (improved && elapsed() < until) {\n        improved = false;\n\n        vector<State> states = buildPrefixStates(best);\n        if ((int)states.size() <= 1) return;\n\n        vector<int> cuts;\n        auto addCut = [&](int t) {\n            if (t <= 0 || t >= (int)states.size()) return;\n            if (states[t].xcnt <= 0 || states[t].xcnt > 14) return;\n            if ((int)best.size() - t <= 1) return;\n            cuts.push_back(t);\n        };\n\n        int prev = states[0].xcnt;\n        for (int t = 1; t < (int)states.size(); t++) {\n            if (states[t].xcnt < prev) {\n                addCut(t);\n                prev = states[t].xcnt;\n            }\n        }\n\n        int st = max(1, (int)states.size() - 45);\n        for (int t = st; t + 1 < (int)states.size(); t += 3) {\n            if (states[t].xcnt <= 10) addCut(t);\n        }\n\n        sort(cuts.begin(), cuts.end());\n        cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n        sort(cuts.begin(), cuts.end(), [&](int a, int b) {\n            if (states[a].xcnt != states[b].xcnt) return states[a].xcnt < states[b].xcnt;\n            return a > b;\n        });\n\n        if ((int)cuts.size() > 26) cuts.resize(26);\n\n        for (int cut : cuts) {\n            if (elapsed() >= until) break;\n\n            int rem = states[cut].xcnt;\n            int limit = (int)best.size() - cut - 1;\n            if (limit <= 0) continue;\n\n            vector<Op> comp;\n\n            if (rem <= 6 && elapsed() < until) {\n                comp = singleTailSearch(states[cut], limit, min(until, elapsed() + 0.026));\n            }\n\n            if (comp.empty() && elapsed() < until) {\n                comp = tailMacroSearch(states[cut], limit, min(until, elapsed() + 0.026));\n            }\n\n            if (!comp.empty()) {\n                vector<Op> ops;\n                ops.reserve(cut + comp.size());\n                ops.insert(ops.end(), best.begin(), best.begin() + cut);\n                ops.insert(ops.end(), comp.begin(), comp.end());\n\n                if (truncateToPerfectPrefix(ops) && isPerfectFull(ops) && ops.size() < best.size()) {\n                    best = std::move(ops);\n                    pruneSequence(best, min(until, elapsed() + 0.015));\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n}\n\n// ---------- Main ----------\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START = chrono::steady_clock::now();\n\n    cin >> N;\n    FULL = (1u << N) - 1;\n\n    INIT.x.fill(0);\n    INIT.o.fill(0);\n    INIT.xcnt = 0;\n    memset(idxAt, -1, sizeof(idxAt));\n\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') {\n                idxAt[i][j] = (int)initialXs.size();\n                initialXs.push_back({i, j});\n                INIT.x[i] |= 1u << j;\n                INIT.xcnt++;\n            } else if (C[i][j] == 'o') {\n                INIT.o[i] |= 1u << j;\n            }\n        }\n    }\n\n    uint64_t seed = hashState(INIT) ^ 0xa5a5a5a5deadbeefULL;\n    RNG rng(seed);\n    RNG rng2(seed ^ 0x9e3779b97f4a7c15ULL);\n\n    const double HARD = 1.90;\n\n    vector<Op> best = makeHintSequence();\n    truncateToPerfectPrefix(best);\n\n    vector<CoverCand> coverCands = buildCoverCandidates();\n    vector<Plan> plans = generateCoverPlans(coverCands);\n\n    auto consider = [&](vector<Op> ops, double pruneUntil) {\n        if (ops.empty()) return;\n        if (!truncateToPerfectPrefix(ops)) return;\n        if (pruneUntil > elapsed()) pruneSequence(ops, pruneUntil);\n        if (isPerfectFull(ops) && ops.size() < best.size()) {\n            best = std::move(ops);\n        }\n    };\n\n    if (!plans.empty()) {\n        vector<Op> ops = buildRoundTripOps(plans[0], coverCands, 0, rng);\n        consider(ops, 0.20);\n    }\n\n    pruneSequence(best, min(0.22, HARD));\n\n    for (int pi = 0; pi < (int)plans.size() && pi < 10 && elapsed() < 0.45; pi++) {\n        for (int v = 0; v < 6 && elapsed() < 0.45; v++) {\n            {\n                vector<Op> ops = buildOneWayOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.020));\n            }\n            {\n                vector<Op> ops = buildRoundTripOps(plans[pi], coverCands, v, rng);\n                consider(ops, min(0.45, elapsed() + 0.025));\n            }\n        }\n    }\n\n    if (!plans.empty() && elapsed() < 0.50) {\n        vector<int> ord(plans.size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return sumKCover(plans[a].ids, coverCands) < sumKCover(plans[b].ids, coverCands);\n        });\n\n        int lim = min(10, (int)ord.size());\n        for (int ii = 0; ii < lim && elapsed() < 0.50; ii++) {\n            int pi = ord[ii];\n            for (int v = 0; v < 5 && elapsed() < 0.50; v++) {\n                vector<Op> ops = buildOneWayOps(plans[pi], coverCands, v + 2, rng);\n                consider(ops, min(0.50, elapsed() + 0.014));\n            }\n        }\n    }\n\n    pruneSequence(best, min(0.52, HARD));\n\n    // Portfolio beam: original no-setup beam, then a shorter setup-aware beam.\n    if (elapsed() < 0.98) {\n        vector<Op> bops = beamSearch((int)best.size() + 70, 0.98, rng, false);\n        consider(bops, min(1.03, elapsed() + 0.055));\n    }\n\n    if (elapsed() < 1.10) {\n        vector<Op> bops = beamSearch((int)best.size() + 65, 1.10, rng, true);\n        consider(bops, min(1.13, elapsed() + 0.035));\n    }\n\n    // Limited rollout trials.\n    if (elapsed() < 1.22) {\n        for (int t = 0; t < 5 && elapsed() < 1.22; t++) {\n            int limit = min(4 * N * N, (int)best.size() + 60);\n            vector<Op> ops = rolloutTrial(INIT, limit, min(1.22, elapsed() + 0.035), rng2, t);\n            if (!ops.empty()) {\n                double until = elapsed();\n                if ((int)ops.size() < (int)best.size() + 45) {\n                    until = min(1.23, elapsed() + 0.012);\n                }\n                consider(ops, until);\n            }\n        }\n    }\n\n    if (elapsed() < 1.27) {\n        for (int t = 0; t < 4 && elapsed() < 1.27; t++) {\n            LookParam lp = makeLookParam(t, rng2);\n            int limit = min(4 * N * N, (int)best.size() + 60);\n            vector<Op> ops = directStaticTrial(lp, limit, rng2);\n\n            if (!ops.empty()) {\n                double until = elapsed();\n                if ((int)ops.size() < (int)best.size() + 45) {\n                    until = min(1.28, elapsed() + 0.012);\n                }\n                consider(ops, until);\n            }\n        }\n    }\n\n    int trial = 0;\n    int pruneCnt = 0;\n    while (elapsed() < 1.70) {\n        vector<Op> ops;\n\n        if (trial % 13 == 9 && elapsed() < 1.63) {\n            LookParam lp = makeLookParam(100 + trial, rng2);\n            int limit = min(4 * N * N, (int)best.size() + 60);\n            ops = directStaticTrial(lp, limit, rng2);\n        } else {\n            TrialParam tp = makeTrialParam(trial, rng);\n            int limit = min(4 * N * N, (int)best.size() + 70);\n            ops = directTrial(tp, limit, rng);\n        }\n\n        if (!ops.empty()) {\n            double until = elapsed();\n            if ((int)ops.size() < (int)best.size() + 50 && pruneCnt < 26) {\n                until = min(1.715, elapsed() + 0.017);\n                pruneCnt++;\n            }\n            consider(ops, until);\n        }\n\n        trial++;\n    }\n\n    if (elapsed() < 1.73) {\n        pruneSequence(best, min(1.73, HARD));\n    }\n\n    if (elapsed() < 1.805) {\n        suffixDirectImprove(best, 1.805, rng2);\n    }\n\n    if (elapsed() < 1.86) {\n        tailImprove(best, 1.86, rng2);\n    }\n\n    if (elapsed() < 1.885) {\n        pairPruneSequence(best, 1.885);\n    }\n\n    if (elapsed() < 1.895) {\n        randomSubsetPrune(best, 1.895, rng2);\n    }\n\n    if (elapsed() < HARD) {\n        pruneSequence(best, HARD);\n    }\n\n    if (!isPerfectFull(best)) {\n        best = makeHintSequence();\n        truncateToPerfectPrefix(best);\n    }\n\n    for (auto& op : best) {\n        cout << op.d << ' ' << op.p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 100;\nconstexpr int MAXE = 200;\n\nint N, L;\narray<int, MAXN> T;\narray<int, MAXN> Cdes;\narray<int, MAXN> demandIn;\n\nvector<int> activeChoices;\nvector<int> validZs;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n} rng;\n\ntemplate<class Tvec>\nvoid shuffle_vec(vector<Tvec>& v) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nchrono::steady_clock::time_point st_time;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - st_time).count();\n}\n\nstruct Cand {\n    array<int, MAXN> a, b;\n    array<unsigned char, MAXE> prot;\n};\n\nstruct SimResult {\n    long long err;\n    array<int, MAXN> cnt;\n    int last;\n};\n\nstruct Entry {\n    long long err;\n    Cand cand;\n    SimResult res;\n};\n\nCand bestCand;\nSimResult bestRes;\nlong long bestErr = (1LL << 60);\nvector<Entry> pool;\n\ninline long long absl(long long x) {\n    return x >= 0 ? x : -x;\n}\n\nlong long cellCost(long long diff, int mode) {\n    long long a = absl(diff);\n    if (mode == 0) return diff * diff;\n    if (mode == 1) return a;\n    return diff * diff + 1000LL * a;\n}\n\nvoid getDest(const Cand& c, array<int, MAXE>& dest) {\n    for (int i = 0; i < N; ++i) {\n        dest[2 * i] = c.a[i];\n        dest[2 * i + 1] = c.b[i];\n    }\n}\n\nvoid setEdge(Cand& c, int e, int to) {\n    int v = e / 2;\n    if (e & 1) c.b[v] = to;\n    else c.a[v] = to;\n}\n\nvoid flipVertex(Cand& c, int v) {\n    swap(c.a[v], c.b[v]);\n    swap(c.prot[2 * v], c.prot[2 * v + 1]);\n}\n\nSimResult simulate(const Cand& c) {\n    SimResult r;\n    r.cnt.fill(0);\n\n    int x = 0;\n    r.cnt[0] = 1;\n\n    for (int step = 1; step < L; ++step) {\n        int nx = (r.cnt[x] & 1) ? c.a[x] : c.b[x];\n        x = nx;\n        ++r.cnt[x];\n    }\n\n    r.last = x;\n\n    long long e = 0;\n    for (int i = 0; i < N; ++i) {\n        e += llabs((long long)r.cnt[i] - T[i]);\n    }\n    r.err = e;\n    return r;\n}\n\nbool addEvaluated(const Cand& c, const SimResult& r) {\n    bool improved = false;\n\n    if (r.err < bestErr) {\n        bestErr = r.err;\n        bestCand = c;\n        bestRes = r;\n        improved = true;\n    }\n\n    if ((int)pool.size() < 16 || r.err < pool.back().err) {\n        pool.push_back({r.err, c, r});\n        sort(pool.begin(), pool.end(), [](const Entry& x, const Entry& y) {\n            return x.err < y.err;\n        });\n        while ((int)pool.size() > 16) pool.pop_back();\n    }\n\n    return improved;\n}\n\nbool consider(const Cand& c) {\n    SimResult r = simulate(c);\n    return addEvaluated(c, r);\n}\n\nlong long moveDeltaCost(\n    const array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int e,\n    int y\n) {\n    int old = dest[e];\n    int ww = w[e];\n\n    if (old == y) return 0;\n\n    return\n        cellCost(loads[old] - ww - dem[old], objMode) +\n        cellCost(loads[y] + ww - dem[y], objMode) -\n        cellCost(loads[old] - dem[old], objMode) -\n        cellCost(loads[y] - dem[y], objMode);\n}\n\nvoid applyMove(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    int e,\n    int y\n) {\n    int old = dest[e];\n    if (old == y) return;\n\n    int ww = w[e];\n    loads[old] -= ww;\n    loads[y] += ww;\n    dest[e] = y;\n}\n\nvoid optimizeItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty() || items.empty()) return;\n\n    vector<int> order = items;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        bool improved = false;\n\n        if (randomize) shuffle_vec(order);\n\n        for (int e : order) {\n            int ww = w[e];\n            if (ww == 0) continue;\n\n            int old = dest[e];\n            long long oldCostOld = cellCost(loads[old] - dem[old], objMode);\n            long long bestDelta = 0;\n            int bestY = old;\n\n            for (int y : choices) {\n                if (y == old) continue;\n\n                long long delta =\n                    cellCost(loads[old] - ww - dem[old], objMode) +\n                    cellCost(loads[y] + ww - dem[y], objMode) -\n                    oldCostOld -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestY = y;\n                }\n            }\n\n            if (bestY != old) {\n                loads[old] -= ww;\n                loads[bestY] += ww;\n                dest[e] = bestY;\n                improved = true;\n            }\n        }\n\n        int M = (int)order.size();\n\n        for (int ii = 0; ii < M; ++ii) {\n            int e = order[ii];\n            int we = w[e];\n            if (we == 0) continue;\n\n            for (int jj = ii + 1; jj < M; ++jj) {\n                int f = order[jj];\n                int wf = w[f];\n\n                if (wf == 0 || we == wf) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n\n                if (x == y) continue;\n\n                long long nx = loads[x] - we + wf;\n                long long ny = loads[y] - wf + we;\n\n                long long delta =\n                    cellCost(nx - dem[x], objMode) +\n                    cellCost(ny - dem[y], objMode) -\n                    cellCost(loads[x] - dem[x], objMode) -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < 0) {\n                    loads[x] = nx;\n                    loads[y] = ny;\n                    swap(dest[e], dest[f]);\n                    improved = true;\n                }\n            }\n        }\n\n        if (randomize && M >= 3) {\n            int attempts = 1600;\n\n            for (int at = 0; at < attempts; ++at) {\n                int i = rng.randint(M);\n                int j = rng.randint(M);\n                int k = rng.randint(M);\n                if (i == j || j == k || k == i) continue;\n\n                int e = order[i];\n                int f = order[j];\n                int g = order[k];\n\n                int we = w[e];\n                int wf = w[f];\n                int wg = w[g];\n\n                if (we == 0 || wf == 0 || wg == 0) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n                int z = dest[g];\n\n                if (x == y || y == z || z == x) continue;\n\n                {\n                    long long nx = loads[x] - we + wg;\n                    long long ny = loads[y] - wf + we;\n                    long long nz = loads[z] - wg + wf;\n\n                    long long delta =\n                        cellCost(nx - dem[x], objMode) +\n                        cellCost(ny - dem[y], objMode) +\n                        cellCost(nz - dem[z], objMode) -\n                        cellCost(loads[x] - dem[x], objMode) -\n                        cellCost(loads[y] - dem[y], objMode) -\n                        cellCost(loads[z] - dem[z], objMode);\n\n                    if (delta < 0) {\n                        loads[x] = nx;\n                        loads[y] = ny;\n                        loads[z] = nz;\n\n                        dest[e] = y;\n                        dest[f] = z;\n                        dest[g] = x;\n\n                        improved = true;\n                        continue;\n                    }\n                }\n\n                {\n                    long long nx = loads[x] - we + wf;\n                    long long ny = loads[y] - wf + wg;\n                    long long nz = loads[z] - wg + we;\n\n                    long long delta =\n                        cellCost(nx - dem[x], objMode) +\n                        cellCost(ny - dem[y], objMode) +\n                        cellCost(nz - dem[z], objMode) -\n                        cellCost(loads[x] - dem[x], objMode) -\n                        cellCost(loads[y] - dem[y], objMode) -\n                        cellCost(loads[z] - dem[z], objMode);\n\n                    if (delta < 0) {\n                        loads[x] = nx;\n                        loads[y] = ny;\n                        loads[z] = nz;\n\n                        dest[e] = z;\n                        dest[f] = x;\n                        dest[g] = y;\n\n                        improved = true;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid assignItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty()) return;\n\n    vector<int> order = items;\n\n    if (randomize) shuffle_vec(order);\n\n    stable_sort(order.begin(), order.end(), [&](int e1, int e2) {\n        return w[e1] > w[e2];\n    });\n\n    int root = choices[0];\n\n    for (int e : order) {\n        int ww = w[e];\n\n        if (ww == 0) {\n            dest[e] = root;\n            continue;\n        }\n\n        vector<pair<long long, int>> cand;\n        cand.reserve(choices.size());\n\n        for (int y : choices) {\n            long long delta =\n                cellCost(loads[y] + ww - dem[y], objMode) -\n                cellCost(loads[y] - dem[y], objMode);\n            cand.push_back({delta, y});\n        }\n\n        int take = min((int)cand.size(), max(1, topR));\n\n        nth_element(cand.begin(), cand.begin() + take - 1, cand.end());\n        sort(cand.begin(), cand.begin() + take);\n\n        int idx = 0;\n        if (randomize && take > 1) {\n            int r = rng.randint(100);\n            if (r >= 70) idx = 1 + rng.randint(take - 1);\n        }\n\n        int y = cand[idx].second;\n        dest[e] = y;\n        loads[y] += ww;\n    }\n\n    optimizeItems(dest, w, items, choices, loads, dem, objMode, maxPass, randomize);\n}\n\nint computeSCC(\n    const array<int, MAXE>& dest,\n    vector<int>& comp,\n    vector<vector<int>>& comps\n) {\n    comp.assign(N, -1);\n    comps.clear();\n\n    if (activeChoices.empty()) return 0;\n\n    array<char, MAXN> active{};\n    active.fill(0);\n    for (int v : activeChoices) active[v] = 1;\n\n    vector<int> g[MAXN], rg[MAXN];\n\n    for (int v : activeChoices) {\n        for (int p = 0; p < 2; ++p) {\n            int to = dest[2 * v + p];\n            if (0 <= to && to < N && active[to]) {\n                g[v].push_back(to);\n                rg[to].push_back(v);\n            }\n        }\n    }\n\n    vector<int> order;\n    array<char, MAXN> vis{};\n    vis.fill(0);\n\n    function<void(int)> dfs1 = [&](int v) {\n        vis[v] = 1;\n        for (int to : g[v]) {\n            if (!vis[to]) dfs1(to);\n        }\n        order.push_back(v);\n    };\n\n    function<void(int, int)> dfs2 = [&](int v, int id) {\n        comp[v] = id;\n        comps[id].push_back(v);\n        for (int to : rg[v]) {\n            if (comp[to] == -1) dfs2(to, id);\n        }\n    };\n\n    for (int v : activeChoices) {\n        if (!vis[v]) dfs1(v);\n    }\n\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n        if (comp[v] == -1) {\n            comps.push_back({});\n            dfs2(v, (int)comps.size() - 1);\n        }\n    }\n\n    return (int)comps.size();\n}\n\nstruct EdgeChoice {\n    long long delta;\n    int e;\n    int y;\n};\n\nEdgeChoice findBestChange(\n    int A,\n    int B,\n    const vector<vector<int>>& comps,\n    const array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    const array<unsigned char, MAXE>* banned = nullptr\n) {\n    const long long INF = (1LL << 60);\n\n    EdgeChoice best{INF, -1, -1};\n\n    if (A == B) return best;\n\n    for (int positivePass = 0; positivePass < 2; ++positivePass) {\n        best = {INF, -1, -1};\n\n        for (int s : comps[A]) {\n            for (int p = 0; p < 2; ++p) {\n                int e = 2 * s + p;\n                if (banned && (*banned)[e]) continue;\n                if (positivePass == 0 && w[e] == 0) continue;\n\n                for (int y : comps[B]) {\n                    long long delta = moveDeltaCost(dest, w, loads, dem, objMode, e, y);\n\n                    if (\n                        delta < best.delta ||\n                        (delta == best.delta && (best.e == -1 || w[e] < w[best.e]))\n                    ) {\n                        best = {delta, e, y};\n                    }\n                }\n            }\n        }\n\n        if (best.e != -1) return best;\n    }\n\n    return best;\n}\n\nvoid applyEdgeChoice(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    array<unsigned char, MAXE>& prot,\n    const EdgeChoice& ch\n) {\n    if (ch.e == -1) return;\n\n    applyMove(dest, w, loads, ch.e, ch.y);\n    prot[ch.e] = 1;\n}\n\nvoid repairStrongFull(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 4; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        sort(order.begin(), order.end(), [&](int x, int y) {\n            long long sx = 0;\n            long long sy = 0;\n\n            for (int v : comps[x]) sx += dem[v];\n            for (int v : comps[y]) sy += dem[v];\n\n            long long lhs = sx * (long long)comps[y].size();\n            long long rhs = sy * (long long)comps[x].size();\n\n            if (lhs != rhs) return lhs > rhs;\n            return x < y;\n        });\n\n        array<unsigned char, MAXE> used{};\n        used.fill(0);\n\n        bool changed = false;\n\n        for (int i = 0; i < K; ++i) {\n            int A = order[i];\n            int B = order[(i + 1) % K];\n\n            EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode, &used);\n            if (ch.e == -1) continue;\n\n            int old = dest[ch.e];\n\n            applyEdgeChoice(dest, w, loads, prot, ch);\n            used[ch.e] = 1;\n\n            if (old != ch.y) changed = true;\n        }\n\n        if (!changed) return;\n    }\n}\n\nvoid repairStrongSmart(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 6; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        vector<vector<int>> cg(K);\n        vector<int> indeg(K, 0), outdeg(K, 0);\n\n        for (int v : activeChoices) {\n            int cv = comp[v];\n\n            for (int p = 0; p < 2; ++p) {\n                int to = dest[2 * v + p];\n                if (to < 0 || to >= N) continue;\n\n                int cu = comp[to];\n                if (cu == -1 || cu == cv) continue;\n\n                cg[cv].push_back(cu);\n                ++outdeg[cv];\n                ++indeg[cu];\n            }\n        }\n\n        vector<int> sources, sinks;\n\n        for (int c = 0; c < K; ++c) {\n            if (indeg[c] == 0) sources.push_back(c);\n            if (outdeg[c] == 0) sinks.push_back(c);\n        }\n\n        if (sources.empty() || sinks.empty()) {\n            repairStrongFull(dest, w, loads, dem, objMode, prot);\n            return;\n        }\n\n        vector<int> indegTopo(K, 0);\n\n        for (int c = 0; c < K; ++c) {\n            for (int to : cg[c]) ++indegTopo[to];\n        }\n\n        queue<int> q;\n        for (int c = 0; c < K; ++c) {\n            if (indegTopo[c] == 0) q.push(c);\n        }\n\n        vector<int> topo;\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            topo.push_back(v);\n\n            for (int to : cg[v]) {\n                --indegTopo[to];\n                if (indegTopo[to] == 0) q.push(to);\n            }\n        }\n\n        vector<int> pos(K, 0);\n        for (int i = 0; i < (int)topo.size(); ++i) {\n            pos[topo[i]] = i;\n        }\n\n        sort(sources.begin(), sources.end(), [&](int x, int y) {\n            return pos[x] < pos[y];\n        });\n        sort(sinks.begin(), sinks.end(), [&](int x, int y) {\n            return pos[x] < pos[y];\n        });\n\n        int M = max((int)sources.size(), (int)sinks.size());\n\n        vector<int> seqS(M), seqZ(M);\n\n        for (int i = 0; i < M; ++i) {\n            seqS[i] = sources[i % sources.size()];\n            seqZ[i] = sinks[i % sinks.size()];\n        }\n\n        const long long INF = (1LL << 60);\n\n        int bestShift = -1;\n        long long bestTotal = INF;\n\n        for (int shift = 0; shift < M; ++shift) {\n            long long total = 0;\n            bool ok = true;\n\n            for (int i = 0; i < M; ++i) {\n                int A = seqZ[i];\n                int B = seqS[(i + 1 + shift) % M];\n\n                if (A == B) {\n                    ok = false;\n                    break;\n                }\n\n                EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode);\n                if (ch.e == -1) {\n                    ok = false;\n                    break;\n                }\n\n                total += ch.delta;\n                if (total > bestTotal) break;\n            }\n\n            if (ok && total < bestTotal) {\n                bestTotal = total;\n                bestShift = shift;\n            }\n        }\n\n        if (bestShift == -1) bestShift = 0;\n\n        array<unsigned char, MAXE> used{};\n        used.fill(0);\n\n        bool changed = false;\n\n        for (int i = 0; i < M; ++i) {\n            int A = seqZ[i];\n            int B = seqS[(i + 1 + bestShift) % M];\n\n            if (A == B) {\n                for (int s : sources) {\n                    if (s != A) {\n                        B = s;\n                        break;\n                    }\n                }\n                if (A == B) continue;\n            }\n\n            EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode, &used);\n            if (ch.e == -1) continue;\n\n            int old = dest[ch.e];\n\n            applyEdgeChoice(dest, w, loads, prot, ch);\n            used[ch.e] = 1;\n\n            if (old != ch.y) changed = true;\n        }\n\n        if (!changed) {\n            repairStrongFull(dest, w, loads, dem, objMode, prot);\n            return;\n        }\n    }\n\n    repairStrongFull(dest, w, loads, dem, objMode, prot);\n}\n\nvoid optimizeNonProtected(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot,\n    int passes,\n    bool randomize\n) {\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (!prot[e] && w[e] > 0) items.push_back(e);\n    }\n\n    if (!items.empty()) {\n        optimizeItems(dest, w, items, activeChoices, loads, dem,\n                      objMode, passes, randomize);\n    }\n}\n\nvoid applyRepairType(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot,\n    int repairType,\n    bool randomize\n) {\n    if (repairType == 0) return;\n\n    if (repairType == 1) {\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n        optimizeNonProtected(dest, w, loads, dem, objMode, prot, 2, randomize);\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n    } else {\n        repairStrongFull(dest, w, loads, dem, objMode, prot);\n        optimizeNonProtected(dest, w, loads, dem, objMode, prot, 2, randomize);\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n    }\n}\n\nCand buildSimpleCycle(bool activeOnly) {\n    Cand c;\n    c.prot.fill(0);\n\n    if (activeOnly && !activeChoices.empty()) {\n        int root = activeChoices[0];\n\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = root;\n            c.b[i] = root;\n        }\n\n        int m = (int)activeChoices.size();\n\n        for (int k = 0; k < m; ++k) {\n            int v = activeChoices[k];\n            int to = activeChoices[(k + 1) % m];\n\n            c.a[v] = to;\n            c.b[v] = to;\n        }\n    } else {\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = (i + 1) % N;\n            c.b[i] = (i + 1) % N;\n        }\n    }\n\n    return c;\n}\n\nCand buildFree(\n    int z,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    int repairType\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] > 0) items.push_back(e);\n        else dest[e] = root;\n    }\n\n    assignItems(dest, w, items, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand buildBackbone(\n    int fixedParity,\n    int z,\n    int K,\n    int noiseAmp,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct NK {\n        int key;\n        int dem;\n        int node;\n    };\n\n    vector<NK> keys;\n    keys.reserve(activeChoices.size());\n\n    for (int v : activeChoices) {\n        int key = demandIn[v];\n\n        if (noiseAmp > 0) {\n            key += rng.randint(2 * noiseAmp + 1) - noiseAmp;\n        }\n\n        keys.push_back({key, demandIn[v], v});\n    }\n\n    sort(keys.begin(), keys.end(), [](const NK& x, const NK& y) {\n        if (x.key != y.key) return x.key > y.key;\n        if (x.dem != y.dem) return x.dem > y.dem;\n        return x.node < y.node;\n    });\n\n    vector<int> base;\n    for (auto& x : keys) base.push_back(x.node);\n\n    vector<int> order;\n    int m = (int)base.size();\n\n    if (m == 0) {\n        order.push_back(0);\n    } else {\n        K = max(1, min(K, m));\n\n        for (int r = 0; r < K; ++r) {\n            for (int idx = r; idx < m; idx += K) {\n                order.push_back(base[idx]);\n            }\n        }\n    }\n\n    root = order[0];\n    dest.fill(root);\n\n    array<char, MAXN> isAct{};\n    isAct.fill(0);\n    for (int v : order) isAct[v] = 1;\n\n    vector<int> flexItems;\n    flexItems.reserve(MAXE);\n\n    for (int k = 0; k < (int)order.size(); ++k) {\n        int s = order[k];\n        int to = order[(k + 1) % order.size()];\n\n        int fixedIdx = 2 * s + fixedParity;\n        int flexIdx = 2 * s + (1 - fixedParity);\n\n        dest[fixedIdx] = to;\n        prot[fixedIdx] = 1;\n        loads[to] += w[fixedIdx];\n\n        flexItems.push_back(flexIdx);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (isAct[i]) continue;\n\n        for (int p = 0; p < 2; ++p) {\n            int e = 2 * i + p;\n\n            if (w[e] > 0) flexItems.push_back(e);\n            else dest[e] = root;\n        }\n    }\n\n    assignItems(dest, w, flexItems, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand rebalanceCandidate(\n    const Entry& base,\n    bool fullReassign,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    int repairType\n) {\n    array<int, MAXE> dest;\n    getDest(base.cand, dest);\n\n    array<unsigned char, MAXE> prot = base.cand.prot;\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = base.res.cnt[i] - (base.res.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    array<long long, MAXN> loads;\n    loads.fill(0);\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n\n    if (fullReassign) {\n        for (int e = 0; e < 2 * N; ++e) {\n            if (prot[e]) {\n                loads[dest[e]] += w[e];\n            } else {\n                items.push_back(e);\n                dest[e] = root;\n            }\n        }\n\n        assignItems(dest, w, items, activeChoices, loads, demandIn,\n                    objMode, topR, maxPass, randomize);\n    } else {\n        for (int e = 0; e < 2 * N; ++e) {\n            loads[dest[e]] += w[e];\n\n            if (!prot[e]) {\n                items.push_back(e);\n            }\n        }\n\n        optimizeItems(dest, w, items, activeChoices, loads, demandIn,\n                      objMode, maxPass, randomize);\n    }\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nbool validZ(int z) {\n    if (z < 0 || z >= N) return false;\n    if (Cdes[z] <= 0) return false;\n    if (z == 0 && Cdes[0] <= 1) return false;\n    return true;\n}\n\nint randomZ() {\n    if (!validZs.empty()) {\n        return validZs[rng.randint((int)validZs.size())];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (Cdes[i] > 0) return i;\n    }\n\n    return 0;\n}\n\nbool tryLocalImprove(double TL) {\n    if (activeChoices.empty()) return false;\n\n    array<int, MAXE> dest;\n    getDest(bestCand, dest);\n\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = bestRes.cnt[i] - (bestRes.last == i ? 1 : 0);\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct Change {\n        long long delta;\n        int type;\n        int e;\n        int f;\n        int y;\n    };\n\n    vector<Change> moves;\n    moves.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        int ww = w[e];\n        if (ww == 0) continue;\n\n        int old = dest[e];\n\n        for (int y : activeChoices) {\n            if (y == old) continue;\n\n            long long delta =\n                llabs((long long)bestRes.cnt[old] - ww - T[old]) +\n                llabs((long long)bestRes.cnt[y] + ww - T[y]) -\n                llabs((long long)bestRes.cnt[old] - T[old]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) {\n                moves.push_back({delta, 0, e, -1, y});\n            }\n        }\n    }\n\n    sort(moves.begin(), moves.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    int testLimit = min(48, (int)moves.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n        setEdge(c, moves[i].e, moves[i].y);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    vector<Change> swaps;\n    swaps.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] == 0) continue;\n\n        for (int f = e + 1; f < 2 * N; ++f) {\n            if (w[f] == 0) continue;\n\n            int x = dest[e];\n            int y = dest[f];\n\n            if (x == y) continue;\n\n            int we = w[e];\n            int wf = w[f];\n\n            if (we == wf) continue;\n\n            long long nx = (long long)bestRes.cnt[x] - we + wf;\n            long long ny = (long long)bestRes.cnt[y] - wf + we;\n\n            long long delta =\n                llabs(nx - T[x]) +\n                llabs(ny - T[y]) -\n                llabs((long long)bestRes.cnt[x] - T[x]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) {\n                swaps.push_back({delta, 1, e, f, -1});\n            }\n        }\n    }\n\n    sort(swaps.begin(), swaps.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    testLimit = min(48, (int)swaps.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n\n        int e = swaps[i].e;\n        int f = swaps[i].f;\n\n        setEdge(c, e, dest[f]);\n        setEdge(c, f, dest[e]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool tryFlipImprove(double TL) {\n    vector<int> verts;\n    verts.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        if (bestCand.a[i] != bestCand.b[i]) verts.push_back(i);\n    }\n\n    if (verts.empty()) return false;\n\n    sort(verts.begin(), verts.end(), [&](int x, int y) {\n        if (bestRes.cnt[x] != bestRes.cnt[y]) return bestRes.cnt[x] > bestRes.cnt[y];\n        return x < y;\n    });\n\n    int singleLimit = min(55, (int)verts.size());\n\n    for (int idx = 0; idx < singleLimit && elapsed_sec() < TL; ++idx) {\n        Cand c = bestCand;\n        flipVertex(c, verts[idx]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    if (elapsed_sec() > TL - 0.07) return false;\n\n    int attempts = 16;\n\n    for (int at = 0; at < attempts && elapsed_sec() < TL; ++at) {\n        Cand c = bestCand;\n\n        vector<int> order = verts;\n        shuffle_vec(order);\n\n        int k = 2 + rng.randint(3);\n        k = min(k, (int)order.size());\n\n        for (int i = 0; i < k; ++i) {\n            flipVertex(c, order[i]);\n        }\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\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    cin >> N >> L;\n\n    uint64_t seed = 123456789;\n\n    for (int i = 0; i < N; ++i) {\n        cin >> T[i];\n        seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    }\n\n    rng = RNG(seed);\n    st_time = chrono::steady_clock::now();\n\n    Cdes = T;\n\n    if (T[0] == 0) {\n        Cdes[0] = 1;\n\n        int k = 1;\n        for (int i = 1; i < N; ++i) {\n            if (T[i] > T[k]) k = i;\n        }\n\n        --Cdes[k];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        demandIn[i] = Cdes[i];\n    }\n\n    --demandIn[0];\n\n    if (demandIn[0] < 0) demandIn[0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (demandIn[i] > 0) {\n            activeChoices.push_back(i);\n        }\n    }\n\n    if (activeChoices.empty()) {\n        int k = max_element(Cdes.begin(), Cdes.begin() + N) - Cdes.begin();\n        activeChoices.push_back(k);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (validZ(i)) validZs.push_back(i);\n    }\n\n    if (validZs.empty()) {\n        for (int i = 0; i < N; ++i) {\n            if (Cdes[i] > 0) validZs.push_back(i);\n        }\n    }\n\n    consider(buildSimpleCycle(false));\n    consider(buildSimpleCycle(true));\n\n    vector<int> zlist;\n\n    auto addZ = [&](int z) {\n        if (!validZ(z)) return;\n        if (find(zlist.begin(), zlist.end(), z) == zlist.end()) {\n            zlist.push_back(z);\n        }\n    };\n\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        return Cdes[x] > Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) {\n        addZ(ids[i]);\n    }\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        if ((Cdes[x] > 0) != (Cdes[y] > 0)) return Cdes[x] > 0;\n        return Cdes[x] < Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) {\n        addZ(ids[i]);\n    }\n\n    addZ(0);\n\n    if (zlist.empty() && !validZs.empty()) {\n        zlist.push_back(validZs[0]);\n    }\n\n    const double TL = 1.86;\n    const double PHASE_FREE_DET = 0.55;\n    const double PHASE_FREE_RAND = 1.04;\n    const double PHASE_REBAL = 1.58;\n    const double PHASE_FLIP_START = 1.70;\n\n    for (int z : zlist) {\n        if (elapsed_sec() > PHASE_FREE_DET) break;\n\n        for (int repairType : {1, 0, 2}) {\n            if (elapsed_sec() > PHASE_FREE_DET) break;\n\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() > PHASE_FREE_DET) break;\n\n                Cand c = buildFree(z, mode, 1, 8, false, repairType);\n                consider(c);\n            }\n        }\n    }\n\n    for (int z : zlist) {\n        if (elapsed_sec() > 0.78) break;\n\n        for (int fixed = 0; fixed < 2; ++fixed) {\n            if (elapsed_sec() > 0.78) break;\n\n            for (int K = 1; K <= 4; ++K) {\n                if (elapsed_sec() > 0.78) break;\n\n                Cand c = buildBackbone(fixed, z, K, 0, 0, 1, 4, false);\n                consider(c);\n            }\n        }\n    }\n\n    while (elapsed_sec() < PHASE_FREE_RAND) {\n        int z = randomZ();\n        int mode = rng.randint(3);\n        int topR = 1 + rng.randint(5);\n        int maxPass = 3 + rng.randint(5);\n\n        int r = rng.randint(100);\n        int repairType;\n\n        if (r < 72) repairType = 1;\n        else if (r < 90) repairType = 2;\n        else repairType = 0;\n\n        Cand c = buildFree(z, mode, topR, maxPass, true, repairType);\n        consider(c);\n    }\n\n    for (int rep = 0; rep < 4 && elapsed_sec() < 1.25 && !pool.empty(); ++rep) {\n        Entry base = pool[0];\n\n        for (int fullInt = 0; fullInt < 2; ++fullInt) {\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() >= 1.25) break;\n\n                bool full = fullInt != 0;\n                int maxPass = full ? 7 : 10;\n\n                Cand c = rebalanceCandidate(base, full, mode, 1, maxPass, false, 1);\n                consider(c);\n            }\n        }\n    }\n\n    int it = 0;\n\n    while (elapsed_sec() < PHASE_REBAL && !pool.empty()) {\n        Entry base;\n\n        if (it % 3 == 0) {\n            base = pool[0];\n        } else {\n            base = pool[rng.randint((int)pool.size())];\n        }\n\n        bool full = (it % 3 != 1);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? (4 + rng.randint(4)) : (6 + rng.randint(4));\n\n        int repairType = (rng.randint(100) < 85) ? 1 : 2;\n\n        Cand c = rebalanceCandidate(base, full, mode, topR, maxPass, true, repairType);\n        consider(c);\n\n        ++it;\n    }\n\n    bool localAllowed = true;\n    bool flipAllowed = true;\n\n    while (elapsed_sec() < TL) {\n        if (bestErr == 0) break;\n\n        if (localAllowed) {\n            if (tryLocalImprove(TL)) {\n                localAllowed = true;\n                flipAllowed = true;\n                continue;\n            }\n\n            localAllowed = false;\n        }\n\n        if (flipAllowed && elapsed_sec() > PHASE_FLIP_START) {\n            if (tryFlipImprove(TL)) {\n                localAllowed = true;\n                flipAllowed = true;\n                continue;\n            }\n\n            flipAllowed = false;\n        }\n\n        if (pool.empty() || elapsed_sec() >= TL) break;\n\n        Entry base = pool[rng.randint((int)pool.size())];\n\n        bool full = rng.randint(2);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? 4 : 7;\n\n        int repairType = (rng.randint(100) < 88) ? 1 : 2;\n\n        bool imp = consider(\n            rebalanceCandidate(base, full, mode, topR, maxPass, true, repairType)\n        );\n\n        if (imp) {\n            localAllowed = true;\n            flipAllowed = true;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestCand.a[i] << ' ' << bestCand.b[i] << '\\n';\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, varp, norm2;\n    vector<int> sx_int, sy_int;\n    vector<unsigned long long> hilb;\n\n    vector<float> distBase;\n    vector<float> distRank;\n    vector<unsigned char> known; // 0 none, 1 prequery, 2 final in-group query\n\n    vector<float> bonusMat;\n    vector<vector<pair<int, float>>> bonusAdj;\n\n    unordered_set<unsigned long long> usedQueries;\n    unordered_map<unsigned long long, vector<pair<int,int>>> responseMap;\n\n    int queryCount = 0;\n    float knownEvalFactor;\n    float knownFinalFactor;\n    float knownFinalGroupFactor;\n\n    mt19937 rng{1234567};\n\n    int ID(int i, int j) const { return i * N + j; }\n\n    static unsigned long long hilbertOrder(int x, int y) {\n        const int B = 14;\n        const int SZ = 1 << B;\n        unsigned long long d = 0;\n\n        for (int s = SZ / 2; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (unsigned long long)s * (unsigned long long)s * ((3 * rx) ^ ry);\n\n            if (ry == 0) {\n                if (rx == 1) {\n                    x = SZ - 1 - x;\n                    y = SZ - 1 - y;\n                }\n                swap(x, y);\n            }\n        }\n\n        return d;\n    }\n\n    static unsigned long long mortonOrder(int x, int y) {\n        unsigned long long z = 0;\n        for (int b = 0; b < 14; b++) {\n            z |= (unsigned long long)((x >> b) & 1) << (2 * b);\n            z |= (unsigned long long)((y >> b) & 1) << (2 * b + 1);\n        }\n        return z;\n    }\n\n    unsigned long long subsetHash(vector<int> s) const {\n        sort(s.begin(), s.end());\n\n        unsigned long long h = 1469598103934665603ULL;\n        h ^= (unsigned long long)s.size();\n        h *= 1099511628211ULL;\n\n        for (int v : s) {\n            h ^= (unsigned long long)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n\n        return h;\n    }\n\n    void readInput() {\n        cin >> N >> M >> Q >> L >> W;\n\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N);\n        rx.resize(N);\n        ly.resize(N);\n        ry.resize(N);\n        cx.resize(N);\n        cy.resize(N);\n        varp.resize(N);\n        norm2.resize(N);\n        sx_int.resize(N);\n        sy_int.resize(N);\n        hilb.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n\n            double wx = rx[i] - lx[i];\n            double wy = ry[i] - ly[i];\n\n            varp[i] = (wx * wx + wy * wy) / 12.0;\n            norm2[i] = cx[i] * cx[i] + cy[i] * cy[i];\n        }\n\n        const int SZ = 1 << 14;\n\n        for (int i = 0; i < N; i++) {\n            sx_int[i] = min(SZ - 1, max(0, (int)llround(cx[i] * (SZ - 1) / 10000.0)));\n            sy_int[i] = min(SZ - 1, max(0, (int)llround(cy[i] * (SZ - 1) / 10000.0)));\n            hilb[i] = hilbertOrder(sx_int[i], sy_int[i]);\n        }\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        knownEvalFactor = (float)(0.72 - 0.22 * unc);\n        knownFinalFactor = (float)(0.82 - 0.22 * unc);\n        knownFinalGroupFactor = max(0.45f, knownFinalFactor * 0.85f);\n    }\n\n    void computeDistances() {\n        distBase.assign(N * N, 0.0f);\n        distRank.assign(N * N, 0.0f);\n\n        vector<array<double, 9>> qx(N), qy(N), qw(N);\n\n        const double p[3] = {\n            -sqrt(3.0 / 5.0),\n            0.0,\n            sqrt(3.0 / 5.0)\n        };\n\n        const double w1[3] = {\n            5.0 / 18.0,\n            8.0 / 18.0,\n            5.0 / 18.0\n        };\n\n        for (int i = 0; i < N; i++) {\n            double mx = 0.5 * (lx[i] + rx[i]);\n            double my = 0.5 * (ly[i] + ry[i]);\n            double hx = 0.5 * (rx[i] - lx[i]);\n            double hy = 0.5 * (ry[i] - ly[i]);\n\n            int id = 0;\n            for (int a = 0; a < 3; a++) {\n                for (int b = 0; b < 3; b++) {\n                    qx[i][id] = mx + hx * p[a];\n                    qy[i][id] = my + hy * p[b];\n                    qw[i][id] = w1[a] * w1[b];\n                    id++;\n                }\n            }\n        }\n\n        const double alpha = 0.70;\n\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 cd = sqrt(dx * dx + dy * dy);\n\n                double oldBase = sqrt(dx * dx + dy * dy + alpha * (varp[i] + varp[j]));\n\n                double quad = 0.0;\n                for (int a = 0; a < 9; a++) {\n                    for (int b = 0; b < 9; b++) {\n                        double ddx = qx[i][a] - qx[j][b];\n                        double ddy = qy[i][a] - qy[j][b];\n                        quad += qw[i][a] * qw[j][b] * sqrt(ddx * ddx + ddy * ddy);\n                    }\n                }\n\n                double base = 0.80 * quad + 0.20 * oldBase;\n\n                double gx = 0.0, gy = 0.0;\n\n                if (rx[i] < lx[j]) gx = lx[j] - rx[i];\n                else if (rx[j] < lx[i]) gx = lx[i] - rx[j];\n\n                if (ry[i] < ly[j]) gy = ly[j] - ry[i];\n                else if (ry[j] < ly[i]) gy = ly[i] - ry[j];\n\n                double minRect = sqrt(gx * gx + gy * gy);\n                double rankd = 0.70 * minRect + 0.30 * cd;\n\n                distBase[ID(i, j)] = distBase[ID(j, i)] = (float)base;\n                distRank[ID(i, j)] = distRank[ID(j, i)] = (float)rankd;\n            }\n        }\n\n        known.assign(N * N, 0);\n    }\n\n    vector<pair<int,int>> askNew(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        usedQueries.insert(h);\n\n        cout << \"? \" << subset.size();\n        for (int v : subset) cout << ' ' << v;\n        cout << '\\n';\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        int l = (int)subset.size();\n        ret.reserve(l - 1);\n\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            if (a > b) swap(a, b);\n            ret.emplace_back(a, b);\n        }\n\n        queryCount++;\n        responseMap[h] = ret;\n        return ret;\n    }\n\n    vector<pair<int,int>> getOrAsk(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        auto it = responseMap.find(h);\n\n        if (it != responseMap.end() && (int)it->second.size() == (int)subset.size() - 1) {\n            return it->second;\n        }\n\n        if (queryCount >= Q) return {};\n        return askNew(subset);\n    }\n\n    void addKnownEdges(const vector<pair<int,int>>& es, unsigned char level = 1) {\n        for (auto [a, b] : es) {\n            if (a > b) swap(a, b);\n            int id1 = ID(a, b), id2 = ID(b, a);\n            if (known[id1] < level) known[id1] = level;\n            if (known[id2] < level) known[id2] = level;\n        }\n    }\n\n    vector<int> buildSubsetGlobal(int center, int variant, int mode) {\n        vector<pair<float,int>> arr;\n        arr.reserve(N - 1);\n\n        for (int v = 0; v < N; v++) {\n            if (v == center) continue;\n            float d = (mode == 0 ? distRank[ID(center, v)] : distBase[ID(center, v)]);\n            arr.emplace_back(d, v);\n        }\n\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n\n            for (int i = 0; i < common; i++) {\n                sub.push_back(arr[i].second);\n            }\n\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n\n        return sub;\n    }\n\n    vector<int> buildSubsetInGroup(int center, const vector<int>& group, int variant) {\n        vector<pair<float,int>> arr;\n        arr.reserve(group.size());\n\n        for (int v : group) {\n            if (v == center) continue;\n            arr.emplace_back(distBase[ID(center, v)], v);\n        }\n\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n\n            for (int i = 0; i < common; i++) {\n                sub.push_back(arr[i].second);\n            }\n\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n\n        return sub;\n    }\n\n    int reserveFinalQueryCount() const {\n        int res = 0;\n        int chunk = L - 1;\n\n        for (int g : G) {\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                res++;\n            } else {\n                int total = g - 1;\n                int full = total / chunk;\n                int rem = total % chunk;\n\n                res += full;\n                if (rem >= 2) res++;\n            }\n        }\n\n        return min(res, Q);\n    }\n\n    void performPrequeries(int targetQueries) {\n        if (targetQueries <= 0) return;\n\n        vector<int> byUnc(N), byHilb(N);\n        iota(byUnc.begin(), byUnc.end(), 0);\n        iota(byHilb.begin(), byHilb.end(), 0);\n\n        sort(byUnc.begin(), byUnc.end(), [&](int a, int b) {\n            if (varp[a] != varp[b]) return varp[a] > varp[b];\n            return a < b;\n        });\n\n        sort(byHilb.begin(), byHilb.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n\n        vector<int> centers;\n        vector<char> seen(N, 0);\n\n        for (int t = 0; t < N; t++) {\n            int c1 = byUnc[t];\n\n            if (!seen[c1]) {\n                seen[c1] = 1;\n                centers.push_back(c1);\n            }\n\n            int c2 = byHilb[(t * 37) % N];\n\n            if (!seen[c2]) {\n                seen[c2] = 1;\n                centers.push_back(c2);\n            }\n        }\n\n        for (int c : centers) {\n            if (queryCount >= targetQueries) break;\n\n            for (int v = 0; v < 4 && queryCount < targetQueries; v++) {\n                int mode = v & 1;\n                int variant = v / 2;\n\n                auto sub = buildSubsetGlobal(c, variant, mode);\n                if ((int)sub.size() < 2) continue;\n\n                unsigned long long h = subsetHash(sub);\n                if (usedQueries.count(h)) continue;\n\n                auto ret = askNew(sub);\n                addKnownEdges(ret, 1);\n                break;\n            }\n        }\n\n        int attempts = 0;\n\n        while (queryCount < targetQueries && attempts < 5000) {\n            int c = attempts % N;\n            int variant = (attempts / N) % 6;\n            int mode = (attempts / (N * 6)) & 1;\n            attempts++;\n\n            auto sub = buildSubsetGlobal(c, variant, mode);\n            if ((int)sub.size() < 2) continue;\n\n            unsigned long long h = subsetHash(sub);\n            if (usedQueries.count(h)) continue;\n\n            auto ret = askNew(sub);\n            addKnownEdges(ret, 1);\n        }\n    }\n\n    float evalWeight(int u, int v) const {\n        float d = distBase[ID(u, v)];\n        if (known[ID(u, v)]) d *= knownEvalFactor;\n        return d;\n    }\n\n    double primCostEval(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        if (n <= 1) return 0.0;\n\n        vector<float> best(n, 1e30f);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\n\n        double cost = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n\n            used[v] = 1;\n            cost += best[v];\n\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    float w = evalWeight(vs[v], vs[u]);\n                    if (w < best[u]) best[u] = w;\n                }\n            }\n        }\n\n        return cost;\n    }\n\n    double evalCandidate(const vector<int>& gid) const {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n\n        for (int i = 0; i < N; i++) {\n            if (gid[i] < 0 || gid[i] >= M) return 1e100;\n            groups[gid[i]].push_back(i);\n        }\n\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) return 1e100;\n        }\n\n        double score = 0.0;\n        for (int k = 0; k < M; k++) score += primCostEval(groups[k]);\n\n        return score;\n    }\n\n    vector<vector<int>> makeCityOrders() {\n        vector<vector<int>> orders;\n        const int S = (1 << 14) - 1;\n\n        auto addHilbert = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n\n                    if (type == 1) {\n                        tx = y;\n                        ty = x;\n                    } else if (type == 2) {\n                        tx = S - x;\n                        ty = y;\n                    } else if (type == 3) {\n                        tx = x;\n                        ty = S - y;\n                    } else if (type == 4) {\n                        tx = S - x;\n                        ty = S - y;\n                    } else if (type == 5) {\n                        tx = S - y;\n                        ty = x;\n                    }\n\n                    return hilbertOrder(tx, ty);\n                };\n\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 6; t++) addHilbert(t);\n\n        auto addMorton = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n\n                    if (type == 1) {\n                        tx = y;\n                        ty = x;\n                    } else if (type == 2) {\n                        tx = S - x;\n                        ty = y;\n                    } else if (type == 3) {\n                        tx = x;\n                        ty = S - y;\n                    }\n\n                    return mortonOrder(tx, ty);\n                };\n\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addMorton(t);\n\n        auto addSnake = [&](int axis) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            const int B = 28;\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                int ba, bb, ia, ib;\n\n                if (axis == 0) {\n                    ba = sx_int[a] * B / (S + 1);\n                    bb = sx_int[b] * B / (S + 1);\n                    ia = (ba & 1) ? (S - sy_int[a]) : sy_int[a];\n                    ib = (bb & 1) ? (S - sy_int[b]) : sy_int[b];\n\n                    if (ba != bb) return ba < bb;\n                    if (ia != ib) return ia < ib;\n                    return sx_int[a] < sx_int[b];\n                } else {\n                    ba = sy_int[a] * B / (S + 1);\n                    bb = sy_int[b] * B / (S + 1);\n                    ia = (ba & 1) ? (S - sx_int[a]) : sx_int[a];\n                    ib = (bb & 1) ? (S - sx_int[b]) : sx_int[b];\n\n                    if (ba != bb) return ba < bb;\n                    if (ia != ib) return ia < ib;\n                    return sy_int[a] < sy_int[b];\n                }\n            });\n\n            orders.push_back(ids);\n        };\n\n        addSnake(0);\n        addSnake(1);\n\n        auto addSort = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                double ka, kb;\n\n                if (type == 0) {\n                    ka = cx[a] * 10001.0 + cy[a];\n                    kb = cx[b] * 10001.0 + cy[b];\n                } else if (type == 1) {\n                    ka = cy[a] * 10001.0 + cx[a];\n                    kb = cy[b] * 10001.0 + cx[b];\n                } else if (type == 2) {\n                    ka = cx[a] + cy[a];\n                    kb = cx[b] + cy[b];\n                } else {\n                    ka = cx[a] - cy[a];\n                    kb = cx[b] - cy[b];\n                }\n\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addSort(t);\n\n        return orders;\n    }\n\n    vector<vector<int>> makeGroupOrders() {\n        vector<vector<int>> orders;\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n\n        orders.push_back(ids);\n\n        vector<int> rev = ids;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n\n        vector<int> asc = ids;\n        vector<int> desc = ids;\n\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        orders.push_back(asc);\n        orders.push_back(desc);\n\n        vector<int> zigBigSmall;\n        vector<int> zigSmallBig;\n        zigBigSmall.reserve(M);\n        zigSmallBig.reserve(M);\n\n        for (int l = 0, r = M - 1; l <= r; l++, r--) {\n            zigSmallBig.push_back(asc[l]);\n            if (l != r) zigSmallBig.push_back(asc[r]);\n        }\n\n        for (int l = 0, r = M - 1; l <= r; l++, r--) {\n            zigBigSmall.push_back(desc[l]);\n            if (l != r) zigBigSmall.push_back(desc[r]);\n        }\n\n        orders.push_back(zigSmallBig);\n        orders.push_back(zigBigSmall);\n\n        for (int r = 0; r < 6; r++) {\n            vector<int> p = ids;\n            shuffle(p.begin(), p.end(), rng);\n            orders.push_back(p);\n        }\n\n        return orders;\n    }\n\n    vector<int> gapGreedyGroupOrder(const vector<int>& cityOrder, int mode) {\n        vector<double> gap(N + 1, 0.0), pref(N + 1, 0.0);\n\n        for (int p = 1; p < N; p++) {\n            gap[p] = distBase[ID(cityOrder[p - 1], cityOrder[p])];\n        }\n\n        for (int p = 1; p < N; p++) {\n            pref[p] = pref[p - 1] + gap[p];\n        }\n\n        vector<char> usedG(M, 0);\n        vector<int> order;\n        order.reserve(M);\n\n        int pos = 0;\n\n        for (int step = 0; step < M; step++) {\n            int remSum = N - pos;\n            int remGroups = M - step;\n\n            int best = -1;\n            double bestVal = -1e100;\n\n            for (int k = 0; k < M; k++) {\n                if (usedG[k]) continue;\n\n                int s = G[k];\n                if (s > remSum) continue;\n\n                if (remGroups > 1 && s == remSum) continue;\n\n                double val;\n\n                if (remGroups == 1) {\n                    val = 1e90;\n                } else {\n                    int b = pos + s;\n                    if (b <= 0 || b >= N) continue;\n\n                    double boundary = gap[b];\n\n                    double internalAvg = 0.0;\n                    if (s >= 2) {\n                        internalAvg = (pref[pos + s - 1] - pref[pos]) / (s - 1);\n                    }\n\n                    if (mode == 0) {\n                        val = boundary;\n                    } else if (mode == 1) {\n                        val = boundary / (0.8 + sqrt((double)s));\n                    } else {\n                        val = boundary - 0.15 * internalAvg;\n                    }\n                }\n\n                if (val > bestVal || (val == bestVal && (best == -1 || k < best))) {\n                    bestVal = val;\n                    best = k;\n                }\n            }\n\n            if (best == -1) {\n                for (int k = 0; k < M; k++) {\n                    if (!usedG[k] && G[k] <= remSum) {\n                        best = k;\n                        break;\n                    }\n                }\n            }\n\n            if (best == -1) {\n                for (int k = 0; k < M; k++) {\n                    if (!usedG[k]) {\n                        best = k;\n                        break;\n                    }\n                }\n            }\n\n            usedG[best] = 1;\n            order.push_back(best);\n            pos += G[best];\n        }\n\n        return order;\n    }\n\n    vector<int> partitionCandidate(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n        vector<int> gid(N, -1);\n        int pos = 0;\n\n        for (int g : groupOrder) {\n            for (int t = 0; t < G[g]; t++) {\n                gid[cityOrder[pos++]] = g;\n            }\n        }\n\n        return gid;\n    }\n\n    struct EP {\n        float w;\n        int u, v;\n\n        bool operator<(const EP& other) const {\n            if (w != other.w) return w < other.w;\n            if (u != other.u) return u < other.u;\n            return v < other.v;\n        }\n    };\n\n    vector<EP> makeSortedPairs() {\n        vector<EP> ps;\n        ps.reserve(N * (N - 1) / 2);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                ps.push_back({evalWeight(i, j), i, j});\n            }\n        }\n\n        sort(ps.begin(), ps.end());\n        return ps;\n    }\n\n    vector<int> greedyCandidate(const vector<int>& groupOrder, const vector<EP>& pairs) {\n        vector<int> gid(N, -1);\n        vector<char> alive(N, 1);\n        int rem = N;\n        int ptr = 0;\n\n        auto addCity = [&](vector<int>& sel, int v) {\n            if (!alive[v]) return;\n            alive[v] = 0;\n            rem--;\n            sel.push_back(v);\n        };\n\n        for (int gr : groupOrder) {\n            int need = G[gr];\n            vector<int> sel;\n            sel.reserve(need);\n\n            if (need == rem) {\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        gid[i] = gr;\n                        alive[i] = 0;\n                    }\n                }\n                rem = 0;\n                continue;\n            }\n\n            if (need == 1) {\n                double mx = 0.0, my = 0.0;\n\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        mx += cx[i];\n                        my += cy[i];\n                    }\n                }\n\n                mx /= rem;\n                my /= rem;\n\n                int best = -1;\n                double bestVal = -1.0;\n\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        double dx = cx[i] - mx;\n                        double dy = cy[i] - my;\n                        double val = dx * dx + dy * dy + 0.05 * varp[i];\n\n                        if (val > bestVal) {\n                            bestVal = val;\n                            best = i;\n                        }\n                    }\n                }\n\n                addCity(sel, best);\n            } else {\n                while (ptr < (int)pairs.size() && !(alive[pairs[ptr].u] && alive[pairs[ptr].v])) {\n                    ptr++;\n                }\n\n                if (ptr < (int)pairs.size()) {\n                    addCity(sel, pairs[ptr].u);\n                    addCity(sel, pairs[ptr].v);\n                } else {\n                    for (int i = 0; i < N && (int)sel.size() < min(2, need); i++) {\n                        if (alive[i]) addCity(sel, i);\n                    }\n                }\n\n                vector<float> best(N, 1e30f);\n\n                for (int v = 0; v < N; v++) {\n                    if (alive[v]) {\n                        for (int s : sel) {\n                            best[v] = min(best[v], evalWeight(v, s));\n                        }\n                    }\n                }\n\n                while ((int)sel.size() < need) {\n                    int bv = -1;\n\n                    for (int v = 0; v < N; v++) {\n                        if (alive[v]) {\n                            if (bv == -1 || best[v] < best[bv]) bv = v;\n                        }\n                    }\n\n                    if (bv == -1) break;\n\n                    addCity(sel, bv);\n\n                    for (int v = 0; v < N; v++) {\n                        if (alive[v]) {\n                            best[v] = min(best[v], evalWeight(v, bv));\n                        }\n                    }\n                }\n            }\n\n            for (int v : sel) gid[v] = gr;\n        }\n\n        return gid;\n    }\n\n    void kdRec(vector<int> cities, vector<int> gids, vector<int>& assign, int depth, int mode, mt19937& rr) {\n        if (gids.size() == 1) {\n            int g = gids[0];\n            for (int c : cities) assign[c] = g;\n            return;\n        }\n\n        int n = (int)cities.size();\n\n        double minx = 1e100, maxx = -1e100;\n        double miny = 1e100, maxy = -1e100;\n\n        for (int c : cities) {\n            minx = min(minx, cx[c]);\n            maxx = max(maxx, cx[c]);\n            miny = min(miny, cy[c]);\n            maxy = max(maxy, cy[c]);\n        }\n\n        double rxr = maxx - minx;\n        double ryr = maxy - miny;\n\n        int axis;\n\n        if (mode % 3 == 0) axis = (rxr >= ryr ? 0 : 1);\n        else if (mode % 3 == 1) axis = depth & 1;\n        else axis = (rxr < ryr ? 0 : 1);\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            double ka = axis == 0 ? cx[a] : cy[a];\n            double kb = axis == 0 ? cx[b] : cy[b];\n\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        vector<int> order = gids;\n\n        if (mode >= 3) {\n            shuffle(order.begin(), order.end(), rr);\n        } else if (mode == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] > G[b];\n                return a < b;\n            });\n        } else if (mode == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] < G[b];\n                return a < b;\n            });\n        }\n\n        vector<char> dp(n + 1, 0);\n        vector<int> parS(n + 1, -1), parG(n + 1, -1);\n\n        dp[0] = 1;\n\n        for (int g : order) {\n            int s = G[g];\n\n            for (int sum = n - s; sum >= 0; sum--) {\n                if (dp[sum] && !dp[sum + s]) {\n                    dp[sum + s] = 1;\n                    parS[sum + s] = sum;\n                    parG[sum + s] = g;\n                }\n            }\n        }\n\n        int target = n / 2;\n        int best = -1;\n        int bd = 1e9;\n\n        for (int s = 1; s < n; s++) {\n            if (dp[s]) {\n                int d = abs(s - target);\n\n                if (d < bd) {\n                    bd = d;\n                    best = s;\n                }\n            }\n        }\n\n        if (best == -1) best = G[gids[0]];\n\n        vector<char> selected(M, 0);\n        int cur = best;\n\n        while (cur > 0) {\n            int g = parG[cur];\n            if (g < 0) break;\n            selected[g] = 1;\n            cur = parS[cur];\n        }\n\n        vector<int> leftG, rightG;\n\n        for (int g : gids) {\n            if (selected[g]) leftG.push_back(g);\n            else rightG.push_back(g);\n        }\n\n        if (leftG.empty() || rightG.empty()) {\n            leftG.clear();\n            rightG.clear();\n\n            int acc = 0;\n            for (int g : gids) {\n                if (acc + G[g] <= best && leftG.empty() == false) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else if (acc < best) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else {\n                    rightG.push_back(g);\n                }\n            }\n\n            if (leftG.empty() || rightG.empty()) {\n                leftG = {gids[0]};\n                rightG.assign(gids.begin() + 1, gids.end());\n                best = G[gids[0]];\n            }\n        }\n\n        bool flip = (mode >= 3 && ((depth + mode) & 1));\n\n        vector<int> leftC, rightC;\n\n        if (!flip) {\n            leftC.assign(cities.begin(), cities.begin() + best);\n            rightC.assign(cities.begin() + best, cities.end());\n        } else {\n            leftC.assign(cities.end() - best, cities.end());\n            rightC.assign(cities.begin(), cities.end() - best);\n        }\n\n        kdRec(leftC, leftG, assign, depth + 1, mode, rr);\n        kdRec(rightC, rightG, assign, depth + 1, mode, rr);\n    }\n\n    vector<int> kdCandidate(int mode) {\n        vector<int> cities(N), gids(M), assign(N, -1);\n\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        mt19937 rr(1000 + mode * 97);\n        kdRec(cities, gids, assign, 0, mode, rr);\n\n        return assign;\n    }\n\n    void buildBonus() {\n        bonusMat.assign(N * N, 0.0f);\n        bonusAdj.assign(N, {});\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        double coef = 0.20 + 0.30 * unc;\n        double cap = 2.0e6;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (!known[ID(i, j)]) continue;\n\n                double d = distBase[ID(i, j)];\n                float b = (float)min(cap, coef * d * d);\n\n                bonusMat[ID(i, j)] = bonusMat[ID(j, i)] = b;\n                bonusAdj[i].push_back({j, b});\n                bonusAdj[j].push_back({i, b});\n            }\n        }\n    }\n\n    void localSearch(vector<int>& gid, int maxPass) {\n        vector<double> sxg(M, 0.0), syg(M, 0.0), sqg(M, 0.0);\n\n        for (int i = 0; i < N; i++) {\n            int g = gid[i];\n\n            sxg[g] += cx[i];\n            syg[g] += cy[i];\n            sqg[g] += norm2[i];\n        }\n\n        vector<float> ktg((size_t)N * M, 0.0f);\n\n        for (int u = 0; u < N; u++) {\n            for (auto [v, b] : bonusAdj[u]) {\n                if (u < v) {\n                    ktg[(size_t)u * M + gid[v]] += b;\n                    ktg[(size_t)v * M + gid[u]] += b;\n                }\n            }\n        }\n\n        auto deltaReplace = [&](int g, int out, int in) -> double {\n            double nsx = sxg[g] - cx[out] + cx[in];\n            double nsy = syg[g] - cy[out] + cy[in];\n\n            double oldS2 = sxg[g] * sxg[g] + syg[g] * syg[g];\n            double newS2 = nsx * nsx + nsy * nsy;\n\n            return (-norm2[out] + norm2[in]) - (newS2 - oldS2) / G[g];\n        };\n\n        auto applySwap = [&](int i, int j, int A, int B) {\n            sxg[A] += -cx[i] + cx[j];\n            syg[A] += -cy[i] + cy[j];\n            sqg[A] += -norm2[i] + norm2[j];\n\n            sxg[B] += -cx[j] + cx[i];\n            syg[B] += -cy[j] + cy[i];\n            sqg[B] += -norm2[j] + norm2[i];\n\n            for (auto [t, b] : bonusAdj[i]) {\n                ktg[(size_t)t * M + A] -= b;\n                ktg[(size_t)t * M + B] += b;\n            }\n\n            for (auto [t, b] : bonusAdj[j]) {\n                ktg[(size_t)t * M + B] -= b;\n                ktg[(size_t)t * M + A] += b;\n            }\n\n            gid[i] = B;\n            gid[j] = A;\n        };\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            int swaps = 0;\n\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    int A = gid[i];\n                    int B = gid[j];\n\n                    if (A == B) continue;\n\n                    double ds = deltaReplace(A, i, j) + deltaReplace(B, j, i);\n\n                    float bij = bonusMat[ID(i, j)];\n                    double before = ktg[(size_t)i * M + A] + ktg[(size_t)j * M + B];\n                    double after = ktg[(size_t)i * M + B] + ktg[(size_t)j * M + A] - 2.0 * bij;\n\n                    double delta = ds - (after - before);\n\n                    if (delta < -1e-7) {\n                        applySwap(i, j, A, B);\n                        swaps++;\n                    }\n                }\n            }\n\n            if (swaps == 0) break;\n        }\n    }\n\n    vector<int> makeGrouping() {\n        if (M == 1) return vector<int>(N, 0);\n\n        struct Cand {\n            double score;\n            vector<int> gid;\n        };\n\n        vector<Cand> top;\n        const int TOPK = 8;\n\n        auto addCand = [&](vector<int> gid) {\n            double sc = evalCandidate(gid);\n            if (sc > 1e90) return;\n\n            if ((int)top.size() < TOPK) {\n                top.push_back({sc, move(gid)});\n            } else {\n                int worst = 0;\n\n                for (int i = 1; i < (int)top.size(); i++) {\n                    if (top[i].score > top[worst].score) worst = i;\n                }\n\n                if (sc < top[worst].score) {\n                    top[worst] = {sc, move(gid)};\n                }\n            }\n        };\n\n        auto cityOrders = makeCityOrders();\n        auto groupOrders = makeGroupOrders();\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                addCand(partitionCandidate(co, go));\n            }\n\n            for (int mode = 0; mode < 3; mode++) {\n                auto go = gapGreedyGroupOrder(co, mode);\n                addCand(partitionCandidate(co, go));\n            }\n        }\n\n        auto pairs = makeSortedPairs();\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n\n        vector<int> asc = ids;\n        vector<int> desc = ids;\n\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        addCand(greedyCandidate(asc, pairs));\n        addCand(greedyCandidate(ids, pairs));\n        addCand(greedyCandidate(desc, pairs));\n\n        for (int mode = 0; mode < 6; mode++) {\n            addCand(kdCandidate(mode));\n        }\n\n        if (top.empty()) {\n            auto co = cityOrders[0];\n            auto go = groupOrders[0];\n            return partitionCandidate(co, go);\n        }\n\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        buildBonus();\n\n        vector<int> best = top[0].gid;\n        double bestScore = top[0].score;\n\n        int lim = min(6, (int)top.size());\n        int passes = (M > 250 ? 12 : 9);\n\n        for (int i = 0; i < lim; i++) {\n            vector<int> gid = top[i].gid;\n\n            localSearch(gid, passes);\n\n            double sc = evalCandidate(gid);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = move(gid);\n            }\n        }\n\n        return best;\n    }\n\n    vector<vector<int>> buildGroups(const vector<int>& gid) {\n        vector<vector<int>> groups(M);\n\n        for (int k = 0; k < M; k++) {\n            groups[k].reserve(G[k]);\n        }\n\n        for (int i = 0; i < N; i++) {\n            groups[gid[i]].push_back(i);\n        }\n\n        bool ok = true;\n\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) ok = false;\n        }\n\n        if (!ok) {\n            groups.assign(M, {});\n\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n\n            int pos = 0;\n\n            for (int k = 0; k < M; k++) {\n                for (int t = 0; t < G[k]; t++) {\n                    groups[k].push_back(ids[pos++]);\n                }\n            }\n        }\n\n        return groups;\n    }\n\n    struct FinalTask {\n        double priority;\n        int type; // 0 exact whole group, 1 large-group chunk\n        int group;\n        int chunkIndex;\n        vector<int> subset;\n    };\n\n    void performFinalQueries(\n        vector<vector<int>>& groups,\n        vector<char>& exact,\n        vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        exact.assign(M, 0);\n        exactEdges.assign(M, {});\n\n        vector<FinalTask> tasks;\n        tasks.reserve(1000);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                FinalTask task;\n                task.priority = 1.20 * (g - 1);\n                task.type = 0;\n                task.group = k;\n                task.chunkIndex = 0;\n                task.subset = groups[k];\n\n                tasks.push_back(move(task));\n            } else {\n                vector<int> ord = groups[k];\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                    return a < b;\n                });\n\n                int connector = ord[0];\n                int pos = 1;\n                int chunkIndex = 0;\n\n                while (pos < g) {\n                    int s = min(L - 1, g - pos);\n\n                    if (s >= 2) {\n                        FinalTask task;\n                        task.priority = 0.80 * s;\n                        task.type = 1;\n                        task.group = k;\n                        task.chunkIndex = chunkIndex;\n                        task.subset.reserve(s + 1);\n                        task.subset.push_back(connector);\n\n                        for (int t = 0; t < s; t++) {\n                            task.subset.push_back(ord[pos + t]);\n                        }\n\n                        tasks.push_back(move(task));\n                    }\n\n                    connector = ord[pos + s - 1];\n                    pos += s;\n                    chunkIndex++;\n                }\n            }\n        }\n\n        sort(tasks.begin(), tasks.end(), [](const FinalTask& a, const FinalTask& b) {\n            if (a.priority != b.priority) return a.priority > b.priority;\n            if (a.type != b.type) return a.type < b.type;\n            if (a.chunkIndex != b.chunkIndex) return a.chunkIndex < b.chunkIndex;\n            return a.group < b.group;\n        });\n\n        for (auto& task : tasks) {\n            unsigned long long h = subsetHash(task.subset);\n\n            if (queryCount >= Q && responseMap.find(h) == responseMap.end()) {\n                continue;\n            }\n\n            auto ret = getOrAsk(task.subset);\n            if (ret.empty()) continue;\n\n            addKnownEdges(ret, 2);\n\n            if (task.type == 0) {\n                int k = task.group;\n                int g = (int)groups[k].size();\n\n                if ((int)ret.size() == g - 1) {\n                    exact[k] = 1;\n                    exactEdges[k] = ret;\n                }\n            }\n        }\n\n        if (queryCount >= Q) return;\n\n        vector<int> candGroups;\n        int maxG = 0;\n        vector<vector<int>> ords(M);\n\n        for (int k = 0; k < M; k++) {\n            if (exact[k]) continue;\n\n            int g = (int)groups[k].size();\n            if (g < 3) continue;\n\n            candGroups.push_back(k);\n            ords[k] = groups[k];\n\n            sort(ords[k].begin(), ords[k].end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n\n            maxG = max(maxG, g);\n        }\n\n        for (int variant = 0; variant < 5 && queryCount < Q; variant++) {\n            for (int r = 0; r < maxG && queryCount < Q; r++) {\n                for (int k : candGroups) {\n                    if (queryCount >= Q) break;\n                    if (r >= (int)ords[k].size()) continue;\n\n                    int center = ords[k][r];\n                    auto sub = buildSubsetInGroup(center, groups[k], variant);\n\n                    if ((int)sub.size() < 3) continue;\n\n                    unsigned long long h = subsetHash(sub);\n                    if (usedQueries.count(h)) continue;\n\n                    auto ret = askNew(sub);\n                    addKnownEdges(ret, 2);\n                }\n            }\n        }\n    }\n\n    vector<pair<int,int>> finalPrimEdges(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        vector<pair<int,int>> edges;\n\n        if (n <= 1) return edges;\n\n        vector<float> best(n, 1e30f);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n\n        best[0] = 0.0f;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) {\n                    v = i;\n                }\n            }\n\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                edges.push_back({vs[v], vs[par[v]]});\n            }\n\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    int a = vs[v];\n                    int b = vs[u];\n\n                    float w = distBase[ID(a, b)];\n                    unsigned char lv = known[ID(a, b)];\n\n                    if (lv >= 2) w *= knownFinalGroupFactor;\n                    else if (lv == 1) w *= knownFinalFactor;\n\n                    if (w < best[u]) {\n                        best[u] = w;\n                        par[u] = v;\n                    }\n                }\n            }\n        }\n\n        return edges;\n    }\n\n    void outputAnswer(\n        const vector<vector<int>>& groups,\n        const vector<char>& exact,\n        const vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        vector<vector<pair<int,int>>> ansEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n\n            if (g <= 1) {\n                ansEdges[k] = {};\n            } else if (g == 2) {\n                ansEdges[k] = {{groups[k][0], groups[k][1]}};\n            } else if (exact[k]) {\n                ansEdges[k] = exactEdges[k];\n            } else {\n                ansEdges[k] = finalPrimEdges(groups[k]);\n            }\n        }\n\n        cout << \"!\\n\";\n\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << '\\n';\n\n            for (auto [a, b] : ansEdges[k]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n\n        cout.flush();\n    }\n\n    void solve() {\n        readInput();\n        computeDistances();\n\n        usedQueries.reserve(Q * 4 + 10);\n        responseMap.reserve(Q * 4 + 10);\n\n        int reserveQ = reserveFinalQueryCount();\n        int preBudget = max(0, Q - reserveQ);\n\n        performPrequeries(preBudget);\n\n        vector<int> gid = makeGrouping();\n        auto groups = buildGroups(gid);\n\n        vector<char> exact;\n        vector<vector<pair<int,int>>> exactEdges;\n\n        performFinalQueries(groups, exact, exactEdges);\n\n        outputAnswer(groups, exact, exactEdges);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.solve();\n\n    return 0;\n}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 20;\nstatic const int MAXV = 400;\nstatic const int INF = 1e9;\n\nstruct Grid {\n    uint32_t row[MAXN];\n    uint32_t col[MAXN];\n    int cnt;\n    uint64_t hash;\n    Grid() {\n        memset(row, 0, sizeof(row));\n        memset(col, 0, sizeof(col));\n        cnt = 0;\n        hash = 0;\n    }\n};\n\nstruct Solver {\n    int N, M, V;\n    int LIMIT;\n    uint32_t FULL;\n    vector<int> pos;\n\n    int rr[MAXV], cc[MAXV];\n    int mv[MAXV][4];\n    int targetIdx[MAXV];\n\n    int dr[4] = {-1, 1, 0, 0};\n    int dc[4] = {0, 0, -1, 1};\n    int opp[4] = {1, 0, 3, 2};\n\n    bool future[45][MAXV];\n    int adjVal[45][MAXV];\n\n    uint64_t zob[MAXV];\n    uint64_t rngState;\n\n    int seen[MAXV], distArr[MAXV], prevArr[MAXV], que[MAXV];\n    unsigned char actArr[MAXV];\n    int stamp = 1;\n\n    int validBits[45], inBits[45];\n    bool isPlanOpt[45][16];\n    bool isPlanFOpt[45][16];\n    vector<int> planOpts[45];\n    vector<int> planFOpts[45];\n\n    struct Plan2Opt {\n        int mask;\n        int leave;\n    };\n    vector<Plan2Opt> plan2Opts[45];\n\n    chrono::steady_clock::time_point startTime;\n\n    vector<string> candidates;\n    string pureFallback;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    uint64_t rnd() {\n        uint64_t z = (rngState += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    inline char enc(int type, int d) const {\n        return char(type * 4 + d);\n    }\n\n    inline bool isBlocked(const Grid& g, int v) const {\n        return (g.row[rr[v]] >> cc[v]) & 1u;\n    }\n\n    inline void setBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (!(g.row[r] & br)) {\n            g.row[r] |= br;\n            g.col[c] |= (1u << r);\n            g.cnt++;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void clearBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (g.row[r] & br) {\n            g.row[r] &= ~br;\n            g.col[c] &= ~(1u << r);\n            g.cnt--;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void toggleBlock(Grid& g, int v) {\n        if (isBlocked(g, v)) clearBlock(g, v);\n        else setBlock(g, v);\n    }\n\n    inline int highestBit(uint32_t x) const {\n        return 31 - __builtin_clz(x);\n    }\n\n    inline int slideDestRC(const Grid& g, int r, int c, int d) const {\n        if (d == 0) {\n            uint32_t mask = g.col[c] & ((1u << r) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return (b + 1) * N + c;\n            }\n            return c;\n        } else if (d == 1) {\n            uint32_t mask = g.col[c] & (FULL ^ ((1u << (r + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return (b - 1) * N + c;\n            }\n            return (N - 1) * N + c;\n        } else if (d == 2) {\n            uint32_t mask = g.row[r] & ((1u << c) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return r * N + (b + 1);\n            }\n            return r * N;\n        } else {\n            uint32_t mask = g.row[r] & (FULL ^ ((1u << (c + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return r * N + (b - 1);\n            }\n            return r * N + (N - 1);\n        }\n    }\n\n    inline int slideDest(const Grid& g, int v, int d) const {\n        return slideDestRC(g, rr[v], cc[v], d);\n    }\n\n    void nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n    }\n\n    int bfsSearch(const Grid& g, int s, int t, bool storePath) {\n        if (s < 0 || t < 0) return INF;\n        if (isBlocked(g, s) || isBlocked(g, t)) return INF;\n        if (s == t) return 0;\n\n        nextStamp();\n        int head = 0, tail = 0;\n        que[tail++] = s;\n        seen[s] = stamp;\n        distArr[s] = 0;\n        if (storePath) prevArr[s] = -1;\n\n        while (head < tail) {\n            int v = que[head++];\n            int nd = distArr[v] + 1;\n            int r = rr[v], c = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDestRC(g, r, c, d);\n                if (to == v) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(1, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[v][d];\n                if (to < 0 || isBlocked(g, to)) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(0, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n        }\n        return INF;\n    }\n\n    int bfsDist(const Grid& g, int s, int t) {\n        return bfsSearch(g, s, t, false);\n    }\n\n    bool bfsPath(const Grid& g, int s, int t, string& out) {\n        int d = bfsSearch(g, s, t, true);\n        if (d >= INF) return false;\n        out.clear();\n        int v = t;\n        while (v != s) {\n            out.push_back(char(actArr[v]));\n            v = prevArr[v];\n            if (v < 0) return false;\n        }\n        reverse(out.begin(), out.end());\n        return true;\n    }\n\n    int gridValue(const Grid& g, int stage) const {\n        if (stage < 0) stage = 0;\n        if (stage >= M) stage = M - 1;\n        int val = 0;\n        for (int r = 0; r < N; r++) {\n            uint32_t bits = g.row[r];\n            while (bits) {\n                int c = __builtin_ctz(bits);\n                val += adjVal[stage][r * N + c];\n                bits &= bits - 1;\n            }\n        }\n        return val;\n    }\n\n    void init() {\n        V = N * N;\n        LIMIT = 2 * N * M;\n        FULL = (1u << N) - 1u;\n\n        for (int v = 0; v < V; v++) {\n            rr[v] = v / N;\n            cc[v] = v % N;\n            targetIdx[v] = -1;\n        }\n        for (int i = 0; i < M; i++) targetIdx[pos[i]] = i;\n\n        for (int v = 0; v < V; v++) {\n            for (int d = 0; d < 4; d++) {\n                int nr = rr[v] + dr[d];\n                int nc = cc[v] + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) mv[v][d] = nr * N + nc;\n                else mv[v][d] = -1;\n            }\n        }\n\n        memset(future, 0, sizeof(future));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                future[k][pos[t]] = true;\n            }\n        }\n\n        memset(adjVal, 0, sizeof(adjVal));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                int w = max(1, 8 - (t - k));\n                for (int d = 0; d < 4; d++) {\n                    int v = mv[pos[t]][d];\n                    if (v >= 0) adjVal[k][v] += w;\n                }\n            }\n        }\n\n        rngState = 1234567891234567ULL;\n        for (int p : pos) {\n            rngState ^= uint64_t(p + 1009) * 0x9e3779b97f4a7c15ULL;\n            rnd();\n        }\n        for (int i = 0; i < V; i++) zob[i] = rnd();\n\n        memset(seen, 0, sizeof(seen));\n        memset(isPlanOpt, 0, sizeof(isPlanOpt));\n        memset(isPlanFOpt, 0, sizeof(isPlanFOpt));\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            inBits[k] = 0;\n            validBits[k] = 0;\n            for (int d = 0; d < 4; d++) {\n                int q = mv[p][d];\n                if (q < 0) continue;\n                inBits[k] |= (1 << d);\n                if (!future[k][q]) validBits[k] |= (1 << d);\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~validBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planOpts[k].push_back(sub);\n                isPlanOpt[k][sub] = true;\n            }\n            if (planOpts[k].empty()) {\n                planOpts[k].push_back(0);\n                isPlanOpt[k][0] = true;\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~inBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planFOpts[k].push_back(sub);\n                isPlanFOpt[k][sub] = true;\n            }\n            if (planFOpts[k].empty()) {\n                planFOpts[k].push_back(0);\n                isPlanFOpt[k][0] = true;\n            }\n\n            for (int m : planOpts[k]) {\n                plan2Opts[k].push_back({m, -1});\n                for (int d = 0; d < 4; d++) {\n                    if (mv[p][d] < 0) continue;\n                    if (m & (1 << d)) continue;\n                    plan2Opts[k].push_back({m, d});\n                }\n            }\n        }\n    }\n\n    string makePureMoves() {\n        string s;\n        int r = rr[pos[0]], c = cc[pos[0]];\n\n        for (int k = 1; k < M; k++) {\n            int gr = rr[pos[k]], gc = cc[pos[k]];\n            while (r < gr) s.push_back(enc(0, 1)), r++;\n            while (r > gr) s.push_back(enc(0, 0)), r--;\n            while (c < gc) s.push_back(enc(0, 3)), c++;\n            while (c > gc) s.push_back(enc(0, 2)), c--;\n        }\n        return s;\n    }\n\n    int firstCompletionPrefix(const string& acts) {\n        if (M <= 1) return 0;\n\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return -1;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return -1;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(g, p, d);\n            } else {\n                int to = mv[p][d];\n                if (to < 0) return -1;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                nxt++;\n                if (nxt == M) return t + 1;\n            }\n        }\n        return -1;\n    }\n\n    void addCandidate(const string& acts) {\n        int p = firstCompletionPrefix(acts);\n        if (p < 0 || p > LIMIT) return;\n        candidates.push_back(acts.substr(0, p));\n    }\n\n    string greedyDelete(string a, double endTime = 1.90) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return \"\";\n        a.resize(pref);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (size_t i = 0; i < a.size();) {\n                if (elapsed() > endTime) return a;\n                string b = a;\n                b.erase(b.begin() + i);\n                int p = firstCompletionPrefix(b);\n                if (p >= 0 && p <= LIMIT) {\n                    b.resize(p);\n                    a.swap(b);\n                    changed = true;\n                    if (i > 0) --i;\n                    if (i > a.size()) i = a.size();\n                } else {\n                    ++i;\n                }\n            }\n            if (!changed) break;\n        }\n\n        for (int w = 2; w <= 3; w++) {\n            bool any = true;\n            while (any) {\n                any = false;\n                for (size_t i = 0; i + w <= a.size();) {\n                    if (elapsed() > endTime + 0.02) return a;\n                    string b = a;\n                    b.erase(i, w);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        a.swap(b);\n                        any = true;\n                        if (i > 0) --i;\n                        if (i > a.size()) i = a.size();\n                    } else {\n                        ++i;\n                    }\n                }\n            }\n        }\n\n        return a;\n    }\n\n    string replaceImprove(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        a = greedyDelete(a, min(endTime, 1.91));\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (int i = 0; i < (int)a.size() && elapsed() < endTime; i++) {\n                string bestLocal;\n                int bestLen = (int)a.size();\n\n                for (int code = 0; code < 12 && elapsed() < endTime; code++) {\n                    if (code == (unsigned char)a[i]) continue;\n\n                    string b = a;\n                    b[i] = char(code);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        } else if ((int)b.size() == (int)a.size()) {\n                            int L = max(0, i - 6);\n                            int R = min((int)b.size(), i + 12);\n                            for (int j = L; j < R && elapsed() < endTime; j++) {\n                                string c = b;\n                                c.erase(c.begin() + j);\n                                int pp = firstCompletionPrefix(c);\n                                if (pp >= 0 && pp <= LIMIT) {\n                                    c.resize(pp);\n                                    if ((int)c.size() < bestLen) {\n                                        bestLen = (int)c.size();\n                                        bestLocal = c;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                if (i + 1 < (int)a.size() && elapsed() < endTime) {\n                    string b = a;\n                    swap(b[i], b[i + 1]);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        }\n                    }\n                }\n\n                if (!bestLocal.empty() && bestLen < (int)a.size()) {\n                    string del = greedyDelete(bestLocal, min(endTime, 1.93));\n                    int pp = firstCompletionPrefix(del);\n                    if (pp >= 0 && pp <= LIMIT) {\n                        del.resize(pp);\n                        if (del.size() < bestLocal.size()) bestLocal.swap(del);\n                    }\n                    if (bestLocal.size() < a.size()) {\n                        a.swap(bestLocal);\n                        changed = true;\n                        i = max(-1, i - 6);\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n        return a;\n    }\n\n    bool sameGrid(const Grid& a, const Grid& b) const {\n        for (int r = 0; r < N; r++) {\n            if (a.row[r] != b.row[r]) return false;\n        }\n        return true;\n    }\n\n    struct SegInfo {\n        int k, l, r;\n        Grid sg, eg;\n    };\n\n    bool simulateSegments(const string& acts, vector<SegInfo>& segs) {\n        segs.clear();\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n        int segL = 0;\n        Grid sg = g;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return false;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return false;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(g, p, d);\n            } else {\n                int to = mv[p][d];\n                if (to < 0) return false;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                segs.push_back({nxt - 1, segL, t + 1, sg, g});\n                nxt++;\n                segL = t + 1;\n                sg = g;\n                if (nxt == M) return true;\n            }\n        }\n        return nxt == M;\n    }\n\n    string optimizeOneSegment(const SegInfo& seg, const string& orig, double endTime) {\n        if ((int)orig.size() <= 1) return orig;\n        if (elapsed() > endTime) return orig;\n\n        const int CAP = 10;\n        array<int, MAXV> mark;\n        mark.fill(-1);\n        vector<int> cells;\n\n        auto addCell = [&](int v) {\n            if (v < 0) return;\n            if (mark[v] == -1) {\n                mark[v] = (int)cells.size();\n                cells.push_back(v);\n            }\n        };\n\n        Grid tg = seg.sg;\n        int p = pos[seg.k];\n        int goal = pos[seg.k + 1];\n        vector<int> stops;\n        stops.push_back(p);\n\n        for (unsigned char ch : orig) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(tg, to)) return orig;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(tg, p, d);\n            } else {\n                int q = mv[p][d];\n                if (q < 0) return orig;\n                addCell(q);\n                toggleBlock(tg, q);\n            }\n            stops.push_back(p);\n        }\n\n        if (p != goal) return orig;\n        if (!sameGrid(tg, seg.eg)) return orig;\n\n        for (int v = 0; v < V; v++) {\n            if (isBlocked(seg.sg, v) != isBlocked(seg.eg, v)) addCell(v);\n        }\n\n        if ((int)cells.size() > CAP) return orig;\n\n        array<char, MAXV> exSeen{};\n        vector<pair<int, int>> extras;\n\n        for (int st : stops) {\n            for (int d = 0; d < 4; d++) {\n                int q = mv[st][d];\n                if (q < 0) continue;\n                if (mark[q] != -1 || exSeen[q]) continue;\n                exSeen[q] = 1;\n\n                int sc = adjVal[seg.k][q];\n                if (isBlocked(seg.sg, q)) sc += 50;\n                if (isBlocked(seg.eg, q)) sc += 20;\n                if (targetIdx[q] >= seg.k + 1) sc -= 5;\n                extras.push_back({-sc, q});\n            }\n        }\n\n        sort(extras.begin(), extras.end());\n        for (auto [negSc, q] : extras) {\n            if ((int)cells.size() >= CAP) break;\n            if (-negSc <= 0) continue;\n            addCell(q);\n        }\n\n        int K = (int)cells.size();\n        int S = 1 << K;\n\n        array<int, MAXV> cid;\n        cid.fill(-1);\n        for (int i = 0; i < K; i++) cid[cells[i]] = i;\n\n        int endMask = 0;\n        for (int i = 0; i < K; i++) {\n            int v = cells[i];\n            if (isBlocked(seg.sg, v) != isBlocked(seg.eg, v)) endMask |= (1 << i);\n        }\n\n        vector<array<uint32_t, MAXN>> rows(S), cols(S);\n        for (int r = 0; r < N; r++) rows[0][r] = seg.sg.row[r];\n        for (int c = 0; c < N; c++) cols[0][c] = seg.sg.col[c];\n\n        for (int m = 1; m < S; m++) {\n            int b = __builtin_ctz((unsigned)m);\n            int pm = m & (m - 1);\n            rows[m] = rows[pm];\n            cols[m] = cols[pm];\n\n            int v = cells[b];\n            rows[m][rr[v]] ^= (1u << cc[v]);\n            cols[m][cc[v]] ^= (1u << rr[v]);\n        }\n\n        auto blockedM = [&](int mask, int v) -> bool {\n            return (rows[mask][rr[v]] >> cc[v]) & 1u;\n        };\n\n        if (blockedM(0, pos[seg.k])) return orig;\n        if (blockedM(endMask, goal)) return orig;\n\n        auto slideM = [&](int mask, int v, int d) -> int {\n            int r = rr[v], c = cc[v];\n            if (d == 0) {\n                uint32_t bits = cols[mask][c] & ((1u << r) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return (b + 1) * N + c;\n                }\n                return c;\n            } else if (d == 1) {\n                uint32_t bits = cols[mask][c] & (FULL ^ ((1u << (r + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return (b - 1) * N + c;\n                }\n                return (N - 1) * N + c;\n            } else if (d == 2) {\n                uint32_t bits = rows[mask][r] & ((1u << c) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return r * N + (b + 1);\n                }\n                return r * N;\n            } else {\n                uint32_t bits = rows[mask][r] & (FULL ^ ((1u << (c + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return r * N + (b - 1);\n                }\n                return r * N + (N - 1);\n            }\n        };\n\n        int total = S * V;\n        vector<int> dist(total, -1), par(total, -1);\n        vector<unsigned char> pact(total, 255);\n        vector<int> q;\n        q.reserve(min(total, 200000));\n\n        int startState = pos[seg.k];\n        int goalState = endMask * V + goal;\n        dist[startState] = 0;\n        q.push_back(startState);\n\n        bool found = (startState == goalState);\n        int head = 0;\n        int maxDepth = (int)orig.size() - 1;\n\n        auto tryAdd = [&](int id, int nm, int np, unsigned char ac) -> bool {\n            if (np == goal && nm != endMask) return false;\n            int nid = nm * V + np;\n            if (dist[nid] != -1) return false;\n\n            dist[nid] = dist[id] + 1;\n            par[nid] = id;\n            pact[nid] = ac;\n\n            if (nid == goalState) return true;\n            q.push_back(nid);\n            return false;\n        };\n\n        while (head < (int)q.size() && !found) {\n            if (elapsed() > endTime) return orig;\n            int id = q[head++];\n            int mask = id / V;\n            int v = id - mask * V;\n\n            if (dist[id] >= maxDepth) continue;\n\n            int nd = dist[id] + 1;\n            (void)nd;\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = slideM(mask, v, d);\n                if (to == v) continue;\n                found = tryAdd(id, mask, to, enc(1, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = mv[v][d];\n                if (to < 0 || blockedM(mask, to)) continue;\n                found = tryAdd(id, mask, to, enc(0, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int cell = mv[v][d];\n                if (cell < 0) continue;\n                int ci = cid[cell];\n                if (ci < 0) continue;\n                int nm = mask ^ (1 << ci);\n                found = tryAdd(id, nm, v, enc(2, d));\n            }\n        }\n\n        if (!found || dist[goalState] < 0) return orig;\n        if (dist[goalState] >= (int)orig.size()) return orig;\n\n        string res;\n        int id = goalState;\n        while (id != startState) {\n            res.push_back(char(pact[id]));\n            id = par[id];\n            if (id < 0) return orig;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    string segmentOptimize(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n\n            vector<SegInfo> segs;\n            if (!simulateSegments(a, segs)) return a;\n            if ((int)segs.size() != M - 1) return a;\n\n            for (int si = 0; si < (int)segs.size() && elapsed() < endTime; si++) {\n                const auto& sg = segs[si];\n                string orig = a.substr(sg.l, sg.r - sg.l);\n                string rep = optimizeOneSegment(sg, orig, endTime);\n                if (rep.size() < orig.size()) {\n                    string b;\n                    b.reserve(a.size() - orig.size() + rep.size());\n                    b.append(a, 0, sg.l);\n                    b += rep;\n                    b.append(a, sg.r, string::npos);\n\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        a.swap(b);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return a;\n    }\n\n    int dirToward(int a, int b) const {\n        int vr = rr[b] - rr[a];\n        int vc = cc[b] - cc[a];\n        if (abs(vr) >= abs(vc)) {\n            if (vr < 0) return 0;\n            if (vr > 0) return 1;\n        }\n        if (vc < 0) return 2;\n        if (vc > 0) return 3;\n        return 0;\n    }\n\n    int evalPlan(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int dist = bfsDist(g, p, pos[k + 1]);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    bool buildFromMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            int bestDir = -1;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    if (isBlocked(tg, p)) continue;\n                    setBlock(tg, p);\n\n                    int dist = bfsDist(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                acts.push_back(enc(0, bestDir));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> makeZeroMasks() {\n        return vector<int>(M - 1, 0);\n    }\n\n    vector<int> makeDenseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeExitMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int m = validBits[k];\n            int ex = dirToward(pos[k], pos[k + 1]);\n            m &= ~(1 << ex);\n\n            while (!isPlanOpt[k][m]) {\n                bool removed = false;\n                for (int d = 0; d < 4; d++) {\n                    if (m & (1 << d)) {\n                        m &= ~(1 << d);\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) {\n                    m = 0;\n                    break;\n                }\n            }\n            masks[k] = m;\n        }\n        return masks;\n    }\n\n    vector<int> makeSparseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 100;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = abs(pc - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeValueMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n            for (int m : planOpts[k]) {\n                int val = 0;\n                int pc = __builtin_popcount((unsigned)m);\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q >= 0) val += adjVal[k][q];\n                }\n                int sc = val * 4 - pc * 5;\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planOpts[k].size());\n            masks[k] = planOpts[k][id];\n        }\n        return masks;\n    }\n\n    pair<int, vector<int>> coordinateDescent(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlan(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlan(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    int evalPlan2(const vector<int>& masks, const vector<int>& leaves, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p) || isBlocked(g, goal)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int ld = leaves[k];\n            if (ld >= 0) {\n                int nb = mv[p][ld];\n                if (nb < 0 || isBlocked(g, nb)) return INF;\n                cost++;\n                setBlock(g, p);\n                cost++;\n                if (cost >= cutoff) return cost;\n\n                int dist = bfsDist(g, nb, goal);\n                if (dist >= INF) return INF;\n                cost += dist;\n            } else {\n                int dist = bfsDist(g, p, goal);\n                if (dist >= INF) return INF;\n                cost += dist;\n            }\n\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    vector<int> makeGreedyLeaves(const vector<int>& masks, double beta) {\n        vector<int> leaves(M - 1, -1);\n        Grid g;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) break;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) setBlock(g, q);\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n            int bestDir = -1;\n\n            for (int d = 0; d < 4; d++) {\n                int nb = mv[p][d];\n                if (nb < 0 || isBlocked(g, nb)) continue;\n\n                Grid tg = g;\n                setBlock(tg, p);\n                int dist = bfsDist(tg, nb, goal);\n                if (dist >= INF) continue;\n\n                double score = double(2 + dist) - beta;\n                if (score < bestScore - 1e-9) {\n                    bestScore = score;\n                    bestDir = d;\n                }\n            }\n\n            leaves[k] = bestDir;\n            if (bestDir >= 0) setBlock(g, p);\n        }\n\n        return leaves;\n    }\n\n    vector<int> makeTowardLeaves(const vector<int>& masks) {\n        vector<int> leaves(M - 1, -1);\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int d0 = dirToward(pos[k], pos[k + 1]);\n            if (mv[p][d0] >= 0 && !(masks[k] & (1 << d0))) {\n                leaves[k] = d0;\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    if (mv[p][d] >= 0 && !(masks[k] & (1 << d))) {\n                        leaves[k] = d;\n                        break;\n                    }\n                }\n            }\n        }\n        return leaves;\n    }\n\n    vector<int> makeRandomLeaves(const vector<int>& masks) {\n        vector<int> leaves(M - 1, -1);\n        for (int k = 0; k < M - 1; k++) {\n            vector<int> opts;\n            opts.push_back(-1);\n            opts.push_back(-1);\n            int p = pos[k];\n            for (int d = 0; d < 4; d++) {\n                if (mv[p][d] >= 0 && !(masks[k] & (1 << d))) opts.push_back(d);\n            }\n            leaves[k] = opts[rnd() % opts.size()];\n        }\n        return leaves;\n    }\n\n    struct Plan2Result {\n        int cost;\n        vector<int> masks;\n        vector<int> leaves;\n    };\n\n    Plan2Result coordinateDescent2(vector<int> masks, vector<int> leaves, int maxPass, double endTime) {\n        int curr = evalPlan2(masks, leaves);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldM = masks[k];\n                int oldL = leaves[k];\n                int bestM = oldM;\n                int bestL = oldL;\n                int bestCost = curr;\n\n                for (const auto& op : plan2Opts[k]) {\n                    if (op.mask == oldM && op.leave == oldL) continue;\n                    masks[k] = op.mask;\n                    leaves[k] = op.leave;\n                    int c = evalPlan2(masks, leaves, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestM = op.mask;\n                        bestL = op.leave;\n                    }\n                }\n\n                masks[k] = bestM;\n                leaves[k] = bestL;\n\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks, leaves};\n    }\n\n    bool buildPlan2(const vector<int>& masks, const vector<int>& leaves, string& acts) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int ld = leaves[k];\n            if (ld >= 0) {\n                int nb = mv[p][ld];\n                if (nb < 0 || isBlocked(g, nb)) return false;\n\n                acts.push_back(enc(0, ld));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[ld]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            } else {\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    int distMaybeBlockedGoal(const Grid& g, int s, int goal) {\n        if (s < 0 || goal < 0) return INF;\n        if (isBlocked(g, s)) return INF;\n\n        if (!isBlocked(g, goal)) return bfsDist(g, s, goal);\n\n        int best = INF;\n        for (int gd = 0; gd < 4; gd++) {\n            int nb = mv[goal][gd];\n            if (nb < 0 || isBlocked(g, nb)) continue;\n            int d = bfsDist(g, s, nb);\n            if (d < INF) best = min(best, d + 2);\n        }\n        return best;\n    }\n\n    bool pathMaybeBlockedGoal(Grid& g, int s, int goal, string& out) {\n        out.clear();\n        if (s < 0 || goal < 0) return false;\n        if (isBlocked(g, s)) return false;\n\n        if (!isBlocked(g, goal)) {\n            return bfsPath(g, s, goal, out);\n        }\n\n        int best = INF;\n        int bestNb = -1;\n        int bestEnter = -1;\n\n        for (int gd = 0; gd < 4; gd++) {\n            int nb = mv[goal][gd];\n            if (nb < 0 || isBlocked(g, nb)) continue;\n            int d = bfsDist(g, s, nb);\n            if (d < best) {\n                best = d;\n                bestNb = nb;\n                bestEnter = opp[gd];\n            }\n        }\n\n        if (bestNb < 0) return false;\n\n        string path;\n        if (!bfsPath(g, s, bestNb, path)) return false;\n        out += path;\n\n        out.push_back(enc(2, bestEnter));\n        clearBlock(g, goal);\n        out.push_back(enc(0, bestEnter));\n        return true;\n    }\n\n    int evalPlanF(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & inBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            bool goalWasBlocked = isBlocked(g, goal);\n            int dist = distMaybeBlockedGoal(g, p, goal);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n\n            if (goalWasBlocked) clearBlock(g, goal);\n        }\n\n        return cost;\n    }\n\n    pair<int, vector<int>> coordinateDescentF(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlanF(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planFOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlanF(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    vector<int> makeDenseFMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planFOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeValueFMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n\n            for (int m : planFOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = -5 * pc;\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q < 0) continue;\n                    sc += 4 * adjVal[k][q];\n\n                    int ti = targetIdx[q];\n                    if (ti > k + 1) sc += 18;\n                    else if (ti == k + 1) sc -= 24;\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeFutureTargetMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n\n            for (int m : planFOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = -6 * pc;\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q < 0) continue;\n                    int ti = targetIdx[q];\n                    if (ti > k + 1) sc += 35 - min(20, ti - k);\n                    else if (ti == k + 1) sc -= 40;\n                    sc += adjVal[k][q];\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomFMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planFOpts[k].size());\n            masks[k] = planFOpts[k][id];\n        }\n        return masks;\n    }\n\n    bool buildFromFutureMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & inBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = distMaybeBlockedGoal(g, p, goal);\n            int bestDir = -1;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    setBlock(tg, p);\n\n                    int dist = distMaybeBlockedGoal(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!pathMaybeBlockedGoal(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                if (nb < 0 || isBlocked(g, nb)) return false;\n\n                acts.push_back(enc(0, bestDir));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));\n\n                string path;\n                if (!pathMaybeBlockedGoal(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    struct Node {\n        int parent;\n        string add;\n    };\n\n    struct BeamState {\n        Grid g;\n        int cost;\n        int node;\n        int val;\n    };\n\n    string solveBeam(int keepCount, int keepValue) {\n        vector<Node> nodes;\n        nodes.push_back({-1, \"\"});\n\n        BeamState init;\n        init.cost = 0;\n        init.node = 0;\n        init.val = 0;\n\n        vector<BeamState> beam;\n        beam.push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            vector<BeamState> gen;\n            gen.reserve(beam.size() * 45);\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(beam.size() * 90 + 100);\n            mp.max_load_factor(0.7);\n\n            int p = pos[k];\n            int goal = pos[k + 1];\n\n            auto addState = [&](const BeamState& parent, const Grid& ng, int newCost, const string& app) {\n                if (newCost > LIMIT) return;\n\n                auto it = mp.find(ng.hash);\n                if (it != mp.end()) {\n                    int idx = it->second;\n                    if (newCost >= gen[idx].cost) return;\n                }\n\n                int nodeId = (int)nodes.size();\n                nodes.push_back({parent.node, app});\n\n                BeamState ns;\n                ns.g = ng;\n                ns.cost = newCost;\n                ns.node = nodeId;\n                ns.val = gridValue(ng, k + 1);\n\n                if (it == mp.end()) {\n                    mp[ng.hash] = (int)gen.size();\n                    gen.push_back(ns);\n                } else {\n                    gen[it->second] = ns;\n                }\n            };\n\n            for (const BeamState& st : beam) {\n                int candBits = 0;\n                for (int d = 0; d < 4; d++) {\n                    int q = mv[p][d];\n                    if (q < 0) continue;\n                    bool blk = isBlocked(st.g, q);\n                    if (blk || !future[k][q]) candBits |= (1 << d);\n                }\n\n                for (int sub = candBits;; sub = (sub - 1) & candBits) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    string path;\n                    if (bfsPath(ng, p, goal, path)) {\n                        string app = prep + path;\n                        addState(st, ng, st.cost + (int)app.size(), app);\n                    }\n\n                    if (sub == 0) break;\n                }\n\n                vector<int> backSubs;\n                backSubs.push_back(0);\n                for (int d = 0; d < 4; d++) {\n                    if (candBits & (1 << d)) backSubs.push_back(1 << d);\n                }\n\n                for (int sub : backSubs) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    if (isBlocked(ng, p)) continue;\n\n                    for (int e = 0; e < 4; e++) {\n                        int nb = mv[p][e];\n                        if (nb < 0 || isBlocked(ng, nb)) continue;\n\n                        Grid bg = ng;\n                        setBlock(bg, p);\n\n                        string path;\n                        if (!bfsPath(bg, nb, goal, path)) continue;\n\n                        string app = prep;\n                        app.push_back(enc(0, e));\n                        app.push_back(enc(2, opp[e]));\n                        app += path;\n\n                        addState(st, bg, st.cost + (int)app.size(), app);\n                    }\n                }\n            }\n\n            if (gen.empty()) return \"\";\n\n            if (k == M - 2) {\n                int best = 0;\n                for (int i = 1; i < (int)gen.size(); i++) {\n                    if (gen[i].cost < gen[best].cost) best = i;\n                }\n\n                vector<int> chain;\n                for (int id = gen[best].node; id != -1; id = nodes[id].parent) {\n                    chain.push_back(id);\n                }\n                reverse(chain.begin(), chain.end());\n\n                string res;\n                for (int id : chain) res += nodes[id].add;\n                return res;\n            }\n\n            struct Key {\n                int bc;\n                int bv;\n                int K;\n            };\n\n            vector<Key> keys = {\n                {0, 0, keepCount},\n                {70, 0, keepCount},\n                {130, 0, keepCount},\n                {190, 0, keepCount},\n                {250, 0, keepCount},\n                {0, 18, keepValue},\n                {50, 10, keepValue},\n                {100, 12, keepValue},\n                {150, 16, keepValue},\n                {0, 28, keepValue}\n            };\n\n            vector<char> mark(gen.size(), 0);\n            vector<int> idx(gen.size());\n            iota(idx.begin(), idx.end(), 0);\n\n            for (auto key : keys) {\n                if (key.K <= 0) continue;\n                int K = min(key.K, (int)idx.size());\n\n                auto comp = [&](int a, int b) {\n                    long long ea = 100LL * gen[a].cost - 1LL * key.bc * gen[a].g.cnt - 1LL * key.bv * gen[a].val;\n                    long long eb = 100LL * gen[b].cost - 1LL * key.bc * gen[b].g.cnt - 1LL * key.bv * gen[b].val;\n                    if (ea != eb) return ea < eb;\n                    if (gen[a].cost != gen[b].cost) return gen[a].cost < gen[b].cost;\n                    return gen[a].val > gen[b].val;\n                };\n\n                if (K < (int)idx.size()) {\n                    nth_element(idx.begin(), idx.begin() + K, idx.end(), comp);\n                }\n\n                for (int i = 0; i < K; i++) mark[idx[i]] = 1;\n            }\n\n            vector<BeamState> nxt;\n            nxt.reserve(keepCount * 5 + keepValue * 5 + 5);\n\n            for (int i = 0; i < (int)gen.size(); i++) {\n                if (mark[i]) nxt.push_back(gen[i]);\n            }\n\n            if (nxt.empty()) {\n                int best = min_element(gen.begin(), gen.end(), [](const BeamState& a, const BeamState& b) {\n                    return a.cost < b.cost;\n                }) - gen.begin();\n                nxt.push_back(gen[best]);\n            }\n\n            beam.swap(nxt);\n        }\n\n        return \"\";\n    }\n\n    struct LocalNode {\n        Grid g;\n        int p;\n        int parent;\n        int dist;\n        int altCnt;\n        int valDelta;\n        unsigned char act;\n    };\n\n    inline uint64_t localKey(uint64_t h, int p) const {\n        return h ^ (0x9e3779b97f4a7c15ULL * uint64_t(p + 1));\n    }\n\n    bool localSegmentSearch(\n        const Grid& startG,\n        int s,\n        int goal,\n        int k,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& path,\n        Grid& outG\n    ) {\n        if (elapsed() > endTime) return false;\n        if (isBlocked(startG, s) || isBlocked(startG, goal)) return false;\n        if (s == goal) {\n            path.clear();\n            outG = startG;\n            return true;\n        }\n\n        int base = bfsDist(startG, s, goal);\n        int maxDepth = 24;\n        if (base < INF) maxDepth = min(24, base + slack + 3);\n        maxDepth = max(maxDepth, 8);\n\n        vector<LocalNode> nodes;\n        nodes.reserve(maxNodes + 5);\n        vector<int> q;\n        q.reserve(maxNodes + 5);\n\n        unordered_map<uint64_t, int> mp;\n        mp.reserve(maxNodes * 2 + 100);\n        mp.max_load_factor(0.7);\n\n        LocalNode root;\n        root.g = startG;\n        root.p = s;\n        root.parent = -1;\n        root.dist = 0;\n        root.altCnt = 0;\n        root.valDelta = 0;\n        root.act = 255;\n        nodes.push_back(root);\n        q.push_back(0);\n        mp[localKey(startG.hash, s)] = 0;\n\n        int startCnt = startG.cnt;\n        int bestGoalId = -1;\n        int bestGoalDist = INF;\n        int bestGoalCost = INF;\n        double bestScore = 1e100;\n\n        auto recordGoal = [&](int id) {\n            const LocalNode& nd = nodes[id];\n            bestGoalDist = min(bestGoalDist, nd.dist);\n            double sc = double(nd.dist)\n                - betaCnt * double(nd.g.cnt - startCnt)\n                - betaVal * double(nd.valDelta);\n            if (sc < bestScore - 1e-9 ||\n                (fabs(sc - bestScore) <= 1e-9 && nd.dist < bestGoalCost)) {\n                bestScore = sc;\n                bestGoalId = id;\n                bestGoalCost = nd.dist;\n            }\n        };\n\n        auto addNode = [&](const Grid& ng, int np, int parent, unsigned char act, int ndist, int nalt, int nval) -> int {\n            if ((int)nodes.size() >= maxNodes) return -1;\n            uint64_t key = localKey(ng.hash, np);\n            if (mp.find(key) != mp.end()) return -1;\n\n            int id = (int)nodes.size();\n            LocalNode node;\n            node.g = ng;\n            node.p = np;\n            node.parent = parent;\n            node.dist = ndist;\n            node.altCnt = nalt;\n            node.valDelta = nval;\n            node.act = act;\n            nodes.push_back(node);\n            mp[key] = id;\n            q.push_back(id);\n\n            if (np == goal) recordGoal(id);\n            return id;\n        };\n\n        int head = 0;\n        while (head < (int)q.size()) {\n            if (elapsed() > endTime) return false;\n\n            int id = q[head++];\n            LocalNode cur = nodes[id];\n\n            if (cur.p == goal) continue;\n            if (cur.dist >= maxDepth) continue;\n            if (bestGoalDist < INF && cur.dist >= bestGoalDist + slack) continue;\n\n            int ndist = cur.dist + 1;\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDest(cur.g, cur.p, d);\n                if (to == cur.p) continue;\n                addNode(cur.g, to, id, enc(1, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[cur.p][d];\n                if (to < 0 || isBlocked(cur.g, to)) continue;\n                addNode(cur.g, to, id, enc(0, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int cell = mv[cur.p][d];\n                if (cell < 0) continue;\n\n                bool blk = isBlocked(cur.g, cell);\n                if (!blk && future[k][cell]) continue;\n\n                bool startBlk = isBlocked(startG, cell);\n                bool beforeDiff = (blk != startBlk);\n                int nalt = cur.altCnt + (beforeDiff ? -1 : 1);\n                if (nalt > maxAlt) continue;\n\n                Grid ng = cur.g;\n                toggleBlock(ng, cell);\n\n                int nval = cur.valDelta + (blk ? -adjVal[k][cell] : adjVal[k][cell]);\n                addNode(ng, cur.p, id, enc(2, d), ndist, nalt, nval);\n            }\n        }\n\n        if (bestGoalId < 0) return false;\n\n        path.clear();\n        for (int id = bestGoalId; nodes[id].parent != -1; id = nodes[id].parent) {\n            path.push_back(char(nodes[id].act));\n        }\n        reverse(path.begin(), path.end());\n        outG = nodes[bestGoalId].g;\n        return true;\n    }\n\n    bool buildGreedyActionWithMasks(\n        const vector<int>* masksPtr,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& acts\n    ) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            if (elapsed() > endTime) return false;\n\n            if (masksPtr) {\n                int p = pos[k];\n                if (isBlocked(g, p)) return false;\n\n                int mask = (*masksPtr)[k] & validBits[k];\n                for (int d = 0; d < 4; d++) {\n                    if (!(mask & (1 << d))) continue;\n                    int q = mv[p][d];\n                    if (q < 0 || future[k][q]) continue;\n                    if (!isBlocked(g, q)) {\n                        setBlock(g, q);\n                        acts.push_back(enc(2, d));\n                    }\n                }\n            }\n\n            string seg;\n            Grid ng;\n            bool ok = localSegmentSearch(\n                g, pos[k], pos[k + 1], k,\n                betaCnt, betaVal, maxAlt, slack, maxNodes,\n                endTime, seg, ng\n            );\n\n            if (!ok) {\n                if (!bfsPath(g, pos[k], pos[k + 1], seg)) return false;\n                ng = g;\n            }\n\n            acts += seg;\n            g = ng;\n            if ((int)acts.size() > LIMIT) return false;\n        }\n        return true;\n    }\n\n    void solve() {\n        cin >> N >> M;\n        pos.resize(M);\n        for (int i = 0; i < M; i++) {\n            int r, c;\n            cin >> r >> c;\n            pos[i] = r * N + c;\n        }\n\n        startTime = chrono::steady_clock::now();\n        init();\n\n        pureFallback = makePureMoves();\n        addCandidate(pureFallback);\n\n        string beamAns = solveBeam(25, 8);\n        if (!beamAns.empty()) addCandidate(beamAns);\n\n        vector<pair<int, vector<int>>> maskCands;\n\n        vector<vector<int>> starts;\n        starts.push_back(makeZeroMasks());\n        starts.push_back(makeDenseMasks());\n        starts.push_back(makeExitMasks());\n        starts.push_back(makeSparseMasks());\n        starts.push_back(makeValueMasks());\n        for (int i = 0; i < 5; i++) starts.push_back(makeRandomMasks());\n\n        double planEnd = 1.42;\n\n        for (auto st : starts) {\n            if (elapsed() > planEnd) break;\n            auto res = coordinateDescent(st, 3, planEnd);\n            maskCands.push_back(res);\n        }\n\n        if (maskCands.empty()) {\n            vector<int> z = makeZeroMasks();\n            maskCands.push_back({evalPlan(z), z});\n        }\n\n        sort(maskCands.begin(), maskCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedMaskKeys;\n        vector<double> backBetas = {-1.0, 0.0, 1.0, 1.5, 2.0, 2.5, 3.0};\n\n        int used = 0;\n        for (auto& pr : maskCands) {\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedMaskKeys.count(key)) continue;\n            usedMaskKeys.insert(key);\n\n            for (double beta : backBetas) {\n                string acts;\n                if (buildFromMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            used++;\n            if (used >= 8) break;\n        }\n\n        double plan2End = 1.65;\n        set<string> usedPlan2Keys;\n        int plan2Runs = 0;\n\n        for (int id = 0; id < (int)maskCands.size() && id < 5; id++) {\n            if (elapsed() > plan2End) break;\n\n            vector<vector<int>> leaveStarts;\n            leaveStarts.push_back(vector<int>(M - 1, -1));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 1.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 2.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 3.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 4.5));\n            leaveStarts.push_back(makeTowardLeaves(maskCands[id].second));\n            if (id < 2) leaveStarts.push_back(makeRandomLeaves(maskCands[id].second));\n\n            for (auto leaves : leaveStarts) {\n                if (elapsed() > plan2End) break;\n\n                string key;\n                key.reserve(2 * (M - 1));\n                for (int k = 0; k < M - 1; k++) {\n                    key.push_back(char(maskCands[id].second[k]));\n                    key.push_back(char(leaves[k] + 1));\n                }\n                if (usedPlan2Keys.count(key)) continue;\n                usedPlan2Keys.insert(key);\n\n                auto res = coordinateDescent2(maskCands[id].second, leaves, 2, plan2End);\n                string acts;\n                if (buildPlan2(res.masks, res.leaves, acts)) {\n                    addCandidate(acts);\n                }\n\n                plan2Runs++;\n                if (plan2Runs >= 10) break;\n            }\n            if (plan2Runs >= 10) break;\n        }\n\n        double futureEnd = 1.71;\n        vector<pair<int, vector<int>>> futureCands;\n        vector<vector<int>> fstarts;\n\n        for (int i = 0; i < (int)maskCands.size() && i < 2; i++) {\n            fstarts.push_back(maskCands[i].second);\n        }\n        fstarts.push_back(makeValueFMasks());\n        fstarts.push_back(makeFutureTargetMasks());\n        fstarts.push_back(makeDenseFMasks());\n        fstarts.push_back(makeRandomFMasks());\n\n        for (auto st : fstarts) {\n            if (elapsed() > futureEnd) break;\n            auto res = coordinateDescentF(st, 1, futureEnd);\n            futureCands.push_back(res);\n        }\n\n        sort(futureCands.begin(), futureCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedFutureKeys;\n        int fUsed = 0;\n        vector<double> fBetas = {-1.0, 0.5, 1.5, 2.5};\n\n        for (auto& pr : futureCands) {\n            if (elapsed() > futureEnd + 0.01) break;\n\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedFutureKeys.count(key)) continue;\n            usedFutureKeys.insert(key);\n\n            for (double beta : fBetas) {\n                string acts;\n                if (buildFromFutureMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            fUsed++;\n            if (fUsed >= 3) break;\n        }\n\n        vector<tuple<double, double, int, int, int>> localCfgs = {\n            {0.0, 0.00, 3, 1, 1500},\n            {0.8, 0.09, 4, 2, 2100},\n            {1.1, 0.13, 5, 3, 2500},\n        };\n\n        double localEnd = 1.78;\n        for (auto [bc, bv, ma, sl, mn] : localCfgs) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyActionWithMasks(nullptr, bc, bv, ma, sl, mn, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        for (int id = 0; id < (int)maskCands.size() && id < 2; id++) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyActionWithMasks(&maskCands[id].second, 0.7, 0.08, 4, 2, 1800, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        if (candidates.empty()) candidates.push_back(pureFallback);\n\n        string best = candidates[0];\n        for (const string& s : candidates) {\n            if (s.size() < best.size()) best = s;\n        }\n\n        vector<int> order(candidates.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return candidates[a].size() < candidates[b].size();\n        });\n\n        for (int id : order) {\n            if (elapsed() > 1.87) break;\n            string improved = greedyDelete(candidates[id], 1.87);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        if (elapsed() < 1.925) {\n            string improved = replaceImprove(best, 1.95);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        if (elapsed() < 1.955) {\n            string improved = segmentOptimize(best, 1.985);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        int pp = firstCompletionPrefix(best);\n        if (pp >= 0 && pp <= LIMIT) {\n            best.resize(pp);\n        } else {\n            best = pureFallback;\n        }\n\n        const string A = \"MSA\";\n        const string D = \"UDLR\";\n\n        for (unsigned char ch : best) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            cout << A[type] << ' ' << D[d] << '\\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\n    return 0;\n}"},"16":{"ahc001":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct FastRNG {\n    uint64_t x;\n    FastRNG(uint64_t seed = 88172645463325252ULL) {\n        x = seed ? seed : 88172645463325252ULL;\n    }\n    uint64_t nextU64() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n    int nextInt(int n) { return (int)(nextU64() % (uint64_t)n); }\n    double nextDouble() { return (nextU64() >> 11) * (1.0 / 9007199254740992.0); }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Rect {\n    int a, b, c, d;\n};\n\nstatic uint64_t splitmix64_hash(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nclass Solver {\n    static constexpr int SZ = 10000;\n    static constexpr double TIME_LIMIT = 4.86;\n    static constexpr double FINAL_RESERVE = 0.045;\n\n    int n;\n    vector<int> x, y;\n    vector<long long> r;\n    vector<double> rd, invR;\n    FastRNG rng;\n    Timer timer;\n\n    struct State {\n        vector<Rect> rect;\n        vector<double> val;\n        double total = 0.0;\n    };\n\n    struct Move {\n        bool ok = false;\n        int dir = 0;\n        int coord = 0;\n        double newScore = 0.0;\n        double delta = 0.0;\n    };\n\n    struct PairMove {\n        bool ok = false;\n        int orient = 0;\n        int i = -1, j = -1;\n        int coord = 0;\n        double newScoreI = 0.0;\n        double newScoreJ = 0.0;\n        double delta = 0.0;\n    };\n\n    struct LineComp {\n        int orient = 0;\n        int coord = -1;\n        vector<int> A;\n        vector<int> B;\n    };\n\n    struct LineMove {\n        bool ok = false;\n        int orient = 0;\n        int coord = -1;\n        int newCoord = 0;\n        vector<int> A, B;\n        double delta = 0.0;\n    };\n\n    struct SplitCand {\n        int orient;\n        int k;\n        int t;\n        double cost;\n    };\n\n    long long rectArea(const Rect& rc) const {\n        return 1LL * (rc.c - rc.a) * (rc.d - rc.b);\n    }\n\n    double scoreOne(int i, long long s) const {\n        double ratio;\n        if (s <= r[i]) ratio = (double)s * invR[i];\n        else ratio = rd[i] / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    static double scoreRatio(long long s, long long target) {\n        double ratio;\n        if (s <= target) ratio = (double)s / (double)target;\n        else ratio = (double)target / (double)s;\n        return 2.0 * ratio - ratio * ratio;\n    }\n\n    State makeState(const vector<Rect>& rects) const {\n        State st;\n        st.rect = rects;\n        st.val.assign(n, 0.0);\n        for (int i = 0; i < n; i++) {\n            st.val[i] = scoreOne(i, rectArea(st.rect[i]));\n            st.total += st.val[i];\n        }\n        return st;\n    }\n\n    int clampLL(long long v, int lo, int hi) const {\n        if (v < lo) return lo;\n        if (v > hi) return hi;\n        return (int)v;\n    }\n\n    bool yOverlap(const Rect& p, const Rect& q) const {\n        return max(p.b, q.b) < min(p.d, q.d);\n    }\n\n    bool xOverlap(const Rect& p, const Rect& q) const {\n        return max(p.a, q.a) < min(p.c, q.c);\n    }\n\n    bool overlapRect(const Rect& p, const Rect& q) const {\n        return xOverlap(p, q) && yOverlap(p, q);\n    }\n\n    void sortIds(vector<int>& ord, int orient) const {\n        if (orient == 0) {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (x[u] != x[v]) return x[u] < x[v];\n                return y[u] < y[v];\n            });\n        } else {\n            sort(ord.begin(), ord.end(), [&](int u, int v) {\n                if (y[u] != y[v]) return y[u] < y[v];\n                return x[u] < x[v];\n            });\n        }\n    }\n\n    vector<SplitCand> generateSplitCands(const vector<int>& ids, const Rect& box) const {\n        int m = (int)ids.size();\n        vector<SplitCand> cands;\n        if (m <= 1) return cands;\n\n        long long totalR = 0;\n        for (int id : ids) totalR += r[id];\n\n        long long A = rectArea(box);\n        int W = box.c - box.a;\n        int H = box.d - box.b;\n\n        cands.reserve(m * 40);\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<int> ord = ids;\n            sortIds(ord, orient);\n\n            long long pref = 0;\n            for (int k = 1; k < m; k++) {\n                pref += r[ord[k - 1]];\n\n                int lo, hi;\n                if (orient == 0) {\n                    int xl = x[ord[k - 1]];\n                    int xr = x[ord[k]];\n                    lo = max(box.a + 1, xl + 1);\n                    hi = min(box.c - 1, xr);\n                } else {\n                    int yl = y[ord[k - 1]];\n                    int yr = y[ord[k]];\n                    lo = max(box.b + 1, yl + 1);\n                    hi = min(box.d - 1, yr);\n                }\n\n                if (lo > hi) continue;\n\n                vector<int> ts;\n                ts.reserve(32);\n\n                auto addT = [&](int t) {\n                    if (t < lo || t > hi) return;\n                    for (int u : ts) if (u == t) return;\n                    ts.push_back(t);\n                };\n\n                auto addReal = [&](long double real) {\n                    long long f = (long long)floorl(real);\n                    for (long long v = f - 2; v <= f + 2; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                    long long rr = (long long)llroundl(real);\n                    for (long long v = rr - 1; v <= rr + 1; v++) {\n                        addT(clampLL(v, lo, hi));\n                    }\n                };\n\n                if (orient == 0) {\n                    long double prop = box.a + ((long double)A * pref / totalR) / H;\n                    long double exactL = box.a + (long double)pref / H;\n                    long double exactR = box.a + ((long double)A - (long double)(totalR - pref)) / H;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                } else {\n                    long double prop = box.b + ((long double)A * pref / totalR) / W;\n                    long double exactL = box.b + (long double)pref / W;\n                    long double exactR = box.b + ((long double)A - (long double)(totalR - pref)) / W;\n                    addReal(prop);\n                    addReal(exactL);\n                    addReal(exactR);\n                }\n\n                addT(lo);\n                addT(hi);\n\n                for (int t : ts) {\n                    long long leftA;\n                    if (orient == 0) leftA = 1LL * (t - box.a) * H;\n                    else leftA = 1LL * W * (t - box.b);\n\n                    long long rightA = A - leftA;\n                    if (leftA <= 0 || rightA <= 0) continue;\n\n                    double sc =\n                        k * scoreRatio(leftA, pref) +\n                        (m - k) * scoreRatio(rightA, totalR - pref);\n\n                    double loss = 1.0 - sc / m;\n\n                    auto aspectPenalty = [&](int ww, int hh, int cnt) -> double {\n                        if (cnt <= 1) return 0.0;\n                        double ar = max((double)ww / hh, (double)hh / ww);\n                        return 0.00025 * (cnt / (double)m) * max(0.0, log(ar) - 2.0);\n                    };\n\n                    double cost = loss;\n                    cost += 0.00020 * abs(m - 2 * k) / (double)m;\n\n                    if (orient == 0) {\n                        cost += aspectPenalty(t - box.a, H, k);\n                        cost += aspectPenalty(box.c - t, H, m - k);\n                    } else {\n                        cost += aspectPenalty(W, t - box.b, k);\n                        cost += aspectPenalty(W, box.d - t, m - k);\n                    }\n\n                    cands.push_back({orient, k, t, cost});\n                }\n            }\n        }\n\n        return cands;\n    }\n\n    void buildRec(const vector<int>& ids, const Rect& box, vector<Rect>& out, double temp) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return;\n        }\n\n        vector<SplitCand> cands = generateSplitCands(ids, box);\n\n        if (cands.empty()) {\n            for (int id : ids) {\n                out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            }\n            return;\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int chosen = 0;\n        if (temp > 1e-12) {\n            double bestCost = cands[0].cost;\n            double maxDiff = max(0.03, temp * 12.0);\n\n            vector<pair<int, double>> cumulative;\n            double sum = 0.0;\n            for (int i = 0; i < (int)cands.size(); i++) {\n                double diff = cands[i].cost - bestCost;\n                if (diff > maxDiff) continue;\n                double w = exp(-diff / temp);\n                if (w < 1e-12) continue;\n                sum += w;\n                cumulative.push_back({i, sum});\n            }\n\n            if (sum > 0.0) {\n                double z = rng.nextDouble() * sum;\n                for (auto [idx, cum] : cumulative) {\n                    if (z <= cum) {\n                        chosen = idx;\n                        break;\n                    }\n                }\n            }\n        }\n\n        SplitCand sp = cands[chosen];\n\n        vector<int> ord = ids;\n        sortIds(ord, sp.orient);\n\n        vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n        vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n        if (sp.orient == 0) {\n            Rect L{box.a, box.b, sp.t, box.d};\n            Rect R{sp.t, box.b, box.c, box.d};\n            buildRec(leftIds, L, out, temp);\n            buildRec(rightIds, R, out, temp);\n        } else {\n            Rect B{box.a, box.b, box.c, sp.t};\n            Rect T{box.a, sp.t, box.c, box.d};\n            buildRec(leftIds, B, out, temp);\n            buildRec(rightIds, T, out, temp);\n        }\n    }\n\n    double scoreIds(const vector<Rect>& rects, const vector<int>& ids) const {\n        double s = 0.0;\n        for (int id : ids) s += scoreOne(id, rectArea(rects[id]));\n        return s;\n    }\n\n    double buildRecBeam(const vector<int>& ids, const Rect& box, vector<Rect>& out, double stopTime) {\n        int m = (int)ids.size();\n        if (m == 1) {\n            out[ids[0]] = box;\n            return scoreOne(ids[0], rectArea(box));\n        }\n\n        if (timer.elapsed() > stopTime) {\n            buildRec(ids, box, out, 0.0);\n            return scoreIds(out, ids);\n        }\n\n        vector<SplitCand> cands = generateSplitCands(ids, box);\n        if (cands.empty()) {\n            for (int id : ids) out[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            return scoreIds(out, ids);\n        }\n\n        sort(cands.begin(), cands.end(), [](const SplitCand& p, const SplitCand& q) {\n            return p.cost < q.cost;\n        });\n\n        int width;\n        if (m <= 3) width = 10;\n        else if (m <= 5) width = 5;\n        else width = 3;\n\n        width = min(width, (int)cands.size());\n\n        double best = -1e100;\n        vector<Rect> bestOut = out;\n\n        for (int ci = 0; ci < width; ci++) {\n            if (timer.elapsed() > stopTime) break;\n\n            SplitCand sp = cands[ci];\n            vector<int> ord = ids;\n            sortIds(ord, sp.orient);\n\n            vector<int> leftIds(ord.begin(), ord.begin() + sp.k);\n            vector<int> rightIds(ord.begin() + sp.k, ord.end());\n\n            vector<Rect> tmp = out;\n            double sc = 0.0;\n\n            if (sp.orient == 0) {\n                Rect L{box.a, box.b, sp.t, box.d};\n                Rect R{sp.t, box.b, box.c, box.d};\n                sc += buildRecBeam(leftIds, L, tmp, stopTime);\n                sc += buildRecBeam(rightIds, R, tmp, stopTime);\n            } else {\n                Rect B{box.a, box.b, box.c, sp.t};\n                Rect T{box.a, sp.t, box.c, box.d};\n                sc += buildRecBeam(leftIds, B, tmp, stopTime);\n                sc += buildRecBeam(rightIds, T, tmp, stopTime);\n            }\n\n            if (sc > best) {\n                best = sc;\n                bestOut = std::move(tmp);\n            }\n        }\n\n        if (best < -1e90) {\n            buildRec(ids, box, out, 0.0);\n            return scoreIds(out, ids);\n        }\n\n        out = std::move(bestOut);\n        return best;\n    }\n\n    vector<Rect> buildRecursive(double temp) {\n        vector<Rect> out(n);\n        vector<int> ids(n);\n        iota(ids.begin(), ids.end(), 0);\n        buildRec(ids, Rect{0, 0, SZ, SZ}, out, temp);\n        return out;\n    }\n\n    vector<Rect> buildUnit() const {\n        vector<Rect> rects(n);\n        for (int i = 0; i < n; i++) {\n            rects[i] = {x[i], y[i], x[i] + 1, y[i] + 1};\n        }\n        return rects;\n    }\n\n    pair<int, int> legalInterval(const State& st, int i, int dir) const {\n        const Rect& ri = st.rect[i];\n\n        if (dir == 0) {\n            int lo = 0;\n            int hi = min(x[i], ri.c - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.a < ri.c) {\n                    lo = max(lo, rj.c);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 1) {\n            int lo = max(x[i] + 1, ri.a + 1);\n            int hi = SZ;\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (yOverlap(ri, rj) && rj.c > ri.a) {\n                    hi = min(hi, rj.a);\n                }\n            }\n            return {lo, hi};\n        }\n\n        if (dir == 2) {\n            int lo = 0;\n            int hi = min(y[i], ri.d - 1);\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (xOverlap(ri, rj) && rj.b < ri.d) {\n                    lo = max(lo, rj.d);\n                }\n            }\n            return {lo, hi};\n        }\n\n        int lo = max(y[i] + 1, ri.b + 1);\n        int hi = SZ;\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& rj = st.rect[j];\n            if (xOverlap(ri, rj) && rj.d > ri.b) {\n                hi = min(hi, rj.b);\n            }\n        }\n        return {lo, hi};\n    }\n\n    int getCoord(const Rect& rc, int dir) const {\n        if (dir == 0) return rc.a;\n        if (dir == 1) return rc.c;\n        if (dir == 2) return rc.b;\n        return rc.d;\n    }\n\n    void setCoord(Rect& rc, int dir, int v) {\n        if (dir == 0) rc.a = v;\n        else if (dir == 1) rc.c = v;\n        else if (dir == 2) rc.b = v;\n        else rc.d = v;\n    }\n\n    long long areaAfterCoord(const Rect& rc, int dir, int coord) const {\n        if (dir == 0) return 1LL * (rc.c - coord) * (rc.d - rc.b);\n        if (dir == 1) return 1LL * (coord - rc.a) * (rc.d - rc.b);\n        if (dir == 2) return 1LL * (rc.c - rc.a) * (rc.d - coord);\n        return 1LL * (rc.c - rc.a) * (coord - rc.b);\n    }\n\n    Move bestEdgeDir(const State& st, int i, int dir) const {\n        Move mv;\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return mv;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n\n        mv.ok = true;\n        mv.dir = dir;\n        mv.coord = cur;\n        mv.newScore = st.val[i];\n        mv.delta = 0.0;\n\n        int cand[48];\n        int cnt = 0;\n\n        auto addCand = [&](int v) {\n            if (v < lo) v = lo;\n            if (v > hi) v = hi;\n            for (int k = 0; k < cnt; k++) if (cand[k] == v) return;\n            cand[cnt++] = v;\n        };\n\n        addCand(cur);\n        addCand(lo);\n        addCand(hi);\n\n        long double real;\n        if (dir == 0 || dir == 1) {\n            int h = rc.d - rc.b;\n            long double wantW = (long double)r[i] / h;\n            if (dir == 0) real = rc.c - wantW;\n            else real = rc.a + wantW;\n        } else {\n            int w = rc.c - rc.a;\n            long double wantH = (long double)r[i] / w;\n            if (dir == 2) real = rc.d - wantH;\n            else real = rc.b + wantH;\n        }\n\n        long long f = (long long)floorl(real);\n        for (long long v = f - 5; v <= f + 5; v++) {\n            addCand(clampLL(v, lo, hi));\n        }\n\n        double bestScore = st.val[i];\n        int bestCoord = cur;\n\n        for (int k = 0; k < cnt; k++) {\n            int v = cand[k];\n            long long ar = areaAfterCoord(rc, dir, v);\n            double ns = scoreOne(i, ar);\n            if (ns > bestScore + 1e-15) {\n                bestScore = ns;\n                bestCoord = v;\n            }\n        }\n\n        mv.coord = bestCoord;\n        mv.newScore = bestScore;\n        mv.delta = bestScore - st.val[i];\n        return mv;\n    }\n\n    Move bestMove(const State& st, int i) const {\n        Move best;\n        best.newScore = st.val[i];\n        for (int dir = 0; dir < 4; dir++) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) continue;\n            if (!best.ok || mv.delta > best.delta) best = mv;\n        }\n        return best;\n    }\n\n    void applyCoord(State& st, int i, int dir, int coord, double newScore) {\n        setCoord(st.rect[i], dir, coord);\n        st.total += newScore - st.val[i];\n        st.val[i] = newScore;\n    }\n\n    void applyMove(State& st, int i, const Move& mv) {\n        applyCoord(st, i, mv.dir, mv.coord, mv.newScore);\n    }\n\n    PairMove bestPairVertical(const State& st, int li, int ri) const {\n        PairMove pm;\n        pm.orient = 0;\n        pm.i = li;\n        pm.j = ri;\n\n        if (li == ri) return pm;\n        const Rect& L = st.rect[li];\n        const Rect& R = st.rect[ri];\n\n        if (L.c > R.a) return pm;\n        if (!yOverlap(L, R)) return pm;\n\n        int lo1 = max(x[li] + 1, L.a + 1);\n        int hi1 = SZ;\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(L, K) && K.c > L.a) hi1 = min(hi1, K.a);\n        }\n\n        int lo2 = 0;\n        int hi2 = min(x[ri], R.c - 1);\n        for (int k = 0; k < n; k++) if (k != li && k != ri) {\n            const Rect& K = st.rect[k];\n            if (yOverlap(R, K) && K.a < R.c) lo2 = max(lo2, K.c);\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int hL = L.d - L.b;\n        int hR = R.d - R.b;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * (t - L.a) * hL;\n            long long a2 = 1LL * (R.c - t) * hR;\n            return scoreOne(li, a1) + scoreOne(ri, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(L.c, lo, hi));\n        test(clampLL(R.a, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) test(clampLL(v, lo, hi));\n        };\n\n        addReal((long double)L.a + (long double)r[li] / hL);\n        addReal((long double)R.c - (long double)r[ri] / hR);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * (bestT - L.a) * hL;\n        long long a2 = 1LL * (R.c - bestT) * hR;\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(li, a1);\n        pm.newScoreJ = scoreOne(ri, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[li] - st.val[ri];\n        return pm;\n    }\n\n    PairMove bestPairHorizontal(const State& st, int bi, int ti) const {\n        PairMove pm;\n        pm.orient = 1;\n        pm.i = bi;\n        pm.j = ti;\n\n        if (bi == ti) return pm;\n        const Rect& B = st.rect[bi];\n        const Rect& T = st.rect[ti];\n\n        if (B.d > T.b) return pm;\n        if (!xOverlap(B, T)) return pm;\n\n        int lo1 = max(y[bi] + 1, B.b + 1);\n        int hi1 = SZ;\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(B, K) && K.d > B.b) hi1 = min(hi1, K.b);\n        }\n\n        int lo2 = 0;\n        int hi2 = min(y[ti], T.d - 1);\n        for (int k = 0; k < n; k++) if (k != bi && k != ti) {\n            const Rect& K = st.rect[k];\n            if (xOverlap(T, K) && K.b < T.d) lo2 = max(lo2, K.d);\n        }\n\n        int lo = max(lo1, lo2);\n        int hi = min(hi1, hi2);\n        if (lo > hi) return pm;\n\n        int wB = B.c - B.a;\n        int wT = T.c - T.a;\n\n        auto eval = [&](int t) -> double {\n            long long a1 = 1LL * wB * (t - B.b);\n            long long a2 = 1LL * wT * (T.d - t);\n            return scoreOne(bi, a1) + scoreOne(ti, a2);\n        };\n\n        double bestScore = -1e100;\n        int bestT = lo;\n\n        auto test = [&](int t) {\n            if (t < lo || t > hi) return;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        };\n\n        test(lo);\n        test(hi);\n        test(clampLL(B.d, lo, hi));\n        test(clampLL(T.b, lo, hi));\n        test(lo + (hi - lo) / 2);\n        test(lo + (hi - lo) / 4);\n        test(lo + 3 * (hi - lo) / 4);\n\n        auto addReal = [&](long double z) {\n            long long f = (long long)floorl(z);\n            for (long long v = f - 6; v <= f + 6; v++) test(clampLL(v, lo, hi));\n        };\n\n        addReal((long double)B.b + (long double)r[bi] / wB);\n        addReal((long double)T.d - (long double)r[ti] / wT);\n\n        int TL = lo, TR = hi;\n        while (TR - TL > 40) {\n            int m1 = TL + (TR - TL) / 3;\n            int m2 = TR - (TR - TL) / 3;\n            if (eval(m1) < eval(m2)) TL = m1;\n            else TR = m2;\n        }\n        for (int t = TL; t <= TR; t++) test(t);\n\n        long long a1 = 1LL * wB * (bestT - B.b);\n        long long a2 = 1LL * wT * (T.d - bestT);\n\n        pm.ok = true;\n        pm.coord = bestT;\n        pm.newScoreI = scoreOne(bi, a1);\n        pm.newScoreJ = scoreOne(ti, a2);\n        pm.delta = pm.newScoreI + pm.newScoreJ - st.val[bi] - st.val[ti];\n        return pm;\n    }\n\n    void applyPair(State& st, const PairMove& pm) {\n        int i = pm.i;\n        int j = pm.j;\n\n        if (pm.orient == 0) {\n            st.rect[i].c = pm.coord;\n            st.rect[j].a = pm.coord;\n        } else {\n            st.rect[i].d = pm.coord;\n            st.rect[j].b = pm.coord;\n        }\n\n        st.total += pm.newScoreI - st.val[i];\n        st.total += pm.newScoreJ - st.val[j];\n\n        st.val[i] = pm.newScoreI;\n        st.val[j] = pm.newScoreJ;\n    }\n\n    void shuffleVector(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int selectBad(const State& st) {\n        int best = rng.nextInt(n);\n        double bv = st.val[best];\n\n        int K = min(n, 6);\n        for (int k = 1; k < K; k++) {\n            int j = rng.nextInt(n);\n            if (st.val[j] < bv) {\n                bv = st.val[j];\n                best = j;\n            }\n        }\n        return best;\n    }\n\n    bool greedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ord);\n\n            bool any = false;\n            for (int id : ord) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairGreedyPasses(State& st, int passes, double stopTime) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            shuffleVector(ord);\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < n; ai++) {\n                int i = ord[ai];\n                for (int bj = ai + 1; bj < n; bj++) {\n                    if ((checks++ & 255) == 0 && timer.elapsed() > stopTime) return globalAny;\n\n                    int j = ord[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    vector<LineComp> buildLineComponents(const State& st, int orient) const {\n        vector<int> coords;\n        coords.reserve(2 * n);\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = st.rect[i];\n            if (orient == 0) {\n                if (0 < rc.c && rc.c < SZ) coords.push_back(rc.c);\n                if (0 < rc.a && rc.a < SZ) coords.push_back(rc.a);\n            } else {\n                if (0 < rc.d && rc.d < SZ) coords.push_back(rc.d);\n                if (0 < rc.b && rc.b < SZ) coords.push_back(rc.b);\n            }\n        }\n\n        sort(coords.begin(), coords.end());\n        coords.erase(unique(coords.begin(), coords.end()), coords.end());\n\n        vector<LineComp> comps;\n\n        for (int coord : coords) {\n            vector<int> A, B;\n            for (int i = 0; i < n; i++) {\n                const Rect& rc = st.rect[i];\n                if (orient == 0) {\n                    if (rc.c == coord) A.push_back(i);\n                    if (rc.a == coord) B.push_back(i);\n                } else {\n                    if (rc.d == coord) A.push_back(i);\n                    if (rc.b == coord) B.push_back(i);\n                }\n            }\n\n            if (A.empty() || B.empty()) continue;\n\n            int na = (int)A.size();\n            int nb = (int)B.size();\n            vector<vector<int>> adj(na + nb);\n\n            for (int i = 0; i < na; i++) {\n                for (int j = 0; j < nb; j++) {\n                    bool ov = (orient == 0)\n                        ? yOverlap(st.rect[A[i]], st.rect[B[j]])\n                        : xOverlap(st.rect[A[i]], st.rect[B[j]]);\n                    if (ov) {\n                        adj[i].push_back(na + j);\n                        adj[na + j].push_back(i);\n                    }\n                }\n            }\n\n            vector<char> vis(na + nb, 0);\n            for (int s = 0; s < na + nb; s++) {\n                if (vis[s]) continue;\n\n                vector<int> q = {s};\n                vis[s] = 1;\n                for (int qi = 0; qi < (int)q.size(); qi++) {\n                    int v = q[qi];\n                    for (int to : adj[v]) {\n                        if (!vis[to]) {\n                            vis[to] = 1;\n                            q.push_back(to);\n                        }\n                    }\n                }\n\n                LineComp cp;\n                cp.orient = orient;\n                cp.coord = coord;\n\n                for (int v : q) {\n                    if (v < na) cp.A.push_back(A[v]);\n                    else cp.B.push_back(B[v - na]);\n                }\n\n                if (!cp.A.empty() && !cp.B.empty()) comps.push_back(std::move(cp));\n            }\n        }\n\n        return comps;\n    }\n\n    bool componentInternalOK(const State& st, const LineComp& cp) const {\n        vector<unsigned char> side(n, 0);\n\n        for (int id : cp.A) {\n            if (side[id] & 1) return false;\n            side[id] |= 1;\n        }\n        for (int id : cp.B) {\n            if (side[id] & 2) return false;\n            if (side[id] & 1) return false;\n            side[id] |= 2;\n        }\n\n        auto perpOverlap = [&](int u, int v) -> bool {\n            if (cp.orient == 0) return yOverlap(st.rect[u], st.rect[v]);\n            else return xOverlap(st.rect[u], st.rect[v]);\n        };\n\n        for (int i = 0; i < (int)cp.A.size(); i++) {\n            for (int j = i + 1; j < (int)cp.A.size(); j++) {\n                if (perpOverlap(cp.A[i], cp.A[j])) return false;\n            }\n        }\n        for (int i = 0; i < (int)cp.B.size(); i++) {\n            for (int j = i + 1; j < (int)cp.B.size(); j++) {\n                if (perpOverlap(cp.B[i], cp.B[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\n    vector<LineComp> buildFrontierComponents(const State& st, int orient) const {\n        const int INF = 1e9;\n        vector<int> bestA(n, INF), bestB(n, INF);\n\n        auto canFace = [&](int i, int j, int& gap) -> bool {\n            if (i == j) return false;\n            const Rect& P = st.rect[i];\n            const Rect& Q = st.rect[j];\n\n            if (orient == 0) {\n                if (!yOverlap(P, Q)) return false;\n                if (P.c <= Q.a) {\n                    gap = Q.a - P.c;\n                    return true;\n                }\n            } else {\n                if (!xOverlap(P, Q)) return false;\n                if (P.d <= Q.b) {\n                    gap = Q.b - P.d;\n                    return true;\n                }\n            }\n            return false;\n        };\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int gap;\n                if (canFace(i, j, gap)) {\n                    bestA[i] = min(bestA[i], gap);\n                    bestB[j] = min(bestB[j], gap);\n                }\n            }\n        }\n\n        vector<vector<int>> adj(2 * n);\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j < n; j++) {\n                int gap;\n                if (canFace(i, j, gap)) {\n                    if (gap == bestA[i] && gap == bestB[j]) {\n                        adj[i].push_back(n + j);\n                        adj[n + j].push_back(i);\n                    }\n                }\n            }\n        }\n\n        vector<LineComp> comps;\n        vector<char> vis(2 * n, 0);\n\n        for (int s = 0; s < 2 * n; s++) {\n            if (vis[s] || adj[s].empty()) continue;\n\n            vector<int> q = {s};\n            vis[s] = 1;\n\n            for (int qi = 0; qi < (int)q.size(); qi++) {\n                int v = q[qi];\n                for (int to : adj[v]) {\n                    if (!vis[to]) {\n                        vis[to] = 1;\n                        q.push_back(to);\n                    }\n                }\n            }\n\n            LineComp cp;\n            cp.orient = orient;\n            cp.coord = -1;\n\n            for (int v : q) {\n                if (v < n) cp.A.push_back(v);\n                else cp.B.push_back(v - n);\n            }\n\n            if (cp.A.empty() || cp.B.empty()) continue;\n            if (!componentInternalOK(st, cp)) continue;\n\n            bool sameCoord = true;\n            int common = -1;\n\n            auto feedCoord = [&](int z) {\n                if (common < 0) common = z;\n                else if (common != z) sameCoord = false;\n            };\n\n            if (orient == 0) {\n                for (int id : cp.A) feedCoord(st.rect[id].c);\n                for (int id : cp.B) feedCoord(st.rect[id].a);\n            } else {\n                for (int id : cp.A) feedCoord(st.rect[id].d);\n                for (int id : cp.B) feedCoord(st.rect[id].b);\n            }\n\n            if (sameCoord) continue;\n            comps.push_back(std::move(cp));\n        }\n\n        return comps;\n    }\n\n    LineMove bestBoundaryComponent(const State& st, const LineComp& cp, double stopTime) {\n        LineMove lm;\n        lm.orient = cp.orient;\n        lm.coord = cp.coord;\n        lm.A = cp.A;\n        lm.B = cp.B;\n\n        if (cp.A.empty() || cp.B.empty()) return lm;\n        if (!componentInternalOK(st, cp)) return lm;\n\n        if (cp.coord >= 0) {\n            if (cp.orient == 0) {\n                for (int id : cp.A) if (st.rect[id].c != cp.coord) return lm;\n                for (int id : cp.B) if (st.rect[id].a != cp.coord) return lm;\n            } else {\n                for (int id : cp.A) if (st.rect[id].d != cp.coord) return lm;\n                for (int id : cp.B) if (st.rect[id].b != cp.coord) return lm;\n            }\n        }\n\n        vector<char> moved(n, 0);\n        double curScore = 0.0;\n\n        for (int id : cp.A) {\n            if (!moved[id]) {\n                moved[id] = 1;\n                curScore += st.val[id];\n            }\n        }\n        for (int id : cp.B) {\n            if (!moved[id]) {\n                moved[id] = 1;\n                curScore += st.val[id];\n            }\n        }\n\n        int lo = 0;\n        int hi = SZ;\n\n        if (cp.orient == 0) {\n            for (int id : cp.A) {\n                const Rect& ri = st.rect[id];\n                lo = max(lo, max(x[id] + 1, ri.a + 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (yOverlap(ri, rk) && rk.c > ri.a) hi = min(hi, rk.a);\n                }\n            }\n\n            for (int id : cp.B) {\n                const Rect& ri = st.rect[id];\n                hi = min(hi, min(x[id], ri.c - 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (yOverlap(ri, rk) && rk.a < ri.c) lo = max(lo, rk.c);\n                }\n            }\n        } else {\n            for (int id : cp.A) {\n                const Rect& ri = st.rect[id];\n                lo = max(lo, max(y[id] + 1, ri.b + 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (xOverlap(ri, rk) && rk.d > ri.b) hi = min(hi, rk.b);\n                }\n            }\n\n            for (int id : cp.B) {\n                const Rect& ri = st.rect[id];\n                hi = min(hi, min(y[id], ri.d - 1));\n\n                for (int k = 0; k < n; k++) if (!moved[k]) {\n                    const Rect& rk = st.rect[k];\n                    if (xOverlap(ri, rk) && rk.b < ri.d) lo = max(lo, rk.d);\n                }\n            }\n        }\n\n        if (lo > hi) return lm;\n\n        auto eval = [&](int t) -> double {\n            double sc = 0.0;\n\n            if (cp.orient == 0) {\n                for (int id : cp.A) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (t - rc.a) * (rc.d - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n                for (int id : cp.B) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - t) * (rc.d - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n            } else {\n                for (int id : cp.A) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - rc.a) * (t - rc.b);\n                    sc += scoreOne(id, ar);\n                }\n                for (int id : cp.B) {\n                    const Rect& rc = st.rect[id];\n                    long long ar = 1LL * (rc.c - rc.a) * (rc.d - t);\n                    sc += scoreOne(id, ar);\n                }\n            }\n\n            return sc;\n        };\n\n        double bestScore = curScore;\n        int bestT = (cp.coord >= 0 ? clampLL(cp.coord, lo, hi) : lo);\n\n        for (int t = lo; t <= hi; t++) {\n            if (((t - lo) & 1023) == 0 && timer.elapsed() > stopTime) break;\n            double sc = eval(t);\n            if (sc > bestScore + 1e-15) {\n                bestScore = sc;\n                bestT = t;\n            }\n        }\n\n        lm.ok = true;\n        lm.newCoord = bestT;\n        lm.delta = bestScore - curScore;\n        return lm;\n    }\n\n    void applyLineMove(State& st, const LineMove& lm) {\n        int t = lm.newCoord;\n\n        if (lm.orient == 0) {\n            for (int id : lm.A) st.rect[id].c = t;\n            for (int id : lm.B) st.rect[id].a = t;\n        } else {\n            for (int id : lm.A) st.rect[id].d = t;\n            for (int id : lm.B) st.rect[id].b = t;\n        }\n\n        vector<char> upd(n, 0);\n        for (int id : lm.A) {\n            if (!upd[id]) {\n                upd[id] = 1;\n                double ns = scoreOne(id, rectArea(st.rect[id]));\n                st.total += ns - st.val[id];\n                st.val[id] = ns;\n            }\n        }\n        for (int id : lm.B) {\n            if (!upd[id]) {\n                upd[id] = 1;\n                double ns = scoreOne(id, rectArea(st.rect[id]));\n                st.total += ns - st.val[id];\n                st.val[id] = ns;\n            }\n        }\n    }\n\n    bool boundarySequentialPass(State& st, int orient, bool includeFrontier, double stopTime) {\n        vector<LineComp> comps = buildLineComponents(st, orient);\n\n        if (includeFrontier) {\n            vector<LineComp> extra = buildFrontierComponents(st, orient);\n            for (auto& cp : extra) comps.push_back(std::move(cp));\n        }\n\n        sort(comps.begin(), comps.end(), [](const LineComp& p, const LineComp& q) {\n            int sp = (int)p.A.size() + (int)p.B.size();\n            int sq = (int)q.A.size() + (int)q.B.size();\n            if (sp != sq) return sp > sq;\n            bool lp = p.coord >= 0;\n            bool lq = q.coord >= 0;\n            if (lp != lq) return lp > lq;\n            return p.coord < q.coord;\n        });\n\n        bool any = false;\n\n        for (const LineComp& cp : comps) {\n            if (timer.elapsed() > stopTime) break;\n\n            LineMove mv = bestBoundaryComponent(st, cp, stopTime);\n            if (mv.ok && mv.delta > 1e-12) {\n                applyLineMove(st, mv);\n                any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool boundaryGreedyPasses(State& st, int passes, double stopTime, bool includeFrontier) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n\n            bool any = false;\n            if (rng.nextInt(2) == 0) {\n                any |= boundarySequentialPass(st, 0, includeFrontier, stopTime);\n                any |= boundarySequentialPass(st, 1, includeFrontier, stopTime);\n            } else {\n                any |= boundarySequentialPass(st, 1, includeFrontier, stopTime);\n                any |= boundarySequentialPass(st, 0, includeFrontier, stopTime);\n            }\n\n            if (!any) break;\n            globalAny = true;\n        }\n\n        return globalAny;\n    }\n\n    Rect groupBoundingBox(const State& st, const vector<int>& ids) const {\n        Rect box{SZ, SZ, 0, 0};\n        for (int id : ids) {\n            const Rect& rc = st.rect[id];\n            box.a = min(box.a, rc.a);\n            box.b = min(box.b, rc.b);\n            box.c = max(box.c, rc.c);\n            box.d = max(box.d, rc.d);\n        }\n        return box;\n    }\n\n    bool bboxClearForGroup(const State& st, const vector<int>& ids, const Rect& box) const {\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n        for (int i = 0; i < n; i++) {\n            if (in[i]) continue;\n            if (overlapRect(st.rect[i], box)) return false;\n        }\n        return true;\n    }\n\n    long long desiredSum(const vector<int>& ids) const {\n        long long s = 0;\n        for (int id : ids) s += r[id];\n        return s;\n    }\n\n    bool boxUsableForGroup(const State& st, const vector<int>& ids, const Rect& box) const {\n        if (!(0 <= box.a && box.a < box.c && box.c <= SZ)) return false;\n        if (!(0 <= box.b && box.b < box.d && box.d <= SZ)) return false;\n\n        for (int id : ids) {\n            if (!(box.a <= x[id] && x[id] + 1 <= box.c)) return false;\n            if (!(box.b <= y[id] && y[id] + 1 <= box.d)) return false;\n        }\n\n        return bboxClearForGroup(st, ids, box);\n    }\n\n    vector<Rect> alternativeRepackBoxes(const State& st, const vector<int>& ids, const Rect& orig) const {\n        vector<Rect> res;\n\n        long long S = 0;\n        int minX = SZ, minY = SZ, maxX1 = 0, maxY1 = 0;\n\n        for (int id : ids) {\n            S += r[id];\n            minX = min(minX, x[id]);\n            minY = min(minY, y[id]);\n            maxX1 = max(maxX1, x[id] + 1);\n            maxY1 = max(maxY1, y[id] + 1);\n        }\n\n        int pW = max(1, maxX1 - minX);\n        int pH = max(1, maxY1 - minY);\n        int oW = orig.c - orig.a;\n        int oH = orig.d - orig.b;\n\n        auto sameBox = [](const Rect& u, const Rect& v) {\n            return u.a == v.a && u.b == v.b && u.c == v.c && u.d == v.d;\n        };\n\n        auto addRect = [&](const Rect& bx) {\n            if ((int)res.size() >= 4) return;\n            if (sameBox(bx, orig)) return;\n            if (!boxUsableForGroup(st, ids, bx)) return;\n            for (const Rect& e : res) if (sameBox(e, bx)) return;\n            res.push_back(bx);\n        };\n\n        auto ceilDiv = [](long long a, long long b) -> long long {\n            return (a + b - 1) / b;\n        };\n\n        auto trySize = [&](long long W0, long long H0) {\n            if ((int)res.size() >= 4) return;\n            if (W0 <= 0 || H0 <= 0) return;\n\n            long long W = max<long long>(W0, pW);\n            long long H = max<long long>(H0, pH);\n\n            if (W > SZ) return;\n\n            long long needH = ceilDiv(S, W);\n            if (H < needH) H = needH;\n\n            if (H > SZ) {\n                H = SZ;\n                long long needW = ceilDiv(S, H);\n                if (W < needW) W = needW;\n            }\n\n            if (W > SZ || H > SZ) return;\n\n            int w = (int)W;\n            int h = (int)H;\n\n            auto placements = [&](bool inside) {\n                int alo = max(0, maxX1 - w);\n                int ahi = min(minX, SZ - w);\n                int blo = max(0, maxY1 - h);\n                int bhi = min(minY, SZ - h);\n\n                if (inside) {\n                    alo = max(alo, orig.a);\n                    ahi = min(ahi, orig.c - w);\n                    blo = max(blo, orig.b);\n                    bhi = min(bhi, orig.d - h);\n                }\n\n                if (alo > ahi || blo > bhi) return;\n\n                vector<int> As, Bs;\n                auto addA = [&](long long v) {\n                    int z = clampLL(v, alo, ahi);\n                    for (int q : As) if (q == z) return;\n                    As.push_back(z);\n                };\n                auto addB = [&](long long v) {\n                    int z = clampLL(v, blo, bhi);\n                    for (int q : Bs) if (q == z) return;\n                    Bs.push_back(z);\n                };\n\n                addA(((long long)orig.a + orig.c - w) / 2);\n                addA(orig.a);\n                addA((long long)orig.c - w);\n                addA((long long)minX - w / 2);\n\n                addB(((long long)orig.b + orig.d - h) / 2);\n                addB(orig.b);\n                addB((long long)orig.d - h);\n                addB((long long)minY - h / 2);\n\n                for (int a : As) {\n                    for (int b : Bs) {\n                        addRect(Rect{a, b, a + w, b + h});\n                        if ((int)res.size() >= 4) return;\n                    }\n                }\n            };\n\n            bool inside = (w <= oW && h <= oH);\n            placements(inside);\n            if (!inside) placements(false);\n        };\n\n        auto ceilDiv2 = ceilDiv;\n\n        trySize(oW, ceilDiv2(S, max(1, oW)));\n        trySize(ceilDiv2(S, max(1, oH)), oH);\n\n        {\n            long double asp = max(0.05L, min(20.0L, (long double)oW / max(1, oH)));\n            long long w = max(1LL, (long long)llroundl(sqrtl((long double)S * asp)));\n            trySize(w, ceilDiv2(S, w));\n        }\n\n        {\n            long long w = max(1LL, (long long)llroundl(sqrtl((long double)S)));\n            trySize(w, ceilDiv2(S, w));\n        }\n\n        {\n            long double asp = max(0.05L, min(20.0L, (long double)pW / max(1, pH)));\n            long long w = max(1LL, (long long)llroundl(sqrtl((long double)S * asp)));\n            trySize(w, ceilDiv2(S, w));\n        }\n\n        trySize(pW, ceilDiv2(S, max(1, pW)));\n        trySize(ceilDiv2(S, max(1, pH)), pH);\n\n        return res;\n    }\n\n    bool closureGroup(const State& st, vector<int> ids, int maxK, vector<int>& out) const {\n        if (ids.empty()) return false;\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if ((int)ids.size() > maxK) return false;\n\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n\n        Rect box = groupBoundingBox(st, ids);\n\n        bool changed = true;\n        while (changed) {\n            changed = false;\n\n            for (int i = 0; i < n; i++) {\n                if (in[i]) continue;\n\n                if (overlapRect(st.rect[i], box)) {\n                    in[i] = 1;\n                    ids.push_back(i);\n\n                    if ((int)ids.size() > maxK) return false;\n\n                    const Rect& rc = st.rect[i];\n                    box.a = min(box.a, rc.a);\n                    box.b = min(box.b, rc.b);\n                    box.c = max(box.c, rc.c);\n                    box.d = max(box.d, rc.d);\n\n                    changed = true;\n                }\n            }\n        }\n\n        sort(ids.begin(), ids.end());\n        out = ids;\n        return true;\n    }\n\n    bool validSubsetRects(const vector<Rect>& v, const vector<int>& ids) const {\n        vector<char> in(n, 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int id : ids) {\n            const Rect& rc = v[id];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[id] && x[id] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[id] && y[id] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < (int)ids.size(); i++) {\n            for (int j = i + 1; j < (int)ids.size(); j++) {\n                if (overlapRect(v[ids[i]], v[ids[j]])) return false;\n            }\n        }\n\n        for (int id : ids) {\n            for (int j = 0; j < n; j++) {\n                if (in[j]) continue;\n                if (overlapRect(v[id], v[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\n    void recomputeSubset(State& st, const vector<int>& ids) {\n        for (int id : ids) {\n            double ns = scoreOne(id, rectArea(st.rect[id]));\n            st.total += ns - st.val[id];\n            st.val[id] = ns;\n        }\n    }\n\n    bool greedySubset(State& st, vector<int> ids, int passes, double stopTime) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ids);\n\n            bool any = false;\n            for (int id : ids) {\n                for (int rep = 0; rep < 4; rep++) {\n                    Move mv = bestMove(st, id);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(st, id, mv);\n                        any = true;\n                        globalAny = true;\n                    } else {\n                        break;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool pairSubsetPass(State& st, vector<int> ids, int passes, double stopTime) {\n        bool globalAny = false;\n\n        for (int pass = 0; pass < passes; pass++) {\n            if (timer.elapsed() > stopTime) return globalAny;\n            shuffleVector(ids);\n\n            bool any = false;\n            int checks = 0;\n\n            for (int ai = 0; ai < (int)ids.size(); ai++) {\n                int i = ids[ai];\n                for (int bj = ai + 1; bj < (int)ids.size(); bj++) {\n                    if ((checks++ & 63) == 0 && timer.elapsed() > stopTime) return globalAny;\n\n                    int j = ids[bj];\n                    const Rect& A = st.rect[i];\n                    const Rect& B = st.rect[j];\n\n                    PairMove best;\n                    best.delta = 0.0;\n\n                    if (yOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.c <= B.a) mv = bestPairVertical(st, i, j);\n                        else if (B.c <= A.a) mv = bestPairVertical(st, j, i);\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (xOverlap(A, B)) {\n                        PairMove mv;\n                        if (A.d <= B.b) mv = bestPairHorizontal(st, i, j);\n                        else if (B.d <= A.b) mv = bestPairHorizontal(st, j, i);\n                        if (mv.ok && (!best.ok || mv.delta > best.delta)) best = mv;\n                    }\n\n                    if (best.ok && best.delta > 1e-12) {\n                        applyPair(st, best);\n                        any = true;\n                        globalAny = true;\n                    }\n                }\n            }\n\n            if (!any) break;\n        }\n\n        return globalAny;\n    }\n\n    bool tryRepackGroup(State& st, vector<int> ids, double stopTime, int trials) {\n        if (timer.elapsed() > stopTime) return false;\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if ((int)ids.size() < 2 || (int)ids.size() > 8) return false;\n\n        Rect box = groupBoundingBox(st, ids);\n        if (!(box.a < box.c && box.b < box.d)) return false;\n        if (!bboxClearForGroup(st, ids, box)) return false;\n\n        State bestLocal = st;\n\n        double beforeScore = 0.0;\n        for (int id : ids) beforeScore += st.val[id];\n\n        long long desire = desiredSum(ids);\n        double mismatch = fabs((double)rectArea(box) - (double)desire) / max(1.0, (double)desire);\n        double loss = (double)ids.size() - beforeScore;\n\n        auto consider = [&](const vector<Rect>& fullRects) {\n            if (timer.elapsed() > stopTime) return;\n            if (!validSubsetRects(fullRects, ids)) return;\n\n            State tr = st;\n            for (int id : ids) tr.rect[id] = fullRects[id];\n            recomputeSubset(tr, ids);\n\n            greedySubset(tr, ids, 2, stopTime);\n            pairSubsetPass(tr, ids, 1, stopTime);\n            greedySubset(tr, ids, 1, stopTime);\n\n            if (tr.total > bestLocal.total + 1e-12) bestLocal = std::move(tr);\n        };\n\n        if ((int)ids.size() <= 6 && timer.elapsed() + 0.004 < stopTime) {\n            vector<Rect> rects = st.rect;\n            buildRecBeam(ids, box, rects, stopTime);\n            consider(rects);\n        }\n\n        {\n            vector<Rect> rects = st.rect;\n            buildRec(ids, box, rects, 0.0);\n            consider(rects);\n        }\n\n        if ((loss > 0.015 || mismatch > 0.08) && timer.elapsed() + 0.005 < stopTime) {\n            vector<Rect> altBoxes = alternativeRepackBoxes(st, ids, box);\n\n            int used = 0;\n            for (const Rect& bx : altBoxes) {\n                if (used >= 3) break;\n                if (timer.elapsed() + 0.003 > stopTime) break;\n\n                {\n                    vector<Rect> rects = st.rect;\n                    if ((int)ids.size() <= 5 && timer.elapsed() + 0.004 < stopTime) {\n                        buildRecBeam(ids, bx, rects, stopTime);\n                    } else {\n                        buildRec(ids, bx, rects, 0.0);\n                    }\n                    consider(rects);\n                }\n\n                if (trials >= 4 && (int)ids.size() <= 4 && timer.elapsed() + 0.004 < stopTime) {\n                    vector<Rect> rects = st.rect;\n                    double temp = 0.0005 * pow(500.0, rng.nextDouble());\n                    buildRec(ids, bx, rects, temp);\n                    consider(rects);\n                }\n\n                used++;\n            }\n        }\n\n        if (trials >= 3 && timer.elapsed() < stopTime) {\n            vector<Rect> rects = st.rect;\n            for (int id : ids) rects[id] = {x[id], y[id], x[id] + 1, y[id] + 1};\n            consider(rects);\n        }\n\n        for (int t = 0; t < trials && timer.elapsed() < stopTime; t++) {\n            vector<Rect> rects = st.rect;\n            double temp = 0.0005 * pow(500.0, rng.nextDouble());\n            buildRec(ids, box, rects, temp);\n            consider(rects);\n        }\n\n        if (bestLocal.total > st.total + 1e-12) {\n            st = std::move(bestLocal);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool tryRepackGroupClosure(State& st, vector<int> ids, double stopTime, int trials, int maxK = 8) {\n        vector<int> cl;\n        if (!closureGroup(st, std::move(ids), maxK, cl)) return false;\n        return tryRepackGroup(st, cl, stopTime, trials);\n    }\n\n    bool componentRepackPass(State& st, double stopTime, int maxGroups) {\n        struct GC {\n            double key;\n            vector<int> ids;\n        };\n\n        vector<GC> groups;\n\n        for (int orient = 0; orient < 2; orient++) {\n            vector<LineComp> comps = buildLineComponents(st, orient);\n            for (const LineComp& cp : comps) {\n                vector<int> ids = cp.A;\n                for (int id : cp.B) ids.push_back(id);\n\n                vector<int> cl;\n                if (!closureGroup(st, ids, 8, cl)) continue;\n\n                int k = (int)cl.size();\n                if (k < 2 || k > 8) continue;\n\n                double loss = 0.0;\n                for (int id : cl) loss += 1.0 - st.val[id];\n\n                double key = loss + 0.0015 * k + 1e-5 * rng.nextDouble();\n                groups.push_back({key, cl});\n            }\n        }\n\n        sort(groups.begin(), groups.end(), [](const GC& p, const GC& q) {\n            return p.key > q.key;\n        });\n\n        bool any = false;\n        int tried = 0;\n\n        for (auto& g : groups) {\n            if (timer.elapsed() > stopTime) break;\n            if (tried++ >= maxGroups) break;\n\n            int k = (int)g.ids.size();\n            int trials = (k <= 3 ? 5 : 3);\n\n            if (tryRepackGroup(st, g.ids, stopTime, trials)) any = true;\n        }\n\n        return any;\n    }\n\n    int rectGap(const Rect& A, const Rect& B) const {\n        int dx = 0;\n        if (A.c < B.a) dx = B.a - A.c;\n        else if (B.c < A.a) dx = A.a - B.c;\n\n        int dy = 0;\n        if (A.d < B.b) dy = B.b - A.d;\n        else if (B.d < A.b) dy = A.b - B.d;\n\n        int penalty = (dx > 0 && dy > 0) ? 10000 : 0;\n        return dx + dy + penalty;\n    }\n\n    bool pairBlockRepackPass(State& st, double stopTime, int maxGroups) {\n        struct PC {\n            double key;\n            int i, j;\n        };\n\n        vector<PC> cand;\n        bool stop = false;\n\n        for (int i = 0; i < n && !stop; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (((int)cand.size() & 511) == 0 && timer.elapsed() > stopTime) {\n                    stop = true;\n                    break;\n                }\n\n                int g = rectGap(st.rect[i], st.rect[j]);\n                double loss = (1.0 - st.val[i]) + (1.0 - st.val[j]);\n\n                if (g > 8000 && loss < 0.05) continue;\n\n                double key = loss - 0.0000015 * g + 0.0001 / (1.0 + g) + 1e-5 * rng.nextDouble();\n                cand.push_back({key, i, j});\n            }\n        }\n\n        sort(cand.begin(), cand.end(), [](const PC& p, const PC& q) {\n            return p.key > q.key;\n        });\n\n        bool any = false;\n        int lim = min(maxGroups, (int)cand.size());\n\n        for (int t = 0; t < lim; t++) {\n            if (timer.elapsed() > stopTime) break;\n            if (tryRepackGroupClosure(st, vector<int>{cand[t].i, cand[t].j}, stopTime, 3, 8)) any = true;\n        }\n\n        return any;\n    }\n\n    bool neighborClosureRepackPass(State& st, double stopTime, int maxBase) {\n        vector<int> ord(n);\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int u, int v) {\n            return st.val[u] < st.val[v];\n        });\n\n        bool any = false;\n        int bases = min(maxBase, n);\n\n        for (int bi = 0; bi < bases && timer.elapsed() < stopTime; bi++) {\n            int base = ord[bi];\n\n            vector<pair<int, int>> near;\n            near.reserve(n - 1);\n            for (int j = 0; j < n; j++) {\n                if (j == base) continue;\n                near.push_back({rectGap(st.rect[base], st.rect[j]), j});\n            }\n            sort(near.begin(), near.end());\n\n            int lim = min(4, (int)near.size());\n            for (int t = 0; t < lim && timer.elapsed() < stopTime; t++) {\n                if (tryRepackGroupClosure(st, vector<int>{base, near[t].second}, stopTime, 3, 8)) any = true;\n            }\n\n            if (near.size() >= 2 && timer.elapsed() < stopTime) {\n                vector<int> g{base, near[0].second, near[1].second};\n                if (tryRepackGroupClosure(st, g, stopTime, 3, 8)) any = true;\n            }\n\n            if (near.size() >= 3 && timer.elapsed() < stopTime) {\n                vector<int> g{base, near[0].second, near[1].second, near[2].second};\n                if (tryRepackGroupClosure(st, g, stopTime, 2, 8)) any = true;\n            }\n        }\n\n        return any;\n    }\n\n    bool randomBlockRepackAttempts(State& st, double stopTime, int attempts) {\n        bool any = false;\n\n        for (int at = 0; at < attempts && timer.elapsed() < stopTime; at++) {\n            int base;\n            if (rng.nextDouble() < 0.75) base = selectBad(st);\n            else base = rng.nextInt(n);\n\n            vector<int> group{base};\n            vector<char> used(n, 0);\n            used[base] = 1;\n\n            int target = 2 + rng.nextInt(4);\n\n            for (int step = 1; step < target && timer.elapsed() < stopTime; step++) {\n                vector<pair<double, int>> cands;\n\n                for (int j = 0; j < n; j++) {\n                    if (used[j]) continue;\n\n                    int g = 1e9;\n                    for (int id : group) {\n                        g = min(g, rectGap(st.rect[id], st.rect[j]));\n                    }\n\n                    double key = (double)g - 1800.0 * (1.0 - st.val[j]) + 20.0 * rng.nextDouble();\n                    cands.push_back({key, j});\n                }\n\n                if (cands.empty()) break;\n                sort(cands.begin(), cands.end());\n\n                int lim = min(6, (int)cands.size());\n                int pick = 0;\n                if (rng.nextDouble() > 0.70) pick = rng.nextInt(lim);\n\n                int add = cands[pick].second;\n                used[add] = 1;\n                group.push_back(add);\n\n                if ((int)group.size() >= 2) {\n                    if (tryRepackGroupClosure(st, group, stopTime, 3, 8)) {\n                        any = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        return any;\n    }\n\n    void randomGreedyOps(State& st, int ops, double stopTime) {\n        for (int op = 0; op < ops; op++) {\n            if ((op & 255) == 0 && timer.elapsed() > stopTime) break;\n\n            int i;\n            if (rng.nextDouble() < 0.85) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Move mv = bestMove(st, i);\n            if (mv.ok && mv.delta > 1e-12) applyMove(st, i, mv);\n        }\n    }\n\n    bool randomPairMove(State& st) {\n        int i;\n        if (rng.nextDouble() < 0.80) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n\n        static constexpr int K = 8;\n        int cand[K];\n        int gap[K];\n        int cnt = 0;\n\n        auto addCand = [&](int j, int g) {\n            if (cnt < K) {\n                cand[cnt] = j;\n                gap[cnt] = g;\n                cnt++;\n            } else {\n                int worst = 0;\n                for (int t = 1; t < K; t++) {\n                    if (gap[t] > gap[worst]) worst = t;\n                }\n                if (g < gap[worst] || rng.nextDouble() < 0.02) {\n                    cand[worst] = j;\n                    gap[worst] = g;\n                }\n            }\n        };\n\n        const Rect& R = st.rect[i];\n\n        for (int j = 0; j < n; j++) if (j != i) {\n            const Rect& Q = st.rect[j];\n\n            if (dir == 0) {\n                if (Q.c <= R.a && yOverlap(Q, R)) addCand(j, R.a - Q.c);\n            } else if (dir == 1) {\n                if (R.c <= Q.a && yOverlap(R, Q)) addCand(j, Q.a - R.c);\n            } else if (dir == 2) {\n                if (Q.d <= R.b && xOverlap(Q, R)) addCand(j, R.b - Q.d);\n            } else {\n                if (R.d <= Q.b && xOverlap(R, Q)) addCand(j, Q.b - R.d);\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int pos = 0;\n        for (int t = 1; t < cnt; t++) if (gap[t] < gap[pos]) pos = t;\n        if (rng.nextDouble() < 0.35) pos = rng.nextInt(cnt);\n\n        int j = cand[pos];\n\n        PairMove mv;\n        if (dir == 0) mv = bestPairVertical(st, j, i);\n        else if (dir == 1) mv = bestPairVertical(st, i, j);\n        else if (dir == 2) mv = bestPairHorizontal(st, j, i);\n        else mv = bestPairHorizontal(st, i, j);\n\n        if (mv.ok && mv.delta > 1e-12) {\n            applyPair(st, mv);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomResize(State& st, double temp, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.55) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int dir = rng.nextInt(4);\n        auto [lo, hi] = legalInterval(st, i, dir);\n        if (lo > hi) return false;\n\n        const Rect& rc = st.rect[i];\n        int cur = getCoord(rc, dir);\n        if (lo == hi) return false;\n\n        int coord = cur;\n        double q = rng.nextDouble();\n\n        if (q < 0.25) {\n            Move mv = bestEdgeDir(st, i, dir);\n            if (!mv.ok) return false;\n            coord = mv.coord;\n        } else if (q < 0.80) {\n            long long ar = rectArea(rc);\n            bool under = ar < r[i];\n            bool preferImprove = rng.nextDouble() < 0.72;\n\n            int sign;\n            if (dir == 0 || dir == 2) sign = under ? -1 : +1;\n            else sign = under ? +1 : -1;\n\n            if (!preferImprove) sign = -sign;\n\n            int maxd = (sign < 0 ? cur - lo : hi - cur);\n            if (maxd <= 0) {\n                sign = -sign;\n                maxd = (sign < 0 ? cur - lo : hi - cur);\n            }\n\n            if (maxd > 0) {\n                int step = 1 + (int)(3000.0 * (1.0 - progress) * (1.0 - progress));\n                int d = 1 + rng.nextInt(min(maxd, step));\n                coord = cur + sign * d;\n            } else {\n                coord = lo + rng.nextInt(hi - lo + 1);\n            }\n        } else {\n            coord = lo + rng.nextInt(hi - lo + 1);\n        }\n\n        if (coord == cur) return false;\n\n        long long newArea = areaAfterCoord(rc, dir, coord);\n        double ns = scoreOne(i, newArea);\n        double delta = ns - st.val[i];\n\n        if (delta >= 0.0 || rng.nextDouble() < exp(delta / max(temp, 1e-9))) {\n            applyCoord(st, i, dir, coord, ns);\n            return true;\n        }\n        return false;\n    }\n\n    bool randomShift(State& st, double progress) {\n        int i;\n        if (rng.nextDouble() < 0.5) i = selectBad(st);\n        else i = rng.nextInt(n);\n\n        int orient = rng.nextInt(2);\n        Rect& ri = st.rect[i];\n\n        int lo, hi;\n\n        if (orient == 0) {\n            lo = max(-ri.a, x[i] + 1 - ri.c);\n            hi = min(SZ - ri.c, x[i] - ri.a);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!yOverlap(ri, rj)) continue;\n\n                if (rj.c <= ri.a) lo = max(lo, rj.c - ri.a);\n                else if (rj.a >= ri.c) hi = min(hi, rj.a - ri.c);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.a += d;\n            ri.c += d;\n            return true;\n        } else {\n            lo = max(-ri.b, y[i] + 1 - ri.d);\n            hi = min(SZ - ri.d, y[i] - ri.b);\n\n            for (int j = 0; j < n; j++) if (j != i) {\n                const Rect& rj = st.rect[j];\n                if (!xOverlap(ri, rj)) continue;\n\n                if (rj.d <= ri.b) lo = max(lo, rj.d - ri.b);\n                else if (rj.b >= ri.d) hi = min(hi, rj.b - ri.d);\n            }\n\n            if (lo > hi || (lo == 0 && hi == 0)) return false;\n\n            int d = 0;\n            if (rng.nextDouble() < 0.70) {\n                int step = 1 + (int)(1200.0 * (1.0 - progress));\n                int L = max(lo, -step);\n                int R = min(hi, step);\n                if (L <= R) d = L + rng.nextInt(R - L + 1);\n            } else {\n                d = lo + rng.nextInt(hi - lo + 1);\n            }\n\n            if (d == 0) return false;\n            ri.b += d;\n            ri.d += d;\n            return true;\n        }\n    }\n\n    bool randomReshape(State& st, double progress) {\n        for (int attempt = 0; attempt < 3; attempt++) {\n            int i;\n            if (rng.nextDouble() < 0.25) i = selectBad(st);\n            else i = rng.nextInt(n);\n\n            Rect oldRect = st.rect[i];\n            double oldVal = st.val[i];\n            double oldTotal = st.total;\n\n            int dir1 = rng.nextInt(4);\n            int dir2;\n            if (dir1 < 2) dir2 = 2 + rng.nextInt(2);\n            else dir2 = rng.nextInt(2);\n\n            auto [lo, hi] = legalInterval(st, i, dir1);\n            if (lo > hi) continue;\n\n            int cur = getCoord(st.rect[i], dir1);\n            if (lo == hi) continue;\n\n            int coord = cur;\n            double q = rng.nextDouble();\n\n            if (q < 0.22) {\n                coord = (rng.nextInt(2) ? lo : hi);\n            } else {\n                int step = 1 + (int)(2600.0 * (1.0 - progress) + 80.0);\n                int L = max(lo, cur - step);\n                int R = min(hi, cur + step);\n                if (L > R) {\n                    L = lo;\n                    R = hi;\n                }\n                coord = L + rng.nextInt(R - L + 1);\n            }\n\n            if (coord == cur) {\n                if (cur > lo) coord = cur - 1;\n                else if (cur < hi) coord = cur + 1;\n                else continue;\n            }\n\n            long long ar1 = areaAfterCoord(st.rect[i], dir1, coord);\n            double ns1 = scoreOne(i, ar1);\n            applyCoord(st, i, dir1, coord, ns1);\n\n            Move mv = bestEdgeDir(st, i, dir2);\n            if (mv.ok) applyMove(st, i, mv);\n\n            bool changed =\n                st.rect[i].a != oldRect.a || st.rect[i].b != oldRect.b ||\n                st.rect[i].c != oldRect.c || st.rect[i].d != oldRect.d;\n\n            if (changed && st.val[i] + 1e-12 >= oldVal) return true;\n\n            st.rect[i] = oldRect;\n            st.val[i] = oldVal;\n            st.total = oldTotal;\n        }\n\n        return false;\n    }\n\n    State initialSolution() {\n        constexpr double INIT_END = 0.80;\n\n        State best;\n        bool hasBest = false;\n\n        auto consider = [&](const State& st) {\n            if (!hasBest || st.total > best.total) {\n                best = st;\n                hasBest = true;\n            }\n        };\n\n        {\n            vector<Rect> rects = buildRecursive(0.0);\n            State st = makeState(rects);\n            greedyPasses(st, 5, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            boundaryGreedyPasses(st, 1, INIT_END, false);\n            randomGreedyOps(st, 5 * n, INIT_END);\n            consider(st);\n        }\n\n        if (timer.elapsed() < INIT_END) {\n            vector<Rect> rects = buildUnit();\n            State st = makeState(rects);\n            greedyPasses(st, 7, INIT_END);\n            randomGreedyOps(st, 12 * n, INIT_END);\n            pairGreedyPasses(st, 1, INIT_END);\n            consider(st);\n        }\n\n        while (timer.elapsed() < INIT_END) {\n            double temp = 0.00035 * pow(180.0, rng.nextDouble());\n            vector<Rect> rects = buildRecursive(temp);\n            State st = makeState(rects);\n\n            greedyPasses(st, 2, INIT_END);\n            randomGreedyOps(st, 3 * n, INIT_END);\n            consider(st);\n        }\n\n        return best;\n    }\n\n    State improve(State bestState) {\n        State cur = bestState;\n\n        double preEnd = min(TIME_LIMIT - 0.72, timer.elapsed() + 0.38);\n        boundaryGreedyPasses(cur, 2, preEnd, true);\n        pairGreedyPasses(cur, 1, preEnd);\n        greedyPasses(cur, 2, preEnd);\n        boundaryGreedyPasses(cur, 1, preEnd, true);\n\n        if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n        double saStart = timer.elapsed();\n        double saEnd = TIME_LIMIT - 0.50;\n\n        int iter = 0;\n        double progress = 0.0;\n        double temp = 0.05;\n\n        while (true) {\n            if ((iter & 1023) == 0) {\n                double now = timer.elapsed();\n                if (now > saEnd) break;\n\n                progress = (now - saStart) / max(1e-9, saEnd - saStart);\n                progress = min(1.0, max(0.0, progress));\n\n                double T0 = 0.050;\n                double T1 = 0.00001;\n                temp = T0 * pow(T1 / T0, progress);\n            }\n\n            double q = rng.nextDouble();\n\n            if (q < 0.05) {\n                randomShift(cur, progress);\n            } else if (q < 0.12) {\n                randomReshape(cur, progress);\n            } else if (q < 0.34) {\n                int i;\n                if (rng.nextDouble() < 0.82) i = selectBad(cur);\n                else i = rng.nextInt(n);\n\n                Move mv = bestMove(cur, i);\n                if (mv.ok && mv.delta > 1e-12) applyMove(cur, i, mv);\n            } else if (q < 0.62) {\n                randomPairMove(cur);\n            } else {\n                randomResize(cur, temp, progress);\n            }\n\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            if ((iter & 65535) == 0) {\n                double threshold = max(1.0, 0.015 * n);\n                if (cur.total < bestState.total - threshold) cur = bestState;\n            }\n\n            iter++;\n        }\n\n        cur = bestState;\n\n        int stagnant = 0;\n        const double finalLoopEnd = TIME_LIMIT - FINAL_RESERVE;\n\n        while (timer.elapsed() < finalLoopEnd) {\n            bool imp = false;\n\n            imp |= boundaryGreedyPasses(cur, 1, finalLoopEnd, true);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            imp |= pairGreedyPasses(cur, 1, finalLoopEnd);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            imp |= greedyPasses(cur, 1, finalLoopEnd);\n            if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n            double rem = finalLoopEnd - timer.elapsed();\n            if (rem > 0.18) {\n                double blockStop = min(finalLoopEnd, timer.elapsed() + 0.13);\n\n                imp |= componentRepackPass(cur, blockStop, 24);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= neighborClosureRepackPass(cur, blockStop, 7);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= pairBlockRepackPass(cur, blockStop, 20);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n\n                imp |= randomBlockRepackAttempts(cur, blockStop, 7);\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n            }\n\n            for (int k = 0; k < 240 && timer.elapsed() < finalLoopEnd; k++) {\n                double q = rng.nextDouble();\n\n                if (q < 0.28) {\n                    if (randomPairMove(cur)) imp = true;\n                } else if (q < 0.40) {\n                    if (randomReshape(cur, 1.0)) imp = true;\n                } else {\n                    int i;\n                    if (rng.nextDouble() < 0.90) i = selectBad(cur);\n                    else i = rng.nextInt(n);\n\n                    Move mv = bestMove(cur, i);\n                    if (mv.ok && mv.delta > 1e-12) {\n                        applyMove(cur, i, mv);\n                        imp = true;\n                    }\n                }\n\n                if (cur.total > bestState.total + 1e-12) bestState = cur;\n            }\n\n            if (!imp) {\n                stagnant++;\n                if (stagnant >= 4) break;\n            } else {\n                stagnant = 0;\n            }\n        }\n\n        State polish = bestState;\n        greedyPasses(polish, 2, TIME_LIMIT);\n        pairGreedyPasses(polish, 1, TIME_LIMIT);\n        boundaryGreedyPasses(polish, 1, TIME_LIMIT, false);\n        greedyPasses(polish, 1, TIME_LIMIT);\n        if (polish.total > bestState.total + 1e-12) bestState = std::move(polish);\n\n        return bestState;\n    }\n\n    bool validateRects(const vector<Rect>& v) const {\n        if ((int)v.size() != n) return false;\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = v[i];\n            if (!(0 <= rc.a && rc.a < rc.c && rc.c <= SZ)) return false;\n            if (!(0 <= rc.b && rc.b < rc.d && rc.d <= SZ)) return false;\n            if (!(rc.a <= x[i] && x[i] + 1 <= rc.c)) return false;\n            if (!(rc.b <= y[i] && y[i] + 1 <= rc.d)) return false;\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = i + 1; j < n; j++) {\n                if (xOverlap(v[i], v[j]) && yOverlap(v[i], v[j])) return false;\n            }\n        }\n\n        return true;\n    }\n\npublic:\n    void run() {\n        ios::sync_with_stdio(false);\n        cin.tie(nullptr);\n\n        cin >> n;\n        x.resize(n);\n        y.resize(n);\n        r.resize(n);\n        rd.resize(n);\n        invR.resize(n);\n\n        uint64_t seed = 1234567891234567ULL;\n        for (int i = 0; i < n; i++) {\n            cin >> x[i] >> y[i] >> r[i];\n            rd[i] = (double)r[i];\n            invR[i] = 1.0 / rd[i];\n\n            uint64_t z = ((uint64_t)x[i] << 32) ^ ((uint64_t)y[i] << 16) ^ (uint64_t)r[i];\n            seed ^= splitmix64_hash(z + seed);\n        }\n        rng = FastRNG(seed);\n\n        timer.reset();\n\n        State bestState = initialSolution();\n        bestState = improve(bestState);\n\n        if (!validateRects(bestState.rect)) {\n            bestState = makeState(buildUnit());\n        }\n\n        for (int i = 0; i < n; i++) {\n            const Rect& rc = bestState.rect[i];\n            cout << rc.a << ' ' << rc.b << ' ' << rc.c << ' ' << rc.d << '\\n';\n        }\n    }\n};\n\nint main() {\n    Solver solver;\n    solver.run();\n    return 0;\n}","ahc002":"#pragma GCC optimize(\"O3,unroll-loops\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Solver {\n    static constexpr int N = 50;\n    static constexpr int V = N * N;\n    static constexpr int MAXT = V + 5;\n    static constexpr int MAXB = (V + 63) / 64;\n    static constexpr int POOL_LIMIT = 14;\n\n    using Bits = array<uint64_t, MAXB>;\n\n    int si, sj;\n    int startCell;\n    int M;\n\n    int tile[V];\n    int val[V];\n    int tilePot[MAXT];\n\n    int tileCnt[MAXT];\n    int tileCells[MAXT][2];\n    int tileMate[V];\n\n    int adj[V][4];\n    int adjN[V];\n    int borderDist[V];\n\n    int vis[MAXT];\n    int visitToken = 1;\n\n    int seenCell[V];\n    int seenTile[MAXT];\n    int seenBest[MAXT];\n    int bfsStamp = 1;\n    int que[V];\n\n    int pathIndex[V];\n    int rotSeen[V];\n    int rotStamp = 1;\n\n    Timer timer;\n    RNG rng;\n\n    double TL = 1.93;\n\n    vector<int> bestCells;\n    vector<int> bestCum;\n    int bestScore = -1;\n\n    vector<int> curCells;\n\n    struct PathCand {\n        vector<int> cells;\n        vector<int> cum;\n        int score;\n        uint64_t hash;\n    };\n\n    vector<PathCand> pool;\n\n    struct Params {\n        int reachW = 0;\n        int scoreW = 0;\n        int degW = 0;\n        int noise = 0;\n        int locW = 0;\n        int lossW = 0;\n        int endPenalty = 0;\n        int borderW = 0;\n        int straightW = 0;\n        int cntW = 0;\n    };\n\n    struct FloodResult {\n        int pot;\n        int cnt;\n    };\n\n    void buildAdj() {\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int c = i * N + j;\n                adjN[c] = 0;\n                borderDist[c] = min(min(i, N - 1 - i), min(j, N - 1 - j));\n\n                if (i > 0) adj[c][adjN[c]++] = c - N;\n                if (i + 1 < N) adj[c][adjN[c]++] = c + N;\n                if (j > 0) adj[c][adjN[c]++] = c - 1;\n                if (j + 1 < N) adj[c][adjN[c]++] = c + 1;\n            }\n        }\n    }\n\n    void read() {\n        cin >> si >> sj;\n        startCell = si * N + sj;\n\n        uint64_t h = 0x123456789abcdefULL;\n        auto mix = [&](uint64_t v) {\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        };\n\n        mix(si);\n        mix(sj);\n\n        fill(tileCnt, tileCnt + MAXT, 0);\n\n        int maxTid = -1;\n        for (int i = 0; i < V; i++) {\n            cin >> tile[i];\n            maxTid = max(maxTid, tile[i]);\n            mix((uint64_t)tile[i] + 1009);\n\n            int tid = tile[i];\n            int c = tileCnt[tid]++;\n            if (c < 2) tileCells[tid][c] = i;\n        }\n\n        M = maxTid + 1;\n\n        for (int i = 0; i < V; i++) {\n            cin >> val[i];\n            mix((uint64_t)val[i] + 9176);\n        }\n\n        fill(tilePot, tilePot + MAXT, 0);\n        for (int i = 0; i < V; i++) {\n            tilePot[tile[i]] = max(tilePot[tile[i]], val[i]);\n        }\n\n        fill(tileMate, tileMate + V, -1);\n        for (int t = 0; t < M; t++) {\n            if (tileCnt[t] == 2) {\n                int a = tileCells[t][0];\n                int b = tileCells[t][1];\n                tileMate[a] = b;\n                tileMate[b] = a;\n            }\n        }\n\n        memset(vis, 0, sizeof(vis));\n        memset(seenCell, 0, sizeof(seenCell));\n        memset(seenTile, 0, sizeof(seenTile));\n        memset(rotSeen, 0, sizeof(rotSeen));\n\n        rng = RNG(h);\n        buildAdj();\n    }\n\n    int newVisitToken() {\n        ++visitToken;\n        if (visitToken == INT_MAX) {\n            memset(vis, 0, sizeof(vis));\n            visitToken = 1;\n        }\n        return visitToken;\n    }\n\n    int newBfsStamp() {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            memset(seenCell, 0, sizeof(seenCell));\n            memset(seenTile, 0, sizeof(seenTile));\n            bfsStamp = 1;\n        }\n        return bfsStamp;\n    }\n\n    int newRotStamp() {\n        ++rotStamp;\n        if (rotStamp == INT_MAX) {\n            memset(rotSeen, 0, sizeof(rotSeen));\n            rotStamp = 1;\n        }\n        return rotStamp;\n    }\n\n    inline bool bitTest(const Bits& bits, int tid) const {\n        return (bits[tid >> 6] >> (tid & 63)) & 1ULL;\n    }\n\n    inline void bitSet(Bits& bits, int tid) const {\n        bits[tid >> 6] |= 1ULL << (tid & 63);\n    }\n\n    inline void bitClear(Bits& bits, int tid) const {\n        bits[tid >> 6] &= ~(1ULL << (tid & 63));\n    }\n\n    inline bool adjacentCell(int a, int b) const {\n        int d = abs(a - b);\n        if (d == N) return true;\n        if (d == 1 && a / N == b / N) return true;\n        return false;\n    }\n\n    inline int manhattanCell(int a, int b) const {\n        return abs(a / N - b / N) + abs(a % N - b % N);\n    }\n\n    void makeBitsFromPath(const vector<int>& path, Bits& bits) const {\n        bits.fill(0);\n        for (int c : path) bitSet(bits, tile[c]);\n    }\n\n    uint64_t calcPathHash(const vector<int>& cells) const {\n        uint64_t h = 0xcbf29ce484222325ULL;\n        for (int c : cells) {\n            h ^= (uint64_t)c + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n            h *= 0x100000001b3ULL;\n        }\n        h ^= (uint64_t)cells.size() * 0x9e3779b97f4a7c15ULL;\n        return h;\n    }\n\n    void sortPool() {\n        sort(pool.begin(), pool.end(), [](const PathCand& a, const PathCand& b) {\n            if (a.score != b.score) return a.score > b.score;\n            return a.cells.size() > b.cells.size();\n        });\n\n        vector<PathCand> np;\n        np.reserve(POOL_LIMIT);\n\n        for (auto& pc : pool) {\n            bool dup = false;\n            for (auto& q : np) {\n                if (q.hash == pc.hash && q.cells.size() == pc.cells.size()) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) {\n                np.push_back(std::move(pc));\n                if ((int)np.size() >= POOL_LIMIT) break;\n            }\n        }\n\n        pool.swap(np);\n    }\n\n    void addCandidate(const vector<int>& cells, int = -1) {\n        if (cells.empty()) return;\n\n        vector<int> cum(cells.size());\n        int s = 0;\n        for (int i = 0; i < (int)cells.size(); i++) {\n            s += val[cells[i]];\n            cum[i] = s;\n        }\n\n        uint64_t h = calcPathHash(cells);\n\n        if (s > bestScore || (s == bestScore && cells.size() > bestCells.size())) {\n            bestScore = s;\n            bestCells = cells;\n            bestCum = cum;\n        }\n\n        bool good = false;\n        if ((int)pool.size() < POOL_LIMIT) good = true;\n        else if (s + 2500 >= pool.back().score) good = true;\n        else if (s + 4500 >= bestScore) good = true;\n\n        if (!good) return;\n\n        PathCand pc;\n        pc.cells = cells;\n        pc.cum = std::move(cum);\n        pc.score = s;\n        pc.hash = h;\n\n        pool.push_back(std::move(pc));\n        sortPool();\n    }\n\n    void setBestFrom(const vector<int>& cells, int score) {\n        addCandidate(cells, score);\n    }\n\n    void considerCurrent(int score) {\n        addCandidate(curCells, score);\n    }\n\n    int choosePoolIndex() {\n        if (pool.empty()) return -1;\n\n        int n = (int)pool.size();\n        int r = rng.nextInt(100);\n\n        if (r < 58) return 0;\n        if (r < 82) return rng.nextInt(min(n, 4));\n        if (r < 95) return rng.nextInt(min(n, 8));\n        return rng.nextInt(n);\n    }\n\n    inline int degreeAfterToken(int cell, int forbidTid, int token) {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localNeighborSumToken(int cell, int forbidTid, int token) {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (vis[tid] == token) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int degreeAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            cnt++;\n        }\n        return cnt;\n    }\n\n    inline int localSumAfterBits(const Bits& bits, int cell, int forbidTid) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            int tid = tile[nb];\n            if (tid == forbidTid) continue;\n            if (bitTest(bits, tid)) continue;\n            s += val[nb];\n        }\n        return s;\n    }\n\n    inline int countUnvisitedMoves(const Bits& bits, int cell) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) cnt++;\n        }\n        return cnt;\n    }\n\n    inline int sumUnvisitedMoveValues(const Bits& bits, int cell) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (!bitTest(bits, tile[nb])) s += val[nb];\n        }\n        return s;\n    }\n\n    FloodResult floodPotential(int start, int forbidTid, int token) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (tid == forbidTid) continue;\n                if (vis[tid] == token) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    FloodResult floodPotentialBits(int start, const Bits& bits) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        int pot = 0;\n        int cnt = 0;\n\n        while (head < tail) {\n            int v = que[head++];\n            int vtid = tile[v];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n                int tid = tile[nb];\n\n                if (bitTest(bits, tid)) continue;\n                if (tid == vtid) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n\n                if (seenTile[tid] != stamp) {\n                    seenTile[tid] = stamp;\n                    seenBest[tid] = val[nb];\n                    pot += val[nb];\n                    cnt++;\n                } else if (val[nb] > seenBest[tid]) {\n                    pot += val[nb] - seenBest[tid];\n                    seenBest[tid] = val[nb];\n                }\n            }\n        }\n\n        return {pot, cnt};\n    }\n\n    Params makeParams(bool flood) {\n        Params p;\n\n        if (flood) {\n            int rwArr[4] = {6, 8, 10, 12};\n            int exArr[5] = {0, 0, 2, 4, 6};\n\n            p.reachW = rwArr[rng.nextInt(4)];\n            p.scoreW = p.reachW + exArr[rng.nextInt(5)];\n\n            if (rng.nextInt(10) < 8) {\n                p.degW = 40 + rng.nextInt(260);\n            } else {\n                p.degW = -(20 + rng.nextInt(100));\n            }\n\n            p.noise = 20 + rng.nextInt(250);\n            p.locW = (rng.nextInt(4) == 0 ? 1 : 0);\n            p.cntW = rng.nextInt(6);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(16) : -rng.nextInt(8));\n            p.straightW = rng.nextInt(101) - 50;\n        } else {\n            p.scoreW = 4 + rng.nextInt(18);\n\n            int mode = rng.nextInt(10);\n            if (mode < 5) {\n                p.degW = 200 + rng.nextInt(700);\n            } else if (mode < 8) {\n                p.degW = 50 + rng.nextInt(250);\n            } else {\n                p.degW = -(20 + rng.nextInt(120));\n            }\n\n            p.noise = 100 + rng.nextInt(900);\n            p.locW = rng.nextInt(4);\n            p.lossW = rng.nextInt(8);\n            p.endPenalty = 3000 + rng.nextInt(7000);\n            p.borderW = (rng.nextInt(100) < 80 ? rng.nextInt(25) : -rng.nextInt(10));\n            p.straightW = rng.nextInt(121) - 60;\n        }\n\n        return p;\n    }\n\n    Params makePilotParam() {\n        Params p;\n        p.scoreW = 8 + rng.nextInt(22);\n\n        int mode = rng.nextInt(100);\n        if (mode < 55) {\n            p.degW = 180 + rng.nextInt(620);\n        } else if (mode < 85) {\n            p.degW = 30 + rng.nextInt(220);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = rng.nextInt(5);\n        p.lossW = rng.nextInt(9);\n        p.endPenalty = 3500 + rng.nextInt(8000);\n        p.borderW = (rng.nextInt(100) < 82 ? rng.nextInt(26) : -rng.nextInt(12));\n        p.straightW = rng.nextInt(151) - 75;\n        p.noise = 0;\n        return p;\n    }\n\n    Params makePosaParam() {\n        Params p;\n        p.scoreW = 10 + rng.nextInt(25);\n\n        int mode = rng.nextInt(100);\n        if (mode < 70) {\n            p.degW = 80 + rng.nextInt(500);\n        } else if (mode < 90) {\n            p.degW = rng.nextInt(120);\n        } else {\n            p.degW = -(20 + rng.nextInt(120));\n        }\n\n        p.locW = 1 + rng.nextInt(4);\n        p.lossW = 3 + rng.nextInt(8);\n        p.endPenalty = 1000 + rng.nextInt(5000);\n        p.borderW = (rng.nextInt(100) < 75 ? rng.nextInt(20) : -rng.nextInt(8));\n        p.straightW = rng.nextInt(81) - 40;\n        p.noise = 50 + rng.nextInt(600);\n        return p;\n    }\n\n    int chooseCutLength(int L) {\n        if (L <= 1) return 0;\n\n        int r = rng.nextInt(100);\n\n        if (r < 22) return 0;\n\n        int cut = 0;\n\n        if (r < 66) {\n            int maxSuf = min(L - 1, 900);\n            int a = 1 + rng.nextInt(maxSuf);\n            int b = 1 + rng.nextInt(maxSuf);\n            int suf;\n            if (rng.nextInt(100) < 75) {\n                suf = min(a, b);\n            } else {\n                suf = max(a, b);\n            }\n            cut = L - 1 - suf;\n        } else if (r < 88) {\n            int a = rng.nextInt(L - 1);\n            int b = rng.nextInt(L - 1);\n            cut = max(a, b);\n        } else {\n            cut = rng.nextInt(L - 1);\n        }\n\n        return max(0, min(cut, L - 2));\n    }\n\n    int chooseSmartCut(const vector<int>& cells, const vector<int>& cum) {\n        int L = (int)cells.size();\n        if (L <= 2) return chooseCutLength(L);\n\n        Bits bits;\n        bits.fill(0);\n\n        long long bestEval = LLONG_MIN;\n        int bestCut = -1;\n\n        for (int i = 0; i < L - 1; i++) {\n            bitSet(bits, tile[cells[i]]);\n\n            int nextTid = tile[cells[i + 1]];\n            int altCnt = 0;\n            int altSum = 0;\n            int altMax = 0;\n\n            for (int k = 0; k < adjN[cells[i]]; k++) {\n                int nb = adj[cells[i]][k];\n                int tid = tile[nb];\n\n                if (bitTest(bits, tid)) continue;\n                if (tid == nextTid) continue;\n\n                altCnt++;\n                altSum += val[nb];\n                altMax = max(altMax, val[nb]);\n            }\n\n            if (altCnt == 0) continue;\n\n            int suffixLoss = cum[L - 1] - cum[i];\n\n            long long ev = 0;\n            ev += 15000LL * altCnt;\n            ev += 180LL * altSum;\n            ev += 280LL * altMax;\n            ev -= 2LL * suffixLoss;\n            ev += cum[i] / 3;\n            ev += rng.nextInt(30000);\n\n            if (ev > bestEval) {\n                bestEval = ev;\n                bestCut = i;\n            }\n        }\n\n        if (bestCut >= 0) return bestCut;\n        return chooseCutLength(L);\n    }\n\n    int chooseCutForBase(const PathCand& base, int zeroProb, int smartProb) {\n        int L = (int)base.cells.size();\n        if (L <= 1) return 0;\n\n        if (rng.nextInt(100) < zeroProb) return 0;\n        if (rng.nextInt(100) < smartProb) return chooseSmartCut(base.cells, base.cum);\n\n        return chooseCutLength(L);\n    }\n\n    void posaExtendLocal(vector<int>& path, int& score, Bits& bits, double stopTime, const Params& par) {\n        if (path.empty()) return;\n\n        fill(pathIndex, pathIndex + V, -1);\n        for (int i = 0; i < (int)path.size(); i++) pathIndex[path[i]] = i;\n\n        int stamp = newRotStamp();\n        rotSeen[path.back()] = stamp;\n\n        int rotationsSinceAppend = 0;\n        int rotLimit = 25 + rng.nextInt(65);\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() < M) {\n            int L = (int)path.size();\n            int pos = path.back();\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc > 0) {\n                int prev = (L >= 2 ? path[L - 2] : -1);\n                int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n                long long bestEval = LLONG_MIN;\n                int bestIdx = 0;\n\n                for (int a = 0; a < nc; a++) {\n                    int cell = candCell[a];\n                    int tid = candTid[a];\n\n                    int deg = degreeAfterBits(bits, cell, tid);\n                    int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                    long long ev = 0;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n                    ev -= 1LL * par.borderW * borderDist[cell];\n\n                    if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                    if (prev != -1 && cell - pos == lastDiff) ev += par.straightW;\n                    if (par.noise > 0) ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n\n                    if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                        bestEval = ev;\n                        bestIdx = a;\n                    }\n                }\n\n                int nxt = candCell[bestIdx];\n                int tid = candTid[bestIdx];\n\n                pathIndex[nxt] = L;\n                path.push_back(nxt);\n                bitSet(bits, tid);\n                score += val[nxt];\n\n                rotationsSinceAppend = 0;\n                rotLimit = 25 + rng.nextInt(65);\n                stamp = newRotStamp();\n                rotSeen[path.back()] = stamp;\n\n                continue;\n            }\n\n            if (L < 3) break;\n\n            int opts[4];\n            long long evs[4];\n            int no = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int idx = pathIndex[nb];\n\n                if (idx >= 0 && idx <= L - 3) {\n                    int newEnd = path[idx + 1];\n                    int cnt = countUnvisitedMoves(bits, newEnd);\n                    int sum = sumUnvisitedMoveValues(bits, newEnd);\n\n                    long long ev = 0;\n                    ev += 100000LL * cnt;\n                    ev += 120LL * sum;\n                    ev += 5LL * val[newEnd];\n                    ev -= 8LL * borderDist[newEnd];\n                    ev += rng.nextInt(10000);\n\n                    if (rotSeen[newEnd] == stamp) ev -= 60000;\n\n                    opts[no] = idx;\n                    evs[no] = ev;\n                    no++;\n                }\n            }\n\n            if (no == 0) break;\n\n            int bestOpt = 0;\n            for (int i = 1; i < no; i++) {\n                if (evs[i] > evs[bestOpt]) bestOpt = i;\n            }\n\n            int idx = opts[bestOpt];\n            int l = idx + 1;\n\n            reverse(path.begin() + l, path.end());\n\n            for (int i = l; i < L; i++) pathIndex[path[i]] = i;\n\n            rotSeen[path.back()] = stamp;\n\n            rotationsSinceAppend++;\n            if (rotationsSinceAppend > rotLimit) break;\n        }\n    }\n\n    int runGreedyFromPath(\n        const vector<int>& prefix,\n        int prefixScore,\n        bool useFlood,\n        const Params& par,\n        bool allowPosa = false\n    ) {\n        int token = newVisitToken();\n\n        curCells = prefix;\n\n        for (int c : curCells) vis[tile[c]] = token;\n\n        int score = prefixScore;\n        int pos = curCells.back();\n\n        int iter = 0;\n\n        while (true) {\n            if ((iter++ & 15) == 0 && timer.elapsed() > TL) break;\n\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (vis[tid] != token) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int prev = -1;\n            int lastDiff = 999999;\n            if ((int)curCells.size() >= 2) {\n                prev = curCells[(int)curCells.size() - 2];\n                lastDiff = pos - prev;\n            }\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterToken(cell, tid, token);\n                int loc = (par.locW ? localNeighborSumToken(cell, tid, token) : 0);\n\n                long long ev = 0;\n\n                if (useFlood) {\n                    FloodResult fr = floodPotential(cell, tid, token);\n                    ev += 1LL * par.reachW * fr.pot;\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.cntW * fr.cnt;\n                } else {\n                    ev += 1LL * par.scoreW * val[cell];\n                    ev -= 1LL * par.degW * deg;\n                    ev += 1LL * par.locW * loc;\n                    ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                    if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                }\n\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) ev += par.straightW;\n\n                if (par.noise > 0) ev += rng.nextInt(par.noise * 2 + 1) - par.noise;\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            vis[tid] = token;\n            score += val[nxt];\n            curCells.push_back(nxt);\n            pos = nxt;\n        }\n\n        if (allowPosa && timer.elapsed() < TL - 0.025 && score + 3500 >= bestScore) {\n            Bits bits;\n            makeBitsFromPath(curCells, bits);\n            Params pp = makePosaParam();\n            double stop = min(TL, timer.elapsed() + 0.012 + (rng.nextInt(100) < 30 ? 0.018 : 0.0));\n            posaExtendLocal(curCells, score, bits, stop, pp);\n        }\n\n        return score;\n    }\n\n    int runGreedyBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        bool useFlood,\n        const Params& par,\n        bool allowPosa = false\n    ) {\n        int L = (int)baseCells.size();\n        if (L == 0) return 0;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> prefix;\n        prefix.reserve(cut + 1);\n\n        for (int i = 0; i <= cut; i++) prefix.push_back(baseCells[i]);\n\n        return runGreedyFromPath(prefix, baseCum[cut], useFlood, par, allowPosa);\n    }\n\n    int runGreedy(int cut, bool useFlood, const Params& par) {\n        return runGreedyBase(bestCells, bestCum, cut, useFlood, par, false);\n    }\n\n    int rolloutScore(Bits& bits, int prev, int pos, int score, const Params& par, vector<int>* suffix) const {\n        while (true) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            int lastDiff = (prev == -1 ? 999999 : pos - prev);\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                int deg = degreeAfterBits(bits, cell, tid);\n                int loc = (par.locW ? localSumAfterBits(bits, cell, tid) : 0);\n\n                long long ev = 0;\n                ev += 1LL * par.scoreW * val[cell];\n                ev -= 1LL * par.degW * deg;\n                ev += 1LL * par.locW * loc;\n                ev += 1LL * par.lossW * (val[cell] - tilePot[tid]);\n\n                if (deg == 0 && nc > 1) ev -= par.endPenalty;\n                ev -= 1LL * par.borderW * borderDist[cell];\n\n                if (prev != -1 && cell - pos == lastDiff) ev += par.straightW;\n\n                if (ev > bestEval || (ev == bestEval && cell < candCell[bestIdx])) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            if (suffix) suffix->push_back(nxt);\n\n            prev = pos;\n            pos = nxt;\n        }\n\n        return score;\n    }\n\n    void considerRolloutPath(\n        const vector<int>& prefix,\n        int cand,\n        const Bits& bitsAfterCand,\n        int prev,\n        int scoreAfterCand,\n        const Params& par,\n        int estimatedScore\n    ) {\n        if (estimatedScore + 1800 < bestScore) return;\n\n        Bits b = bitsAfterCand;\n        vector<int> suffix;\n        suffix.reserve(1000);\n\n        int exactScore = rolloutScore(b, prev, cand, scoreAfterCand, par, &suffix);\n\n        if (exactScore + 2500 >= bestScore) {\n            vector<int> full;\n            full.reserve(prefix.size() + 1 + suffix.size());\n            full.insert(full.end(), prefix.begin(), prefix.end());\n            full.push_back(cand);\n            full.insert(full.end(), suffix.begin(), suffix.end());\n            addCandidate(full, exactScore);\n        }\n    }\n\n    int runPilotFromPath(\n        const vector<int>& initialPath,\n        int initialScore,\n        int variants,\n        bool allowPosa = false,\n        bool useReach = false\n    ) {\n        if (initialPath.empty()) return 0;\n\n        vector<int> path = initialPath;\n        path.reserve(V);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        int score = initialScore;\n        int pos = path.back();\n\n        Params pars[4];\n        variants = max(1, min(variants, 4));\n        for (int i = 0; i < variants; i++) pars[i] = makePilotParam();\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            int candCell[4];\n            int candTid[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int tid = tile[nb];\n                if (!bitTest(bits, tid)) {\n                    candCell[nc] = nb;\n                    candTid[nc] = tid;\n                    nc++;\n                }\n            }\n\n            if (nc == 0) break;\n\n            long long bestEval = LLONG_MIN;\n            int bestIdx = 0;\n\n            for (int a = 0; a < nc; a++) {\n                int cell = candCell[a];\n                int tid = candTid[a];\n\n                Bits bitsAfter = bits;\n                bitSet(bitsAfter, tid);\n\n                int scoreAfter = score + val[cell];\n                int bestSim = -1;\n                int bestPar = 0;\n\n                for (int r = 0; r < variants; r++) {\n                    Bits b = bitsAfter;\n                    int simScore = rolloutScore(b, pos, cell, scoreAfter, pars[r], nullptr);\n\n                    if (simScore > bestSim) {\n                        bestSim = simScore;\n                        bestPar = r;\n                    }\n                }\n\n                FloodResult fr{0, 0};\n                if (useReach) fr = floodPotentialBits(cell, bitsAfter);\n\n                if (bestSim + (useReach ? fr.pot / 30 : 0) >= bestScore - 1800) {\n                    considerRolloutPath(path, cell, bitsAfter, pos, scoreAfter, pars[bestPar], bestSim);\n                }\n\n                long long ev = 1LL * bestSim * 1000;\n                ev += 3LL * val[cell];\n\n                if (useReach) {\n                    ev += 32LL * fr.pot;\n                    ev += 180LL * fr.cnt;\n                }\n\n                ev += rng.nextInt(1001) - 500;\n\n                if (ev > bestEval || (ev == bestEval && rng.nextInt(2) == 0)) {\n                    bestEval = ev;\n                    bestIdx = a;\n                }\n            }\n\n            int nxt = candCell[bestIdx];\n            int tid = candTid[bestIdx];\n\n            bitSet(bits, tid);\n            score += val[nxt];\n            path.push_back(nxt);\n            pos = nxt;\n\n            if (score > bestScore || (score == bestScore && path.size() > bestCells.size())) {\n                setBestFrom(path, score);\n            }\n\n            if ((++iter & 7) == 0 && timer.elapsed() > TL) break;\n        }\n\n        if (allowPosa && timer.elapsed() < TL - 0.025 && score + 6000 >= bestScore) {\n            Params pp = makePosaParam();\n            double stop = min(TL, timer.elapsed() + 0.010 + (rng.nextInt(100) < 40 ? 0.018 : 0.0));\n            posaExtendLocal(path, score, bits, stop, pp);\n        }\n\n        addCandidate(path, score);\n        return score;\n    }\n\n    int runPilotBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        int variants,\n        bool allowPosa = false,\n        bool useReach = false\n    ) {\n        int L = (int)baseCells.size();\n        if (L == 0) return 0;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> prefix;\n        prefix.reserve(cut + 1);\n\n        for (int i = 0; i <= cut; i++) prefix.push_back(baseCells[i]);\n\n        return runPilotFromPath(prefix, baseCum[cut], variants, allowPosa, useReach);\n    }\n\n    int runPilot(int cut, int variants, bool allowPosa = false, bool useReach = false) {\n        return runPilotBase(bestCells, bestCum, cut, variants, allowPosa, useReach);\n    }\n\n    void runPosaFromBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        double budget\n    ) {\n        if (timer.elapsed() >= TL || budget <= 0) return;\n\n        int L = (int)baseCells.size();\n        if (L == 0) return;\n\n        cut = max(0, min(cut, L - 1));\n\n        vector<int> path;\n        path.reserve(V);\n        for (int i = 0; i <= cut; i++) path.push_back(baseCells[i]);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        int score = baseCum[cut];\n\n        Params p = makePosaParam();\n        double stop = min(TL, timer.elapsed() + budget);\n        posaExtendLocal(path, score, bits, stop, p);\n\n        addCandidate(path, score);\n    }\n\n    bool runRotationExtendFromBase(\n        const vector<int>& baseCells,\n        const vector<int>& baseCum,\n        int cut,\n        bool pilotMode\n    ) {\n        if (timer.elapsed() >= TL) return false;\n\n        int L0 = (int)baseCells.size();\n        if (L0 < 3) return false;\n\n        cut = max(0, min(cut, L0 - 1));\n        if (cut < 2) return false;\n\n        vector<int> path;\n        path.reserve(V);\n        for (int i = 0; i <= cut; i++) path.push_back(baseCells[i]);\n\n        int score = baseCum[cut];\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        fill(pathIndex, pathIndex + V, -1);\n        for (int i = 0; i < (int)path.size(); i++) pathIndex[path[i]] = i;\n\n        int stamp = newRotStamp();\n        rotSeen[path.back()] = stamp;\n\n        int maxRot = 1 + rng.nextInt(8);\n        bool rotated = false;\n\n        for (int step = 0; step < maxRot && timer.elapsed() < TL; step++) {\n            int L = (int)path.size();\n            if (L < 3) break;\n\n            int pos = path.back();\n\n            int opts[4];\n            long long evs[4];\n            int no = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n                int idx = pathIndex[nb];\n\n                if (idx >= 0 && idx <= L - 3) {\n                    int newEnd = path[idx + 1];\n                    int cnt = countUnvisitedMoves(bits, newEnd);\n                    int sum = sumUnvisitedMoveValues(bits, newEnd);\n\n                    long long ev = 0;\n                    ev += 100000LL * cnt;\n                    ev += 150LL * sum;\n                    ev += 5LL * val[newEnd];\n                    ev -= 6LL * borderDist[newEnd];\n                    ev += rng.nextInt(12000);\n\n                    if (rotSeen[newEnd] == stamp) ev -= 70000;\n\n                    opts[no] = idx;\n                    evs[no] = ev;\n                    no++;\n                }\n            }\n\n            if (no == 0) break;\n\n            int bestOpt = 0;\n            for (int i = 1; i < no; i++) {\n                if (evs[i] > evs[bestOpt]) bestOpt = i;\n            }\n\n            int idx = opts[bestOpt];\n            int l = idx + 1;\n\n            reverse(path.begin() + l, path.end());\n\n            for (int i = l; i < (int)path.size(); i++) pathIndex[path[i]] = i;\n\n            rotated = true;\n            rotSeen[path.back()] = stamp;\n\n            if (countUnvisitedMoves(bits, path.back()) > 0 && rng.nextInt(100) < 75) break;\n        }\n\n        if (!rotated) return false;\n        if (timer.elapsed() >= TL) return false;\n        if (countUnvisitedMoves(bits, path.back()) == 0) return false;\n\n        if (pilotMode) {\n            int variants = (timer.elapsed() < 0.95 && rng.nextInt(100) < 45 ? 2 : 1);\n            bool useReach = rng.nextInt(100) < 15;\n            runPilotFromPath(path, score, variants, rng.nextInt(100) < 35, useReach);\n        } else {\n            Params p = makeParams(false);\n            int sc = runGreedyFromPath(path, score, false, p, true);\n            considerCurrent(sc);\n        }\n\n        return true;\n    }\n\n    int countFreeForInsert(const Bits& bits, int cell, int target) const {\n        int cnt = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (nb == target) cnt++;\n            else if (!bitTest(bits, tile[nb])) cnt++;\n        }\n        return cnt;\n    }\n\n    int sumFreeForInsert(const Bits& bits, int cell, int target) const {\n        int s = 0;\n        for (int k = 0; k < adjN[cell]; k++) {\n            int nb = adj[cell][k];\n            if (nb == target) continue;\n            if (!bitTest(bits, tile[nb])) s += val[nb];\n        }\n        return s;\n    }\n\n    bool targetReachableFrom(int start, int target, const Bits& bits) {\n        int stamp = newBfsStamp();\n\n        int head = 0, tail = 0;\n        que[tail++] = start;\n        seenCell[start] = stamp;\n\n        while (head < tail) {\n            int v = que[head++];\n\n            for (int k = 0; k < adjN[v]; k++) {\n                int nb = adj[v][k];\n\n                if (nb == target) return true;\n\n                int tid = tile[nb];\n                if (bitTest(bits, tid)) continue;\n                if (tid == tile[v]) continue;\n                if (seenCell[nb] == stamp) continue;\n\n                seenCell[nb] = stamp;\n                que[tail++] = nb;\n            }\n        }\n\n        return false;\n    }\n\n    bool tryRectangleOnce(vector<int>& path, int& score, Bits& bits) {\n        int L = (int)path.size();\n        if (L + 2 > M) return false;\n\n        int bestI = -1;\n        int bestC = -1;\n        int bestD = -1;\n        long long bestEval = LLONG_MIN;\n\n        auto checkPair = [&](int i, int c, int d) {\n            if (c < 0 || c >= V || d < 0 || d >= V) return;\n\n            int tc = tile[c];\n            int td = tile[d];\n\n            if (tc == td) return;\n            if (bitTest(bits, tc)) return;\n            if (bitTest(bits, td)) return;\n\n            if (!adjacentCell(path[i], c)) return;\n            if (!adjacentCell(c, d)) return;\n            if (!adjacentCell(d, path[i + 1])) return;\n\n            int gain = val[c] + val[d];\n            if (gain <= 0) return;\n\n            long long ev = 1000LL * gain + rng.nextInt(1000);\n\n            if (ev > bestEval) {\n                bestEval = ev;\n                bestI = i;\n                bestC = c;\n                bestD = d;\n            }\n        };\n\n        for (int i = 0; i + 1 < L; i++) {\n            int a = path[i];\n            int b = path[i + 1];\n            int diff = b - a;\n\n            if (diff == 1 || diff == -1) {\n                if (a / N != b / N) continue;\n\n                if (a >= N && b >= N) checkPair(i, a - N, b - N);\n                if (a + N < V && b + N < V) checkPair(i, a + N, b + N);\n            } else if (diff == N || diff == -N) {\n                if (a % N > 0 && b % N > 0) checkPair(i, a - 1, b - 1);\n                if (a % N + 1 < N && b % N + 1 < N) checkPair(i, a + 1, b + 1);\n            }\n        }\n\n        if (bestI < 0) return false;\n\n        path.insert(path.begin() + bestI + 1, bestD);\n        path.insert(path.begin() + bestI + 1, bestC);\n\n        bitSet(bits, tile[bestC]);\n        bitSet(bits, tile[bestD]);\n        score += val[bestC] + val[bestD];\n\n        return true;\n    }\n\n    void augmentRectangles(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() + 2 <= M) {\n            if (!tryRectangleOnce(path, score, bits)) break;\n        }\n    }\n\n    bool buildDetourForEdge(vector<int>& path, int& score, Bits& bits, int edgeIdx, double stopTime) {\n        int L = (int)path.size();\n        if (edgeIdx < 0 || edgeIdx + 1 >= L) return false;\n        if (L >= M) return false;\n\n        int a = path[edgeIdx];\n        int target = path[edgeIdx + 1];\n\n        Bits usedTmp = bits;\n\n        vector<int> det;\n        vector<int> bestDet;\n        det.reserve(160);\n        bestDet.reserve(160);\n\n        int pos = a;\n        int gain = 0;\n        int bestGain = -1;\n\n        int maxSteps = min(M - L, 25 + rng.nextInt(100));\n\n        struct Cand {\n            int cell;\n            long long ev;\n        };\n\n        for (int step = 0; step < maxSteps && timer.elapsed() < stopTime && timer.elapsed() < TL; step++) {\n            if (!det.empty() && adjacentCell(pos, target)) {\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestDet = det;\n                }\n            }\n\n            Cand cand[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n\n                if (nb == target) continue;\n\n                int tid = tile[nb];\n                if (bitTest(usedTmp, tid)) continue;\n\n                Bits tmp = usedTmp;\n                bitSet(tmp, tid);\n\n                if (!targetReachableFrom(nb, target, tmp)) continue;\n\n                int deg = countFreeForInsert(tmp, nb, target);\n                int loc = sumFreeForInsert(tmp, nb, target);\n                int dist = manhattanCell(nb, target);\n\n                long long ev = 0;\n                ev += 1000LL * val[nb];\n                ev -= 260LL * deg;\n                ev += 3LL * loc;\n                ev += 22LL * dist;\n                ev -= 8LL * borderDist[nb];\n\n                if (adjacentCell(nb, target) && (int)det.size() < 5) ev -= 1500;\n\n                ev += rng.nextInt(5000);\n\n                cand[nc++] = {nb, ev};\n            }\n\n            if (nc == 0) break;\n\n            int bi = 0;\n            for (int i = 1; i < nc; i++) {\n                if (cand[i].ev > cand[bi].ev) bi = i;\n            }\n\n            int nxt = cand[bi].cell;\n            int tid = tile[nxt];\n\n            bitSet(usedTmp, tid);\n            det.push_back(nxt);\n            gain += val[nxt];\n            pos = nxt;\n        }\n\n        if (!det.empty() && adjacentCell(pos, target)) {\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestDet = det;\n            }\n        }\n\n        if (bestGain <= 0 || bestDet.empty()) return false;\n\n        for (int c : bestDet) {\n            if (bitTest(bits, tile[c])) return false;\n        }\n\n        path.insert(path.begin() + edgeIdx + 1, bestDet.begin(), bestDet.end());\n\n        for (int c : bestDet) {\n            bitSet(bits, tile[c]);\n            score += val[c];\n        }\n\n        return true;\n    }\n\n    bool tryDetourInsertionOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L >= M) return false;\n\n        struct EdgeOpt {\n            int idx;\n            long long ev;\n        };\n\n        vector<EdgeOpt> opts;\n        opts.reserve(L);\n\n        for (int i = 0; i + 1 < L; i++) {\n            int a = path[i];\n            int b = path[i + 1];\n\n            int ca = countUnvisitedMoves(bits, a);\n            int cb = countUnvisitedMoves(bits, b);\n\n            if (ca == 0 || cb == 0) continue;\n\n            int sa = sumUnvisitedMoveValues(bits, a);\n            int sb = sumUnvisitedMoveValues(bits, b);\n\n            long long ev = 0;\n            ev += 120000LL * min(ca, cb);\n            ev += 160LL * (sa + sb);\n            ev += rng.nextInt(50000);\n\n            opts.push_back({i, ev});\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(16, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const EdgeOpt& a, const EdgeOpt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const EdgeOpt& a, const EdgeOpt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(8, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildDetourForEdge(path, score, bits, opts[t].idx, stopTime)) return true;\n        }\n\n        return false;\n    }\n\n    void augmentDetours(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int success = 0;\n        int fail = 0;\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && (int)path.size() < M) {\n            if (tryDetourInsertionOnce(path, score, bits, stopTime)) {\n                success++;\n                fail = 0;\n\n                augmentRectangles(path, score, bits, min(stopTime, timer.elapsed() + 0.006));\n\n                if (success >= 20) break;\n            } else {\n                fail++;\n                if (fail >= 2) break;\n            }\n        }\n    }\n\n    bool buildSegmentReroute(vector<int>& path, int& score, Bits& bits, int i, int j, double stopTime) {\n        int L = (int)path.size();\n        if (i < 0 || j >= L || j <= i + 1) return false;\n\n        int oldLen = j - i - 1;\n        if (oldLen <= 0) return false;\n\n        Bits base = bits;\n        int oldGain = 0;\n\n        for (int k = i + 1; k < j; k++) {\n            bitClear(base, tile[path[k]]);\n            oldGain += val[path[k]];\n        }\n\n        int capacity = M - (L - oldLen);\n        if (capacity <= 0) return false;\n\n        int a = path[i];\n        int target = path[j];\n\n        Bits usedTmp = base;\n\n        vector<int> det;\n        vector<int> bestDet;\n        det.reserve(200);\n        bestDet.reserve(200);\n\n        int pos = a;\n        int gain = 0;\n        int bestGain = -1;\n\n        int maxSteps = min(capacity, oldLen + 45 + rng.nextInt(90));\n\n        struct Cand {\n            int cell;\n            long long ev;\n        };\n\n        for (int step = 0; step < maxSteps && timer.elapsed() < stopTime && timer.elapsed() < TL; step++) {\n            if (!det.empty() && adjacentCell(pos, target)) {\n                if (gain > bestGain) {\n                    bestGain = gain;\n                    bestDet = det;\n                }\n            }\n\n            Cand cand[4];\n            int nc = 0;\n\n            for (int k = 0; k < adjN[pos]; k++) {\n                int nb = adj[pos][k];\n\n                if (nb == target) continue;\n\n                int tid = tile[nb];\n                if (bitTest(usedTmp, tid)) continue;\n\n                Bits tmp = usedTmp;\n                bitSet(tmp, tid);\n\n                if (!targetReachableFrom(nb, target, tmp)) continue;\n\n                int deg = countFreeForInsert(tmp, nb, target);\n                int loc = sumFreeForInsert(tmp, nb, target);\n                int dist = manhattanCell(nb, target);\n\n                long long ev = 0;\n                ev += 1000LL * val[nb];\n                ev -= 230LL * deg;\n                ev += 4LL * loc;\n                ev -= 8LL * borderDist[nb];\n\n                if (step * 3 < maxSteps * 2) ev += 20LL * dist;\n                else ev -= 70LL * dist;\n\n                if (adjacentCell(nb, target) && gain + val[nb] <= oldGain + 80) ev -= 3500;\n                if (adjacentCell(nb, target) && step < 3) ev -= 1200;\n\n                ev += rng.nextInt(6000);\n\n                cand[nc++] = {nb, ev};\n            }\n\n            if (nc == 0) break;\n\n            int bi = 0;\n            for (int t = 1; t < nc; t++) {\n                if (cand[t].ev > cand[bi].ev) bi = t;\n            }\n\n            int nxt = cand[bi].cell;\n            int tid = tile[nxt];\n\n            bitSet(usedTmp, tid);\n            det.push_back(nxt);\n            gain += val[nxt];\n            pos = nxt;\n        }\n\n        if (!det.empty() && adjacentCell(pos, target)) {\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestDet = det;\n            }\n        }\n\n        if (bestGain <= oldGain || bestDet.empty()) return false;\n\n        Bits check = base;\n        for (int c : bestDet) {\n            int tid = tile[c];\n            if (bitTest(check, tid)) return false;\n            bitSet(check, tid);\n        }\n\n        bits = check;\n        score += bestGain - oldGain;\n\n        path.erase(path.begin() + i + 1, path.begin() + j);\n        path.insert(path.begin() + i + 1, bestDet.begin(), bestDet.end());\n\n        return true;\n    }\n\n    bool trySegmentRerouteOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L < 4) return false;\n\n        struct Opt {\n            int i;\n            int j;\n            long long ev;\n        };\n\n        vector<Opt> opts;\n        opts.reserve(256);\n\n        int maxSpan = 4 + rng.nextInt(18);\n\n        for (int i = 0; i + 2 < L; i++) {\n            int oldGain = 0;\n\n            for (int span = 2; span <= maxSpan && i + span < L; span++) {\n                oldGain += val[path[i + span - 1]];\n\n                int j = i + span;\n                int oldLen = span - 1;\n\n                int a = path[i];\n                int b = path[j];\n\n                int releasedEndVal = val[path[i + 1]];\n                if (j - 1 != i + 1) releasedEndVal += val[path[j - 1]];\n\n                int ca = countUnvisitedMoves(bits, a) + countUnvisitedMoves(bits, b) + (oldLen == 1 ? 1 : 2);\n                int sa = sumUnvisitedMoveValues(bits, a) + sumUnvisitedMoveValues(bits, b) + releasedEndVal;\n                int dist = manhattanCell(a, b);\n\n                long long ev = 0;\n                ev += 100000LL * ca;\n                ev += 170LL * sa;\n                ev -= 460LL * oldGain;\n                ev += 11500LL * oldLen;\n                ev -= 1200LL * dist;\n                ev += rng.nextInt(65000);\n\n                opts.push_back({i, j, ev});\n            }\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(18, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const Opt& a, const Opt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(7, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildSegmentReroute(path, score, bits, opts[t].i, opts[t].j, stopTime)) return true;\n        }\n\n        return false;\n    }\n\n    void augmentReroutes(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int success = 0;\n        int fail = 0;\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && success < 8) {\n            if (trySegmentRerouteOnce(path, score, bits, stopTime)) {\n                success++;\n                fail = 0;\n                augmentRectangles(path, score, bits, min(stopTime, timer.elapsed() + 0.006));\n            } else {\n                fail++;\n                if (fail >= 2) break;\n            }\n        }\n    }\n\n    struct DetourResult {\n        vector<int> cells;\n        int gain = -1;\n    };\n\n    DetourResult beamDetourSearch(\n        const Bits& baseBits,\n        int start,\n        int target,\n        int maxLen,\n        double stopTime,\n        int oldGain,\n        int width,\n        bool segmentMode\n    ) {\n        DetourResult res;\n        if (maxLen <= 0) return res;\n\n        struct Node {\n            int parent;\n            int cell;\n        };\n\n        struct State {\n            Bits bits;\n            int pos;\n            int gain;\n            int node;\n            int len;\n            long long eval;\n        };\n\n        vector<Node> nodes;\n        nodes.reserve(width * maxLen * 3 + 16);\n\n        vector<State> cur, cand;\n        cur.reserve(width);\n        cand.reserve(width * 4 + 8);\n\n        State init;\n        init.bits = baseBits;\n        init.pos = start;\n        init.gain = 0;\n        init.node = -1;\n        init.len = 0;\n        init.eval = 0;\n        cur.push_back(init);\n\n        int bestGain = oldGain;\n        int bestNode = -1;\n        int bestLen = 0;\n\n        for (int depth = 0; depth < maxLen && !cur.empty(); depth++) {\n            if (timer.elapsed() >= stopTime || timer.elapsed() >= TL) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                if (st.len > 0 && adjacentCell(st.pos, target)) {\n                    if (st.gain > bestGain || (st.gain == bestGain && st.len > bestLen)) {\n                        bestGain = st.gain;\n                        bestNode = st.node;\n                        bestLen = st.len;\n                    }\n                }\n\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    if (nb == target) continue;\n\n                    int tid = tile[nb];\n                    if (bitTest(st.bits, tid)) continue;\n\n                    int newLen = st.len + 1;\n                    int dist = manhattanCell(nb, target);\n\n                    if (dist - 1 > maxLen - newLen) continue;\n\n                    State ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.pos = nb;\n                    ch.gain = st.gain + val[nb];\n                    ch.len = newLen;\n\n                    nodes.push_back({st.node, nb});\n                    ch.node = (int)nodes.size() - 1;\n\n                    int deg = countFreeForInsert(ch.bits, nb, target);\n                    int loc = sumFreeForInsert(ch.bits, nb, target);\n\n                    long long ev = 0;\n                    ev += 1000LL * ch.gain;\n                    ev += 4LL * loc;\n                    ev -= 220LL * deg;\n                    ev -= 7LL * borderDist[nb];\n\n                    if (newLen * 3 < maxLen * 2) {\n                        ev += (segmentMode ? 18LL : 26LL) * dist;\n                    } else {\n                        ev -= (segmentMode ? 80LL : 95LL) * dist;\n                    }\n\n                    if (adjacentCell(nb, target)) {\n                        if (ch.gain > bestGain || (ch.gain == bestGain && ch.len > bestLen)) {\n                            bestGain = ch.gain;\n                            bestNode = ch.node;\n                            bestLen = ch.len;\n                        }\n\n                        if (ch.gain <= oldGain + 100) ev -= 2500;\n                        else ev += 1200;\n                    }\n\n                    ev += rng.nextInt(4500);\n                    ch.eval = ev;\n\n                    cand.push_back(std::move(ch));\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const State& a, const State& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            cur.swap(cand);\n        }\n\n        if (bestGain <= oldGain || bestNode < 0) return res;\n\n        vector<int> rev;\n        int x = bestNode;\n        while (x != -1) {\n            rev.push_back(nodes[x].cell);\n            x = nodes[x].parent;\n        }\n        reverse(rev.begin(), rev.end());\n\n        res.cells = std::move(rev);\n        res.gain = bestGain;\n        return res;\n    }\n\n    bool buildBeamDetourForEdge(vector<int>& path, int& score, Bits& bits, int edgeIdx, double stopTime) {\n        int L = (int)path.size();\n        if (edgeIdx < 0 || edgeIdx + 1 >= L) return false;\n        if (L >= M) return false;\n\n        int a = path[edgeIdx];\n        int target = path[edgeIdx + 1];\n\n        int maxLen = min(M - L, 55 + rng.nextInt(55));\n        int width = 18 + rng.nextInt(10);\n\n        DetourResult dr = beamDetourSearch(bits, a, target, maxLen, stopTime, 0, width, false);\n\n        if (dr.gain <= 0 || dr.cells.empty()) return false;\n        if (!adjacentCell(a, dr.cells.front())) return false;\n        if (!adjacentCell(dr.cells.back(), target)) return false;\n\n        Bits check = bits;\n        for (int c : dr.cells) {\n            int tid = tile[c];\n            if (bitTest(check, tid)) return false;\n            bitSet(check, tid);\n        }\n\n        bits = check;\n        path.insert(path.begin() + edgeIdx + 1, dr.cells.begin(), dr.cells.end());\n        score += dr.gain;\n\n        return true;\n    }\n\n    bool tryBeamDetourInsertionOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L >= M) return false;\n\n        struct EdgeOpt {\n            int idx;\n            long long ev;\n        };\n\n        vector<EdgeOpt> opts;\n        opts.reserve(L);\n\n        for (int i = 0; i + 1 < L; i++) {\n            int a = path[i];\n            int b = path[i + 1];\n\n            int ca = countUnvisitedMoves(bits, a);\n            int cb = countUnvisitedMoves(bits, b);\n            if (ca == 0 || cb == 0) continue;\n\n            int sa = sumUnvisitedMoveValues(bits, a);\n            int sb = sumUnvisitedMoveValues(bits, b);\n\n            long long ev = 0;\n            ev += 150000LL * min(ca, cb);\n            ev += 190LL * (sa + sb);\n            ev += rng.nextInt(70000);\n\n            opts.push_back({i, ev});\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(12, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const EdgeOpt& a, const EdgeOpt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const EdgeOpt& a, const EdgeOpt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(5, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildBeamDetourForEdge(path, score, bits, opts[t].idx, stopTime)) return true;\n        }\n\n        return false;\n    }\n\n    bool buildBeamSegmentReroute(vector<int>& path, int& score, Bits& bits, int i, int j, double stopTime) {\n        int L = (int)path.size();\n        if (i < 0 || j >= L || j <= i + 1) return false;\n\n        int oldLen = j - i - 1;\n        if (oldLen <= 0) return false;\n\n        Bits base = bits;\n        int oldGain = 0;\n\n        for (int k = i + 1; k < j; k++) {\n            bitClear(base, tile[path[k]]);\n            oldGain += val[path[k]];\n        }\n\n        int capacity = M - (L - oldLen);\n        if (capacity <= 0) return false;\n\n        int a = path[i];\n        int target = path[j];\n\n        int maxLen = min(capacity, oldLen + 55 + rng.nextInt(60));\n        int width = 18 + rng.nextInt(12);\n\n        DetourResult dr = beamDetourSearch(base, a, target, maxLen, stopTime, oldGain, width, true);\n\n        if (dr.gain <= oldGain || dr.cells.empty()) return false;\n        if (!adjacentCell(a, dr.cells.front())) return false;\n        if (!adjacentCell(dr.cells.back(), target)) return false;\n\n        Bits check = base;\n        for (int c : dr.cells) {\n            int tid = tile[c];\n            if (bitTest(check, tid)) return false;\n            bitSet(check, tid);\n        }\n\n        bits = check;\n        score += dr.gain - oldGain;\n\n        path.erase(path.begin() + i + 1, path.begin() + j);\n        path.insert(path.begin() + i + 1, dr.cells.begin(), dr.cells.end());\n\n        return true;\n    }\n\n    bool tryBeamSegmentRerouteOnce(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int L = (int)path.size();\n        if (L < 4) return false;\n\n        struct Opt {\n            int i;\n            int j;\n            long long ev;\n        };\n\n        vector<Opt> opts;\n        opts.reserve(256);\n\n        int maxSpan = 3 + rng.nextInt(16);\n\n        for (int i = 0; i + 2 < L; i++) {\n            int oldGain = 0;\n\n            for (int span = 2; span <= maxSpan && i + span < L; span++) {\n                oldGain += val[path[i + span - 1]];\n\n                int j = i + span;\n                int oldLen = span - 1;\n\n                int a = path[i];\n                int b = path[j];\n\n                int releasedEndVal = val[path[i + 1]];\n                if (j - 1 != i + 1) releasedEndVal += val[path[j - 1]];\n\n                int ca = countUnvisitedMoves(bits, a) + countUnvisitedMoves(bits, b) + (oldLen == 1 ? 1 : 2);\n                int sa = sumUnvisitedMoveValues(bits, a) + sumUnvisitedMoveValues(bits, b) + releasedEndVal;\n                int dist = manhattanCell(a, b);\n\n                long long ev = 0;\n                ev += 115000LL * ca;\n                ev += 185LL * sa;\n                ev -= 500LL * oldGain;\n                ev += 13000LL * oldLen;\n                ev -= 1000LL * dist;\n                ev += rng.nextInt(80000);\n\n                opts.push_back({i, j, ev});\n            }\n        }\n\n        if (opts.empty()) return false;\n\n        int keep = min<int>(12, opts.size());\n        if ((int)opts.size() > keep) {\n            nth_element(\n                opts.begin(),\n                opts.begin() + keep,\n                opts.end(),\n                [](const Opt& a, const Opt& b) {\n                    return a.ev > b.ev;\n                }\n            );\n            opts.resize(keep);\n        }\n\n        sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n            return a.ev > b.ev;\n        });\n\n        int trials = min<int>(5, opts.size());\n        for (int t = 0; t < trials && timer.elapsed() < stopTime && timer.elapsed() < TL; t++) {\n            if (buildBeamSegmentReroute(path, score, bits, opts[t].i, opts[t].j, stopTime)) return true;\n        }\n\n        return false;\n    }\n\n    void augmentBeamLocal(vector<int>& path, int& score, Bits& bits, double stopTime) {\n        int success = 0;\n        int fail = 0;\n\n        while (timer.elapsed() < stopTime && timer.elapsed() < TL && success < 5) {\n            bool ok = false;\n\n            if ((int)path.size() < M && rng.nextInt(100) < 42) {\n                ok = tryBeamDetourInsertionOnce(path, score, bits, stopTime);\n                if (!ok && timer.elapsed() < stopTime) ok = tryBeamSegmentRerouteOnce(path, score, bits, stopTime);\n            } else {\n                ok = tryBeamSegmentRerouteOnce(path, score, bits, stopTime);\n                if (!ok && (int)path.size() < M && timer.elapsed() < stopTime) {\n                    ok = tryBeamDetourInsertionOnce(path, score, bits, stopTime);\n                }\n            }\n\n            if (ok) {\n                success++;\n                fail = 0;\n                augmentRectangles(path, score, bits, min(stopTime, timer.elapsed() + 0.006));\n            } else {\n                fail++;\n                if (fail >= 3) break;\n            }\n        }\n    }\n\n    void augmentPathLocal(vector<int>& path, int& score, double stopTime) {\n        if (path.empty()) return;\n\n        path.reserve(V);\n\n        Bits bits;\n        makeBitsFromPath(path, bits);\n\n        double start = timer.elapsed();\n        double budget = max(0.0, stopTime - start);\n\n        augmentRectangles(path, score, bits, min(stopTime, start + min(0.018, budget * 0.12)));\n\n        if (timer.elapsed() < stopTime) {\n            augmentDetours(path, score, bits, min(stopTime, start + budget * 0.44));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentReroutes(path, score, bits, min(stopTime, start + budget * 0.66));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentBeamLocal(path, score, bits, min(stopTime, start + budget * 0.90));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentDetours(path, score, bits, min(stopTime, start + budget * 0.97));\n        }\n\n        if (timer.elapsed() < stopTime) {\n            augmentRectangles(path, score, bits, stopTime);\n        }\n    }\n\n    void finalAugment(double budget) {\n        if (budget <= 0 || pool.empty()) return;\n\n        double endTime = min(TL, timer.elapsed() + budget);\n\n        bool lastImproved = true;\n        int diversityCursor = 1;\n        int planned = min(5, max(1, (int)pool.size()));\n\n        for (int attempt = 0; attempt < planned && timer.elapsed() < endTime; attempt++) {\n            if (pool.empty()) break;\n\n            double remain = endTime - timer.elapsed();\n            if (remain <= 0.003) break;\n\n            int bi = 0;\n\n            if (attempt == 0) {\n                bi = 0;\n            } else if (attempt == 1) {\n                bi = lastImproved ? 0 : min(diversityCursor++, (int)pool.size() - 1);\n            } else if (attempt == 2) {\n                bi = min(diversityCursor++, (int)pool.size() - 1);\n            } else if (attempt == 3) {\n                bi = 0;\n            } else {\n                bi = min(diversityCursor++, (int)pool.size() - 1);\n            }\n\n            bi = max(0, min(bi, (int)pool.size() - 1));\n\n            PathCand base = pool[bi];\n\n            double slice = remain / (planned - attempt);\n            if (bi == 0) {\n                slice *= (attempt == 0 ? 1.65 : 1.30);\n            } else {\n                slice *= 0.95;\n            }\n\n            double stop = min(endTime, timer.elapsed() + slice);\n\n            vector<int> path = base.cells;\n            int score = base.score;\n\n            int beforeBest = bestScore;\n            augmentPathLocal(path, score, stop);\n\n            if (validatePath(path)) addCandidate(path, score);\n\n            lastImproved = (bestScore > beforeBest);\n        }\n\n        if (timer.elapsed() < endTime - 0.004 && !pool.empty()) {\n            runPosaFromBase(pool[0].cells, pool[0].cum, (int)pool[0].cells.size() - 1, endTime - timer.elapsed());\n        }\n    }\n\n    struct BeamNode {\n        int parent;\n        int cell;\n        int score;\n    };\n\n    struct BeamState {\n        Bits bits;\n        int pos;\n        int prev;\n        int score;\n        int node;\n        long long eval;\n    };\n\n    void runBeam(double endTime, int width) {\n        if (timer.elapsed() >= endTime) return;\n\n        vector<BeamNode> nodes;\n        nodes.reserve(width * 1200);\n\n        vector<BeamState> cur, nxt, cand;\n        cur.reserve(width);\n        nxt.reserve(width);\n        cand.reserve(width * 4 + 10);\n\n        BeamState init;\n        init.bits.fill(0);\n        bitSet(init.bits, tile[startCell]);\n        init.pos = startCell;\n        init.prev = -1;\n        init.score = val[startCell];\n        init.node = 0;\n        init.eval = init.score;\n\n        nodes.push_back({-1, startCell, val[startCell]});\n        cur.push_back(init);\n\n        int localBestScore = val[startCell];\n        int localBestNode = 0;\n\n        int degBias = -120 + rng.nextInt(241);\n        int noise = 2000 + rng.nextInt(4000);\n\n        for (int depth = 0; depth < M && !cur.empty(); depth++) {\n            if (timer.elapsed() >= endTime) break;\n\n            cand.clear();\n\n            for (const auto& st : cur) {\n                for (int k = 0; k < adjN[st.pos]; k++) {\n                    int nb = adj[st.pos][k];\n                    int tid = tile[nb];\n\n                    if (bitTest(st.bits, tid)) continue;\n\n                    BeamState ch;\n                    ch.bits = st.bits;\n                    bitSet(ch.bits, tid);\n                    ch.prev = st.pos;\n                    ch.pos = nb;\n                    ch.score = st.score + val[nb];\n                    ch.node = st.node;\n\n                    int deg = degreeAfterBits(st.bits, nb, tid);\n                    int loc = localSumAfterBits(st.bits, nb, tid);\n\n                    long long ev = 1LL * ch.score * 100;\n                    ev += 3LL * loc;\n                    ev += 1LL * degBias * deg;\n                    ev -= 10LL * borderDist[nb];\n\n                    if (deg == 0) ev -= 4000;\n                    ev += rng.nextInt(noise);\n\n                    ch.eval = ev;\n                    cand.push_back(ch);\n                }\n            }\n\n            if (cand.empty()) break;\n\n            if ((int)cand.size() > width) {\n                nth_element(\n                    cand.begin(),\n                    cand.begin() + width,\n                    cand.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.eval > b.eval;\n                    }\n                );\n                cand.resize(width);\n            }\n\n            nxt.clear();\n\n            for (auto& ch : cand) {\n                int parent = ch.node;\n                nodes.push_back({parent, ch.pos, ch.score});\n                ch.node = (int)nodes.size() - 1;\n\n                if (ch.score > localBestScore) {\n                    localBestScore = ch.score;\n                    localBestNode = ch.node;\n                }\n\n                nxt.push_back(std::move(ch));\n            }\n\n            cur.swap(nxt);\n        }\n\n        if (localBestScore + 2500 >= bestScore) {\n            vector<int> cells;\n            int x = localBestNode;\n            while (x != -1) {\n                cells.push_back(nodes[x].cell);\n                x = nodes[x].parent;\n            }\n            reverse(cells.begin(), cells.end());\n            addCandidate(cells, localBestScore);\n        }\n\n        if (!cur.empty() && timer.elapsed() < endTime + 0.08) {\n            int take = min<int>(20, cur.size());\n\n            if ((int)cur.size() > take) {\n                nth_element(\n                    cur.begin(),\n                    cur.begin() + take,\n                    cur.end(),\n                    [](const BeamState& a, const BeamState& b) {\n                        return a.score > b.score;\n                    }\n                );\n            }\n\n            cur.resize(take);\n\n            for (auto& st : cur) {\n                if (timer.elapsed() > endTime + 0.10) break;\n\n                vector<int> prefix;\n                int x = st.node;\n                while (x != -1) {\n                    prefix.push_back(nodes[x].cell);\n                    x = nodes[x].parent;\n                }\n                reverse(prefix.begin(), prefix.end());\n\n                Params p = makePilotParam();\n                Bits b = st.bits;\n                vector<int> suffix;\n                suffix.reserve(1000);\n\n                int sc = rolloutScore(b, st.prev, st.pos, st.score, p, &suffix);\n\n                if (sc + 2500 >= bestScore) {\n                    vector<int> full = prefix;\n                    full.insert(full.end(), suffix.begin(), suffix.end());\n                    addCandidate(full, sc);\n                }\n            }\n        }\n    }\n\n    bool optimizeRepresentativesDP(vector<int>& path, int& score) {\n        int L = (int)path.size();\n        if (L <= 1) return false;\n\n        static int opt0[V], opt1[V], optN[V];\n        static int dp[V][2];\n        static int par[V][2];\n\n        constexpr int NEG = -1000000000;\n\n        for (int i = 0; i < L; i++) {\n            int c = path[i];\n            opt0[i] = c;\n            opt1[i] = -1;\n            optN[i] = 1;\n\n            // The initial cell must stay fixed.\n            if (i > 0 && tileMate[c] != -1) {\n                opt1[i] = tileMate[c];\n                optN[i] = 2;\n            }\n        }\n\n        dp[0][0] = val[opt0[0]];\n        dp[0][1] = NEG;\n        par[0][0] = par[0][1] = -1;\n\n        for (int i = 1; i < L; i++) {\n            dp[i][0] = dp[i][1] = NEG;\n            par[i][0] = par[i][1] = -1;\n\n            int optsCur[2] = {opt0[i], opt1[i]};\n\n            for (int o = 0; o < optN[i]; o++) {\n                int c = optsCur[o];\n\n                int optsPrev[2] = {opt0[i - 1], opt1[i - 1]};\n\n                for (int p = 0; p < optN[i - 1]; p++) {\n                    if (dp[i - 1][p] <= NEG / 2) continue;\n                    if (!adjacentCell(optsPrev[p], c)) continue;\n\n                    int ns = dp[i - 1][p] + val[c];\n\n                    if (ns > dp[i][o]) {\n                        dp[i][o] = ns;\n                        par[i][o] = p;\n                    }\n                }\n            }\n        }\n\n        int bestO = 0;\n        if (dp[L - 1][1] > dp[L - 1][0]) bestO = 1;\n\n        int newScore = dp[L - 1][bestO];\n        if (newScore <= score) return false;\n\n        vector<int> np(L);\n\n        int o = bestO;\n        for (int i = L - 1; i >= 0; i--) {\n            np[i] = (o == 0 ? opt0[i] : opt1[i]);\n            o = par[i][o];\n            if (i > 0 && o < 0) return false;\n        }\n\n        path.swap(np);\n        score = newScore;\n        return true;\n    }\n\n    bool validatePath(const vector<int>& cells) const {\n        if (cells.empty()) return false;\n        if (cells[0] != startCell) return false;\n\n        vector<char> used(M, 0);\n\n        for (int i = 0; i < (int)cells.size(); i++) {\n            int c = cells[i];\n            if (c < 0 || c >= V) return false;\n\n            int tid = tile[c];\n            if (used[tid]) return false;\n            used[tid] = 1;\n\n            if (i > 0) {\n                int d = abs(cells[i] - cells[i - 1]);\n                if (!(d == 1 || d == N)) return false;\n                if (d == 1 && cells[i] / N != cells[i - 1] / N) return false;\n            }\n        }\n\n        return true;\n    }\n\n    string cellsToMoves(const vector<int>& cells) const {\n        string s;\n        s.reserve(cells.size());\n\n        for (int i = 1; i < (int)cells.size(); i++) {\n            int d = cells[i] - cells[i - 1];\n\n            if (d == -N) s.push_back('U');\n            else if (d == N) s.push_back('D');\n            else if (d == -1) s.push_back('L');\n            else if (d == 1) s.push_back('R');\n        }\n\n        return s;\n    }\n\n    string solve() {\n        timer.reset();\n\n        pool.clear();\n        bestCells.clear();\n        bestCum.clear();\n        bestScore = -1;\n\n        vector<int> init{startCell};\n        addCandidate(init, val[startCell]);\n\n        curCells.reserve(V);\n\n        for (int i = 0; i < 22 && timer.elapsed() < 0.09; i++) {\n            bool flood = (i % 6 == 0);\n            Params par = makeParams(flood);\n            int sc = runGreedy(0, flood, par);\n            considerCurrent(sc);\n        }\n\n        runBeam(0.23, 280);\n\n        if (!pool.empty() && timer.elapsed() < 0.38) {\n            runPosaFromBase(pool[0].cells, pool[0].cum, (int)pool[0].cells.size() - 1, 0.035);\n        }\n\n        int iter = 0;\n\n        while (timer.elapsed() < TL) {\n            double e = timer.elapsed();\n\n            if (TL - e < 0.190) {\n                finalAugment(max(0.0, TL - e - 0.004));\n                break;\n            }\n\n            if (pool.empty()) {\n                vector<int> init2{startCell};\n                addCandidate(init2, val[startCell]);\n            }\n\n            int mode = rng.nextInt(100);\n\n            if (e < 0.75) {\n                if (mode < 56) {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (iter <= 8 || base.cells.size() < 2 || rng.nextInt(100) < 32) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 12, 35);\n                    }\n\n                    int variants = (e < 0.60 ? 2 : (rng.nextInt(100) < 35 ? 2 : 1));\n                    bool useReach = rng.nextInt(100) < 16;\n\n                    runPilotBase(base.cells, base.cum, cut, variants, false, useReach);\n                } else if (mode < 72) {\n                    int bi = (rng.nextInt(100) < 68 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 68) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 45);\n\n                    runRotationExtendFromBase(base.cells, base.cum, cut, rng.nextInt(100) < 76);\n                } else if (mode < 82) {\n                    int bi = (rng.nextInt(100) < 75 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 75) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 45);\n\n                    runPosaFromBase(base.cells, base.cum, cut, 0.012 + 0.010 * (rng.nextInt(100) < 35));\n                } else {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int floodProb = 38;\n                    bool flood = (rng.nextInt(100) < floodProb);\n\n                    int cut;\n                    if (iter < 10 || base.cells.size() < 2 || rng.nextInt(100) < 30) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 18, 30);\n                    }\n\n                    Params par = makeParams(flood);\n                    int sc = runGreedyBase(base.cells, base.cum, cut, flood, par);\n                    considerCurrent(sc);\n                }\n            } else {\n                if (mode < 40) {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (base.cells.size() < 2 || rng.nextInt(100) < 26) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 10, 40);\n                    }\n\n                    int variants = (rng.nextInt(100) < 30 ? 2 : 1);\n                    bool allowPosa = (rng.nextInt(100) < 18);\n                    bool useReach = rng.nextInt(100) < 12;\n\n                    runPilotBase(base.cells, base.cum, cut, variants, allowPosa, useReach);\n                } else if (mode < 66) {\n                    int bi = (rng.nextInt(100) < 62 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 62) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 3, 45);\n\n                    runRotationExtendFromBase(base.cells, base.cum, cut, rng.nextInt(100) < 78);\n                } else if (mode < 86) {\n                    int bi = (rng.nextInt(100) < 80 ? 0 : choosePoolIndex());\n                    const PathCand& base = pool[bi];\n\n                    int cut;\n                    if (rng.nextInt(100) < 80) cut = (int)base.cells.size() - 1;\n                    else cut = chooseCutForBase(base, 5, 40);\n\n                    runPosaFromBase(base.cells, base.cum, cut, 0.018 + 0.020 * (rng.nextInt(100) < 40));\n                } else {\n                    int bi = choosePoolIndex();\n                    const PathCand& base = pool[bi];\n\n                    int floodProb = 52;\n                    bool flood = (rng.nextInt(100) < floodProb);\n\n                    int cut;\n                    if (base.cells.size() < 2 || rng.nextInt(100) < 28) {\n                        cut = 0;\n                    } else {\n                        cut = chooseCutForBase(base, 15, 35);\n                    }\n\n                    Params par = makeParams(flood);\n                    int sc = runGreedyBase(base.cells, base.cum, cut, flood, par);\n                    considerCurrent(sc);\n                }\n            }\n\n            iter++;\n        }\n\n        // Exact monotonic representative optimization for all elite tile-order paths.\n        // This is cheap and can rescue near-best paths whose chosen squares were suboptimal.\n        if (timer.elapsed() < TL - 0.002 && !pool.empty()) {\n            vector<PathCand> reps = pool;\n            sort(reps.begin(), reps.end(), [](const PathCand& a, const PathCand& b) {\n                if (a.score != b.score) return a.score > b.score;\n                return a.cells.size() > b.cells.size();\n            });\n\n            int lim = min<int>((int)reps.size(), POOL_LIMIT);\n\n            for (int i = 0; i < lim && timer.elapsed() < TL - 0.001; i++) {\n                vector<int> p = reps[i].cells;\n                int sc = reps[i].score;\n\n                if (optimizeRepresentativesDP(p, sc) && validatePath(p)) {\n                    addCandidate(p, sc);\n                }\n            }\n        }\n\n        if (!validatePath(bestCells)) {\n            bool found = false;\n            for (auto& pc : pool) {\n                if (validatePath(pc.cells)) {\n                    bestCells = pc.cells;\n                    bestCum = pc.cum;\n                    bestScore = pc.score;\n                    found = true;\n                    break;\n                }\n            }\n            if (!found) return \"\";\n        }\n\n        return cellsToMoves(bestCells);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.read();\n\n    cout << solver.solve() << '\\n';\n\n    return 0;\n}","ahc003":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 30;\nstatic constexpr int LINE_VARS = 2 * N;\n\nstatic constexpr int BINS = 4;\nstatic constexpr int HBIN_VARS = N * BINS;\nstatic constexpr int BIN_VARS = 2 * N * BINS;\n\nstatic constexpr int SEG_VARS = 2 * LINE_VARS;\n\nstatic constexpr int FINE_BINS = 6;\nstatic constexpr int HFINE_VARS = N * FINE_BINS;\nstatic constexpr int FINE_VARS = 2 * N * FINE_BINS;\n\nstatic constexpr int H_EDGES = N * (N - 1);\nstatic constexpr int EDGE_VARS = 2 * H_EDGES;\n\nstatic constexpr int EXPLORE_TURNS = 100;\n\nstatic inline double clampd(double x, double lo, double hi) {\n    return min(hi, max(lo, x));\n}\n\nstatic inline int popcnt(uint32_t x) {\n    return __builtin_popcount(x);\n}\n\nstatic inline uint32_t lowMask(int x) {\n    if (x <= 0) return 0;\n    return (1u << x) - 1u;\n}\n\nstruct RidgeModel {\n    int n;\n    vector<double> ata;\n    vector<double> atb;\n\n    RidgeModel(int n_ = 0) : n(n_), ata(n_ * n_, 0.0), atb(n_, 0.0) {}\n\n    void addObservation(const vector<pair<int, int>>& counts, int steps, double result) {\n        if (steps <= 0) return;\n\n        vector<pair<int, double>> f;\n        f.reserve(counts.size());\n\n        double inv_steps = 1.0 / steps;\n        for (auto [idx, cnt] : counts) {\n            if (cnt > 0) f.push_back({idx, cnt * inv_steps});\n        }\n\n        double target = result * inv_steps;\n\n        for (auto [ia, va] : f) {\n            double* row = &ata[ia * n];\n            atb[ia] += va * target;\n            for (auto [ib, vb] : f) {\n                row[ib] += va * vb;\n            }\n        }\n    }\n\n    void solve(const vector<double>& prior, double lambda, vector<double>& out) const {\n        vector<double> a = ata;\n        vector<double> b(n);\n\n        for (int i = 0; i < n; i++) {\n            a[i * n + i] += lambda;\n            b[i] = atb[i] + lambda * prior[i];\n        }\n\n        for (int i = 0; i < n; i++) {\n            for (int j = 0; j <= i; j++) {\n                double sum = a[i * n + j];\n                for (int k = 0; k < j; k++) {\n                    sum -= a[i * n + k] * a[j * n + k];\n                }\n\n                if (i == j) {\n                    if (sum < 1e-9) sum = 1e-9;\n                    a[i * n + j] = sqrt(sum);\n                } else {\n                    a[i * n + j] = sum / a[j * n + j];\n                }\n            }\n        }\n\n        vector<double> y(n);\n        for (int i = 0; i < n; i++) {\n            double sum = b[i];\n            for (int k = 0; k < i; k++) sum -= a[i * n + k] * y[k];\n            y[i] = sum / a[i * n + i];\n        }\n\n        out.assign(n, 0.0);\n        for (int i = n - 1; i >= 0; i--) {\n            double sum = y[i];\n            for (int k = i + 1; k < n; k++) sum -= a[k * n + i] * out[k];\n            out[i] = sum / a[i * n + i];\n            out[i] = clampd(out[i], 1000.0, 9000.0);\n        }\n    }\n};\n\nstruct Observation {\n    int result = 0;\n    int steps = 0;\n    array<uint32_t, LINE_VARS> mask;\n\n    Observation() {\n        mask.fill(0);\n    }\n};\n\nstruct Solver {\n    RidgeModel lineModel;\n    RidgeModel binModel;\n    RidgeModel fineModel;\n\n    vector<double> lineEst;\n    vector<double> binDelta;\n    vector<double> segEst;\n    vector<double> fineDelta;\n    vector<double> edgeDelta;\n\n    array<int, LINE_VARS> lineSeen{};\n    array<int, BIN_VARS> binSeen{};\n    array<int, FINE_VARS> fineSeen{};\n    array<int, EDGE_VARS> edgeSeen{};\n    array<int, EDGE_VARS> edgeLearnSeen{};\n\n    array<int, LINE_VARS> split{};\n    array<int, SEG_VARS> segSupport{};\n\n    vector<Observation> observations;\n\n    mt19937 rng;\n    int turn = 0;\n\n    double segGlobalConf = 0.0;\n\n    bool fineReady = false;\n    double fineValidationConf = 1.0;\n    deque<pair<double, double>> fineValidationWindow;\n\n    double edgeValidationConf = 1.0;\n    deque<pair<double, double>> edgeValidationWindow;\n\n    Solver()\n        : lineModel(LINE_VARS),\n          binModel(BIN_VARS),\n          fineModel(FINE_VARS),\n          lineEst(LINE_VARS, 5000.0),\n          binDelta(BIN_VARS, 0.0),\n          segEst(SEG_VARS, 5000.0),\n          fineDelta(FINE_VARS, 0.0),\n          edgeDelta(EDGE_VARS, 0.0),\n          rng(1234567) {\n        lineSeen.fill(0);\n        binSeen.fill(0);\n        fineSeen.fill(0);\n        edgeSeen.fill(0);\n        edgeLearnSeen.fill(0);\n        split.fill(14);\n        segSupport.fill(0);\n    }\n\n    static int hVar(int i, int j) {\n        int q = j * BINS / (N - 1);\n        return i * BINS + q;\n    }\n\n    static int vVar(int i, int j) {\n        int q = i * BINS / (N - 1);\n        return HBIN_VARS + j * BINS + q;\n    }\n\n    static int fineHVar(int i, int j) {\n        int q = j * FINE_BINS / (N - 1);\n        return i * FINE_BINS + q;\n    }\n\n    static int fineVVar(int i, int j) {\n        int q = i * FINE_BINS / (N - 1);\n        return HFINE_VARS + j * FINE_BINS + q;\n    }\n\n    static int hEdge(int i, int j) {\n        return i * (N - 1) + j;\n    }\n\n    static int vEdge(int i, int j) {\n        return H_EDGES + i * N + j;\n    }\n\n    double globalWeight() const {\n        return clampd(turn / 300.0, 0.0, 1.0);\n    }\n\n    double binWeight() const {\n        return clampd((turn - 80) / 420.0, 0.0, 1.0);\n    }\n\n    double segmentWeight() const {\n        double t = clampd((turn - 110) / 390.0, 0.0, 1.0);\n        return t * segGlobalConf;\n    }\n\n    double fineWeight() const {\n        double t = clampd((turn - 300) / 500.0, 0.0, 1.0);\n        return 0.40 * t * fineValidationConf;\n    }\n\n    double edgeWeight() const {\n        double t = clampd((turn - 520) / 400.0, 0.0, 1.0);\n        return 0.15 * t * edgeValidationConf;\n    }\n\n    double rawStructH(int i, int j) const {\n        int line = i;\n        int bv = hVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (j < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        return clampd(raw, 1000.0, 9000.0);\n    }\n\n    double rawStructV(int i, int j) const {\n        int line = N + j;\n        int bv = vVar(i, j);\n\n        double bw = binWeight();\n        double base = lineEst[line] + bw * binDelta[bv];\n\n        int side = (i < split[line] ? 0 : 1);\n        int sv = 2 * line + side;\n\n        double cov = clampd(segSupport[sv] / 25.0, 0.0, 1.0);\n        double sw = 0.90 * segmentWeight() * cov;\n\n        double raw = (1.0 - sw) * base + sw * segEst[sv];\n        return clampd(raw, 1000.0, 9000.0);\n    }\n\n    double rawNoEdgeH(int i, int j) const {\n        double raw = rawStructH(i, j);\n\n        if (fineReady) {\n            int fv = fineHVar(i, j);\n            double seenConf = clampd((fineSeen[fv] - 3.0) / 12.0, 0.0, 1.0);\n            double fw = fineWeight() * seenConf;\n            raw = clampd(raw + fw * fineDelta[fv], 1000.0, 9000.0);\n        }\n\n        return raw;\n    }\n\n    double rawNoEdgeV(int i, int j) const {\n        double raw = rawStructV(i, j);\n\n        if (fineReady) {\n            int fv = fineVVar(i, j);\n            double seenConf = clampd((fineSeen[fv] - 3.0) / 12.0, 0.0, 1.0);\n            double fw = fineWeight() * seenConf;\n            raw = clampd(raw + fw * fineDelta[fv], 1000.0, 9000.0);\n        }\n\n        return raw;\n    }\n\n    double hCostNoFine(int i, int j) const {\n        double raw = rawStructH(i, j);\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCostNoFine(int i, int j) const {\n        double raw = rawStructV(i, j);\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double hCostNoEdge(int i, int j) const {\n        double raw = rawNoEdgeH(i, j);\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCostNoEdge(int i, int j) const {\n        double raw = rawNoEdgeV(i, j);\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double hCost(int i, int j) const {\n        double raw = rawNoEdgeH(i, j);\n\n        int e = hEdge(i, j);\n        double seenConf = clampd((edgeLearnSeen[e] - 2.0) / 8.0, 0.0, 1.0);\n        double ew = edgeWeight() * seenConf;\n        raw = clampd(raw + ew * edgeDelta[e], 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    double vCost(int i, int j) const {\n        double raw = rawNoEdgeV(i, j);\n\n        int e = vEdge(i, j);\n        double seenConf = clampd((edgeLearnSeen[e] - 2.0) / 8.0, 0.0, 1.0);\n        double ew = edgeWeight() * seenConf;\n        raw = clampd(raw + ew * edgeDelta[e], 1000.0, 9000.0);\n\n        double g = globalWeight();\n        return clampd(5000.0 + g * (raw - 5000.0), 1000.0, 9000.0);\n    }\n\n    static void appendVertical(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    }\n\n    static void appendHorizontal(string& s, int from, int to) {\n        if (to > from) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    }\n\n    string makeDirect(int si, int sj, int ti, int tj, bool horizontalFirst) const {\n        string s;\n        if (horizontalFirst) {\n            appendHorizontal(s, sj, tj);\n            appendVertical(s, si, ti);\n        } else {\n            appendVertical(s, si, ti);\n            appendHorizontal(s, sj, tj);\n        }\n        return s;\n    }\n\n    string makeViaRow(int si, int sj, int ti, int tj, int r) const {\n        string s;\n        appendVertical(s, si, r);\n        appendHorizontal(s, sj, tj);\n        appendVertical(s, r, ti);\n        return s;\n    }\n\n    string makeViaCol(int si, int sj, int ti, int tj, int c) const {\n        string s;\n        appendHorizontal(s, sj, c);\n        appendVertical(s, si, ti);\n        appendHorizontal(s, c, tj);\n        return s;\n    }\n\n    bool validatePath(int si, int sj, int ti, int tj, const string& path) const {\n        array<char, N * N> vis{};\n        int r = si, c = sj;\n        vis[r * N + c] = 1;\n\n        for (char ch : path) {\n            if (ch == 'U') r--;\n            else if (ch == 'D') r++;\n            else if (ch == 'L') c--;\n            else if (ch == 'R') c++;\n            else return false;\n\n            if (r < 0 || r >= N || c < 0 || c >= N) return false;\n\n            int id = r * N + c;\n            if (vis[id]) return false;\n            vis[id] = 1;\n        }\n\n        return r == ti && c == tj;\n    }\n\n    double estimatePathCost(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCost(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCost(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCost(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCost(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double estimatePathCostNoEdge(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCostNoEdge(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCostNoEdge(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCostNoEdge(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCostNoEdge(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double estimatePathCostNoFine(int si, int sj, const string& path) const {\n        int r = si, c = sj;\n        double total = 0.0;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                total += hCostNoFine(r, c);\n                c++;\n            } else if (ch == 'L') {\n                total += hCostNoFine(r, c - 1);\n                c--;\n            } else if (ch == 'D') {\n                total += vCostNoFine(r, c);\n                r++;\n            } else if (ch == 'U') {\n                total += vCostNoFine(r - 1, c);\n                r--;\n            }\n        }\n\n        return total;\n    }\n\n    double explorationSeenScore(int si, int sj, const string& path) const {\n        array<char, LINE_VARS> lu{};\n        array<char, BIN_VARS> bu{};\n\n        int r = si, c = sj;\n\n        for (char ch : path) {\n            int line = -1, bv = -1;\n\n            if (ch == 'R') {\n                line = r;\n                bv = hVar(r, c);\n                c++;\n            } else if (ch == 'L') {\n                c--;\n                line = r;\n                bv = hVar(r, c);\n            } else if (ch == 'D') {\n                line = N + c;\n                bv = vVar(r, c);\n                r++;\n            } else if (ch == 'U') {\n                r--;\n                line = N + c;\n                bv = vVar(r, c);\n            }\n\n            if (line >= 0) lu[line] = 1;\n            if (bv >= 0) bu[bv] = 1;\n        }\n\n        double score = 0.0;\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lu[i]) score += lineSeen[i];\n        }\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (bu[i]) score += 0.35 * binSeen[i];\n        }\n\n        return score;\n    }\n\n    string chooseBestDirect(int si, int sj, int ti, int tj) const {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        return (c1 <= c2 ? p1 : p2);\n    }\n\n    string chooseExplorationPath(int si, int sj, int ti, int tj) {\n        string p1 = makeDirect(si, sj, ti, tj, true);\n        string p2 = makeDirect(si, sj, ti, tj, false);\n\n        double c1 = estimatePathCost(si, sj, p1);\n        double c2 = estimatePathCost(si, sj, p2);\n\n        double s1 = explorationSeenScore(si, sj, p1);\n        double s2 = explorationSeenScore(si, sj, p2);\n\n        double bonus = 1500.0 * (1.0 - turn / double(EXPLORE_TURNS));\n\n        double v1 = c1 + bonus * s1;\n        double v2 = c2 + bonus * s2;\n\n        if (abs(v1 - v2) < 1e-9) {\n            return (rng() & 1) ? p1 : p2;\n        }\n        return (v1 <= v2 ? p1 : p2);\n    }\n\n    string bestCorridorPath(int si, int sj, int ti, int tj) const {\n        string best;\n        double bestCost = 1e100;\n\n        auto consider = [&](const string& p) {\n            if (!validatePath(si, sj, ti, tj, p)) return;\n\n            double c = estimatePathCost(si, sj, p);\n            if (c < bestCost - 1e-9 ||\n                (abs(c - bestCost) < 1e-9 && (best.empty() || p.size() < best.size()))) {\n                bestCost = c;\n                best = p;\n            }\n        };\n\n        consider(makeDirect(si, sj, ti, tj, true));\n        consider(makeDirect(si, sj, ti, tj, false));\n\n        for (int r = 0; r < N; r++) {\n            consider(makeViaRow(si, sj, ti, tj, r));\n        }\n        for (int c = 0; c < N; c++) {\n            consider(makeViaCol(si, sj, ti, tj, c));\n        }\n\n        if (best.empty()) best = chooseBestDirect(si, sj, ti, tj);\n        return best;\n    }\n\n    string dijkstra(int si, int sj, int ti, int tj, bool useFine, bool useEdge) const {\n        int S = si * N + sj;\n        int T = ti * N + tj;\n\n        const double INF = 1e100;\n        vector<double> dist(N * N, INF);\n        vector<int> pre(N * N, -1);\n        vector<char> pmove(N * N, 0);\n\n        using P = pair<double, int>;\n        priority_queue<P, vector<P>, greater<P>> pq;\n\n        dist[S] = 0.0;\n        pre[S] = S;\n        pq.push({0.0, S});\n\n        while (!pq.empty()) {\n            auto [d, u] = pq.top();\n            pq.pop();\n\n            if (d > dist[u] + 1e-9) continue;\n            if (u == T) break;\n\n            int r = u / N;\n            int c = u % N;\n\n            int dirs[4];\n            bool used[4] = {};\n            int m = 0;\n\n            auto addDir = [&](int x) {\n                if (!used[x]) {\n                    used[x] = true;\n                    dirs[m++] = x;\n                }\n            };\n\n            if (ti < r) addDir(0);\n            if (ti > r) addDir(1);\n            if (tj < c) addDir(2);\n            if (tj > c) addDir(3);\n            for (int x = 0; x < 4; x++) addDir(x);\n\n            for (int idx = 0; idx < 4; idx++) {\n                int dir = dirs[idx];\n\n                int nr = r, nc = c;\n                char mv = '?';\n                double w = 0.0;\n\n                if (dir == 0) {\n                    if (r == 0) continue;\n                    nr = r - 1;\n                    mv = 'U';\n                    if (!useFine) w = vCostNoFine(r - 1, c);\n                    else if (!useEdge) w = vCostNoEdge(r - 1, c);\n                    else w = vCost(r - 1, c);\n                } else if (dir == 1) {\n                    if (r == N - 1) continue;\n                    nr = r + 1;\n                    mv = 'D';\n                    if (!useFine) w = vCostNoFine(r, c);\n                    else if (!useEdge) w = vCostNoEdge(r, c);\n                    else w = vCost(r, c);\n                } else if (dir == 2) {\n                    if (c == 0) continue;\n                    nc = c - 1;\n                    mv = 'L';\n                    if (!useFine) w = hCostNoFine(r, c - 1);\n                    else if (!useEdge) w = hCostNoEdge(r, c - 1);\n                    else w = hCost(r, c - 1);\n                } else {\n                    if (c == N - 1) continue;\n                    nc = c + 1;\n                    mv = 'R';\n                    if (!useFine) w = hCostNoFine(r, c);\n                    else if (!useEdge) w = hCostNoEdge(r, c);\n                    else w = hCost(r, c);\n                }\n\n                int v = nr * N + nc;\n                double nd = d + w;\n\n                if (nd + 1e-9 < dist[v]) {\n                    dist[v] = nd;\n                    pre[v] = u;\n                    pmove[v] = mv;\n                    pq.push({nd, v});\n                }\n            }\n        }\n\n        if (pre[T] == -1) return \"\";\n\n        string path;\n        int cur = T;\n        while (cur != S) {\n            path.push_back(pmove[cur]);\n            cur = pre[cur];\n            if (cur < 0) return \"\";\n        }\n\n        reverse(path.begin(), path.end());\n        return path;\n    }\n\n    string choosePath(int si, int sj, int ti, int tj) {\n        if (turn < EXPLORE_TURNS) {\n            return chooseExplorationPath(si, sj, ti, tj);\n        }\n\n        string safe = bestCorridorPath(si, sj, ti, tj);\n        string p = dijkstra(si, sj, ti, tj, true, true);\n\n        if (p.empty() || !validatePath(si, sj, ti, tj, p)) {\n            return safe;\n        }\n\n        if (turn >= 620 && edgeWeight() > 1e-9) {\n            string pne = dijkstra(si, sj, ti, tj, true, false);\n\n            if (!pne.empty() && validatePath(si, sj, ti, tj, pne)) {\n                double cfP = estimatePathCost(si, sj, p);\n                double ceP = estimatePathCostNoEdge(si, sj, p);\n                double cfN = estimatePathCost(si, sj, pne);\n                double ceN = estimatePathCostNoEdge(si, sj, pne);\n\n                double trustEdge = clampd(0.65 + 0.25 * edgeValidationConf, 0.70, 0.90);\n                double scoreP = trustEdge * cfP + (1.0 - trustEdge) * ceP;\n                double scoreN = trustEdge * cfN + (1.0 - trustEdge) * ceN;\n\n                if (scoreN < scoreP * 0.998 && (int)pne.size() <= (int)p.size() + 35) {\n                    p = pne;\n                }\n            }\n        }\n\n        if (fineReady && turn >= 380) {\n            string pn = dijkstra(si, sj, ti, tj, false, false);\n\n            if (!pn.empty() && validatePath(si, sj, ti, tj, pn)) {\n                double cfP = estimatePathCost(si, sj, p);\n                double csP = estimatePathCostNoFine(si, sj, p);\n                double cfN = estimatePathCost(si, sj, pn);\n                double csN = estimatePathCostNoFine(si, sj, pn);\n\n                double trustFine = clampd(0.70 + 0.22 * fineValidationConf, 0.80, 0.92);\n\n                double scoreP = trustFine * cfP + (1.0 - trustFine) * csP;\n                double scoreN = trustFine * cfN + (1.0 - trustFine) * csN;\n\n                if (scoreN < scoreP * 0.997 && (int)pn.size() <= (int)p.size() + 40) {\n                    p = pn;\n                }\n            }\n        }\n\n        int manhattan = abs(si - ti) + abs(sj - tj);\n\n        int extraLimit;\n        if (turn < 200) extraLimit = 12;\n        else if (turn < 350) extraLimit = 25;\n        else if (turn < 500) extraLimit = 45;\n        else if (turn < 700) extraLimit = 65;\n        else extraLimit = 80 + int(20.0 * segGlobalConf);\n\n        double cd = estimatePathCost(si, sj, p);\n        double cs = estimatePathCost(si, sj, safe);\n\n        int extra = int(p.size()) - manhattan;\n\n        if (extra > extraLimit) {\n            if ((int)p.size() > manhattan + 130) return safe;\n            if (cd > cs * 0.82) return safe;\n        }\n\n        int lenDiff = int(p.size()) - int(safe.size());\n        if (lenDiff > 30) {\n            double requiredRatio = 1.0 - min(0.08, 0.001 * lenDiff);\n            if (cd > cs * requiredRatio) return safe;\n        }\n\n        return p;\n    }\n\n    void updateFineValidation(int si, int sj, const string& path, int result) {\n        if (!fineReady || turn < 350 || result <= 0) return;\n\n        double ps = estimatePathCostNoFine(si, sj, path);\n        double pf = estimatePathCostNoEdge(si, sj, path);\n\n        double denom = max(1.0, double(result));\n        double es = (ps - result) / denom;\n        double ef = (pf - result) / denom;\n\n        double es2 = min(0.25, es * es);\n        double ef2 = min(0.25, ef * ef);\n\n        fineValidationWindow.push_back({es2, ef2});\n        if ((int)fineValidationWindow.size() > 220) fineValidationWindow.pop_front();\n\n        if ((int)fineValidationWindow.size() < 120) {\n            fineValidationConf = 1.0;\n            return;\n        }\n\n        double ss = 0.0;\n        double sf = 0.0;\n        for (auto [a, b] : fineValidationWindow) {\n            ss += a;\n            sf += b;\n        }\n\n        ss /= fineValidationWindow.size();\n        sf /= fineValidationWindow.size();\n\n        double worse = sf - ss;\n\n        if (worse <= 0.0008) {\n            fineValidationConf = 1.0;\n        } else {\n            fineValidationConf = clampd(1.0 - (worse - 0.0008) / 0.0030 * 0.45, 0.55, 1.0);\n        }\n    }\n\n    void updateEdgeValidation(int si, int sj, const string& path, int result) {\n        if (turn < 600 || result <= 0) return;\n\n        double ps = estimatePathCostNoEdge(si, sj, path);\n        double pe = estimatePathCost(si, sj, path);\n\n        double denom = max(1.0, double(result));\n        double es = (ps - result) / denom;\n        double ee = (pe - result) / denom;\n\n        double es2 = min(0.25, es * es);\n        double ee2 = min(0.25, ee * ee);\n\n        edgeValidationWindow.push_back({es2, ee2});\n        if ((int)edgeValidationWindow.size() > 180) edgeValidationWindow.pop_front();\n\n        if ((int)edgeValidationWindow.size() < 90) {\n            edgeValidationConf = 1.0;\n            return;\n        }\n\n        double ss = 0.0;\n        double se = 0.0;\n        for (auto [a, b] : edgeValidationWindow) {\n            ss += a;\n            se += b;\n        }\n\n        ss /= edgeValidationWindow.size();\n        se /= edgeValidationWindow.size();\n\n        double worse = se - ss;\n\n        if (worse <= 0.0006) {\n            edgeValidationConf = 1.0;\n        } else {\n            edgeValidationConf = clampd(1.0 - (worse - 0.0006) / 0.0025 * 0.50, 0.50, 1.0);\n        }\n    }\n\n    void updateEdgeResidual(int si, int sj, const string& path, int result, const vector<int>& edgeList) {\n        if (turn < 300 || result <= 0 || path.empty()) return;\n\n        double pred = estimatePathCostNoEdge(si, sj, path);\n        double residual = result - pred;\n\n        double per = residual / double(path.size());\n        per = clampd(per, -2200.0, 2200.0);\n\n        double prog = clampd((turn - 300) / 500.0, 0.0, 1.0);\n        double lr = 0.10 + 0.08 * prog;\n\n        for (int e : edgeList) {\n            edgeLearnSeen[e]++;\n            int c = max(1, edgeLearnSeen[e]);\n            double rate = lr / sqrt(1.0 + 0.04 * c);\n            edgeDelta[e] += rate * per;\n            edgeDelta[e] = clampd(edgeDelta[e], -1800.0, 1800.0);\n        }\n    }\n\n    void updateModelsWithResult(int si, int sj, const string& path, int result) {\n        updateFineValidation(si, sj, path, result);\n        updateEdgeValidation(si, sj, path, result);\n\n        Observation ob;\n        ob.result = result;\n        ob.steps = (int)path.size();\n\n        array<int, LINE_VARS> lineCnt{};\n        array<int, BIN_VARS> binCnt{};\n        array<int, FINE_VARS> fineCnt{};\n\n        vector<int> edgeList;\n        edgeList.reserve(path.size());\n\n        int r = si;\n        int c = sj;\n\n        for (char ch : path) {\n            if (ch == 'R') {\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n                int fv = fineHVar(r, c);\n                int ev = hEdge(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                edgeSeen[ev]++;\n                edgeList.push_back(ev);\n\n                ob.mask[line] |= (1u << pos);\n                c++;\n            } else if (ch == 'L') {\n                c--;\n\n                int line = r;\n                int pos = c;\n                int bv = hVar(r, c);\n                int fv = fineHVar(r, c);\n                int ev = hEdge(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                edgeSeen[ev]++;\n                edgeList.push_back(ev);\n\n                ob.mask[line] |= (1u << pos);\n            } else if (ch == 'D') {\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n                int fv = fineVVar(r, c);\n                int ev = vEdge(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                edgeSeen[ev]++;\n                edgeList.push_back(ev);\n\n                ob.mask[line] |= (1u << pos);\n                r++;\n            } else if (ch == 'U') {\n                r--;\n\n                int line = N + c;\n                int pos = r;\n                int bv = vVar(r, c);\n                int fv = fineVVar(r, c);\n                int ev = vEdge(r, c);\n\n                lineCnt[line]++;\n                binCnt[bv]++;\n                fineCnt[fv]++;\n                edgeSeen[ev]++;\n                edgeList.push_back(ev);\n\n                ob.mask[line] |= (1u << pos);\n            }\n        }\n\n        vector<pair<int, int>> lf;\n        vector<pair<int, int>> bf;\n        vector<pair<int, int>> ff;\n\n        for (int i = 0; i < LINE_VARS; i++) {\n            if (lineCnt[i] > 0) {\n                lf.push_back({i, lineCnt[i]});\n                lineSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < BIN_VARS; i++) {\n            if (binCnt[i] > 0) {\n                bf.push_back({i, binCnt[i]});\n                binSeen[i]++;\n            }\n        }\n\n        for (int i = 0; i < FINE_VARS; i++) {\n            if (fineCnt[i] > 0) {\n                ff.push_back({i, fineCnt[i]});\n                fineSeen[i]++;\n            }\n        }\n\n        lineModel.addObservation(lf, ob.steps, result);\n        binModel.addObservation(bf, ob.steps, result);\n        fineModel.addObservation(ff, ob.steps, result);\n\n        observations.push_back(ob);\n\n        updateEdgeResidual(si, sj, path, result, edgeList);\n    }\n\n    double predictObsSegment(const Observation& ob) const {\n        double sum = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            uint32_t m = ob.mask[line];\n            if (!m) continue;\n\n            int total = popcnt(m);\n            int x = split[line];\n            int cl = popcnt(m & lowMask(x));\n            int cr = total - cl;\n\n            sum += segEst[2 * line] * cl;\n            sum += segEst[2 * line + 1] * cr;\n        }\n\n        return sum / ob.steps;\n    }\n\n    void seedSplitsFromBin() {\n        static const int bounds[3] = {8, 15, 22};\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 2) continue;\n\n            double val[BINS];\n\n            for (int q = 0; q < BINS; q++) {\n                int idx;\n                if (line < N) idx = line * BINS + q;\n                else idx = HBIN_VARS + (line - N) * BINS + q;\n\n                val[q] = lineEst[line] + binDelta[idx];\n            }\n\n            double bestDiff = 0.0;\n            int bestBoundary = split[line];\n\n            for (int q = 0; q + 1 < BINS; q++) {\n                double d = abs(val[q + 1] - val[q]);\n                if (d > bestDiff) {\n                    bestDiff = d;\n                    bestBoundary = bounds[q];\n                }\n            }\n\n            double segDiff = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (bestDiff > 450.0 &&\n                (segDiff < 700.0 || observations.size() < 180)) {\n                split[line] = bestBoundary;\n            }\n        }\n    }\n\n    void solveSegmentRidge(double lambda) {\n        RidgeModel model(SEG_VARS);\n        segSupport.fill(0);\n\n        for (const auto& ob : observations) {\n            vector<pair<int, int>> f;\n            f.reserve(16);\n\n            for (int line = 0; line < LINE_VARS; line++) {\n                uint32_t m = ob.mask[line];\n                if (!m) continue;\n\n                int total = popcnt(m);\n                int x = split[line];\n                int cl = popcnt(m & lowMask(x));\n                int cr = total - cl;\n\n                if (cl > 0) {\n                    f.push_back({2 * line, cl});\n                    segSupport[2 * line] += cl;\n                }\n                if (cr > 0) {\n                    f.push_back({2 * line + 1, cr});\n                    segSupport[2 * line + 1] += cr;\n                }\n            }\n\n            model.addObservation(f, ob.steps, ob.result);\n        }\n\n        vector<double> prior(SEG_VARS);\n        for (int i = 0; i < SEG_VARS; i++) {\n            prior[i] = lineEst[i / 2];\n        }\n\n        model.solve(prior, lambda, segEst);\n    }\n\n    void refineSplits() {\n        int m = (int)observations.size();\n        if (m < 60) return;\n\n        vector<double> pred(m);\n        vector<double> target(m);\n\n        for (int i = 0; i < m; i++) {\n            pred[i] = predictObsSegment(observations[i]);\n            target[i] = observations[i].result / double(observations[i].steps);\n        }\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            double v0 = segEst[2 * line];\n            double v1 = segEst[2 * line + 1];\n\n            if (abs(v0 - v1) < 250.0) continue;\n\n            int active = 0;\n            for (const auto& ob : observations) {\n                if (ob.mask[line]) active++;\n            }\n\n            if (active < 8) continue;\n\n            int oldX = split[line];\n            uint32_t oldMask = lowMask(oldX);\n\n            double bestSSE = 1e100;\n            double oldSSE = 1e100;\n            int bestX = oldX;\n\n            for (int x = 1; x <= 28; x++) {\n                uint32_t xm = lowMask(x);\n                double sse = 0.0;\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    double baseResidualTarget = target[idx] - pred[idx] + oldContr;\n\n                    int newLeft = popcnt(mask & xm);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    double res = baseResidualTarget - newContr;\n                    sse += res * res;\n                }\n\n                if (x == oldX) oldSSE = sse;\n\n                if (sse < bestSSE) {\n                    bestSSE = sse;\n                    bestX = x;\n                }\n            }\n\n            double threshold = max(20000.0, 0.001 * oldSSE);\n\n            if (bestX != oldX && bestSSE + threshold < oldSSE) {\n                uint32_t newMask = lowMask(bestX);\n\n                for (int idx = 0; idx < m; idx++) {\n                    const auto& ob = observations[idx];\n                    uint32_t mask = ob.mask[line];\n                    if (!mask) continue;\n\n                    int total = popcnt(mask);\n\n                    int oldLeft = popcnt(mask & oldMask);\n                    double oldContr = (v0 * oldLeft + v1 * (total - oldLeft)) / ob.steps;\n\n                    int newLeft = popcnt(mask & newMask);\n                    double newContr = (v0 * newLeft + v1 * (total - newLeft)) / ob.steps;\n\n                    pred[idx] += newContr - oldContr;\n                }\n\n                split[line] = bestX;\n            }\n        }\n    }\n\n    void updateSegmentConfidence() {\n        int strong = 0;\n        int usable = 0;\n        double sumConf = 0.0;\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            if (lineSeen[line] < 3) continue;\n            if (segSupport[2 * line] < 6) continue;\n            if (segSupport[2 * line + 1] < 6) continue;\n\n            usable++;\n\n            double d = abs(segEst[2 * line] - segEst[2 * line + 1]);\n\n            if (d > 900.0) strong++;\n            sumConf += clampd((d - 500.0) / 1500.0, 0.0, 1.0);\n        }\n\n        double c1 = clampd((strong - 4) / 18.0, 0.0, 1.0);\n\n        double c2 = 0.0;\n        if (usable > 0) {\n            double avg = sumConf / usable;\n            c2 = clampd((avg - 0.12) / 0.38, 0.0, 1.0);\n        }\n\n        segGlobalConf = max(c1, 0.8 * c2);\n    }\n\n    double priorFineValue(int line, int q) const {\n        double sum = 0.0;\n        int cnt = 0;\n\n        for (int pos = 0; pos < N - 1; pos++) {\n            int qq = pos * FINE_BINS / (N - 1);\n            if (qq != q) continue;\n\n            if (line < N) {\n                sum += rawStructH(line, pos);\n            } else {\n                int col = line - N;\n                sum += rawStructV(pos, col);\n            }\n            cnt++;\n        }\n\n        if (cnt == 0) return lineEst[line];\n        return sum / cnt;\n    }\n\n    void solveFineModel(int observationsCount) {\n        vector<double> prior(FINE_VARS, 5000.0);\n\n        for (int line = 0; line < LINE_VARS; line++) {\n            for (int q = 0; q < FINE_BINS; q++) {\n                int idx;\n                if (line < N) idx = line * FINE_BINS + q;\n                else idx = HFINE_VARS + (line - N) * FINE_BINS + q;\n\n                prior[idx] = priorFineValue(line, q);\n            }\n        }\n\n        double prog = min(1.0, observationsCount / 900.0);\n        double lambdaFine = 1.05 - 0.45 * prog;\n\n        vector<double> absFine;\n        fineModel.solve(prior, lambdaFine, absFine);\n\n        for (int i = 0; i < FINE_VARS; i++) {\n            fineDelta[i] = clampd(absFine[i] - prior[i], -1300.0, 1300.0);\n        }\n\n        fineReady = true;\n    }\n\n    void solveModels(int observationsCount) {\n        vector<double> priorLine(LINE_VARS, 5000.0);\n        lineModel.solve(priorLine, 0.1, lineEst);\n\n        int binPeriod = (observationsCount < 300 ? 10 : 20);\n        if (observationsCount % binPeriod == 0) {\n            vector<double> priorBin(BIN_VARS);\n\n            for (int i = 0; i < N; i++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[i * BINS + q] = lineEst[i];\n                }\n            }\n\n            for (int j = 0; j < N; j++) {\n                for (int q = 0; q < BINS; q++) {\n                    priorBin[HBIN_VARS + j * BINS + q] = lineEst[N + j];\n                }\n            }\n\n            double prog = min(1.0, observationsCount / 800.0);\n            double lambdaBin = 1.5 - prog;\n\n            vector<double> absBin;\n            binModel.solve(priorBin, lambdaBin, absBin);\n\n            for (int i = 0; i < BIN_VARS; i++) {\n                binDelta[i] = absBin[i] - priorBin[i];\n            }\n        }\n\n        if (observationsCount >= 80) {\n            int segPeriod = (observationsCount < 300 ? 20 : 30);\n\n            if (observationsCount % segPeriod == 0) {\n                seedSplitsFromBin();\n\n                double prog = min(1.0, observationsCount / 900.0);\n                double lambdaSeg = 0.9 - 0.55 * prog;\n\n                solveSegmentRidge(lambdaSeg);\n                refineSplits();\n                solveSegmentRidge(lambdaSeg);\n                updateSegmentConfidence();\n            }\n        }\n\n        if (observationsCount >= 280 && (observationsCount - 280) % 80 == 0) {\n            solveFineModel(observationsCount);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n\n    for (int k = 0; k < 1000; k++) {\n        int si, sj, ti, tj;\n        if (!(cin >> si >> sj >> ti >> tj)) return 0;\n\n        solver.turn = k;\n\n        string path = solver.choosePath(si, sj, ti, tj);\n\n        cout << path << '\\n' << flush;\n\n        int result;\n        if (!(cin >> result)) return 0;\n\n        solver.updateModelsWithResult(si, sj, path, result);\n\n        if (k + 1 < 1000) {\n            solver.solveModels(k + 1);\n        }\n    }\n\n    return 0;\n}","ahc004":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int SZ = 20;\nstatic const int CELLS = 400;\nstatic const int POS = 800;\nstatic const int DOT = 8;\nstatic const int MAXPLEN = 20;\nstatic const int MASK_WORDS = 13;\n\nusing Mask = array<uint64_t, MASK_WORDS>;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int randint(int n) { return (int)(next() % n); }\n    double drand() { return (next() >> 11) * (1.0 / 9007199254740992.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};\n\nint M_input, U, TOTAL;\ndouble avgLen = 0.0;\nint maxLenInput = 0;\n\nvector<string> uniqStr;\nvector<vector<uint8_t>> S;\nvector<int> Ls, W;\n\nvector<Mask> strMasks;\nvector<vector<int>> strContainsList;\nvector<int> strContainVal;\n\nuint16_t posCell[POS][MAXPLEN];\nvector<uint32_t> cellIncs[CELLS];\nint nearVal[13][13];\n\nXorShift rng;\n\ninline int countDotsVec(const vector<uint8_t>& g) {\n    int d = 0;\n    for (auto x : g) if (x == DOT) d++;\n    return d;\n}\n\nvoid initNearVal() {\n    memset(nearVal, 0, sizeof(nearVal));\n    for (int l = 1; l <= 12; l++) {\n        for (int m = 0; m <= l; m++) {\n            int q = l - m;\n            nearVal[l][m] = q * q * q;\n        }\n    }\n}\n\nvoid initPosCells() {\n    for (int pos = 0; pos < POS; pos++) {\n        for (int p = 0; p < MAXPLEN; p++) {\n            if (pos < 400) {\n                int r = pos / SZ;\n                int c = pos % SZ;\n                posCell[pos][p] = r * SZ + (c + p) % SZ;\n            } else {\n                int q = pos - 400;\n                int r = q / SZ;\n                int c = q % SZ;\n                posCell[pos][p] = ((r + p) % SZ) * SZ + c;\n            }\n        }\n    }\n}\n\nvoid buildIncidences() {\n    long long totalInc = 0;\n    for (int i = 0; i < U; i++) totalInc += 1LL * POS * Ls[i];\n    int reserveEach = (int)(totalInc / CELLS + 100);\n    for (int c = 0; c < CELLS; c++) cellIncs[c].reserve(reserveEach);\n\n    for (int sid = 0; sid < U; sid++) {\n        int base = sid * POS;\n        for (int pos = 0; pos < POS; pos++) {\n            int pid = base + pos;\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[pos][p];\n                uint32_t code = (uint32_t(pid) << 3) | uint32_t(S[sid][p]);\n                cellIncs[cell].push_back(code);\n            }\n        }\n    }\n}\n\nstruct State {\n    vector<uint8_t> grid;\n    vector<uint8_t> mism;\n    vector<uint16_t> cover;\n    vector<array<uint16_t, 13>> hist;\n    vector<array<int16_t, 13>> hdelta;\n\n    int obj = 0;\n\n    vector<int> markP, markS;\n    vector<int16_t> deltaM, deltaC;\n    vector<int> touchedP, touchedS;\n    int tagP = 1, tagS = 1;\n\n    void init() {\n        int Ptot = U * POS;\n        grid.assign(CELLS, DOT);\n        mism.assign(Ptot, 0);\n        cover.assign(U, 0);\n        hist.resize(U);\n        hdelta.resize(U);\n        for (auto& a : hist) a.fill(0);\n        for (auto& a : hdelta) a.fill(0);\n\n        markP.assign(Ptot, 0);\n        markS.assign(U, 0);\n        deltaM.assign(Ptot, 0);\n        deltaC.assign(U, 0);\n        touchedP.reserve(250000);\n        touchedS.reserve(U);\n    }\n\n    void nextTagP() {\n        ++tagP;\n        if (tagP == INT_MAX) {\n            fill(markP.begin(), markP.end(), 0);\n            tagP = 1;\n        }\n    }\n\n    void nextTagS() {\n        ++tagS;\n        if (tagS == INT_MAX) {\n            fill(markS.begin(), markS.end(), 0);\n            tagS = 1;\n        }\n    }\n\n    void build(const vector<uint8_t>& g) {\n        grid = g;\n        fill(cover.begin(), cover.end(), 0);\n        obj = 0;\n\n        for (int sid = 0; sid < U; sid++) {\n            hist[sid].fill(0);\n            int base = sid * POS;\n            const auto& str = S[sid];\n            int len = Ls[sid];\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = 0;\n                for (int p = 0; p < len; p++) {\n                    if (grid[posCell[pos][p]] != str[p]) m++;\n                }\n                mism[base + pos] = (uint8_t)m;\n                hist[sid][m]++;\n            }\n\n            cover[sid] = hist[sid][0];\n            if (cover[sid] > 0) obj += W[sid];\n        }\n    }\n\n    int evalChanges(const int cells[], const uint8_t vals[], int cnt) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        auto addSid = [&](int sid, int dc) {\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                deltaC[sid] = 0;\n                touchedS.push_back(sid);\n            }\n            deltaC[sid] += (int16_t)dc;\n        };\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (oldm == 0 && newm > 0) addSid(sid, -1);\n            else if (oldm > 0 && newm == 0) addSid(sid, +1);\n        }\n\n        int delta = 0;\n        for (int sid : touchedS) {\n            int cc = cover[sid];\n            int nc = cc + deltaC[sid];\n            if (cc == 0 && nc > 0) delta += W[sid];\n            else if (cc > 0 && nc == 0) delta -= W[sid];\n        }\n        return delta;\n    }\n\n    long long evalChangesSoft(const int cells[], const uint8_t vals[], int cnt, long long exactBonus) {\n        if (cnt <= 0) return 0;\n\n        nextTagP();\n        touchedP.clear();\n\n        for (int i = 0; i < cnt; i++) {\n            int cell = cells[i];\n            int oldc = grid[cell];\n            int newc = vals[i];\n            if (oldc == newc) continue;\n\n            for (uint32_t code : cellIncs[cell]) {\n                int pid = int(code >> 3);\n                int req = int(code & 7);\n                int dm = (newc != req) - (oldc != req);\n                if (dm == 0) continue;\n\n                if (markP[pid] != tagP) {\n                    markP[pid] = tagP;\n                    deltaM[pid] = 0;\n                    touchedP.push_back(pid);\n                }\n                deltaM[pid] += (int16_t)dm;\n            }\n        }\n\n        nextTagS();\n        touchedS.clear();\n\n        for (int pid : touchedP) {\n            int dm = deltaM[pid];\n            if (dm == 0) continue;\n\n            int oldm = mism[pid];\n            int newm = oldm + dm;\n            int sid = pid / POS;\n\n            if (markS[sid] != tagS) {\n                markS[sid] = tagS;\n                hdelta[sid].fill(0);\n                touchedS.push_back(sid);\n            }\n\n            hdelta[sid][oldm]--;\n            hdelta[sid][newm]++;\n        }\n\n        long long exactDelta = 0;\n        long long nearDelta = 0;\n\n        for (int sid : touchedS) {\n            int oldCov = cover[sid];\n            int newCov = hist[sid][0] + hdelta[sid][0];\n\n            if (oldCov == 0 && newCov > 0) exactDelta += W[sid];\n            else if (oldCov > 0 && newCov == 0) exactDelta -= W[sid];\n\n            int len = Ls[sid];\n\n            int oldMin = 0;\n            while (oldMin <= len && hist[sid][oldMin] == 0) oldMin++;\n\n            int newMin = 0;\n            while (newMin <= len && hist[sid][newMin] + hdelta[sid][newMin] <= 0) newMin++;\n\n            nearDelta += 1LL * W[sid] * (nearVal[len][newMin] - nearVal[len][oldMin]);\n\n            int oldRed = min(oldCov, 4);\n            int newRed = min(newCov, 4);\n            nearDelta += 80LL * W[sid] * (newRed - oldRed);\n        }\n\n        return exactDelta * exactBonus + nearDelta;\n    }\n\n    void changeCell(int cell, uint8_t newc) {\n        int oldc = grid[cell];\n        if (oldc == newc) return;\n\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            bool was = (oldc != req);\n            bool now = (newc != req);\n            if (was == now) continue;\n\n            int sid = pid / POS;\n            int m = mism[pid];\n\n            if (!was && now) {\n                hist[sid][m]--;\n                hist[sid][m + 1]++;\n\n                if (m == 0) {\n                    cover[sid]--;\n                    if (cover[sid] == 0) obj -= W[sid];\n                }\n                mism[pid] = (uint8_t)(m + 1);\n            } else {\n                hist[sid][m]--;\n                hist[sid][m - 1]++;\n\n                if (m == 1) {\n                    if (cover[sid] == 0) obj += W[sid];\n                    cover[sid]++;\n                }\n                mism[pid] = (uint8_t)(m - 1);\n            }\n        }\n\n        grid[cell] = newc;\n    }\n\n    void applyChanges(const int cells[], const uint8_t vals[], int cnt) {\n        for (int i = 0; i < cnt; i++) changeCell(cells[i], vals[i]);\n    }\n};\n\nstruct Best {\n    int obj = -1;\n    int dots = 1000000000;\n    vector<uint8_t> grid;\n\n    void consider(const State& st) {\n        int d = countDotsVec(st.grid);\n        bool upd = false;\n        if (st.obj > obj) upd = true;\n        else if (st.obj == obj) {\n            if (st.obj == TOTAL) {\n                if (d > dots) upd = true;\n            } else {\n                if (grid.empty() || d < dots) upd = true;\n            }\n        }\n\n        if (upd) {\n            obj = st.obj;\n            dots = d;\n            grid = st.grid;\n        }\n    }\n};\n\nvector<uint8_t> strToVec(const string& s) {\n    vector<uint8_t> v;\n    v.reserve(s.size());\n    for (char c : s) v.push_back((uint8_t)(c - 'A'));\n    return v;\n}\n\nstring vecToString(const vector<uint8_t>& v) {\n    string s;\n    s.reserve(v.size());\n    for (auto x : v) s.push_back(char('A' + x));\n    return s;\n}\n\nstring mergeLinear(const string& a, const string& b, int& ovOut) {\n    if (a.empty()) {\n        ovOut = 0;\n        return b;\n    }\n    if (b.empty()) {\n        ovOut = 0;\n        return a;\n    }\n\n    if (a.find(b) != string::npos) {\n        ovOut = (int)b.size();\n        return a;\n    }\n    if (b.find(a) != string::npos) {\n        ovOut = (int)a.size();\n        return b;\n    }\n\n    int bestOv = -1;\n    string best;\n\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            a.compare(a.size() - ov, ov, b, 0, ov) == 0) {\n            bestOv = ov;\n            best = a + b.substr(ov);\n            break;\n        }\n    }\n\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov <= MAXPLEN &&\n            b.compare(b.size() - ov, ov, a, 0, ov) == 0) {\n            if (ov > bestOv) {\n                bestOv = ov;\n                best = b + a.substr(ov);\n            }\n            break;\n        }\n    }\n\n    if (bestOv >= 0) {\n        ovOut = bestOv;\n        return best;\n    }\n\n    if ((int)a.size() + (int)b.size() <= MAXPLEN) {\n        ovOut = 0;\n        return a + b;\n    }\n\n    ovOut = -1;\n    return \"\";\n}\n\nint directedOverlap(const string& a, const string& b) {\n    int mx = min(a.size(), b.size());\n    for (int ov = mx; ov >= 1; ov--) {\n        if ((int)a.size() + (int)b.size() - ov > MAXPLEN) continue;\n        if (a.compare(a.size() - ov, ov, b, 0, ov) == 0) return ov;\n    }\n    return -1;\n}\n\nbool containsInSegment(const string& seg, const string& sub) {\n    if ((int)sub.size() > MAXPLEN) return false;\n    if ((int)seg.size() == SZ) {\n        string t = seg + seg.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    } else {\n        if (sub.size() > seg.size()) return false;\n        return seg.find(sub) != string::npos;\n    }\n}\n\nbool lineContains(const string& line, const string& sub) {\n    if (line.empty()) return false;\n    if ((int)line.size() == SZ) {\n        string t = line + line.substr(0, sub.size() - 1);\n        return t.find(sub) != string::npos;\n    }\n    if (sub.size() > line.size()) return false;\n    return line.find(sub) != string::npos;\n}\n\nvoid buildStringContainMasks() {\n    strMasks.assign(U, Mask{});\n    strContainsList.assign(U, {});\n    strContainVal.assign(U, 0);\n\n    for (int i = 0; i < U; i++) {\n        strMasks[i].fill(0);\n        for (int j = 0; j < U; j++) {\n            if (containsInSegment(uniqStr[i], uniqStr[j])) {\n                strContainsList[i].push_back(j);\n                strContainVal[i] += W[j];\n                strMasks[i][j >> 6] |= 1ULL << (j & 63);\n            }\n        }\n    }\n}\n\nstruct Segment {\n    vector<uint8_t> ch;\n    int val;\n    vector<int> contains;\n    Mask mask;\n};\n\nvector<Segment> generateSegments() {\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    unordered_set<string> seen;\n    seen.reserve(50000);\n    vector<string> cands;\n    cands.reserve(30000);\n\n    const size_t CAND_CAP = 42000;\n\n    auto addCand = [&](const string& x) {\n        if (x.size() < 2 || x.size() > MAXPLEN) return;\n        if (seen.size() >= CAND_CAP) return;\n        if (seen.insert(x).second) cands.push_back(x);\n    };\n\n    for (int id : ids) addCand(uniqStr[id]);\n\n    int minOv;\n    if (avgLen >= 8.0) minOv = 4;\n    else if (avgLen >= 6.0) minOv = 3;\n    else minOv = 2;\n\n    {\n        vector<string> segs;\n        for (int id : ids) {\n            const string& s = uniqStr[id];\n            bool contained = false;\n            int bestIdx = -1;\n            int bestOv = -1;\n            string bestMerged;\n\n            for (int i = 0; i < (int)segs.size(); i++) {\n                if (segs[i].find(s) != string::npos) {\n                    contained = true;\n                    break;\n                }\n\n                int ov;\n                string merged = mergeLinear(segs[i], s, ov);\n                if (!merged.empty() && (int)merged.size() <= MAXPLEN && ov > bestOv) {\n                    bestOv = ov;\n                    bestIdx = i;\n                    bestMerged = merged;\n                }\n            }\n\n            if (contained) continue;\n\n            if (bestIdx != -1 && bestOv >= minOv) segs[bestIdx] = bestMerged;\n            else segs.push_back(s);\n        }\n        for (auto& x : segs) addCand(x);\n    }\n\n    int pairOv;\n    if (avgLen >= 8.0) pairOv = 4;\n    else if (avgLen >= 6.0) pairOv = 3;\n    else pairOv = 2;\n\n    for (int ai = 0; ai < U && seen.size() < CAND_CAP; ai++) {\n        const string& a = uniqStr[ai];\n        for (int bi = 0; bi < U && seen.size() < CAND_CAP; bi++) {\n            if (ai == bi) continue;\n            const string& b = uniqStr[bi];\n            int ov = directedOverlap(a, b);\n            if (ov >= pairOv) {\n                string m = a + b.substr(ov);\n                addCand(m);\n            }\n        }\n    }\n\n    int seedOv = minOv;\n    int seedLimit = U;\n    for (int si = 0; si < seedLimit && seen.size() < CAND_CAP; si++) {\n        string cur = uniqStr[ids[si]];\n        addCand(cur);\n\n        for (int step = 0; step < 6 && (int)cur.size() < MAXPLEN; step++) {\n            int bestOv = seedOv - 1;\n            int bestScore = -1;\n            string bestMerged;\n\n            for (int tid : ids) {\n                const string& t = uniqStr[tid];\n                if (cur.find(t) != string::npos) continue;\n\n                int ov;\n                string merged = mergeLinear(cur, t, ov);\n                if (merged.empty() || merged == cur || (int)merged.size() > MAXPLEN) continue;\n                if (ov < seedOv) continue;\n\n                int score = ov * 10000 + W[tid] * 100 + Ls[tid] * 10 + int(rng.next() & 31);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestOv = ov;\n                    bestMerged = merged;\n                }\n            }\n\n            if (bestScore < 0 || bestOv < seedOv) break;\n            cur = bestMerged;\n            addCand(cur);\n        }\n    }\n\n    vector<Segment> res;\n    res.reserve(cands.size());\n\n    for (auto& seg : cands) {\n        int val = 0;\n        vector<int> cont;\n        for (int i = 0; i < U; i++) {\n            if (containsInSegment(seg, uniqStr[i])) {\n                val += W[i];\n                cont.push_back(i);\n            }\n        }\n\n        if (val >= 2) {\n            Segment sg;\n            sg.ch = strToVec(seg);\n            sg.val = val;\n            sg.contains = std::move(cont);\n            sg.mask.fill(0);\n            for (int sid : sg.contains) {\n                sg.mask[sid >> 6] |= 1ULL << (sid & 63);\n            }\n            res.push_back(std::move(sg));\n        }\n    }\n\n    sort(res.begin(), res.end(), [](const Segment& a, const Segment& b) {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.contains.size() != b.contains.size()) return a.contains.size() > b.contains.size();\n        return a.ch.size() > b.ch.size();\n    });\n\n    int lim = (avgLen >= 7.0 ? 440 : 540);\n    if ((int)res.size() > lim) res.resize(lim);\n    return res;\n}\n\nstruct CItem {\n    int type;\n    int idx;\n    int len;\n    int val;\n    int group;\n    uint32_t rnd;\n};\n\nconst vector<uint8_t>& getItemChars(const CItem& it, const vector<Segment>& segs) {\n    if (it.type == 0) return S[it.idx];\n    return segs[it.idx].ch;\n}\n\nvector<uint8_t> constructGreedy(int mode, const vector<Segment>& segs, Timer& timer, double endTime) {\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<CItem> items;\n\n    if (mode == 1 || mode == 2) {\n        int lim = min((int)segs.size(), avgLen >= 7.0 ? 150 : 220);\n        for (int i = 0; i < lim; i++) {\n            items.push_back({1, i, (int)segs[i].ch.size(), segs[i].val,\n                             mode == 1 ? 0 : 0, (uint32_t)rng.next()});\n        }\n    }\n\n    for (int sid = 0; sid < U; sid++) {\n        int group = (mode == 1 ? 1 : 0);\n        items.push_back({0, sid, Ls[sid], W[sid], group, (uint32_t)rng.next()});\n    }\n\n    sort(items.begin(), items.end(), [&](const CItem& a, const CItem& b) {\n        if (a.group != b.group) return a.group < b.group;\n\n        if (mode == 2) {\n            int sa = a.val * 1000 + a.len * 50 + int(a.rnd & 127);\n            int sb = b.val * 1000 + b.len * 50 + int(b.rnd & 127);\n            return sa > sb;\n        }\n\n        if (a.len != b.len) return a.len > b.len;\n        if (a.val != b.val) return a.val > b.val;\n        return a.rnd < b.rnd;\n    });\n\n    int processed = 0;\n    for (const CItem& it : items) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n\n        const auto& ch = getItemChars(it, segs);\n        int len = (int)ch.size();\n\n        int bestPos = -1;\n        int bestScore = INT_MIN;\n        bool already = false;\n\n        for (int pos = 0; pos < POS; pos++) {\n            int match = 0;\n            bool conflict = false;\n\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[pos][p];\n                int g = grid[cell];\n                if (g == DOT) continue;\n                if (g == ch[p]) match++;\n                else {\n                    conflict = true;\n                    break;\n                }\n            }\n\n            if (!conflict) {\n                if (match == len) {\n                    already = true;\n                    break;\n                }\n\n                int score = match * 10000 - (len - match) * 5 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestPos = pos;\n                }\n            }\n        }\n\n        if (already) continue;\n\n        if (bestPos != -1) {\n            for (int p = 0; p < len; p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n    }\n\n    return grid;\n}\n\nvector<uint8_t> constructRowPack(Timer& timer, double endTime) {\n    vector<string> rows(SZ, \"\");\n\n    vector<int> ids(U);\n    iota(ids.begin(), ids.end(), 0);\n    vector<uint32_t> rk(U);\n    for (int i = 0; i < U; i++) rk[i] = (uint32_t)rng.next();\n\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        if (W[a] != W[b]) return W[a] > W[b];\n        return rk[a] < rk[b];\n    });\n\n    int processed = 0;\n    for (int sid : ids) {\n        if ((processed++ & 31) == 0 && timer.elapsed() > endTime) break;\n        const string& s = uniqStr[sid];\n\n        bool covered = false;\n        for (auto& row : rows) {\n            if (lineContains(row, s)) {\n                covered = true;\n                break;\n            }\n        }\n        if (covered) continue;\n\n        int bestR = -1;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        for (int r = 0; r < SZ; r++) {\n            int ov;\n            string merged;\n            if (rows[r].empty()) {\n                ov = 0;\n                merged = s;\n            } else {\n                merged = mergeLinear(rows[r], s, ov);\n            }\n\n            if (merged.empty() || (int)merged.size() > SZ) continue;\n\n            int score = ov * 1000 + (rows[r].empty() ? 0 : 100) - (int)merged.size();\n            if (score > bestScore) {\n                bestScore = score;\n                bestR = r;\n                bestMerged = merged;\n            }\n        }\n\n        if (bestR != -1) rows[bestR] = bestMerged;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nstruct RowCand {\n    string s;\n    vector<int> contains;\n    int val;\n};\n\nvector<uint8_t> constructCoverRows(const vector<Segment>& segments, Timer& timer, double endTime) {\n    unordered_set<string> seen;\n    seen.reserve(2000);\n    vector<string> candStr;\n\n    auto add = [&](const string& s) {\n        if (s.size() < 2 || s.size() > 20) return;\n        if (seen.insert(s).second) candStr.push_back(s);\n    };\n\n    for (const auto& sg : segments) add(vecToString(sg.ch));\n    for (const auto& s : uniqStr) add(s);\n\n    vector<RowCand> cands;\n    cands.reserve(candStr.size());\n\n    for (auto& cs : candStr) {\n        int val = 0;\n        vector<int> cont;\n        for (int sid = 0; sid < U; sid++) {\n            if (containsInSegment(cs, uniqStr[sid])) {\n                val += W[sid];\n                cont.push_back(sid);\n            }\n        }\n        if (val > 0) cands.push_back({cs, std::move(cont), val});\n    }\n\n    sort(cands.begin(), cands.end(), [](const RowCand& a, const RowCand& b) {\n        if (a.val != b.val) return a.val > b.val;\n        if (a.contains.size() != b.contains.size()) return a.contains.size() > b.contains.size();\n        return a.s.size() > b.s.size();\n    });\n\n    int candLimit = avgLen <= 5.0 ? 700 : 520;\n    if ((int)cands.size() > candLimit) cands.resize(candLimit);\n\n    vector<string> rows(SZ, \"\");\n    vector<char> covered(U, 0);\n\n    int moves = 0;\n    while (timer.elapsed() < endTime && moves < 120) {\n        int bestR = -1;\n        int bestC = -1;\n        int bestGain = 0;\n        int bestScore = INT_MIN;\n        string bestMerged;\n\n        int iterCnt = 0;\n        for (int ci = 0; ci < (int)cands.size(); ci++) {\n            const auto& cd = cands[ci];\n\n            int approxGain = 0;\n            for (int sid : cd.contains) if (!covered[sid]) approxGain += W[sid];\n            if (approxGain <= 0) continue;\n\n            for (int r = 0; r < SZ; r++) {\n                if (((++iterCnt) & 4095) == 0 && timer.elapsed() > endTime) break;\n\n                if ((int)rows[r].size() == SZ) {\n                    if (lineContains(rows[r], cd.s)) continue;\n                    else continue;\n                }\n\n                int ov = 0;\n                string merged = rows[r].empty() ? cd.s : mergeLinear(rows[r], cd.s, ov);\n                if (merged.empty() || (int)merged.size() > SZ) continue;\n\n                int gain = approxGain;\n                int added = (int)merged.size() - (int)rows[r].size();\n                int score = gain * 100000 + ov * 1800 - added * 120 + int(rng.next() & 1023);\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestGain = gain;\n                    bestR = r;\n                    bestC = ci;\n                    bestMerged = merged;\n                }\n            }\n            if (timer.elapsed() > endTime) break;\n        }\n\n        if (bestR < 0 || bestGain <= 0 || bestC < 0) break;\n\n        rows[bestR] = bestMerged;\n        for (int sid = 0; sid < U; sid++) {\n            if (!covered[sid] && lineContains(rows[bestR], uniqStr[sid])) {\n                covered[sid] = 1;\n            }\n        }\n        moves++;\n    }\n\n    vector<uint8_t> grid(CELLS, DOT);\n    for (int r = 0; r < SZ; r++) {\n        for (int c = 0; c < (int)rows[r].size() && c < SZ; c++) {\n            grid[r * SZ + c] = (uint8_t)(rows[r][c] - 'A');\n        }\n    }\n    return grid;\n}\n\nvector<uint8_t> constructCoverPlace(const vector<Segment>& segments, Timer& timer, double endTime) {\n    struct PItem {\n        int type;\n        int idx;\n        int val;\n        int len;\n    };\n\n    vector<PItem> items;\n    items.reserve(U + segments.size());\n\n    int segLim = min((int)segments.size(), avgLen >= 7.0 ? 280 : 360);\n    for (int i = 0; i < segLim; i++) {\n        items.push_back({1, i, segments[i].val, (int)segments[i].ch.size()});\n    }\n    for (int sid = 0; sid < U; sid++) {\n        items.push_back({0, sid, strContainVal[sid], Ls[sid]});\n    }\n\n    auto getCh = [&](const PItem& it) -> const vector<uint8_t>& {\n        if (it.type == 0) return S[it.idx];\n        return segments[it.idx].ch;\n    };\n\n    auto getCont = [&](const PItem& it) -> const vector<int>& {\n        if (it.type == 0) return strContainsList[it.idx];\n        return segments[it.idx].contains;\n    };\n\n    vector<uint8_t> grid(CELLS, DOT);\n    vector<char> covered(U, 0);\n\n    auto pushTop = [&](vector<pair<long long,int>>& top, long long key, int idx, int lim) {\n        if ((int)top.size() < lim) {\n            top.push_back({key, idx});\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)top.size(); i++) {\n            if (top[i].first < top[wi].first) wi = i;\n        }\n        if (key > top[wi].first) top[wi] = {key, idx};\n    };\n\n    int maxMoves = avgLen <= 5.0 ? 180 : 150;\n\n    for (int step = 0; step < maxMoves && timer.elapsed() < endTime; step++) {\n        const int TOP_ITEMS = 22;\n        vector<pair<long long,int>> top;\n        top.reserve(TOP_ITEMS);\n\n        for (int ii = 0; ii < (int)items.size(); ii++) {\n            if ((ii & 63) == 0 && timer.elapsed() > endTime) break;\n            const auto& it = items[ii];\n            const auto& cont = getCont(it);\n\n            int gain = 0;\n            for (int sid : cont) if (!covered[sid]) gain += W[sid];\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL + 1LL * it.val * 120LL\n                          + 1LL * it.len * 50LL + (long long)(rng.next() & 4095);\n            pushTop(top, key, ii, TOP_ITEMS);\n        }\n\n        if (top.empty()) break;\n\n        int bestItem = -1;\n        int bestPos = -1;\n        int bestCnt = -1;\n        long long bestScore = LLONG_MIN;\n\n        for (auto [_, ii] : top) {\n            const auto& it = items[ii];\n            const auto& ch = getCh(it);\n            const auto& cont = getCont(it);\n            int len = (int)ch.size();\n\n            int gain = 0;\n            for (int sid : cont) if (!covered[sid]) gain += W[sid];\n            if (gain <= 0) continue;\n\n            for (int pos = 0; pos < POS; pos++) {\n                if ((pos & 255) == 0 && timer.elapsed() > endTime) break;\n\n                bool conflict = false;\n                int overlap = 0;\n                int cnt = 0;\n\n                for (int p = 0; p < len; p++) {\n                    int cell = posCell[pos][p];\n                    int g = grid[cell];\n                    if (g == DOT) {\n                        cnt++;\n                    } else if (g == ch[p]) {\n                        overlap++;\n                    } else {\n                        conflict = true;\n                        break;\n                    }\n                }\n\n                if (conflict) continue;\n\n                long long score = 1LL * gain * 1000000LL\n                                + 1LL * overlap * 5000LL\n                                - 1LL * cnt * 250LL\n                                + 1LL * it.len * 20LL\n                                + (long long)(rng.next() & 1023);\n\n                if (score > bestScore) {\n                    bestScore = score;\n                    bestItem = ii;\n                    bestPos = pos;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestItem < 0) break;\n\n        const auto& it = items[bestItem];\n        const auto& ch = getCh(it);\n        const auto& cont = getCont(it);\n\n        if (bestCnt > 0) {\n            for (int p = 0; p < (int)ch.size(); p++) {\n                int cell = posCell[bestPos][p];\n                if (grid[cell] == DOT) grid[cell] = ch[p];\n            }\n        }\n\n        for (int sid : cont) covered[sid] = 1;\n    }\n\n    return grid;\n}\n\nint makePlacementChanges(const State& st, int sid, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    const auto& str = S[sid];\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = str[p];\n        if (st.grid[cell] != ch) {\n            cells[cnt] = cell;\n            vals[cnt] = ch;\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nint makeSequenceChanges(const State& st, const vector<uint8_t>& ch, int pos, int cells[], uint8_t vals[]) {\n    int cnt = 0;\n    int len = (int)ch.size();\n    for (int p = 0; p < len; p++) {\n        int cell = posCell[pos][p];\n        if (st.grid[cell] != ch[p]) {\n            cells[cnt] = cell;\n            vals[cnt] = ch[p];\n            cnt++;\n        }\n    }\n    return cnt;\n}\n\nbool tryInsert(State& st, int sid, int K, int maxChange, bool allowZero, double temp, int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    const int MAXK = 12;\n    K = min(K, MAXK);\n\n    int candPos[MAXK];\n    uint32_t candKey[MAXK];\n    int candN = 0;\n\n    auto updateWorst = [&]() {\n        int wi = 0;\n        for (int i = 1; i < candN; i++) {\n            if (candKey[i] > candKey[wi]) wi = i;\n        }\n        return wi;\n    };\n\n    int base = sid * POS;\n\n    for (int pos = 0; pos < POS; pos++) {\n        int m = st.mism[base + pos];\n        if (m == 0) return false;\n        if (m > maxChange) continue;\n\n        uint32_t key = (uint32_t(m) << 20) | uint32_t(rng.next() & ((1u << 20) - 1));\n        if (candN < K) {\n            candPos[candN] = pos;\n            candKey[candN] = key;\n            candN++;\n        } else {\n            int wi = updateWorst();\n            if (key < candKey[wi]) {\n                candPos[wi] = pos;\n                candKey[wi] = key;\n            }\n        }\n    }\n\n    if (candN == 0) return false;\n\n    int bestD = INT_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (int i = 0; i < candN; i++) {\n        int cnt = makePlacementChanges(st, sid, candPos[i], tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 30) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nvoid shuffleVec(vector<int>& v) {\n    for (int i = (int)v.size() - 1; i > 0; i--) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nint softCellSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    static const long long EXACT_BONUS = 3000000LL;\n\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int exactImpTotal = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int changes = 0;\n        int exactImp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            long long bestScore = 0;\n            int bestCh = old;\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                long long sc = st.evalChangesSoft(oneCell, oneVal, 1, EXACT_BONUS);\n                if (sc > bestScore || (sc == bestScore && sc > 0 && rng.randint(2) == 0)) {\n                    bestScore = sc;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestScore > 0) {\n                int before = st.obj;\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                exactImp += st.obj - before;\n                changes++;\n                if (st.obj >= best.obj) best.consider(st);\n                if (st.obj == TOTAL) return exactImpTotal + exactImp;\n            }\n        }\n\n        exactImpTotal += exactImp;\n        if (changes == 0) break;\n    }\n\n    best.consider(st);\n    return exactImpTotal;\n}\n\ninline int maskWeight(const Mask& m) {\n    int sum = 0;\n    for (int w = 0; w < MASK_WORDS; w++) {\n        uint64_t x = m[w];\n        while (x) {\n            int b = __builtin_ctzll(x);\n            int id = w * 64 + b;\n            if (id < U) sum += W[id];\n            x &= x - 1;\n        }\n    }\n    return sum;\n}\n\nvoid buildLossMasks(const State& st, vector<Mask>& masks) {\n    for (auto& m : masks) m.fill(0);\n\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] != 1) continue;\n\n        int base = sid * POS;\n        int exactPos = -1;\n        for (int pos = 0; pos < POS; pos++) {\n            if (st.mism[base + pos] == 0) {\n                exactPos = pos;\n                break;\n            }\n        }\n        if (exactPos < 0) continue;\n\n        int word = sid >> 6;\n        uint64_t bit = 1ULL << (sid & 63);\n\n        for (int p = 0; p < Ls[sid]; p++) {\n            int cell = posCell[exactPos][p];\n            masks[cell][word] |= bit;\n        }\n    }\n}\n\nint approxPlacementLoss(const State& st, const vector<Mask>& masks, int sid, int pos,\n                        int& cnt, const Mask* excludeMask = nullptr) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    for (int p = 0; p < Ls[sid]; p++) {\n        int cell = posCell[pos][p];\n        uint8_t ch = S[sid][p];\n        if (st.grid[cell] == ch) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    if (excludeMask) {\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] &= ~((*excludeMask)[w]);\n    } else {\n        tmp[sid >> 6] &= ~(1ULL << (sid & 63));\n    }\n\n    return maskWeight(tmp);\n}\n\nint approxSequenceLoss(const State& st, const vector<Mask>& masks, const vector<uint8_t>& ch,\n                       int pos, int& cnt, const Mask* excludeMask = nullptr) {\n    Mask tmp;\n    tmp.fill(0);\n    cnt = 0;\n\n    int len = (int)ch.size();\n    for (int p = 0; p < len; p++) {\n        int cell = posCell[pos][p];\n        if (st.grid[cell] == ch[p]) continue;\n\n        cnt++;\n        const Mask& lm = masks[cell];\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] |= lm[w];\n    }\n\n    if (excludeMask) {\n        for (int w = 0; w < MASK_WORDS; w++) tmp[w] &= ~((*excludeMask)[w]);\n    }\n\n    return maskWeight(tmp);\n}\n\nbool tryInsertConflict(State& st, int sid, const vector<Mask>& masks,\n                       int kLoss, int kMis, bool allowZero, double temp,\n                       int& appliedDelta) {\n    appliedDelta = 0;\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt, &strMasks[sid]);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 250 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 1200LL - 1LL * c.cnt * 30LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 45) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nbool tryPlaceSequenceConflict(State& st, const vector<uint8_t>& ch, const vector<Mask>& masks,\n                              int kLoss, int kMis, bool allowZero, double temp,\n                              int& appliedDelta, const Mask* excludeMask = nullptr) {\n    appliedDelta = 0;\n\n    struct Cand {\n        int pos;\n        int loss;\n        int cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n    topLoss.reserve(kLoss + 1);\n    topMis.reserve(kMis + 1);\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) {\n            if (v[i].key > v[wi].key) wi = i;\n        }\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxSequenceLoss(st, masks, ch, pos, cnt, excludeMask);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 180 + (long long)(rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 45 + (long long)(rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    cand.reserve(topLoss.size() + topMis.size());\n\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) {\n            if (x.pos == c.pos) return;\n        }\n        cand.push_back(c);\n    };\n\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    if (cand.empty()) return false;\n\n    int bestD = INT_MIN;\n    long long bestScore = LLONG_MIN;\n    int bestCnt = 0;\n    int bestCells[25];\n    uint8_t bestVals[25];\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makeSequenceChanges(st, ch, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 700LL - 1LL * c.cnt * 20LL\n                        + (long long)(rng.next() & 1023);\n\n        if (score > bestScore) {\n            bestScore = score;\n            bestD = d;\n            bestCnt = cnt;\n            for (int j = 0; j < cnt; j++) {\n                bestCells[j] = tmpCells[j];\n                bestVals[j] = tmpVals[j];\n            }\n        }\n    }\n\n    if (bestD == INT_MIN) return false;\n\n    bool accept = false;\n    if (bestD > 0) accept = true;\n    else if (bestD == 0 && allowZero && rng.randint(100) < 35) accept = true;\n    else if (bestD < 0 && temp > 1e-9) {\n        double p = exp((double)bestD / temp);\n        if (rng.drand() < p) accept = true;\n    }\n\n    if (!accept) return false;\n\n    st.applyChanges(bestCells, bestVals, bestCnt);\n    appliedDelta = bestD;\n    return true;\n}\n\nstruct SmallMove {\n    int d = INT_MIN;\n    long long score = LLONG_MIN;\n    int cnt = 0;\n    array<int, 25> cells;\n    array<uint8_t, 25> vals;\n};\n\nbool findBestInsertConflictMove(State& st, int sid, const vector<Mask>& masks,\n                                int kLoss, int kMis, SmallMove& mv) {\n    mv = SmallMove();\n    if (st.cover[sid] > 0) return false;\n\n    struct Cand {\n        int pos, loss, cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) if (v[i].key > v[wi].key) wi = i;\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxPlacementLoss(st, masks, sid, pos, cnt, &strMasks[sid]);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 220 + (rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 50 + (rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) if (x.pos == c.pos) return;\n        cand.push_back(c);\n    };\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makePlacementChanges(st, sid, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 700LL - 1LL * c.cnt * 20LL\n                        + (rng.next() & 1023);\n\n        if (d > mv.d || (d == mv.d && score > mv.score)) {\n            mv.d = d;\n            mv.score = score;\n            mv.cnt = cnt;\n            for (int i = 0; i < cnt; i++) {\n                mv.cells[i] = tmpCells[i];\n                mv.vals[i] = tmpVals[i];\n            }\n        }\n    }\n\n    return mv.d != INT_MIN;\n}\n\nbool findBestSequenceConflictMove(State& st, const vector<uint8_t>& ch, const vector<Mask>& masks,\n                                  int kLoss, int kMis, SmallMove& mv,\n                                  const Mask* excludeMask = nullptr) {\n    mv = SmallMove();\n\n    struct Cand {\n        int pos, loss, cnt;\n        long long key;\n    };\n\n    vector<Cand> topLoss, topMis;\n\n    auto pushTop = [&](vector<Cand>& v, int lim, Cand c) {\n        if (lim <= 0) return;\n        if ((int)v.size() < lim) {\n            v.push_back(c);\n            return;\n        }\n        int wi = 0;\n        for (int i = 1; i < (int)v.size(); i++) if (v[i].key > v[wi].key) wi = i;\n        if (c.key < v[wi].key) v[wi] = c;\n    };\n\n    for (int pos = 0; pos < POS; pos++) {\n        int cnt;\n        int loss = approxSequenceLoss(st, masks, ch, pos, cnt, excludeMask);\n        if (cnt == 0) return false;\n\n        long long keyLoss = 1LL * loss * 100000 + 1LL * cnt * 150 + (rng.next() & 255);\n        long long keyMis = 1LL * cnt * 100000 + 1LL * loss * 40 + (rng.next() & 255);\n\n        pushTop(topLoss, kLoss, {pos, loss, cnt, keyLoss});\n        pushTop(topMis, kMis, {pos, loss, cnt, keyMis});\n    }\n\n    vector<Cand> cand;\n    auto addUnique = [&](const Cand& c) {\n        for (auto& x : cand) if (x.pos == c.pos) return;\n        cand.push_back(c);\n    };\n    for (auto& c : topLoss) addUnique(c);\n    for (auto& c : topMis) addUnique(c);\n\n    int tmpCells[25];\n    uint8_t tmpVals[25];\n\n    for (const Cand& c : cand) {\n        int cnt = makeSequenceChanges(st, ch, c.pos, tmpCells, tmpVals);\n        if (cnt == 0) continue;\n\n        int d = st.evalChanges(tmpCells, tmpVals, cnt);\n        long long score = 1LL * d * 1000000LL - 1LL * c.loss * 450LL - 1LL * c.cnt * 15LL\n                        + (rng.next() & 1023);\n\n        if (d > mv.d || (d == mv.d && score > mv.score)) {\n            mv.d = d;\n            mv.score = score;\n            mv.cnt = cnt;\n            for (int i = 0; i < cnt; i++) {\n                mv.cells[i] = tmpCells[i];\n                mv.vals[i] = tmpVals[i];\n            }\n        }\n    }\n\n    return mv.d != INT_MIN;\n}\n\nvoid greedyImproveConflict(State& st, Timer& timer, double endTime, Best& best,\n                           int maxIter, int sampleLimit) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n\n    for (int it = 0; it < maxIter && timer.elapsed() < endTime && st.obj < TOTAL; it++) {\n        buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) if (st.cover[sid] == 0) unc.push_back(sid);\n        if (unc.empty()) break;\n\n        vector<pair<int,int>> order;\n        order.reserve(unc.size());\n\n        for (int sid : unc) {\n            int minM = 13;\n            for (int m = 0; m <= Ls[sid]; m++) {\n                if (st.hist[sid][m] > 0) {\n                    minM = m;\n                    break;\n                }\n            }\n            int key = W[sid] * 200 + Ls[sid] * 80 - minM * 70 + rng.randint(200);\n            order.push_back({-key, sid});\n        }\n\n        sort(order.begin(), order.end());\n        if ((int)order.size() > sampleLimit) order.resize(sampleLimit);\n\n        SmallMove bestMv;\n        int checked = 0;\n\n        for (auto [_, sid] : order) {\n            if (((++checked) & 15) == 0 && timer.elapsed() > endTime) break;\n\n            SmallMove mv;\n            if (!findBestInsertConflictMove(st, sid, masks, 5, 3, mv)) continue;\n\n            if (mv.d > bestMv.d || (mv.d == bestMv.d && mv.score > bestMv.score)) {\n                bestMv = mv;\n            }\n        }\n\n        if (bestMv.d <= 0 || bestMv.d == INT_MIN) break;\n\n        st.applyChanges(bestMv.cells.data(), bestMv.vals.data(), bestMv.cnt);\n        best.consider(st);\n    }\n}\n\nvoid greedyImproveSegments(State& st, Timer& timer, double endTime, Best& best,\n                           const vector<Segment>& segments, int maxIter, int segSample) {\n    if (segments.empty() || st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n\n    for (int it = 0; it < maxIter && timer.elapsed() < endTime && st.obj < TOTAL; it++) {\n        buildLossMasks(st, masks);\n\n        struct Pick {\n            long long key;\n            int idx;\n        };\n\n        vector<Pick> picks;\n        picks.reserve(segments.size());\n\n        for (int i = 0; i < (int)segments.size(); i++) {\n            int gain = 0;\n            for (int sid : segments[i].contains) {\n                if (st.cover[sid] == 0) gain += W[sid];\n            }\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL + 1LL * segments[i].val * 100LL\n                          + 1LL * (int)segments[i].ch.size() * 30LL + (rng.next() & 4095);\n            picks.push_back({key, i});\n        }\n\n        if (picks.empty()) break;\n\n        sort(picks.begin(), picks.end(), [](const Pick& a, const Pick& b) {\n            return a.key > b.key;\n        });\n\n        if ((int)picks.size() > segSample) picks.resize(segSample);\n\n        SmallMove bestMv;\n\n        for (auto& p : picks) {\n            if (timer.elapsed() > endTime) break;\n\n            const Segment& sg = segments[p.idx];\n            SmallMove mv;\n            if (!findBestSequenceConflictMove(st, sg.ch, masks, 5, 3, mv, &sg.mask)) continue;\n\n            if (mv.d > bestMv.d || (mv.d == bestMv.d && mv.score > bestMv.score)) {\n                bestMv = mv;\n            }\n        }\n\n        if (bestMv.d <= 0 || bestMv.d == INT_MIN) break;\n\n        st.applyChanges(bestMv.cells.data(), bestMv.vals.data(), bestMv.cnt);\n        best.consider(st);\n    }\n}\n\nvoid conflictSearch(State& st, Timer& timer, double endTime, Best& best) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 5 == 0) buildLossMasks(st, masks);\n\n        vector<int> unc;\n        unc.reserve(U);\n        for (int sid = 0; sid < U; sid++) {\n            if (st.cover[sid] == 0) unc.push_back(sid);\n        }\n        if (unc.empty()) break;\n\n        int sid = unc[rng.randint((int)unc.size())];\n\n        int samples = min(26, (int)unc.size());\n        int bestKey = -1;\n        for (int t = 0; t < samples; t++) {\n            int x = unc[rng.randint((int)unc.size())];\n\n            int minM = 13;\n            const auto& hh = st.hist[x];\n            for (int m = 0; m <= Ls[x]; m++) {\n                if (hh[m] > 0) {\n                    minM = m;\n                    break;\n                }\n            }\n\n            int key = Ls[x] * 100 + W[x] * 35 - minM * 30 + rng.randint(120);\n            if (key > bestKey) {\n                bestKey = key;\n                sid = x;\n            }\n        }\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.12 + 1.15 * frac;\n\n        int d;\n        bool ok = tryInsertConflict(st, sid, masks, 9, 5, true, temp, d);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 8);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 150) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n                iter = 0;\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nvoid segmentSearch(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    if (segments.empty() || st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int noProgress = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && st.obj < TOTAL) {\n        if (iter % 4 == 0) buildLossMasks(st, masks);\n\n        struct Pick {\n            long long key;\n            int idx;\n            int gain;\n        };\n\n        vector<Pick> top;\n        top.reserve(10);\n\n        auto pushPick = [&](Pick p) {\n            if ((int)top.size() < 10) {\n                top.push_back(p);\n                return;\n            }\n            int wi = 0;\n            for (int i = 1; i < (int)top.size(); i++) {\n                if (top[i].key < top[wi].key) wi = i;\n            }\n            if (p.key > top[wi].key) top[wi] = p;\n        };\n\n        for (int i = 0; i < (int)segments.size(); i++) {\n            int gain = 0;\n            for (int sid : segments[i].contains) {\n                if (st.cover[sid] == 0) gain += W[sid];\n            }\n            if (gain <= 0) continue;\n\n            long long key = 1LL * gain * 100000LL\n                          + 1LL * segments[i].val * 120LL\n                          + 1LL * (int)segments[i].ch.size() * 30LL\n                          + (long long)(rng.next() & 4095);\n            pushPick({key, i, gain});\n        }\n\n        if (top.empty()) break;\n\n        int chooseLim = min(5, (int)top.size());\n        nth_element(top.begin(), top.begin() + chooseLim - 1, top.end(),\n                    [](const Pick& a, const Pick& b) { return a.key > b.key; });\n        int idx = top[rng.randint(chooseLim)].idx;\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n        double temp = 0.10 + 1.05 * frac;\n\n        int d;\n        bool ok = tryPlaceSequenceConflict(st, segments[idx].ch, masks, 11, 6, true, temp, d,\n                                           &segments[idx].mask);\n\n        iter++;\n\n        if (ok) {\n            best.consider(st);\n\n            if (st.obj > localBestObj) {\n                localBestObj = st.obj;\n                localBestGrid = st.grid;\n                noProgress = 0;\n            } else if (d > 0) {\n                noProgress = max(0, noProgress - 10);\n            } else {\n                noProgress++;\n            }\n\n            if (st.obj == TOTAL) break;\n\n            if (st.obj < localBestObj - 14) {\n                st.build(localBestGrid);\n                noProgress = 0;\n            }\n        } else {\n            noProgress++;\n        }\n\n        if (noProgress > 80) {\n            if (st.obj < localBestObj) {\n                st.build(localBestGrid);\n            }\n            noProgress = 0;\n        }\n    }\n\n    best.consider(st);\n}\n\nvoid forceWalk(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    if (st.obj == TOTAL) return;\n\n    vector<Mask> masks(CELLS);\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    int iter = 0;\n    int stagnant = 0;\n    double start = timer.elapsed();\n\n    while (timer.elapsed() < endTime && localBestObj < TOTAL) {\n        if (iter % 4 == 0) buildLossMasks(st, masks);\n\n        SmallMove mv;\n        bool found = false;\n\n        bool useSeg = (avgLen >= 5.2 && !segments.empty() && rng.randint(100) < 35);\n\n        if (useSeg) {\n            int bestIdx = -1;\n            long long bestKey = LLONG_MIN;\n\n            int trials = min(90, max(1, (int)segments.size()));\n            for (int t = 0; t < trials; t++) {\n                int idx;\n                if (t < 35 && t < (int)segments.size()) idx = t;\n                else idx = rng.randint((int)segments.size());\n\n                int gain = 0;\n                for (int sid : segments[idx].contains) {\n                    if (st.cover[sid] == 0) gain += W[sid];\n                }\n                if (gain <= 0) continue;\n\n                long long key = 1LL * gain * 100000LL + 1LL * segments[idx].val * 80LL\n                              + 1LL * (int)segments[idx].ch.size() * 30LL + (rng.next() & 4095);\n                if (key > bestKey) {\n                    bestKey = key;\n                    bestIdx = idx;\n                }\n            }\n\n            if (bestIdx >= 0) {\n                found = findBestSequenceConflictMove(st, segments[bestIdx].ch, masks, 8, 5, mv,\n                                                     &segments[bestIdx].mask);\n            }\n        }\n\n        if (!found) {\n            vector<int> unc;\n            unc.reserve(U);\n            for (int sid = 0; sid < U; sid++) if (st.cover[sid] == 0) unc.push_back(sid);\n            if (unc.empty()) break;\n\n            int sid = unc[rng.randint((int)unc.size())];\n            int samples = min(30, (int)unc.size());\n            int bestKey = INT_MIN;\n\n            for (int t = 0; t < samples; t++) {\n                int x = unc[rng.randint((int)unc.size())];\n                int minM = 13;\n                for (int m = 0; m <= Ls[x]; m++) {\n                    if (st.hist[x][m] > 0) {\n                        minM = m;\n                        break;\n                    }\n                }\n                int key = W[x] * 180 + Ls[x] * 90 - minM * 65 + rng.randint(160);\n                if (key > bestKey) {\n                    bestKey = key;\n                    sid = x;\n                }\n            }\n\n            found = findBestInsertConflictMove(st, sid, masks, 8, 5, mv);\n        }\n\n        iter++;\n\n        if (!found || mv.d == INT_MIN) {\n            stagnant++;\n            if (stagnant > 50 && st.obj < localBestObj) {\n                st.build(localBestGrid);\n                stagnant = 0;\n            }\n            continue;\n        }\n\n        double now = timer.elapsed();\n        double denom = max(1e-9, endTime - start);\n        double frac = max(0.0, (endTime - now) / denom);\n\n        int tolerance = 10 + (TOTAL - localBestObj) / 7 + (int)(18 * frac);\n        tolerance = min(tolerance, 55);\n        int maxNeg = 3 + (int)(12 * frac);\n\n        bool accept = false;\n        if (mv.d >= 0) accept = true;\n        else if (mv.d >= -maxNeg) accept = true;\n        else if (st.obj + mv.d >= localBestObj - tolerance) accept = true;\n        else if (rng.randint(100) < 3) accept = true;\n\n        if (!accept) {\n            stagnant++;\n            if (stagnant > 80 && st.obj < localBestObj) {\n                st.build(localBestGrid);\n                stagnant = 0;\n            }\n            continue;\n        }\n\n        st.applyChanges(mv.cells.data(), mv.vals.data(), mv.cnt);\n        best.consider(st);\n\n        if (st.obj > localBestObj) {\n            localBestObj = st.obj;\n            localBestGrid = st.grid;\n            stagnant = 0;\n            if (st.obj == TOTAL) break;\n        } else {\n            stagnant++;\n        }\n\n        if (st.obj < localBestObj - tolerance || stagnant > 120) {\n            st.build(localBestGrid);\n            stagnant = 0;\n        }\n    }\n\n    st.build(localBestGrid);\n    best.consider(st);\n}\n\nint repairPass(State& st, Timer& timer, double endTime, int K, int maxChange,\n               bool allowZero, double temp, Best& best) {\n    vector<int> ids;\n    ids.reserve(U);\n    for (int sid = 0; sid < U; sid++) {\n        if (st.cover[sid] == 0) ids.push_back(sid);\n    }\n    if (ids.empty()) return 0;\n\n    shuffleVec(ids);\n    stable_sort(ids.begin(), ids.end(), [](int a, int b) {\n        if (Ls[a] != Ls[b]) return Ls[a] > Ls[b];\n        return W[a] > W[b];\n    });\n\n    int before = st.obj;\n    int applied = 0;\n\n    for (int sid : ids) {\n        if (timer.elapsed() > endTime) break;\n        if (st.cover[sid] > 0) continue;\n\n        int d;\n        if (tryInsert(st, sid, K, maxChange, allowZero, temp, d)) {\n            applied++;\n            if (d > 0 || st.obj == TOTAL) best.consider(st);\n            if (st.obj == TOTAL) break;\n        }\n    }\n\n    best.consider(st);\n    return st.obj - before + applied / 1000000;\n}\n\nvoid fillDots(State& st, Timer& timer, double endTime, Best& best) {\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] != DOT) continue;\n\n        int bestD = INT_MIN;\n        int bestCh = 0;\n        oneCell[0] = cell;\n\n        for (int ch = 0; ch < 8; ch++) {\n            oneVal[0] = (uint8_t)ch;\n            int d = st.evalChanges(oneCell, oneVal, 1);\n            if (d > bestD || (d == bestD && rng.randint(2) == 0)) {\n                bestD = d;\n                bestCh = ch;\n            }\n        }\n\n        oneVal[0] = (uint8_t)bestCh;\n        st.applyChanges(oneCell, oneVal, 1);\n        best.consider(st);\n\n        if (st.obj == TOTAL) return;\n    }\n\n    best.consider(st);\n}\n\nint cellHillSweep(State& st, Timer& timer, double endTime, Best& best, int maxSweeps) {\n    vector<int> cells(CELLS);\n    iota(cells.begin(), cells.end(), 0);\n\n    int totalImp = 0;\n    int oneCell[1];\n    uint8_t oneVal[1];\n\n    for (int sw = 0; sw < maxSweeps; sw++) {\n        shuffleVec(cells);\n        int imp = 0;\n\n        for (int cell : cells) {\n            if (timer.elapsed() > endTime) break;\n\n            int old = st.grid[cell];\n            int bestD = 0;\n            int bestCh = old;\n\n            oneCell[0] = cell;\n\n            for (int ch = 0; ch < 8; ch++) {\n                if (ch == old) continue;\n                oneVal[0] = (uint8_t)ch;\n                int d = st.evalChanges(oneCell, oneVal, 1);\n                if (d > bestD || (d == bestD && d > 0 && rng.randint(2) == 0)) {\n                    bestD = d;\n                    bestCh = ch;\n                }\n            }\n\n            if (bestCh != old && bestD > 0) {\n                oneVal[0] = (uint8_t)bestCh;\n                st.applyChanges(oneCell, oneVal, 1);\n                imp += bestD;\n                best.consider(st);\n                if (st.obj == TOTAL) return totalImp + imp;\n            }\n        }\n\n        totalImp += imp;\n        if (imp == 0) break;\n    }\n\n    best.consider(st);\n    return totalImp;\n}\n\nvoid voteRefineOne(State& st, Timer& timer, double endTime, Best& best, int iters, bool weighted) {\n    vector<uint8_t> localBestGrid = st.grid;\n    int localBestObj = st.obj;\n\n    static int votes[CELLS][8];\n\n    for (int it = 0; it < iters && timer.elapsed() < endTime; it++) {\n        memset(votes, 0, sizeof(votes));\n\n        for (int cell = 0; cell < CELLS; cell++) {\n            int old = st.grid[cell];\n            if (0 <= old && old < 8) votes[cell][old] += 1;\n        }\n\n        for (int sid = 0; sid < U; sid++) {\n            if ((sid & 31) == 0 && timer.elapsed() > endTime) break;\n\n            int base = sid * POS;\n            int bestM = 100;\n            int bestPos = 0;\n            int seen = 0;\n\n            for (int pos = 0; pos < POS; pos++) {\n                int m = st.mism[base + pos];\n                if (m < bestM) {\n                    bestM = m;\n                    bestPos = pos;\n                    seen = 1;\n                } else if (m == bestM) {\n                    seen++;\n                    if (rng.randint(seen) == 0) bestPos = pos;\n                }\n            }\n\n            int wt = W[sid];\n            if (weighted) wt *= max(1, Ls[sid] - bestM);\n\n            for (int p = 0; p < Ls[sid]; p++) {\n                int cell = posCell[bestPos][p];\n                votes[cell][S[sid][p]] += wt;\n            }\n        }\n\n        vector<uint8_t> ng = st.grid;\n\n        for (int cell = 0; cell < CELLS; cell++) {\n            int bestCh = ng[cell];\n            int bestV = -1;\n            for (int ch = 0; ch < 8; ch++) {\n                int v = votes[cell][ch];\n                if (v > bestV || (v == bestV && rng.randint(2) == 0)) {\n                    bestV = v;\n                    bestCh = ch;\n                }\n            }\n            if (bestV > 0) ng[cell] = (uint8_t)bestCh;\n        }\n\n        st.build(ng);\n        best.consider(st);\n\n        if (st.obj > localBestObj) {\n            localBestObj = st.obj;\n            localBestGrid = st.grid;\n        }\n    }\n\n    st.build(localBestGrid);\n    best.consider(st);\n}\n\nvoid voteRefine(State& st, Timer& timer, double endTime, Best& best, int iters) {\n    if (iters < 2) {\n        voteRefineOne(st, timer, endTime, best, iters, false);\n        return;\n    }\n\n    vector<uint8_t> baseGrid = st.grid;\n    int baseObj = st.obj;\n\n    double now = timer.elapsed();\n    double mid = now + max(0.0, endTime - now) * 0.5;\n\n    voteRefineOne(st, timer, mid, best, 1, false);\n    vector<uint8_t> simpleGrid = st.grid;\n    int simpleObj = st.obj;\n\n    st.build(baseGrid);\n\n    voteRefineOne(st, timer, endTime, best, 1, true);\n    vector<uint8_t> weightedGrid = st.grid;\n    int weightedObj = st.obj;\n\n    if (simpleObj > weightedObj || (simpleObj == weightedObj && rng.randint(2) == 0)) {\n        st.build(simpleGrid);\n    } else {\n        st.build(weightedGrid);\n    }\n\n    if (st.obj < baseObj) st.build(baseGrid);\n    best.consider(st);\n}\n\nbool hasDots(const vector<uint8_t>& g) {\n    for (auto x : g) if (x == DOT) return true;\n    return false;\n}\n\nvoid localSearch(State& st, Timer& timer, double endTime, Best& best, const vector<Segment>& segments) {\n    best.consider(st);\n    if (st.obj == TOTAL) return;\n\n    int maxChFull = (avgLen >= 8.0 ? 5 : 6);\n\n    if (hasDots(st.grid)) {\n        for (int pass = 0; pass < 2 && timer.elapsed() < endTime; pass++) {\n            int before = st.obj;\n            repairPass(st, timer, endTime, 3, maxLenInput, false, -1.0, best);\n            if (st.obj == TOTAL) return;\n            if (st.obj == before) break;\n        }\n    }\n\n    if (st.obj == TOTAL) return;\n\n    if (hasDots(st.grid)) {\n        fillDots(st, timer, endTime, best);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (avgLen >= 5.5 && timer.elapsed() + 0.07 < endTime) {\n        double vtEnd = min(endTime, timer.elapsed() + 0.10);\n        voteRefine(st, timer, vtEnd, best, 2);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() + 0.05 < endTime && st.obj < TOTAL) {\n        softCellSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n    }\n\n    for (int cyc = 0; cyc < 2 && timer.elapsed() < endTime; cyc++) {\n        int before = st.obj;\n        repairPass(st, timer, endTime, 5, maxChFull, false, -1.0, best);\n        if (st.obj == TOTAL) return;\n\n        cellHillSweep(st, timer, endTime, best, 1);\n        if (st.obj == TOTAL) return;\n\n        if (st.obj <= before && cyc > 0) break;\n    }\n\n    if (timer.elapsed() + 0.06 < endTime && st.obj < TOTAL) {\n        greedyImproveConflict(st, timer, min(endTime, timer.elapsed() + 0.12), best, 4, 80);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (avgLen >= 5.5 && timer.elapsed() + 0.10 < endTime && st.obj < TOTAL) {\n        greedyImproveSegments(st, timer, min(endTime, timer.elapsed() + 0.10), best, segments, 2, 7);\n        if (st.obj == TOTAL) return;\n\n        double rem = endTime - timer.elapsed();\n        double segEnd = min(endTime, timer.elapsed() + rem * 0.42);\n        segmentSearch(st, timer, segEnd, best, segments);\n        if (st.obj == TOTAL) return;\n    }\n\n    if (timer.elapsed() < endTime && st.obj < TOTAL) {\n        conflictSearch(st, timer, endTime, best);\n    }\n\n    best.consider(st);\n}\n\nvoid dotMaximize(Best& best, State& st, Timer& timer, double endTime) {\n    if (best.obj < TOTAL) return;\n\n    st.build(best.grid);\n    if (st.obj < TOTAL) return;\n\n    vector<pair<int,int>> order;\n    order.reserve(CELLS);\n\n    for (int cell = 0; cell < CELLS; cell++) {\n        if (st.grid[cell] == DOT) continue;\n\n        int impact = 0;\n        for (uint32_t code : cellIncs[cell]) {\n            int pid = int(code >> 3);\n            int req = int(code & 7);\n            if (st.grid[cell] == req && st.mism[pid] == 0) {\n                int sid = pid / POS;\n                impact += (st.cover[sid] <= 1 ? 1000 * W[sid] : 1);\n            }\n        }\n        impact = impact * 1024 + rng.randint(1024);\n        order.push_back({impact, cell});\n    }\n\n    sort(order.begin(), order.end());\n\n    int oneCell[1];\n    uint8_t oneVal[1] = {(uint8_t)DOT};\n\n    for (auto [_, cell] : order) {\n        if (timer.elapsed() > endTime) break;\n        if (st.grid[cell] == DOT) continue;\n\n        oneCell[0] = cell;\n        int d = st.evalChanges(oneCell, oneVal, 1);\n        if (st.obj + d == TOTAL) {\n            st.applyChanges(oneCell, oneVal, 1);\n        }\n    }\n\n    best.consider(st);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int Nin;\n    cin >> Nin >> M_input;\n\n    vector<string> input(M_input);\n    uint64_t h = 1469598103934665603ULL;\n\n    unordered_map<string, int> mp;\n    mp.reserve(M_input * 2);\n\n    int totalLen = 0;\n    for (int i = 0; i < M_input; i++) {\n        cin >> input[i];\n        mp[input[i]]++;\n        totalLen += (int)input[i].size();\n        maxLenInput = max(maxLenInput, (int)input[i].size());\n        for (char c : input[i]) {\n            h ^= (uint64_t)c;\n            h *= 1099511628211ULL;\n        }\n    }\n\n    rng = XorShift(88172645463325252ULL ^ h);\n\n    vector<pair<string,int>> pairs;\n    pairs.reserve(mp.size());\n    for (auto& kv : mp) pairs.push_back(kv);\n    sort(pairs.begin(), pairs.end());\n\n    U = (int)pairs.size();\n    TOTAL = M_input;\n    avgLen = (double)totalLen / M_input;\n\n    uniqStr.reserve(U);\n    S.reserve(U);\n    Ls.reserve(U);\n    W.reserve(U);\n\n    for (auto& kv : pairs) {\n        uniqStr.push_back(kv.first);\n        S.push_back(strToVec(kv.first));\n        Ls.push_back((int)kv.first.size());\n        W.push_back(kv.second);\n    }\n\n    Timer timer;\n\n    initNearVal();\n    initPosCells();\n    buildIncidences();\n    buildStringContainMasks();\n\n    vector<Segment> segments = generateSegments();\n\n    State st;\n    st.init();\n\n    Best best;\n\n    vector<int> modes;\n    if (avgLen <= 5.2) {\n        modes = {5, 4, 0, 1};\n    } else if (avgLen <= 6.2) {\n        modes = {5, 1, 4, 0};\n    } else {\n        modes = {1, 5, 0, 3};\n    }\n\n    const double SEARCH_END = 2.62;\n    const double FINAL_END = 2.90;\n\n    for (int r = 0; r < (int)modes.size() && timer.elapsed() < SEARCH_END; r++) {\n        int mode = modes[r];\n        vector<uint8_t> grid;\n\n        double cEnd = SEARCH_END;\n        if (mode == 4) cEnd = min(SEARCH_END, timer.elapsed() + (avgLen <= 5.2 ? 0.23 : 0.17));\n        else if (mode == 5) cEnd = min(SEARCH_END, timer.elapsed() + (avgLen <= 5.2 ? 0.23 : 0.19));\n        else if (mode == 3) cEnd = min(SEARCH_END, timer.elapsed() + 0.08);\n\n        if (mode == 3) {\n            grid = constructRowPack(timer, cEnd);\n        } else if (mode == 4) {\n            grid = constructCoverRows(segments, timer, cEnd);\n        } else if (mode == 5) {\n            grid = constructCoverPlace(segments, timer, cEnd);\n        } else {\n            grid = constructGreedy(mode, segments, timer, cEnd);\n        }\n\n        st.build(grid);\n\n        double rem = SEARCH_END - timer.elapsed();\n        int left = (int)modes.size() - r;\n        double slice = max(0.05, rem / max(1, left));\n        double endTime = min(SEARCH_END, timer.elapsed() + slice);\n\n        localSearch(st, timer, endTime, best, segments);\n\n        if (best.obj == TOTAL) break;\n    }\n\n    if (best.grid.empty()) {\n        vector<uint8_t> g(CELLS);\n        for (int i = 0; i < CELLS; i++) g[i] = rng.randint(8);\n        st.build(g);\n        best.consider(st);\n    }\n\n    if (best.obj == TOTAL) {\n        dotMaximize(best, st, timer, FINAL_END);\n    } else {\n        st.build(best.grid);\n\n        if (hasDots(st.grid)) {\n            fillDots(st, timer, FINAL_END, best);\n        }\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            voteRefine(st, timer, min(FINAL_END, timer.elapsed() + 0.12), best, 2);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            greedyImproveSegments(st, timer, min(FINAL_END, timer.elapsed() + 0.12), best, segments, 3, 8);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (avgLen >= 5.5 && st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            double rem = FINAL_END - timer.elapsed();\n            segmentSearch(st, timer, min(FINAL_END, timer.elapsed() + rem * 0.35), best, segments);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.05 < FINAL_END) {\n            softCellSweep(st, timer, FINAL_END, best, 1);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.06 < FINAL_END) {\n            greedyImproveConflict(st, timer, min(FINAL_END, timer.elapsed() + 0.16), best, 6, 110);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() + 0.08 < FINAL_END) {\n            forceWalk(st, timer, min(FINAL_END, timer.elapsed() + 0.20), best, segments);\n        }\n\n        if (best.obj > st.obj) st.build(best.grid);\n\n        if (st.obj < TOTAL && timer.elapsed() < FINAL_END) {\n            conflictSearch(st, timer, FINAL_END, best);\n        }\n\n        if (best.obj == TOTAL) {\n            dotMaximize(best, st, timer, FINAL_END);\n        } else {\n            st.build(best.grid);\n            if (hasDots(st.grid)) fillDots(st, timer, FINAL_END, best);\n\n            if (st.obj < TOTAL) {\n                cellHillSweep(st, timer, FINAL_END, best, 3);\n            }\n\n            if (best.obj == TOTAL) {\n                dotMaximize(best, st, timer, FINAL_END);\n            }\n        }\n    }\n\n    if (best.obj < TOTAL) {\n        for (auto& x : best.grid) {\n            if (x == DOT) x = rng.randint(8);\n        }\n    }\n\n    for (int r = 0; r < SZ; r++) {\n        string line;\n        line.reserve(SZ);\n        for (int c = 0; c < SZ; c++) {\n            uint8_t x = best.grid[r * SZ + c];\n            if (x == DOT) line.push_back('.');\n            else line.push_back(char('A' + x));\n        }\n        cout << line << '\\n';\n    }\n\n    return 0;\n}","ahc005":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 Dinic {\n    struct Edge {\n        int to, rev;\n        long long cap;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n    vector<int> level, it;\n\n    Dinic(int n = 0) : n(n), g(n), level(n), it(n) {}\n\n    void add_edge(int fr, int to, long long cap) {\n        Edge a{to, (int)g[to].size(), cap};\n        Edge b{fr, (int)g[fr].size(), 0};\n        g[fr].push_back(a);\n        g[to].push_back(b);\n    }\n\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\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return level[t] >= 0;\n    }\n\n    long long dfs(int v, int t, long long f) {\n        if (v == t) return f;\n\n        for (int &i = it[v]; i < (int)g[v].size(); i++) {\n            Edge &e = g[v][i];\n\n            if (e.cap <= 0 || level[v] + 1 != level[e.to]) continue;\n\n            long long ret = dfs(e.to, t, min(f, e.cap));\n            if (ret > 0) {\n                e.cap -= ret;\n                g[e.to][e.rev].cap += ret;\n                return ret;\n            }\n        }\n\n        return 0;\n    }\n\n    long long max_flow(int s, int t) {\n        long long flow = 0;\n        const long long INF = (1LL << 60);\n\n        while (bfs(s, t)) {\n            fill(it.begin(), it.end(), 0);\n\n            while (true) {\n                long long f = dfs(s, t, INF);\n                if (!f) break;\n                flow += f;\n            }\n        }\n\n        return flow;\n    }\n\n    vector<int> reachable_from(int s) {\n        vector<int> vis(n, 0);\n        queue<int> q;\n        vis[s] = 1;\n        q.push(s);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\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\n        return vis;\n    }\n};\n\nstruct Solver {\n    static constexpr int INF16 = 65535;\n\n    Timer timer;\n\n    int N, si, sj;\n    vector<string> grid;\n\n    int R = 0, S = 0;\n    vector<vector<int>> id;\n    vector<int> rr, cc, wt;\n    vector<array<int, 4>> nbr;\n\n    vector<uint16_t> distMat, parMat;\n\n    vector<int> hid, vid;\n    vector<vector<int>> hCells, vCells;\n    vector<int> visVal;\n    vector<int> segMinH, segMinV;\n\n    vector<int> bestSafeSeq;\n    vector<int> bestFinalSeq;\n    vector<vector<int>> bestFinalEdges;\n    long long bestSafeCost = (1LL << 60);\n    long long bestFinalCost = (1LL << 60);\n\n    inline int D(int a, int b) const {\n        return distMat[(size_t)a * R + b];\n    }\n\n    inline int Sym(int a, int b) const {\n        return D(a, b) + wt[a];\n    }\n\n    char moveChar(int a, int b) const {\n        if (rr[b] == rr[a] - 1) return 'U';\n        if (rr[b] == rr[a] + 1) return 'D';\n        if (cc[b] == cc[a] - 1) return 'L';\n        return 'R';\n    }\n\n    void readInput() {\n        cin >> N >> si >> sj;\n        grid.resize(N);\n        for (int i = 0; i < N; i++) cin >> grid[i];\n    }\n\n    void buildRoadGraph() {\n        id.assign(N, vector<int>(N, -1));\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (grid[i][j] != '#') {\n                    id[i][j] = R++;\n                    rr.push_back(i);\n                    cc.push_back(j);\n                    wt.push_back(grid[i][j] - '0');\n                }\n            }\n        }\n\n        S = id[si][sj];\n\n        nbr.assign(R, array<int, 4>{-1, -1, -1, -1});\n        int di[4] = {-1, 1, 0, 0};\n        int dj[4] = {0, 0, -1, 1};\n\n        for (int v = 0; v < R; v++) {\n            int i = rr[v], j = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n\n                if (0 <= ni && ni < N && 0 <= nj && nj < N && id[ni][nj] >= 0) {\n                    nbr[v][d] = id[ni][nj];\n                }\n            }\n        }\n    }\n\n    void buildSegments() {\n        hid.assign(R, -1);\n        vid.assign(R, -1);\n\n        for (int i = 0; i < N; i++) {\n            int j = 0;\n            while (j < N) {\n                if (id[i][j] < 0) {\n                    j++;\n                    continue;\n                }\n\n                int h = (int)hCells.size();\n                hCells.push_back({});\n\n                while (j < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    hid[v] = h;\n                    hCells.back().push_back(v);\n                    j++;\n                }\n            }\n        }\n\n        for (int j = 0; j < N; j++) {\n            int i = 0;\n            while (i < N) {\n                if (id[i][j] < 0) {\n                    i++;\n                    continue;\n                }\n\n                int vseg = (int)vCells.size();\n                vCells.push_back({});\n\n                while (i < N && id[i][j] >= 0) {\n                    int v = id[i][j];\n                    vid[v] = vseg;\n                    vCells.back().push_back(v);\n                    i++;\n                }\n            }\n        }\n\n        visVal.assign(R, 0);\n        for (int v = 0; v < R; v++) {\n            visVal[v] = (int)hCells[hid[v]].size() + (int)vCells[vid[v]].size() - 1;\n        }\n    }\n\n    void computeAPSP() {\n        distMat.assign((size_t)R * R, INF16);\n        parMat.assign((size_t)R * R, 0);\n\n        vector<uint16_t> dist(R), par(R);\n        vector<int> score(R);\n        vector<unsigned char> used(R);\n        vector<vector<int>> buckets(10);\n        for (auto &b : buckets) b.reserve(max(1, R / 2));\n\n        for (int s = 0; s < R; s++) {\n            fill(dist.begin(), dist.end(), (uint16_t)INF16);\n            fill(par.begin(), par.end(), 0);\n            fill(score.begin(), score.end(), -1);\n            fill(used.begin(), used.end(), 0);\n            for (auto &b : buckets) b.clear();\n\n            dist[s] = 0;\n            par[s] = s;\n            score[s] = visVal[s];\n            buckets[0].push_back(s);\n\n            int cur = 0, done = 0;\n\n            while (done < R) {\n                auto &bk = buckets[cur % 10];\n\n                if (bk.empty()) {\n                    cur++;\n                    continue;\n                }\n\n                int v = bk.back();\n                bk.pop_back();\n\n                if (used[v] || dist[v] != cur) continue;\n\n                used[v] = 1;\n                done++;\n\n                for (int k = 0; k < 4; k++) {\n                    int to = nbr[v][k];\n                    if (to < 0 || used[to]) continue;\n\n                    int nd = cur + wt[to];\n                    int ns = score[v] + visVal[to];\n\n                    if (nd < dist[to] || (nd == dist[to] && ns > score[to])) {\n                        dist[to] = (uint16_t)nd;\n                        par[to] = (uint16_t)v;\n                        score[to] = ns;\n                        buckets[nd % 10].push_back(to);\n                    }\n                }\n            }\n\n            memcpy(distMat.data() + (size_t)s * R, dist.data(), sizeof(uint16_t) * R);\n            memcpy(parMat.data() + (size_t)s * R, par.data(), sizeof(uint16_t) * R);\n        }\n    }\n\n    void computeSegmentApprox() {\n        segMinH.assign(hCells.size(), 1e9);\n        segMinV.assign(vCells.size(), 1e9);\n\n        for (int v = 0; v < R; v++) {\n            int rt = D(S, v) + D(v, S);\n            segMinH[hid[v]] = min(segMinH[hid[v]], rt);\n            segMinV[vid[v]] = min(segMinV[vid[v]], rt);\n        }\n    }\n\n    void getPathCellsUnordered(int a, int b, vector<int> &out) const {\n        out.clear();\n        if (a == b) return;\n\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            int p = parMat[(size_t)a * R + cur];\n            cur = p;\n\n            if (++cnt > R + 5) {\n                out.clear();\n                return;\n            }\n        }\n    }\n\n    void getPathCellsOrdered(int a, int b, vector<int> &out) const {\n        getPathCellsUnordered(a, b, out);\n        reverse(out.begin(), out.end());\n    }\n\n    long long routeCost(const vector<int> &seq) const {\n        if (seq.empty()) return (1LL << 60);\n\n        long long ret = 0;\n        int m = (int)seq.size();\n\n        for (int i = 0; i < m; i++) {\n            ret += D(seq[i], seq[(i + 1) % m]);\n        }\n\n        return ret;\n    }\n\n    struct Cover {\n        const Solver *sol = nullptr;\n        vector<int> cntH, cntV;\n        int bad = 0;\n\n        void init(const Solver *s) {\n            sol = s;\n            cntH.assign(sol->hCells.size(), 0);\n            cntV.assign(sol->vCells.size(), 0);\n            bad = sol->R;\n        }\n\n        void addH(int h, int delta) {\n            int old = cntH[h];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->hCells[h]) {\n                    if (cntV[sol->vid[q]] == 0) bad++;\n                }\n            }\n\n            cntH[h] = neu;\n        }\n\n        void addV(int v, int delta) {\n            int old = cntV[v];\n            int neu = old + delta;\n\n            if (old == 0 && neu > 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad--;\n                }\n            } else if (old > 0 && neu == 0) {\n                for (int q : sol->vCells[v]) {\n                    if (cntH[sol->hid[q]] == 0) bad++;\n                }\n            }\n\n            cntV[v] = neu;\n        }\n\n        void addCell(int p, int delta) {\n            addH(sol->hid[p], delta);\n            addV(sol->vid[p], delta);\n        }\n    };\n\n    void applyPath(Cover &cov, const vector<int> &path, int delta) const {\n        for (int p : path) cov.addCell(p, delta);\n    }\n\n    bool checkpointFull(const vector<int> &seq) const {\n        Cover cov;\n        cov.init(this);\n        for (int p : seq) cov.addCell(p, +1);\n        return cov.bad == 0;\n    }\n\n    void buildStaticEdges(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        int m = (int)seq.size();\n        edgeCells.assign(m, {});\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsUnordered(a, b, edgeCells[i]);\n        }\n    }\n\n    void ensureEdgeCells(const vector<int> &seq, vector<vector<int>> &edgeCells) const {\n        if ((int)edgeCells.size() != (int)seq.size()) {\n            buildStaticEdges(seq, edgeCells);\n        }\n    }\n\n    void buildCoverFromEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells, Cover &cov) const {\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n        for (int i = 0; i < m; i++) {\n            for (int p : edgeCells[i]) cov.addCell(p, +1);\n        }\n    }\n\n    bool actualFullEdges(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (seq.empty()) return false;\n\n        Cover cov;\n        cov.init(this);\n        cov.addCell(S, +1);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                for (int p : edgeCells[i]) cov.addCell(p, +1);\n            }\n        } else {\n            vector<int> path;\n            for (int i = 0; i < m; i++) {\n                int a = seq[i], b = seq[(i + 1) % m];\n                getPathCellsUnordered(a, b, path);\n                for (int p : path) cov.addCell(p, +1);\n            }\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool actualFull(const vector<int> &seq) const {\n        static const vector<vector<int>> emptyEdges;\n        return actualFullEdges(seq, emptyEdges);\n    }\n\n    bool validEdgePaths(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        if (edgeCells.empty()) return true;\n        int m = (int)seq.size();\n        if ((int)edgeCells.size() != m) return false;\n\n        for (int i = 0; i < m; i++) {\n            int cur = seq[i];\n            int cost = 0;\n\n            for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                int p = edgeCells[i][k];\n                int md = abs(rr[cur] - rr[p]) + abs(cc[cur] - cc[p]);\n                if (md != 1) return false;\n                cost += wt[p];\n                cur = p;\n            }\n\n            if (cur != seq[(i + 1) % m]) return false;\n            if (cost != D(seq[i], seq[(i + 1) % m])) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> constructCellCover(double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<unsigned char> covered(R, 0);\n        vector<int> remH(hCells.size()), remV(vCells.size());\n\n        for (int h = 0; h < (int)hCells.size(); h++) remH[h] = (int)hCells[h].size();\n        for (int v = 0; v < (int)vCells.size(); v++) remV[v] = (int)vCells[v].size();\n\n        int uncovered = R;\n\n        auto mark = [&](int q) {\n            if (!covered[q]) {\n                covered[q] = 1;\n                uncovered--;\n                remH[hid[q]]--;\n                remV[vid[q]]--;\n            }\n        };\n\n        auto addCover = [&](int p) {\n            for (int q : hCells[hid[p]]) mark(q);\n            for (int q : vCells[vid[p]]) mark(q);\n        };\n\n        addCover(S);\n\n        vector<double> gp(R + 1, 1.0);\n        for (int g = 1; g <= R; g++) gp[g] = pow((double)g, alpha);\n\n        while (uncovered > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = remH[hid[p]] + remV[vid[p]] - (covered[p] ? 0 : 1);\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int p = 0; p < R; p++) {\n                    if (!covered[p]) {\n                        bestP = p;\n                        bestPos = 0;\n                        break;\n                    }\n                }\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            addCover(bestP);\n        }\n\n        return seq;\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCoverWeights(const vector<long long> &wH,\n                                                                const vector<long long> &wV) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        long long sumW = 0;\n        for (long long x : wH) sumW += x;\n        for (long long x : wV) sumW += x;\n\n        int SRC = 0;\n        int offH = 1;\n        int offV = offH + nH;\n        int SNK = offV + nV;\n\n        Dinic din(SNK + 1);\n\n        for (int h = 0; h < nH; h++) din.add_edge(SRC, offH + h, wH[h]);\n        for (int v = 0; v < nV; v++) din.add_edge(offV + v, SNK, wV[v]);\n\n        long long INF = sumW + 1;\n\n        for (int p = 0; p < R; p++) {\n            din.add_edge(offH + hid[p], offV + vid[p], INF);\n        }\n\n        din.max_flow(SRC, SNK);\n        vector<int> reach = din.reachable_from(SRC);\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int h = 0; h < nH; h++) selH[h] = !reach[offH + h];\n        for (int v = 0; v < nV; v++) selV[v] = reach[offV + v];\n\n        for (int p = 0; p < R; p++) {\n            if (!selH[hid[p]] && !selV[vid[p]]) selH[hid[p]] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> weightedVertexCover(int type) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<long long> wH(nH), wV(nV);\n\n        auto calcW = [&](int minRT, int len, int tp, bool isH) -> long long {\n            len = max(1, len);\n\n            if (tp == 0) return 1;\n            if (tp == 1) return 100 + minRT / 40;\n            if (tp == 2) return 1 + minRT / 20;\n            if (tp == 3) return 1 + minRT / len;\n            if (tp == 4) return 1 + (10LL * minRT) / max(1, len * len);\n            if (tp == 5) return (len <= 1 ? 10000LL + minRT : 1LL + minRT / max(1, 30 * len));\n            if (tp == 6) return max(1LL, 2000LL / len) + minRT / 100;\n            if (tp == 7) {\n                long long base = 1 + minRT / max(1, 18 * len);\n                return isH ? base * 9 : base * 11;\n            }\n\n            return 1 + minRT / max(1, (int)(8.0 * sqrt((double)len)));\n        };\n\n        for (int h = 0; h < nH; h++) {\n            wH[h] = calcW(segMinH[h], (int)hCells[h].size(), type, true);\n        }\n\n        for (int v = 0; v < nV; v++) {\n            wV[v] = calcW(segMinV[v], (int)vCells[v].size(), type, false);\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    pair<vector<char>, vector<char>> preferenceCover(int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<char> selH(nH, 0), selV(nV, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int lh = (int)hCells[h].size();\n            int lv = (int)vCells[v].size();\n\n            bool chooseH = true;\n\n            if (mode == 0) {\n                if (lh != lv) chooseH = lh > lv;\n                else chooseH = segMinH[h] <= segMinV[v];\n            } else if (mode == 1) {\n                long long sh = 1000LL * segMinH[h] / max(1, lh);\n                long long sv = 1000LL * segMinV[v] / max(1, lv);\n                chooseH = sh <= sv;\n            } else {\n                long long sh = 100000LL * segMinH[h] / max(1, lh * lh);\n                long long sv = 100000LL * segMinV[v] / max(1, lv * lv);\n                chooseH = sh <= sv;\n            }\n\n            if (chooseH) selH[h] = 1;\n            else selV[v] = 1;\n        }\n\n        return {selH, selV};\n    }\n\n    pair<vector<char>, vector<char>> insertionWeightedVertexCover(const vector<int> &base, int mode) {\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        const int INF = 1e9;\n        vector<int> insH(nH, INF), insV(nV, INF);\n\n        int m = (int)base.size();\n\n        for (int p = 0; p < R; p++) {\n            int best = INF;\n\n            for (int i = 0; i < m; i++) {\n                int a = base[i], b = base[(i + 1) % m];\n                int extra = D(a, p) + D(p, b) - D(a, b);\n                if (extra < best) best = extra;\n            }\n\n            insH[hid[p]] = min(insH[hid[p]], best);\n            insV[vid[p]] = min(insV[vid[p]], best);\n        }\n\n        vector<long long> wH(nH), wV(nV);\n\n        for (int h = 0; h < nH; h++) {\n            int len = max(1, (int)hCells[h].size());\n            int c = insH[h] == INF ? segMinH[h] : insH[h];\n\n            if (mode == 0) wH[h] = 1 + c / len;\n            else wH[h] = 1 + (10LL * c) / max(1, len * len) + segMinH[h] / 250;\n        }\n\n        for (int v = 0; v < nV; v++) {\n            int len = max(1, (int)vCells[v].size());\n            int c = insV[v] == INF ? segMinV[v] : insV[v];\n\n            if (mode == 0) wV[v] = 1 + c / len;\n            else wV[v] = 1 + (10LL * c) / max(1, len * len) + segMinV[v] / 250;\n        }\n\n        return weightedVertexCoverWeights(wH, wV);\n    }\n\n    vector<int> constructSegmentCover(const vector<char> &selH, const vector<char> &selV,\n                                      double alpha, double lambda) {\n        vector<int> seq;\n        seq.reserve(512);\n        seq.push_back(S);\n\n        vector<char> touchH(hCells.size(), 0), touchV(vCells.size(), 0);\n\n        int remain = 0;\n        for (char x : selH) if (x) remain++;\n        for (char x : selV) if (x) remain++;\n\n        auto touch = [&](int p) {\n            int h = hid[p], v = vid[p];\n\n            if (selH[h] && !touchH[h]) {\n                touchH[h] = 1;\n                remain--;\n            }\n\n            if (selV[v] && !touchV[v]) {\n                touchV[v] = 1;\n                remain--;\n            }\n        };\n\n        touch(S);\n\n        double gp[3] = {1.0, 1.0, pow(2.0, alpha)};\n\n        while (remain > 0) {\n            if (timer.elapsed() > 2.58) break;\n\n            int m = (int)seq.size();\n            double bestScore = 1e100;\n            int bestP = -1, bestPos = 0, bestGain = -1, bestExtra = INT_MAX;\n\n            for (int p = 0; p < R; p++) {\n                int gain = 0;\n                if (selH[hid[p]] && !touchH[hid[p]]) gain++;\n                if (selV[vid[p]] && !touchV[vid[p]]) gain++;\n                if (gain <= 0) continue;\n\n                int be = INT_MAX, bp = 0;\n\n                for (int i = 0; i < m; i++) {\n                    int a = seq[i], b = seq[(i + 1) % m];\n                    int extra = D(a, p) + D(p, b) - D(a, b);\n\n                    if (extra < be) {\n                        be = extra;\n                        bp = i;\n                    }\n                }\n\n                double score = (be + lambda) / gp[gain];\n\n                bool upd = false;\n                if (score < bestScore - 1e-12) upd = true;\n                else if (abs(score - bestScore) <= 1e-12) {\n                    if (gain > bestGain) upd = true;\n                    else if (gain == bestGain && be < bestExtra) upd = true;\n                    else if (gain == bestGain && be == bestExtra && bestP >= 0 && visVal[p] > visVal[bestP]) upd = true;\n                }\n\n                if (upd) {\n                    bestScore = score;\n                    bestP = p;\n                    bestPos = bp;\n                    bestGain = gain;\n                    bestExtra = be;\n                }\n            }\n\n            if (bestP < 0) {\n                for (int h = 0; h < (int)selH.size() && bestP < 0; h++) {\n                    if (selH[h] && !touchH[h]) bestP = hCells[h][0];\n                }\n\n                for (int v = 0; v < (int)selV.size() && bestP < 0; v++) {\n                    if (selV[v] && !touchV[v]) bestP = vCells[v][0];\n                }\n\n                bestPos = 0;\n            }\n\n            seq.insert(seq.begin() + bestPos + 1, bestP);\n            touch(bestP);\n        }\n\n        return seq;\n    }\n\n    bool twoOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n\n        for (int i = 0; i < m - 1; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            reverse(seq.begin() + bi + 1, seq.begin() + bk + 1);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool orOptOnce(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        int bestDelta = 0, bi = -1, bj = -1;\n\n        for (int i = 1; i < m; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int removeCost = Sym(prev, x) + Sym(x, next) - Sym(prev, next);\n\n            for (int j = 0; j < m; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j], b = seq[(j + 1) % m];\n                int addCost = Sym(a, x) + Sym(x, b) - Sym(a, b);\n                int delta = addCost - removeCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi >= 0) {\n            int x = seq[bi];\n            seq.erase(seq.begin() + bi);\n\n            int pos;\n            if (bj > bi) pos = bj;\n            else pos = bj + 1;\n\n            seq.insert(seq.begin() + pos, x);\n            return true;\n        }\n\n        return false;\n    }\n\n    bool orOpt2Once(vector<int> &seq) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bj = -1;\n\n        for (int i = 1; i + 1 < m; i++) {\n            int x = seq[i];\n            int y = seq[i + 1];\n            int prev = seq[i - 1];\n            int next = seq[(i + 2) % m];\n\n            int removeCost = Sym(prev, x) + Sym(y, next) - Sym(prev, next);\n\n            for (int j = 0; j < m; j++) {\n                if (j >= i - 1 && j <= i + 1) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n\n                int addCost = Sym(a, x) + Sym(y, b) - Sym(a, b);\n                int delta = addCost - removeCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi < 0) return false;\n\n        int x = seq[bi];\n        int y = seq[bi + 1];\n\n        seq.erase(seq.begin() + bi, seq.begin() + bi + 2);\n\n        int pos;\n        if (bj < bi) pos = bj + 1;\n        else pos = bj - 1;\n\n        seq.insert(seq.begin() + pos, y);\n        seq.insert(seq.begin() + pos, x);\n\n        return true;\n    }\n\n    void optimizeOrder(vector<int> &seq, double limit) {\n        while (timer.elapsed() < limit) {\n            bool improved = false;\n\n            if (twoOptOnce(seq)) improved = true;\n            if (timer.elapsed() >= limit) break;\n\n            if (orOptOnce(seq)) improved = true;\n            if (timer.elapsed() >= limit) break;\n\n            if (!improved && orOpt2Once(seq)) improved = true;\n\n            if (!improved) break;\n        }\n    }\n\n    void safeRemove(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n\n            for (int i = 1; i < m; i++) {\n                int x = seq[i];\n\n                cov.addCell(x, -1);\n\n                if (cov.bad == 0) {\n                    int prev = seq[i - 1];\n                    int next = seq[(i + 1) % m];\n                    int save = D(prev, x) + D(x, next) - D(prev, next);\n\n                    if (save > bestSave) {\n                        bestSave = save;\n                        bestIdx = i;\n                    }\n                }\n\n                cov.addCell(x, +1);\n            }\n\n            if (bestIdx < 0) break;\n\n            cov.addCell(seq[bestIdx], -1);\n            seq.erase(seq.begin() + bestIdx);\n        }\n    }\n\n    void improveReplace(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                token++;\n                if (token == INT_MAX) {\n                    fill(seen.begin(), seen.end(), 0);\n                    token = 1;\n                }\n\n                cov.addCell(old, -1);\n\n                auto evalCand = [&](int p) {\n                    if (seen[p] == token) return;\n                    seen[p] = token;\n\n                    if (p == old) return;\n\n                    int newCost = D(prev, p) + D(p, next);\n                    int delta = newCost - oldCost;\n\n                    if (delta >= bestDelta) return;\n\n                    cov.addCell(p, +1);\n\n                    if (cov.bad == 0) {\n                        bestDelta = delta;\n                        bestIdx = i;\n                        bestP = p;\n                    }\n\n                    cov.addCell(p, -1);\n                };\n\n                for (int p : hCells[hid[old]]) evalCand(p);\n                for (int p : vCells[vid[old]]) evalCand(p);\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    void improveReplaceCritical(vector<int> &seq, double limit) {\n        Cover cov;\n        cov.init(this);\n\n        for (int p : seq) cov.addCell(p, +1);\n        if (cov.bad != 0) return;\n\n        vector<int> seen(R, 0);\n        int token = 1;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            int bestIdx = -1, bestP = -1, bestDelta = 0;\n\n            for (int i = 1; i < m; i++) {\n                int old = seq[i];\n                int prev = seq[i - 1];\n                int next = seq[(i + 1) % m];\n                int oldCost = D(prev, old) + D(old, next);\n\n                cov.addCell(old, -1);\n\n                if (cov.bad > 0) {\n                    int fb = -1;\n                    for (int q = 0; q < R; q++) {\n                        if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                            fb = q;\n                            break;\n                        }\n                    }\n\n                    if (fb >= 0) {\n                        token++;\n                        if (token == INT_MAX) {\n                            fill(seen.begin(), seen.end(), 0);\n                            token = 1;\n                        }\n\n                        auto evalCand = [&](int p) {\n                            if (seen[p] == token) return;\n                            seen[p] = token;\n                            if (p == old) return;\n\n                            int newCost = D(prev, p) + D(p, next);\n                            int delta = newCost - oldCost;\n                            if (delta >= bestDelta) return;\n\n                            cov.addCell(p, +1);\n                            if (cov.bad == 0) {\n                                bestDelta = delta;\n                                bestIdx = i;\n                                bestP = p;\n                            }\n                            cov.addCell(p, -1);\n                        };\n\n                        for (int p : hCells[hid[fb]]) evalCand(p);\n                        for (int p : vCells[vid[fb]]) evalCand(p);\n                    }\n                }\n\n                cov.addCell(old, +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            int old = seq[bestIdx];\n            cov.addCell(old, -1);\n            cov.addCell(bestP, +1);\n            seq[bestIdx] = bestP;\n        }\n    }\n\n    vector<int> dynamicShortestPath(int a, int b, const Cover &cov) const {\n        vector<int> fallback;\n        getPathCellsUnordered(a, b, fallback);\n\n        if (a == b) return {};\n\n        int target = D(a, b);\n        if (target >= INF16) return fallback;\n\n        int nH = (int)hCells.size();\n        int nV = (int)vCells.size();\n\n        vector<int> badH(nH, 0), badV(nV, 0);\n\n        if (cov.bad > 0) {\n            for (int q = 0; q < R; q++) {\n                if (cov.cntH[hid[q]] == 0 && cov.cntV[vid[q]] == 0) {\n                    badH[hid[q]]++;\n                    badV[vid[q]]++;\n                }\n            }\n        }\n\n        vector<int> reward(R, 0);\n\n        for (int p = 0; p < R; p++) {\n            int h = hid[p], v = vid[p];\n            int g = 0;\n\n            if (cov.cntH[h] == 0) g += badH[h];\n            if (cov.cntV[v] == 0) g += badV[v];\n            if (cov.cntH[h] == 0 && cov.cntV[v] == 0) g--;\n\n            reward[p] = g * 10000 + min(visVal[p], 9999);\n        }\n\n        vector<int> nodes;\n        nodes.reserve(R);\n\n        for (int p = 0; p < R; p++) {\n            if (D(a, p) + D(p, b) == target) nodes.push_back(p);\n        }\n\n        sort(nodes.begin(), nodes.end(), [&](int x, int y) {\n            int dx = D(a, x), dy = D(a, y);\n            if (dx != dy) return dx < dy;\n            return x < y;\n        });\n\n        const long long NEG = -(1LL << 60);\n        vector<long long> dp(R, NEG);\n        vector<int> parent(R, -1);\n\n        dp[a] = 0;\n        parent[a] = a;\n\n        for (int v : nodes) {\n            if (dp[v] == NEG) continue;\n\n            int dv = D(a, v);\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n                if (to < 0) continue;\n\n                if (dv + wt[to] != D(a, to)) continue;\n                if (D(a, to) + D(to, b) != target) continue;\n\n                long long ndp = dp[v] + reward[to];\n\n                if (ndp > dp[to]) {\n                    dp[to] = ndp;\n                    parent[to] = v;\n                }\n            }\n        }\n\n        if (parent[b] < 0) return fallback;\n\n        vector<int> out;\n        int cur = b;\n        int cnt = 0;\n\n        while (cur != a) {\n            out.push_back(cur);\n            cur = parent[cur];\n\n            if (cur < 0 || ++cnt > R + 5) return fallback;\n        }\n\n        return out;\n    }\n\n    bool rerouteEdgesImprove(vector<int> &seq, vector<vector<int>> &edgeCells, double limit) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int m = (int)seq.size();\n        vector<int> ord(m);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            int da = D(seq[a], seq[(a + 1) % m]);\n            int db = D(seq[b], seq[(b + 1) % m]);\n            return da > db;\n        });\n\n        bool any = false;\n\n        for (int pass = 0; pass < 2 && timer.elapsed() < limit; pass++) {\n            bool changed = false;\n\n            for (int idx = 0; idx < m && timer.elapsed() < limit; idx++) {\n                int i = ord[idx];\n\n                vector<int> oldPath = edgeCells[i];\n\n                applyPath(cov, oldPath, -1);\n\n                vector<int> np = dynamicShortestPath(seq[i], seq[(i + 1) % m], cov);\n                applyPath(cov, np, +1);\n\n                if (cov.bad == 0) {\n                    if (np != oldPath) {\n                        edgeCells[i] = np;\n                        changed = true;\n                        any = true;\n                    }\n                } else {\n                    applyPath(cov, np, -1);\n                    applyPath(cov, oldPath, +1);\n                }\n            }\n\n            if (!changed) break;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool pathRemove(vector<int> &seq, vector<vector<int>> &edgeCells, double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 1) break;\n\n            int bestIdx = -1;\n            int bestSave = -1;\n            vector<int> bestNewPath;\n\n            for (int i = 1; i < m; i++) {\n                int prev = seq[i - 1];\n                int x = seq[i];\n                int next = seq[(i + 1) % m];\n\n                int save = D(prev, x) + D(x, next) - D(prev, next);\n                if (save < bestSave) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n\n                vector<int> np;\n                getPathCellsUnordered(prev, next, np);\n\n                applyPath(cov, np, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand = np;\n\n                applyPath(cov, np, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    vector<int> dp = dynamicShortestPath(prev, next, cov);\n\n                    applyPath(cov, dp, +1);\n\n                    if (cov.bad == 0) {\n                        ok = true;\n                        cand = dp;\n                    }\n\n                    applyPath(cov, dp, -1);\n                }\n\n                if (ok && save > bestSave) {\n                    bestSave = save;\n                    bestIdx = i;\n                    bestNewPath = cand;\n                }\n\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestIdx < 0) break;\n\n            applyPath(cov, edgeCells[bestIdx - 1], -1);\n            applyPath(cov, edgeCells[bestIdx], -1);\n            applyPath(cov, bestNewPath, +1);\n\n            seq.erase(seq.begin() + bestIdx);\n            edgeCells[bestIdx - 1] = bestNewPath;\n            edgeCells.erase(edgeCells.begin() + bestIdx);\n        }\n\n        return cov.bad == 0;\n    }\n\n    bool pathBlockRemove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                         double limit, int maxLen, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        while (timer.elapsed() < limit) {\n            int m = (int)seq.size();\n            if (m <= 2) break;\n\n            int bestL = -1, bestR = -1;\n            int bestSave = 0;\n            vector<int> bestPath;\n\n            for (int len = 2; len <= maxLen; len++) {\n                if (len >= m) break;\n\n                for (int l = 1; l + len - 1 < m; l++) {\n                    int r = l + len - 1;\n                    int prev = seq[l - 1];\n                    int next = seq[(r + 1) % m];\n\n                    int oldCost = 0;\n                    for (int e = l - 1; e <= r; e++) {\n                        oldCost += D(seq[e], seq[(e + 1) % m]);\n                    }\n\n                    int save = oldCost - D(prev, next);\n                    if (save <= bestSave) continue;\n\n                    for (int e = l - 1; e <= r; e++) applyPath(cov, edgeCells[e], -1);\n\n                    vector<int> np;\n                    getPathCellsUnordered(prev, next, np);\n                    applyPath(cov, np, +1);\n\n                    bool ok = cov.bad == 0;\n                    vector<int> cand = np;\n\n                    applyPath(cov, np, -1);\n\n                    if (!ok && useDynamic && timer.elapsed() < limit) {\n                        vector<int> dp = dynamicShortestPath(prev, next, cov);\n                        applyPath(cov, dp, +1);\n\n                        if (cov.bad == 0) {\n                            ok = true;\n                            cand = dp;\n                        }\n\n                        applyPath(cov, dp, -1);\n                    }\n\n                    if (ok && save > bestSave) {\n                        bestSave = save;\n                        bestL = l;\n                        bestR = r;\n                        bestPath = cand;\n                    }\n\n                    for (int e = r; e >= l - 1; e--) applyPath(cov, edgeCells[e], +1);\n\n                    if (timer.elapsed() >= limit) break;\n                }\n\n                if (timer.elapsed() >= limit) break;\n            }\n\n            if (bestL < 0) break;\n\n            for (int e = bestL - 1; e <= bestR; e++) applyPath(cov, edgeCells[e], -1);\n            applyPath(cov, bestPath, +1);\n\n            seq.erase(seq.begin() + bestL, seq.begin() + bestR + 1);\n            edgeCells[bestL - 1] = bestPath;\n            edgeCells.erase(edgeCells.begin() + bestL, edgeCells.begin() + bestR + 1);\n        }\n\n        return cov.bad == 0;\n    }\n\n    vector<int> reverseEdgePath(const vector<int> &oldPath, int oldSource) const {\n        vector<int> ret;\n        if (oldPath.empty()) return ret;\n\n        ret.reserve(oldPath.size());\n        ret.push_back(oldSource);\n\n        for (int i = (int)oldPath.size() - 1; i >= 1; i--) {\n            ret.push_back(oldPath[i]);\n        }\n\n        return ret;\n    }\n\n    bool actualTwoOptOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                          Cover &cov, double limit, bool useDynamic) {\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        int bestDelta = 0, bi = -1, bk = -1;\n        vector<int> bestP1, bestP2;\n        vector<vector<int>> bestMid;\n\n        for (int i = 0; i < m - 1 && timer.elapsed() < limit; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n\n            for (int k = i + 2; k < m && timer.elapsed() < limit; k++) {\n                if (i == 0 && k == m - 1) continue;\n\n                int c = seq[k], d = seq[(k + 1) % m];\n                int delta = Sym(a, c) + Sym(b, d) - Sym(a, b) - Sym(c, d);\n\n                if (delta >= bestDelta) continue;\n\n                for (int e = i; e <= k; e++) applyPath(cov, edgeCells[e], -1);\n\n                vector<vector<int>> mid;\n                mid.reserve(max(0, k - i - 1));\n\n                for (int ne = i + 1; ne <= k - 1; ne++) {\n                    int oldIdx = i + k - ne;\n                    mid.push_back(reverseEdgePath(edgeCells[oldIdx], seq[oldIdx]));\n                    applyPath(cov, mid.back(), +1);\n                }\n\n                vector<int> p1, p2;\n                getPathCellsUnordered(a, c, p1);\n                getPathCellsUnordered(b, d, p2);\n\n                applyPath(cov, p1, +1);\n                applyPath(cov, p2, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> cand1 = p1, cand2 = p2;\n\n                applyPath(cov, p2, -1);\n                applyPath(cov, p1, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    cand1 = dynamicShortestPath(a, c, cov);\n                    applyPath(cov, cand1, +1);\n\n                    cand2 = dynamicShortestPath(b, d, cov);\n                    applyPath(cov, cand2, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, cand2, -1);\n                    applyPath(cov, cand1, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bi = i;\n                    bk = k;\n                    bestP1 = cand1;\n                    bestP2 = cand2;\n                    bestMid = mid;\n                }\n\n                for (auto &v : mid) applyPath(cov, v, -1);\n                for (int e = k; e >= i; e--) applyPath(cov, edgeCells[e], +1);\n            }\n        }\n\n        if (bi < 0) return false;\n\n        for (int e = bi; e <= bk; e++) applyPath(cov, edgeCells[e], -1);\n        applyPath(cov, bestP1, +1);\n        for (auto &v : bestMid) applyPath(cov, v, +1);\n        applyPath(cov, bestP2, +1);\n\n        vector<int> newSeq = seq;\n        reverse(newSeq.begin() + bi + 1, newSeq.begin() + bk + 1);\n\n        vector<vector<int>> newEdges = edgeCells;\n        newEdges[bi] = bestP1;\n        for (int t = 0; t < (int)bestMid.size(); t++) {\n            newEdges[bi + 1 + t] = bestMid[t];\n        }\n        newEdges[bk] = bestP2;\n\n        seq.swap(newSeq);\n        edgeCells.swap(newEdges);\n\n        return true;\n    }\n\n    bool actualTwoOptImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                             double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n\n        ensureEdgeCells(seq, edgeCells);\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        bool any = false;\n\n        while (timer.elapsed() < limit) {\n            bool ok = actualTwoOptOnce(seq, edgeCells, cov, limit, useDynamic);\n            if (!ok) break;\n            any = true;\n        }\n\n        return any && cov.bad == 0;\n    }\n\n    void applyOrOptMove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                        int i, int j,\n                        const vector<int> &pPrevNext,\n                        const vector<int> &pAX,\n                        const vector<int> &pXB) {\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n        int m = (int)oldSeq.size();\n\n        vector<int> ns;\n        vector<vector<int>> ne(m);\n\n        ns.reserve(m);\n\n        if (j < i) {\n            for (int k = 0; k <= j; k++) ns.push_back(oldSeq[k]);\n            ns.push_back(oldSeq[i]);\n            for (int k = j + 1; k <= i - 1; k++) ns.push_back(oldSeq[k]);\n            for (int k = i + 1; k < m; k++) ns.push_back(oldSeq[k]);\n\n            for (int k = 0; k < j; k++) ne[k] = oldEdges[k];\n            ne[j] = pAX;\n            ne[j + 1] = pXB;\n            for (int k = j + 2; k <= i - 1; k++) ne[k] = oldEdges[k - 1];\n            ne[i] = pPrevNext;\n            for (int k = i + 1; k < m; k++) ne[k] = oldEdges[k];\n        } else {\n            for (int k = 0; k <= i - 1; k++) ns.push_back(oldSeq[k]);\n            for (int k = i + 1; k <= j; k++) ns.push_back(oldSeq[k]);\n            ns.push_back(oldSeq[i]);\n            for (int k = j + 1; k < m; k++) ns.push_back(oldSeq[k]);\n\n            for (int k = 0; k <= i - 2; k++) ne[k] = oldEdges[k];\n            ne[i - 1] = pPrevNext;\n            for (int k = i; k <= j - 2; k++) ne[k] = oldEdges[k + 1];\n            ne[j - 1] = pAX;\n            ne[j] = pXB;\n            for (int k = j + 1; k < m; k++) ne[k] = oldEdges[k];\n        }\n\n        if ((int)ns.size() == m && (int)ne.size() == m) {\n            seq.swap(ns);\n            edgeCells.swap(ne);\n        }\n    }\n\n    bool actualOrOptOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                         double limit, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 3) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n        vector<int> bestPN, bestAX, bestXB;\n\n        for (int i = 1; i < m && timer.elapsed() < limit; i++) {\n            int x = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int oldCost = D(prev, x) + D(x, next);\n\n            for (int j = 0; j < m && timer.elapsed() < limit; j++) {\n                if (j == i || j == i - 1) continue;\n\n                int a = seq[j];\n                int b = seq[(j + 1) % m];\n\n                int delta = D(prev, next) + D(a, x) + D(x, b)\n                          - oldCost - D(a, b);\n\n                if (delta >= bestDelta) continue;\n\n                applyPath(cov, edgeCells[i - 1], -1);\n                applyPath(cov, edgeCells[i], -1);\n                applyPath(cov, edgeCells[j], -1);\n\n                vector<int> pn, ax, xb;\n                getPathCellsUnordered(prev, next, pn);\n                getPathCellsUnordered(a, x, ax);\n                getPathCellsUnordered(x, b, xb);\n\n                applyPath(cov, pn, +1);\n                applyPath(cov, ax, +1);\n                applyPath(cov, xb, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> candPN = pn, candAX = ax, candXB = xb;\n\n                applyPath(cov, xb, -1);\n                applyPath(cov, ax, -1);\n                applyPath(cov, pn, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    candPN = dynamicShortestPath(prev, next, cov);\n                    applyPath(cov, candPN, +1);\n                    candAX = dynamicShortestPath(a, x, cov);\n                    applyPath(cov, candAX, +1);\n                    candXB = dynamicShortestPath(x, b, cov);\n                    applyPath(cov, candXB, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, candXB, -1);\n                    applyPath(cov, candAX, -1);\n                    applyPath(cov, candPN, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                    bestPN = candPN;\n                    bestAX = candAX;\n                    bestXB = candXB;\n                }\n\n                applyPath(cov, edgeCells[j], +1);\n                applyPath(cov, edgeCells[i], +1);\n                applyPath(cov, edgeCells[i - 1], +1);\n            }\n        }\n\n        if (bestI < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        applyOrOptMove(seq, edgeCells, bestI, bestJ, bestPN, bestAX, bestXB);\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualOrOptImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                            double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualOrOptOnce(seq, edgeCells, limit, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool actualReplaceOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                           double limit, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 2) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestI = -1, bestP = -1;\n        vector<int> bestA, bestB;\n\n        for (int i = 1; i < m && timer.elapsed() < limit; i++) {\n            int old = seq[i];\n            int prev = seq[i - 1];\n            int next = seq[(i + 1) % m];\n            int oldCost = D(prev, old) + D(old, next);\n\n            applyPath(cov, edgeCells[i - 1], -1);\n            applyPath(cov, edgeCells[i], -1);\n\n            for (int p = 0; p < R && timer.elapsed() < limit; p++) {\n                if (p == old || p == prev || p == next) continue;\n\n                int delta = D(prev, p) + D(p, next) - oldCost;\n                if (delta >= bestDelta) continue;\n\n                vector<int> pa, pb;\n                getPathCellsUnordered(prev, p, pa);\n                getPathCellsUnordered(p, next, pb);\n\n                applyPath(cov, pa, +1);\n                applyPath(cov, pb, +1);\n\n                bool ok = cov.bad == 0;\n                vector<int> ca = pa, cb = pb;\n\n                applyPath(cov, pb, -1);\n                applyPath(cov, pa, -1);\n\n                if (!ok && useDynamic && timer.elapsed() < limit) {\n                    ca = dynamicShortestPath(prev, p, cov);\n                    applyPath(cov, ca, +1);\n                    cb = dynamicShortestPath(p, next, cov);\n                    applyPath(cov, cb, +1);\n\n                    if (cov.bad == 0) ok = true;\n\n                    applyPath(cov, cb, -1);\n                    applyPath(cov, ca, -1);\n                }\n\n                if (ok) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestP = p;\n                    bestA = ca;\n                    bestB = cb;\n                }\n            }\n\n            applyPath(cov, edgeCells[i], +1);\n            applyPath(cov, edgeCells[i - 1], +1);\n        }\n\n        if (bestI < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        seq[bestI] = bestP;\n        edgeCells[bestI - 1] = bestA;\n        edgeCells[bestI] = bestB;\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualReplaceImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                              double limit, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualReplaceOnce(seq, edgeCells, limit, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    bool actualBlockReplaceOnce(vector<int> &seq, vector<vector<int>> &edgeCells,\n                                double limit, int maxLen, bool useDynamic) {\n        ensureEdgeCells(seq, edgeCells);\n\n        int m = (int)seq.size();\n        if (m < 4) return false;\n\n        Cover cov;\n        buildCoverFromEdges(seq, edgeCells, cov);\n        if (cov.bad != 0) return false;\n\n        int bestDelta = 0;\n        int bestL = -1, bestR = -1, bestP = -1;\n        vector<int> bestA, bestB;\n\n        for (int len = 2; len <= maxLen && timer.elapsed() < limit; len++) {\n            if (len >= m) break;\n\n            for (int l = 1; l + len - 1 < m && timer.elapsed() < limit; l++) {\n                int r = l + len - 1;\n                int prev = seq[l - 1];\n                int next = seq[(r + 1) % m];\n\n                int oldCost = 0;\n                for (int e = l - 1; e <= r; e++) {\n                    oldCost += D(seq[e], seq[(e + 1) % m]);\n                }\n\n                for (int e = l - 1; e <= r; e++) applyPath(cov, edgeCells[e], -1);\n\n                for (int p = 0; p < R && timer.elapsed() < limit; p++) {\n                    if (p == prev || p == next) continue;\n\n                    int delta = D(prev, p) + D(p, next) - oldCost;\n                    if (delta >= bestDelta) continue;\n\n                    vector<int> pa, pb;\n                    getPathCellsUnordered(prev, p, pa);\n                    getPathCellsUnordered(p, next, pb);\n\n                    applyPath(cov, pa, +1);\n                    applyPath(cov, pb, +1);\n\n                    bool ok = cov.bad == 0;\n                    vector<int> ca = pa, cb = pb;\n\n                    applyPath(cov, pb, -1);\n                    applyPath(cov, pa, -1);\n\n                    if (!ok && useDynamic && timer.elapsed() < limit) {\n                        ca = dynamicShortestPath(prev, p, cov);\n                        applyPath(cov, ca, +1);\n                        cb = dynamicShortestPath(p, next, cov);\n                        applyPath(cov, cb, +1);\n\n                        if (cov.bad == 0) ok = true;\n\n                        applyPath(cov, cb, -1);\n                        applyPath(cov, ca, -1);\n                    }\n\n                    if (ok) {\n                        bestDelta = delta;\n                        bestL = l;\n                        bestR = r;\n                        bestP = p;\n                        bestA = ca;\n                        bestB = cb;\n                    }\n                }\n\n                for (int e = r; e >= l - 1; e--) applyPath(cov, edgeCells[e], +1);\n            }\n        }\n\n        if (bestL < 0) return false;\n\n        vector<int> oldSeq = seq;\n        vector<vector<int>> oldEdges = edgeCells;\n\n        seq.erase(seq.begin() + bestL, seq.begin() + bestR + 1);\n        seq.insert(seq.begin() + bestL, bestP);\n\n        edgeCells[bestL - 1] = bestA;\n        edgeCells.erase(edgeCells.begin() + bestL, edgeCells.begin() + bestR + 1);\n        edgeCells.insert(edgeCells.begin() + bestL, bestB);\n\n        if (!validEdgePaths(seq, edgeCells) || !actualFullEdges(seq, edgeCells)) {\n            seq.swap(oldSeq);\n            edgeCells.swap(oldEdges);\n            return false;\n        }\n\n        return true;\n    }\n\n    bool actualBlockReplaceImprove(vector<int> &seq, vector<vector<int>> &edgeCells,\n                                   double limit, int maxLen, bool useDynamic) {\n        if (seq.empty()) return false;\n        ensureEdgeCells(seq, edgeCells);\n        if (!actualFullEdges(seq, edgeCells)) return false;\n\n        bool any = false;\n        while (timer.elapsed() < limit) {\n            if (!actualBlockReplaceOnce(seq, edgeCells, limit, maxLen, useDynamic)) break;\n            any = true;\n        }\n\n        return any && actualFullEdges(seq, edgeCells);\n    }\n\n    int edgeCellTotal(const vector<vector<int>> &edgeCells) const {\n        int ret = 0;\n        for (auto &v : edgeCells) ret += (int)v.size();\n        return ret;\n    }\n\n    void updateFinalStatic(const vector<int> &seq) {\n        long long c = routeCost(seq);\n\n        if (c < bestFinalCost) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges.clear();\n        }\n    }\n\n    void updateFinalRoute(const vector<int> &seq, const vector<vector<int>> &edgeCells) {\n        long long c = routeCost(seq);\n\n        if (c > bestFinalCost) return;\n        if (!actualFullEdges(seq, edgeCells)) return;\n        if (!edgeCells.empty() && !validEdgePaths(seq, edgeCells)) return;\n\n        bool upd = false;\n\n        if (c < bestFinalCost) {\n            upd = true;\n        } else if (c == bestFinalCost && !edgeCells.empty()) {\n            if (bestFinalEdges.empty() || edgeCellTotal(edgeCells) > edgeCellTotal(bestFinalEdges)) {\n                upd = true;\n            }\n        }\n\n        if (upd) {\n            bestFinalCost = c;\n            bestFinalSeq = seq;\n            bestFinalEdges = edgeCells;\n        }\n    }\n\n    void updateSafe(const vector<int> &seq) {\n        if (!checkpointFull(seq)) return;\n\n        long long c = routeCost(seq);\n\n        if (c < bestSafeCost) {\n            bestSafeCost = c;\n            bestSafeSeq = seq;\n        }\n\n        updateFinalStatic(seq);\n    }\n\n    void processCandidate(vector<int> seq, bool heavy) {\n        if (seq.empty()) return;\n\n        double lim = min(2.50, timer.elapsed() + (heavy ? 0.22 : 0.08));\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n        if (timer.elapsed() < lim) safeRemove(seq, lim);\n\n        if (heavy && timer.elapsed() < lim) {\n            improveReplace(seq, lim);\n            improveReplaceCritical(seq, lim);\n            safeRemove(seq, lim);\n        }\n\n        if (timer.elapsed() < lim) optimizeOrder(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() < 2.62) {\n            vector<int> pseq = seq;\n            vector<vector<int>> pedges;\n\n            double plim = min(2.67, timer.elapsed() + (heavy ? 0.085 : 0.045));\n            bool dyn = heavy || timer.elapsed() < 1.80;\n\n            if (pathRemove(pseq, pedges, plim, dyn)) {\n                if (heavy && timer.elapsed() < plim) {\n                    pathBlockRemove(pseq, pedges, plim, 2, dyn);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    string buildOutput(const vector<int> &seq, const vector<vector<int>> &edgeCells) const {\n        string ans;\n        ans.reserve(200000);\n\n        int m = (int)seq.size();\n\n        if ((int)edgeCells.size() == m) {\n            for (int i = 0; i < m; i++) {\n                int cur = seq[i];\n\n                for (int k = (int)edgeCells[i].size() - 1; k >= 0; k--) {\n                    int p = edgeCells[i][k];\n                    ans.push_back(moveChar(cur, p));\n                    cur = p;\n                }\n            }\n\n            return ans;\n        }\n\n        vector<int> path;\n\n        for (int i = 0; i < m; i++) {\n            int a = seq[i], b = seq[(i + 1) % m];\n            getPathCellsOrdered(a, b, path);\n\n            int cur = a;\n\n            for (int p : path) {\n                ans.push_back(moveChar(cur, p));\n                cur = p;\n            }\n        }\n\n        return ans;\n    }\n\n    string dfsFallback() const {\n        vector<vector<int>> child(R);\n        vector<int> par(R, -1);\n        queue<int> q;\n\n        par[S] = S;\n        q.push(S);\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n\n            for (int k = 0; k < 4; k++) {\n                int to = nbr[v][k];\n\n                if (to >= 0 && par[to] < 0) {\n                    par[to] = v;\n                    child[v].push_back(to);\n                    q.push(to);\n                }\n            }\n        }\n\n        string ans;\n        ans.reserve(max(0, 2 * (R - 1)));\n\n        function<void(int)> dfs = [&](int v) {\n            for (int to : child[v]) {\n                ans.push_back(moveChar(v, to));\n                dfs(to);\n                ans.push_back(moveChar(to, v));\n            }\n        };\n\n        dfs(S);\n        return ans;\n    }\n\n    void finalPolish(bool hard) {\n        if (bestSafeSeq.empty() || timer.elapsed() > 2.76) return;\n\n        vector<int> seq = bestSafeSeq;\n        double lim = 2.84;\n\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n        improveReplace(seq, lim);\n        improveReplaceCritical(seq, lim);\n        safeRemove(seq, lim);\n        optimizeOrder(seq, lim);\n        safeRemove(seq, lim);\n\n        updateSafe(seq);\n\n        if (timer.elapsed() >= 2.86) return;\n\n        vector<int> pseq = seq;\n        vector<vector<int>> pedges;\n\n        if (!hard) {\n            if (pathRemove(pseq, pedges, 2.89, true)) {\n                if (timer.elapsed() < 2.895) {\n                    pathBlockRemove(pseq, pedges, 2.908, 3, true);\n                }\n\n                if (timer.elapsed() < 2.908) {\n                    actualBlockReplaceImprove(pseq, pedges, 2.925, 2, false);\n                }\n\n                if (timer.elapsed() < 2.925) {\n                    actualTwoOptImprove(pseq, pedges, 2.938, true);\n                }\n\n                if (timer.elapsed() < 2.938) {\n                    actualOrOptImprove(pseq, pedges, 2.948, false);\n                }\n\n                if (timer.elapsed() < 2.948) {\n                    actualReplaceImprove(pseq, pedges, 2.955, false);\n                }\n\n                if (timer.elapsed() < 2.955) {\n                    pathRemove(pseq, pedges, 2.960, true);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        } else {\n            if (pathRemove(pseq, pedges, 2.890, true)) {\n                if (timer.elapsed() < 2.890) {\n                    pathBlockRemove(pseq, pedges, 2.905, 3, true);\n                }\n\n                if (timer.elapsed() < 2.905) {\n                    actualTwoOptImprove(pseq, pedges, 2.922, true);\n                }\n\n                if (timer.elapsed() < 2.922) {\n                    rerouteEdgesImprove(pseq, pedges, 2.932);\n                }\n\n                if (timer.elapsed() < 2.932) {\n                    pathRemove(pseq, pedges, 2.940, true);\n                }\n\n                if (timer.elapsed() < 2.940) {\n                    actualBlockReplaceImprove(pseq, pedges, 2.952, 2, false);\n                }\n\n                if (timer.elapsed() < 2.952) {\n                    actualOrOptImprove(pseq, pedges, 2.960, false);\n                }\n\n                if (timer.elapsed() < 2.960) {\n                    actualReplaceImprove(pseq, pedges, 2.965, false);\n                }\n\n                if (timer.elapsed() < 2.965) {\n                    pathRemove(pseq, pedges, 2.970, true);\n                }\n\n                updateFinalRoute(pseq, pedges);\n            }\n        }\n    }\n\n    void finalActualPolish(bool hard) {\n        if (bestFinalSeq.empty()) return;\n\n        if (!hard && timer.elapsed() > 2.90) return;\n        if (hard && timer.elapsed() > 2.91) return;\n\n        vector<int> seq = bestFinalSeq;\n        vector<vector<int>> edges = bestFinalEdges;\n        ensureEdgeCells(seq, edges);\n\n        if (!actualFullEdges(seq, edges)) return;\n\n        if (!hard) {\n            if (timer.elapsed() < 2.915) {\n                pathBlockRemove(seq, edges, 2.925, 3, true);\n            }\n\n            if (timer.elapsed() < 2.925) {\n                actualBlockReplaceImprove(seq, edges, 2.940, 2, false);\n            }\n\n            if (timer.elapsed() < 2.940) {\n                actualOrOptImprove(seq, edges, 2.950, false);\n            }\n\n            if (timer.elapsed() < 2.950) {\n                actualReplaceImprove(seq, edges, 2.957, false);\n            }\n\n            if (timer.elapsed() < 2.957) {\n                pathRemove(seq, edges, 2.962, true);\n            }\n\n            updateFinalRoute(seq, edges);\n        } else {\n            if (timer.elapsed() < 2.915) {\n                pathBlockRemove(seq, edges, 2.925, 3, true);\n            }\n\n            if (timer.elapsed() < 2.925) {\n                actualTwoOptImprove(seq, edges, 2.938, true);\n            }\n\n            if (timer.elapsed() < 2.938) {\n                rerouteEdgesImprove(seq, edges, 2.946);\n            }\n\n            if (timer.elapsed() < 2.946) {\n                pathRemove(seq, edges, 2.952, true);\n            }\n\n            if (timer.elapsed() < 2.952) {\n                actualBlockReplaceImprove(seq, edges, 2.962, 2, false);\n            }\n\n            if (timer.elapsed() < 2.962) {\n                actualOrOptImprove(seq, edges, 2.968, false);\n            }\n\n            if (timer.elapsed() < 2.968) {\n                pathRemove(seq, edges, 2.972, true);\n            }\n\n            updateFinalRoute(seq, edges);\n        }\n    }\n\n    void finalLateTwoOptOpportunity() {\n        if (bestFinalSeq.empty() || timer.elapsed() > 2.960) return;\n\n        vector<int> seq = bestFinalSeq;\n        vector<vector<int>> edges = bestFinalEdges;\n        ensureEdgeCells(seq, edges);\n\n        if (!actualFullEdges(seq, edges)) return;\n\n        if (timer.elapsed() < 2.964) {\n            actualTwoOptImprove(seq, edges, 2.974, true);\n        }\n\n        if (timer.elapsed() < 2.974) {\n            rerouteEdgesImprove(seq, edges, 2.978);\n        }\n\n        if (timer.elapsed() < 2.978) {\n            pathBlockRemove(seq, edges, 2.982, 2, true);\n        }\n\n        if (timer.elapsed() < 2.982) {\n            pathRemove(seq, edges, 2.986, true);\n        }\n\n        updateFinalRoute(seq, edges);\n    }\n\n    void finalRerouteOpportunity() {\n        if (bestFinalSeq.empty() || timer.elapsed() > 2.962) return;\n\n        vector<int> seq = bestFinalSeq;\n        vector<vector<int>> edges = bestFinalEdges;\n        ensureEdgeCells(seq, edges);\n\n        if (!actualFullEdges(seq, edges)) return;\n\n        if (timer.elapsed() < 2.966) {\n            rerouteEdgesImprove(seq, edges, 2.974);\n        }\n\n        if (timer.elapsed() < 2.974) {\n            pathRemove(seq, edges, 2.982, true);\n        }\n\n        updateFinalRoute(seq, edges);\n    }\n\n    void solve() {\n        readInput();\n        buildRoadGraph();\n        buildSegments();\n        computeAPSP();\n        computeSegmentApprox();\n\n        vector<pair<double, double>> cellParams = {\n            {1.25, 0.0},\n            {1.00, 0.0},\n            {1.50, 0.0},\n            {0.75, 0.0},\n            {1.25, 30.0},\n            {1.70, 80.0}\n        };\n\n        for (int i = 0; i < (int)cellParams.size(); i++) {\n            if (i > 0 && timer.elapsed() > 2.18) break;\n\n            auto [a, l] = cellParams[i];\n            vector<int> seq = constructCellCover(a, l);\n            processCandidate(seq, i == 0);\n        }\n\n        vector<int> vcTypes = {0, 2, 3, 1, 5, 4, 6, 7};\n\n        for (int tp : vcTypes) {\n            if (timer.elapsed() > 2.34) break;\n\n            auto [selH, selV] = weightedVertexCover(tp);\n\n            vector<int> seq = constructSegmentCover(selH, selV, 1.0, 25.0);\n            processCandidate(seq, false);\n\n            if (timer.elapsed() > 2.34) break;\n\n            if (tp == 0) {\n                vector<int> seq2 = constructSegmentCover(selH, selV, 1.0, 0.0);\n                processCandidate(seq2, false);\n            }\n        }\n\n        for (int mode = 0; mode < 3; mode++) {\n            if (timer.elapsed() > 2.40) break;\n\n            auto [selH, selV] = preferenceCover(mode);\n            vector<int> seq = constructSegmentCover(selH, selV, 1.2, 10.0);\n            processCandidate(seq, false);\n        }\n\n        if (!bestSafeSeq.empty()) {\n            for (int mode = 0; mode < 2; mode++) {\n                if (timer.elapsed() > 2.43) break;\n\n                auto [selH, selV] = insertionWeightedVertexCover(bestSafeSeq, mode);\n                vector<int> seq = constructSegmentCover(selH, selV, 1.0, 15.0);\n                processCandidate(seq, false);\n            }\n        }\n\n        long long refCost = bestFinalCost;\n        if (refCost >= (1LL << 55)) refCost = bestSafeCost;\n        bool hard = (refCost < (1LL << 55) && refCost > 54LL * N);\n\n        finalPolish(hard);\n        finalActualPolish(hard);\n        finalLateTwoOptOpportunity();\n        if (!hard) finalRerouteOpportunity();\n\n        if (!bestFinalSeq.empty() &&\n            actualFullEdges(bestFinalSeq, bestFinalEdges) &&\n            validEdgePaths(bestFinalSeq, bestFinalEdges)) {\n            cout << buildOutput(bestFinalSeq, bestFinalEdges) << '\\n';\n        } else if (!bestSafeSeq.empty() && actualFull(bestSafeSeq)) {\n            vector<vector<int>> emptyEdges;\n            cout << buildOutput(bestSafeSeq, emptyEdges) << '\\n';\n        } else {\n            cout << dfsFallback() << '\\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\n    return 0;\n}","future-contest-2022-qual":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nconst int MAXN = 1000;\nconst int MAXM = 20;\nconst int MAXK = 20;\nconst int PARTICLES = 128;\n\nint N, M, K, R;\nint reqv[MAXN][MAXK];\n\nvector<int> children_[MAXN];\n\nint statusTask[MAXN]; // 0: unstarted, 1: running, 2: done\nint remDep[MAXN];\nint readyDay[MAXN];\n\nint sumReq[MAXN];\nint descCnt[MAXN];\n\ndouble baseDur[MAXN];\ndouble predDur[MAXM][MAXN];\ndouble sumPred[MAXN];\ndouble upRank_[MAXN];\n\ndouble priorSkill[MAXK];\nint initSkill[MAXK];\nint upperSkill[MAXK];\n\nstatic bitset<MAXN> reachBits[MAXN];\n\nunsigned char particleSkill[PARTICLES][MAXK];\ndouble particlePrior[PARTICLES];\ndouble particleLoss[MAXM][PARTICLES];\n\nstruct Member {\n    int skill[MAXK];\n    vector<int> obsTask;\n    vector<int> obsDur;\n    int task = -1;\n    int startDay = 0;\n};\n\nMember members_[MAXM];\n\ninline double expectedTimeFromW(int w) {\n    if (w <= 0) return 1.0;\n    if (w == 1) return 13.0 / 7.0;\n    if (w == 2) return 17.0 / 7.0;\n    if (w == 3) return 22.0 / 7.0;\n    return (double)w;\n}\n\ninline int calcW(int task, const int skill[]) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        if (reqv[task][k] > skill[k]) {\n            w += reqv[task][k] - skill[k];\n        }\n    }\n    return w;\n}\n\ninline int calcWParticle(int task, int p) {\n    int w = 0;\n    for (int k = 0; k < K; k++) {\n        int s = (int)particleSkill[p][k];\n        if (reqv[task][k] > s) {\n            w += reqv[task][k] - s;\n        }\n    }\n    return w;\n}\n\ninline double durationWithSkill(int task, const int skill[]) {\n    return expectedTimeFromW(calcW(task, skill));\n}\n\ninline double obsLoss(int w, int t) {\n    double p = expectedTimeFromW(w);\n    double diff = p - t;\n    return diff * diff;\n}\n\n// Validation-only loss. The main optimizer intentionally keeps squared loss.\ninline double intervalObsLoss(int w, int t) {\n    if (t <= 1) {\n        if (w == 0) return 0.0;\n        if (w == 1) return 0.5596157879;\n        if (w == 2) return 0.8472978604;\n        if (w == 3) return 1.2527629685;\n        if (w == 4) return 1.9459101491;\n\n        double d = (double)(w - 4);\n        return 1.9459101491 + 2.0 * d * d;\n    }\n\n    int lo = max(1, t - 3);\n    int hi = t + 3;\n\n    if (lo <= w && w <= hi) return 0.0;\n\n    int dist = (w < lo ? lo - w : w - hi);\n    return 1.0 + (double)dist * (double)dist;\n}\n\nconst double PRIOR_W = 0.003;\n\ninline double priorLossComp(int k, int v) {\n    double diff = v - priorSkill[k];\n    return PRIOR_W * diff * diff;\n}\n\ndouble skillNorm(const int skill[]) {\n    double ss = 0.0;\n    for (int k = 0; k < K; k++) ss += (double)skill[k] * skill[k];\n    return sqrt(ss);\n}\n\ndouble evaluateIntervalObjective(int j, const int skill[]) {\n    Member &mem = members_[j];\n\n    double obj = 0.0;\n    for (int k = 0; k < K; k++) {\n        obj += priorLossComp(k, skill[k]);\n    }\n\n    int O = (int)mem.obsTask.size();\n    for (int i = 0; i < O; i++) {\n        int w = calcW(mem.obsTask[i], skill);\n        obj += intervalObsLoss(w, mem.obsDur[i]);\n    }\n\n    return obj;\n}\n\nvoid generateParticles() {\n    mt19937 rng(123456789);\n    normal_distribution<double> nd(0.0, 1.0);\n\n    for (int p = 0; p < PARTICLES; p++) {\n        double z[MAXK];\n        double norm = 0.0;\n\n        for (int k = 0; k < K; k++) {\n            z[k] = fabs(nd(rng));\n            norm += z[k] * z[k];\n        }\n\n        norm = sqrt(max(norm, 1e-12));\n\n        // Stratified norm q in [20, 60], matching the official skill generator.\n        double q = 20.0 + 40.0 * ((double)p + 0.5) / (double)PARTICLES;\n\n        particlePrior[p] = 0.0;\n\n        for (int k = 0; k < K; k++) {\n            int v = (int)llround(q * z[k] / norm);\n            v = max(0, min(60, v));\n            particleSkill[p][k] = (unsigned char)v;\n            particlePrior[p] += priorLossComp(k, v);\n        }\n    }\n\n    for (int j = 0; j < MAXM; j++) {\n        for (int p = 0; p < PARTICLES; p++) {\n            particleLoss[j][p] = 0.0;\n        }\n    }\n}\n\nvoid updateParticleLoss(int member, int task, int dur) {\n    for (int p = 0; p < PARTICLES; p++) {\n        int w = calcWParticle(task, p);\n        particleLoss[member][p] += obsLoss(w, dur);\n    }\n}\n\ndouble runCoordinateDescent(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return 0.0;\n\n    vector<int> w(O);\n    for (int i = 0; i < O; i++) {\n        w[i] = calcW(mem.obsTask[i], mem.skill);\n    }\n\n    double curPrior = 0.0;\n    for (int k = 0; k < K; k++) {\n        curPrior += priorLossComp(k, mem.skill[k]);\n    }\n\n    double curObj = curPrior;\n    for (int i = 0; i < O; i++) {\n        curObj += obsLoss(w[i], mem.obsDur[i]);\n    }\n\n    const int MAX_PASS = 4;\n\n    for (int pass = 0; pass < MAX_PASS; pass++) {\n        bool improved = false;\n\n        for (int k = 0; k < K; k++) {\n            int oldVal = mem.skill[k];\n            double priorExcept = curPrior - priorLossComp(k, oldVal);\n\n            int bestVal = oldVal;\n            double bestObj = curObj;\n\n            for (int v = 0; v <= upperSkill[k]; v++) {\n                if (v == oldVal) continue;\n\n                double obj = priorExcept + priorLossComp(k, v);\n\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > v) {\n                        newContrib = reqv[task][k] - v;\n                    }\n\n                    int nw = w[i] - oldContrib + newContrib;\n                    obj += obsLoss(nw, mem.obsDur[i]);\n\n                    if (obj >= bestObj) break;\n                }\n\n                if (obj + 1e-9 < bestObj) {\n                    bestObj = obj;\n                    bestVal = v;\n                }\n            }\n\n            if (bestVal != oldVal) {\n                for (int i = 0; i < O; i++) {\n                    int task = mem.obsTask[i];\n\n                    int oldContrib = 0;\n                    if (reqv[task][k] > oldVal) {\n                        oldContrib = reqv[task][k] - oldVal;\n                    }\n\n                    int newContrib = 0;\n                    if (reqv[task][k] > bestVal) {\n                        newContrib = reqv[task][k] - bestVal;\n                    }\n\n                    w[i] += newContrib - oldContrib;\n                }\n\n                mem.skill[k] = bestVal;\n                curPrior = priorExcept + priorLossComp(k, bestVal);\n                curObj = bestObj;\n                improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return curObj;\n}\n\nvoid optimizeMember(int j) {\n    Member &mem = members_[j];\n    int O = (int)mem.obsTask.size();\n    if (O == 0) return;\n\n    // Main optimizer.\n    double obj = runCoordinateDescent(j);\n\n    // Conservative multi-start fallback.\n    int threshold = max(6, K / 2);\n    if (O >= threshold) {\n        int bestP = -1;\n        double bestObj = 1e100;\n\n        for (int p = 0; p < PARTICLES; p++) {\n            double cand = particleLoss[j][p] + particlePrior[p];\n            if (cand < bestObj) {\n                bestObj = cand;\n                bestP = p;\n            }\n        }\n\n        if (bestP >= 0 && bestObj + 0.5 < obj) {\n            int savedSkill[MAXK];\n            for (int k = 0; k < K; k++) savedSkill[k] = mem.skill[k];\n\n            double savedIntervalObj = evaluateIntervalObjective(j, savedSkill);\n\n            for (int k = 0; k < K; k++) {\n                mem.skill[k] = (int)particleSkill[bestP][k];\n            }\n\n            double candObj = runCoordinateDescent(j);\n            double candIntervalObj = evaluateIntervalObjective(j, mem.skill);\n            double norm = skillNorm(mem.skill);\n\n            double sqImprove = obj - candObj;\n            double intervalWorsen = candIntervalObj - savedIntervalObj;\n\n            bool normOK = (12.0 <= norm && norm <= 70.0);\n            bool accept = false;\n\n            if (normOK) {\n                if (sqImprove > max(0.75, 0.04 * O) && intervalWorsen <= 0.35) {\n                    accept = true;\n                }\n\n                if (sqImprove > max(8.0, 0.35 * O) && intervalWorsen <= 1.0) {\n                    accept = true;\n                }\n            }\n\n            if (!accept) {\n                for (int k = 0; k < K; k++) mem.skill[k] = savedSkill[k];\n            }\n        }\n    }\n}\n\nvoid updateMemberPredictions(int j) {\n    Member &mem = members_[j];\n\n    double nobs = (double)mem.obsTask.size();\n    double trust = 0.0;\n    if (nobs > 0) trust = nobs / (nobs + 3.0);\n\n    for (int i = 0; i < N; i++) {\n        double pSkill = durationWithSkill(i, mem.skill);\n        double np = trust * pSkill + (1.0 - trust) * baseDur[i];\n\n        sumPred[i] += np - predDur[j][i];\n        predDur[j][i] = np;\n    }\n}\n\nvoid recomputeRanks() {\n    for (int i = N - 1; i >= 0; i--) {\n        if (statusTask[i] == 2) {\n            upRank_[i] = 0.0;\n            continue;\n        }\n\n        double mx = 0.0;\n        for (int v : children_[i]) {\n            if (statusTask[v] != 2) {\n                mx = max(mx, upRank_[v]);\n            }\n        }\n\n        double avg = sumPred[i] / M;\n        upRank_[i] = avg + 0.015 * sumReq[i] + mx;\n    }\n}\n\ndouble taskPriority(int task, int day) {\n    double pr = upRank_[task];\n\n    pr += 0.015 * descCnt[task];\n    pr += 0.25 * (double)children_[task].size();\n\n    int unlock = 0;\n    for (int v : children_[task]) {\n        if (statusTask[v] == 0 && remDep[v] == 1) unlock++;\n    }\n    pr += 2.0 * unlock;\n\n    if (readyDay[task] > 0) {\n        pr += 0.015 * max(0, day - readyDay[task]);\n    }\n\n    return pr;\n}\n\ndouble edgeScore(int member, int task, double prio) {\n    double avg = sumPred[task] / M;\n    double p = predDur[member][task];\n\n    return prio + 0.4 * avg - p;\n}\n\nstruct DeferInfo {\n    bool defer = false;\n    double saving = 0.0;\n    double bestIdle = 0.0;\n    double bestAlt = 0.0;\n    double bestWait = 0.0;\n};\n\n// Conservative specialist-waiting filter.\n// It is used only when there are enough other ready tasks, so it does not\n// intentionally idle workers.\nDeferInfo getDeferInfo(int task, const vector<int> &idle, int day) {\n    DeferInfo info;\n\n    int age = 0;\n    if (readyDay[task] > 0) {\n        age = max(0, day - readyDay[task]);\n    }\n\n    // Never reserve forever.\n    if (age >= 4) return info;\n\n    double bestIdle = 1e100;\n    for (int j : idle) {\n        bestIdle = min(bestIdle, predDur[j][task]);\n    }\n\n    if (bestIdle < 10.0) return info;\n\n    double bestAlt = 1e100;\n    double bestWait = 1e100;\n\n    for (int j = 0; j < M; j++) {\n        if (members_[j].task < 0) continue;\n\n        int obs = (int)members_[j].obsTask.size();\n        if (obs < 5) continue;\n\n        int running = members_[j].task;\n        double elapsed = (double)(day - members_[j].startDay);\n        double predRun = predDur[j][running];\n\n        double wait = predRun - elapsed;\n\n        // If the current task is already overdue compared with our prediction,\n        // do not assume the member will certainly be free tomorrow.\n        if (wait < 1.0) {\n            double over = max(0.0, elapsed - predRun);\n            wait = 1.0 + 0.5 * over;\n        }\n\n        if (wait > 3.0) continue;\n\n        // Small confidence penalty for barely-known specialists.\n        double confidencePenalty = 0.0;\n        if (obs < 8) {\n            confidencePenalty = 0.45 * (8 - obs);\n        }\n\n        double total = wait + predDur[j][task] + confidencePenalty;\n\n        if (total < bestAlt) {\n            bestAlt = total;\n            bestWait = wait;\n        }\n    }\n\n    if (bestAlt > 1e90) return info;\n\n    double saving = bestIdle - bestAlt;\n\n    bool ok = (saving >= 8.0 && saving >= 0.35 * bestIdle);\n\n    // New refinement:\n    // If the task has already waited 3 days, allow one final deferral only\n    // when the specialist is almost surely imminent and the saving is large.\n    if (age >= 3) {\n        ok = ok && (bestWait <= 1.4) && (saving >= 10.0) && (saving >= 0.45 * bestIdle);\n    }\n\n    if (ok) {\n        info.defer = true;\n        info.saving = saving;\n        info.bestIdle = bestIdle;\n        info.bestAlt = bestAlt;\n        info.bestWait = bestWait;\n    }\n\n    return info;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev, cap;\n        ll cost;\n    };\n\n    int V;\n    vector<vector<Edge>> graph;\n\n    MinCostFlow(int n = 0) {\n        init(n);\n    }\n\n    void init(int n) {\n        V = n;\n        graph.assign(V, {});\n    }\n\n    void addEdge(int fr, int to, int cap, ll cost) {\n        Edge f{to, (int)graph[to].size(), cap, cost};\n        Edge r{fr, (int)graph[fr].size(), 0, -cost};\n        graph[fr].push_back(f);\n        graph[to].push_back(r);\n    }\n\n    pair<int, ll> minCostFlow(int s, int t, int maxf) {\n        const ll INF = (1LL << 62);\n\n        int flow = 0;\n        ll cost = 0;\n\n        vector<ll> h(V, 0), dist(V);\n        vector<int> prevv(V), preve(V);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INF);\n            dist[s] = 0;\n\n            priority_queue<pair<ll, int>, vector<pair<ll, int>>, greater<pair<ll, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [cd, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != cd) continue;\n\n                for (int i = 0; i < (int)graph[v].size(); i++) {\n                    Edge &e = graph[v][i];\n                    if (e.cap <= 0) continue;\n\n                    ll nd = dist[v] + e.cost + h[v] - h[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        prevv[e.to] = v;\n                        preve[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INF) break;\n\n            for (int v = 0; v < V; v++) {\n                if (dist[v] < INF) h[v] += dist[v];\n            }\n\n            int add = maxf - flow;\n            ll pathCost = 0;\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                add = min(add, e.cap);\n                pathCost += e.cost;\n            }\n\n            for (int v = t; v != s; v = prevv[v]) {\n                Edge &e = graph[prevv[v]][preve[v]];\n                e.cap -= add;\n                graph[v][e.rev].cap += add;\n            }\n\n            flow += add;\n            cost += pathCost * add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> M >> K >> R)) return 0;\n\n    for (int i = 0; i < N; i++) {\n        sumReq[i] = 0;\n        for (int k = 0; k < K; k++) {\n            cin >> reqv[i][k];\n            sumReq[i] += reqv[i][k];\n        }\n    }\n\n    for (int i = 0; i < R; i++) {\n        int u, v;\n        cin >> u >> v;\n        --u;\n        --v;\n        children_[u].push_back(v);\n        remDep[v]++;\n    }\n\n    double pi = acos(-1.0);\n    double priorComp = 40.0 * sqrt(2.0 / (pi * K));\n\n    for (int k = 0; k < K; k++) {\n        priorSkill[k] = priorComp;\n        initSkill[k] = (int)round(priorComp);\n        initSkill[k] = max(0, min(60, initSkill[k]));\n        upperSkill[k] = 60;\n    }\n\n    generateParticles();\n\n    for (int j = 0; j < M; j++) {\n        for (int k = 0; k < K; k++) {\n            members_[j].skill[k] = initSkill[k];\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        baseDur[i] = durationWithSkill(i, initSkill);\n        sumPred[i] = 0.0;\n    }\n\n    for (int j = 0; j < M; j++) {\n        for (int i = 0; i < N; i++) {\n            predDur[j][i] = baseDur[i];\n            sumPred[i] += predDur[j][i];\n        }\n    }\n\n    for (int i = N - 1; i >= 0; i--) {\n        for (int v : children_[i]) {\n            reachBits[i] |= reachBits[v];\n            reachBits[i].set(v);\n        }\n        descCnt[i] = (int)reachBits[i].count();\n    }\n\n    for (int i = 0; i < N; i++) {\n        statusTask[i] = 0;\n        readyDay[i] = (remDep[i] == 0 ? 1 : -1);\n    }\n\n    static double prioArr[MAXN];\n\n    for (int day = 1;; day++) {\n        recomputeRanks();\n\n        vector<int> idle;\n        for (int j = 0; j < M; j++) {\n            if (members_[j].task < 0) idle.push_back(j);\n        }\n\n        vector<int> readyAll;\n        for (int i = 0; i < N; i++) {\n            if (statusTask[i] == 0 && remDep[i] == 0) {\n                readyAll.push_back(i);\n            }\n        }\n\n        for (int task : readyAll) {\n            prioArr[task] = taskPriority(task, day);\n        }\n\n        vector<int> readyTasks = readyAll;\n\n        // Specialist deferral.\n        if (!idle.empty() && readyAll.size() > idle.size()) {\n            vector<int> keep;\n            vector<pair<double, int>> deferCands; // value for inclusion, task\n\n            for (int task : readyAll) {\n                DeferInfo info = getDeferInfo(task, idle, day);\n\n                if (!info.defer) {\n                    keep.push_back(task);\n                } else {\n                    // If too many tasks are deferrable, still keep a few of the\n                    // most urgent / least beneficial-to-defer ones as candidates.\n                    int age = 0;\n                    if (readyDay[task] > 0) age = max(0, day - readyDay[task]);\n\n                    double includeValue = prioArr[task] - info.saving + 2.0 * age;\n                    deferCands.push_back({includeValue, task});\n                }\n            }\n\n            if ((int)keep.size() >= (int)idle.size()) {\n                readyTasks.swap(keep);\n            } else {\n                sort(deferCands.begin(), deferCands.end(), greater<pair<double, int>>());\n\n                int targetSize = min((int)readyAll.size(), (int)idle.size() + 3);\n\n                for (auto [val, task] : deferCands) {\n                    if ((int)keep.size() >= targetSize) break;\n                    keep.push_back(task);\n                }\n\n                if ((int)keep.size() >= (int)idle.size()) {\n                    readyTasks.swap(keep);\n                }\n            }\n        }\n\n        vector<pair<int, int>> assignments;\n\n        if (!idle.empty() && !readyTasks.empty()) {\n            vector<int> sortedReady = readyTasks;\n            sort(sortedReady.begin(), sortedReady.end(), [&](int a, int b) {\n                if (prioArr[a] != prioArr[b]) return prioArr[a] > prioArr[b];\n                return a < b;\n            });\n\n            vector<int> candidates;\n            vector<char> inCand(N, 0);\n\n            auto addCandidate = [&](int task) {\n                if (!inCand[task]) {\n                    inCand[task] = 1;\n                    candidates.push_back(task);\n                }\n            };\n\n            int topC = min((int)sortedReady.size(), max(200, (int)idle.size() * 10));\n            for (int i = 0; i < topC; i++) {\n                addCandidate(sortedReady[i]);\n            }\n\n            const int BEST_PER_MEMBER = 10;\n\n            for (int member : idle) {\n                priority_queue<\n                    pair<double, int>,\n                    vector<pair<double, int>>,\n                    greater<pair<double, int>>\n                > pq;\n\n                for (int task : readyTasks) {\n                    double sc = edgeScore(member, task, prioArr[task]);\n                    if ((int)pq.size() < BEST_PER_MEMBER) {\n                        pq.push({sc, task});\n                    } else if (sc > pq.top().first) {\n                        pq.pop();\n                        pq.push({sc, task});\n                    }\n                }\n\n                while (!pq.empty()) {\n                    addCandidate(pq.top().second);\n                    pq.pop();\n                }\n            }\n\n            int I = (int)idle.size();\n            int C = (int)candidates.size();\n            int F = min(I, min(C, (int)readyTasks.size()));\n\n            if (F > 0) {\n                int S = 0;\n                int memberBase = 1;\n                int taskBase = memberBase + I;\n                int T = taskBase + C;\n\n                MinCostFlow mcf(T + 1);\n\n                for (int i = 0; i < I; i++) {\n                    mcf.addEdge(S, memberBase + i, 1, 0);\n                }\n\n                for (int c = 0; c < C; c++) {\n                    mcf.addEdge(taskBase + c, T, 1, 0);\n                }\n\n                const ll SCALE = 1000;\n                const ll OFFSET = 1000000000000000LL;\n\n                for (int i = 0; i < I; i++) {\n                    int member = idle[i];\n                    for (int c = 0; c < C; c++) {\n                        int task = candidates[c];\n                        double sc = edgeScore(member, task, prioArr[task]);\n                        ll isc = llround(sc * SCALE);\n                        ll cost = OFFSET - isc;\n                        if (cost < 0) cost = 0;\n                        mcf.addEdge(memberBase + i, taskBase + c, 1, cost);\n                    }\n                }\n\n                mcf.minCostFlow(S, T, F);\n\n                for (int i = 0; i < I; i++) {\n                    int node = memberBase + i;\n\n                    for (auto &e : mcf.graph[node]) {\n                        if (e.to >= taskBase && e.to < taskBase + C && e.cap == 0) {\n                            int member = idle[i];\n                            int task = candidates[e.to - taskBase];\n\n                            if (members_[member].task < 0 &&\n                                statusTask[task] == 0 &&\n                                remDep[task] == 0) {\n                                assignments.push_back({member, task});\n                            }\n                            break;\n                        }\n                    }\n                }\n            }\n        }\n\n        for (auto [member, task] : assignments) {\n            members_[member].task = task;\n            members_[member].startDay = day;\n            statusTask[task] = 1;\n        }\n\n        cout << assignments.size();\n        for (auto [member, task] : assignments) {\n            cout << ' ' << member + 1 << ' ' << task + 1;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int nFinished;\n        if (!(cin >> nFinished)) return 0;\n        if (nFinished == -1) return 0;\n\n        for (int x = 0; x < nFinished; x++) {\n            int f;\n            cin >> f;\n            --f;\n\n            int task = members_[f].task;\n            if (task < 0) continue;\n\n            int dur = day - members_[f].startDay + 1;\n\n            statusTask[task] = 2;\n            members_[f].task = -1;\n\n            members_[f].obsTask.push_back(task);\n            members_[f].obsDur.push_back(dur);\n\n            updateParticleLoss(f, task, dur);\n            optimizeMember(f);\n            updateMemberPredictions(f);\n\n            for (int v : children_[task]) {\n                remDep[v]--;\n                if (remDep[v] == 0 && statusTask[v] == 0) {\n                    readyDay[v] = day + 1;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc006":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int NORD = 1000;\nstatic constexpr int OFF = 1000;\nstatic constexpr int NID = 2001;\nstatic constexpr int INF = 1e9;\n\nint X[NID], Y[NID];\nint orderCentral[NORD + 1];\nvector<unsigned short> distMat;\n\ninline int distId(int a, int b) {\n    return distMat[a * NID + b];\n}\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ull) : x(seed) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int m) {\n        return (int)(next() % (uint64_t)m);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct InsertRes {\n    int delta;\n    int p;\n    int q;\n};\n\nstruct Solution {\n    vector<int> route;\n    bitset<NORD + 1> selected;\n    int len = INF;\n};\n\nint routeCost(const vector<int>& route) {\n    int s = 0;\n    for (int i = 0; i + 1 < (int)route.size(); i++) {\n        s += distId(route[i], route[i + 1]);\n    }\n    return s;\n}\n\nint selectedCount(const Solution& sol) {\n    return (int)sol.selected.count();\n}\n\nvector<int> selectedList(const Solution& sol) {\n    vector<int> v;\n    v.reserve(50);\n    for (int i = 1; i <= NORD; i++) {\n        if (sol.selected.test(i)) v.push_back(i);\n    }\n    return v;\n}\n\nInsertRes bestInsertion(const vector<int>& route, int oid) {\n    static constexpr int MAXG = 205;\n\n    int G = (int)route.size() - 1;\n    int P = oid;\n    int D = OFF + oid;\n    int pd = distId(P, D);\n\n    int addP[MAXG], addD[MAXG], consec[MAXG];\n    int suf[MAXG + 1], sufIdx[MAXG + 1];\n\n    for (int g = 0; g < G; g++) {\n        int A = route[g];\n        int B = route[g + 1];\n        int base = distId(A, B);\n\n        int dAP = distId(A, P);\n        int dPB = distId(P, B);\n        int dAD = distId(A, D);\n        int dDB = distId(D, B);\n\n        addP[g] = dAP + dPB - base;\n        addD[g] = dAD + dDB - base;\n        consec[g] = dAP + pd + dDB - base;\n    }\n\n    suf[G] = INF;\n    sufIdx[G] = -1;\n\n    for (int g = G - 1; g >= 0; g--) {\n        if (addD[g] <= suf[g + 1]) {\n            suf[g] = addD[g];\n            sufIdx[g] = g;\n        } else {\n            suf[g] = suf[g + 1];\n            sufIdx[g] = sufIdx[g + 1];\n        }\n    }\n\n    InsertRes best{INF, 0, 0};\n\n    for (int p = 0; p < G; p++) {\n        if (consec[p] < best.delta) {\n            best = {consec[p], p, p};\n        }\n\n        if (p + 1 < G) {\n            int cost = addP[p] + suf[p + 1];\n            if (cost < best.delta) {\n                best = {cost, p, sufIdx[p + 1]};\n            }\n        }\n    }\n\n    return best;\n}\n\nvoid insertOrder(vector<int>& route, int oid, const InsertRes& res) {\n    int P = oid;\n    int D = OFF + oid;\n\n    if (res.q == res.p) {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.p + 2, D);\n    } else {\n        route.insert(route.begin() + res.p + 1, P);\n        route.insert(route.begin() + res.q + 2, D);\n    }\n}\n\nSolution buildGreedy(int seed) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    auto add = [&](int oid, const InsertRes& res) {\n        insertOrder(sol.route, oid, res);\n        sol.selected.set(oid);\n        sol.len += res.delta;\n        cnt++;\n    };\n\n    if (seed > 0) {\n        InsertRes res = bestInsertion(sol.route, seed);\n        add(seed, res);\n    }\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        add(bestOid, best);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildFromPool(const vector<int>& pool) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    int cnt = 0;\n\n    while (cnt < 50) {\n        int bestOid = -1;\n        int bestTie = INF;\n        InsertRes best{INF, 0, 0};\n\n        for (int oid : pool) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int tie = orderCentral[oid];\n\n            if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                best = res;\n                bestOid = oid;\n                bestTie = tie;\n            }\n        }\n\n        if (bestOid == -1) {\n            for (int oid = 1; oid <= NORD; oid++) {\n                if (sol.selected.test(oid)) continue;\n\n                InsertRes res = bestInsertion(sol.route, oid);\n                int tie = orderCentral[oid];\n\n                if (res.delta < best.delta || (res.delta == best.delta && tie < bestTie)) {\n                    best = res;\n                    bestOid = oid;\n                    bestTie = tie;\n                }\n            }\n        }\n\n        insertOrder(sol.route, bestOid, best);\n        sol.selected.set(bestOid);\n        sol.len += best.delta;\n        cnt++;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution buildRandomizedGreedy(const vector<int>& pool, XorShift& rng, int topR, int bias) {\n    struct Choice {\n        int rank;\n        int oid;\n        InsertRes res;\n    };\n\n    topR = min(topR, 16);\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected.reset();\n    sol.len = 0;\n\n    for (int cnt = 0; cnt < 50; cnt++) {\n        Choice top[16];\n        int ts = 0;\n\n        auto consider = [&](int oid) {\n            if (sol.selected.test(oid)) return;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rank = res.delta + bias * orderCentral[oid] / 100;\n\n            Choice c{rank, oid, res};\n\n            if (ts < topR) {\n                top[ts++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < ts; i++) {\n                    if (top[i].rank > top[worst].rank) worst = i;\n                }\n                if (c.rank < top[worst].rank) top[worst] = c;\n            }\n        };\n\n        for (int oid : pool) consider(oid);\n\n        if (ts == 0) {\n            for (int oid = 1; oid <= NORD; oid++) consider(oid);\n        }\n\n        sort(top, top + ts, [](const Choice& a, const Choice& b) {\n            if (a.rank != b.rank) return a.rank < b.rank;\n            return a.oid < b.oid;\n        });\n\n        int pick = 0;\n        if (ts > 1) {\n            int r = rng.nextInt(100);\n            if (r < 55) pick = 0;\n            else if (r < 75) pick = min(1, ts - 1);\n            else if (r < 90) pick = min(2, ts - 1);\n            else pick = rng.nextInt(ts);\n        }\n\n        Choice c = top[pick];\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nvector<Solution> buildBeam(const vector<int>& pool, int W, int K, int bias) {\n    struct State {\n        vector<int> route;\n        bitset<NORD + 1> selected;\n        int len;\n    };\n\n    struct Choice {\n        int rank;\n        int len;\n        int oid;\n        InsertRes res;\n    };\n\n    K = min(K, 16);\n\n    vector<State> beam;\n    State init;\n    init.route = {0, 0};\n    init.selected.reset();\n    init.len = 0;\n    beam.push_back(init);\n\n    for (int step = 0; step < 50; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int oid) {\n                if (st.selected.test(oid)) return;\n\n                InsertRes res = bestInsertion(st.route, oid);\n                int nl = st.len + res.delta;\n                int rank = nl + bias * orderCentral[oid] / 100;\n\n                Choice c{rank, nl, oid, res};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int oid : pool) consider(oid);\n\n            if (ts == 0) {\n                for (int oid = 1; oid <= NORD; oid++) consider(oid);\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                if (a.rank != b.rank) return a.rank < b.rank;\n                return a.oid < b.oid;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                insertOrder(ch.route, top[i].oid, top[i].res);\n                ch.selected.set(top[i].oid);\n                ch.len = top[i].len;\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            return a.len < b.len;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    vector<Solution> res;\n\n    for (auto& st : beam) {\n        if ((int)st.selected.count() != 50) continue;\n\n        Solution sol;\n        sol.route = std::move(st.route);\n        sol.selected = st.selected;\n        sol.len = routeCost(sol.route);\n        res.push_back(std::move(sol));\n    }\n\n    sort(res.begin(), res.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    return res;\n}\n\nvector<int> removeOrderRoute(const vector<int>& route, int oid) {\n    vector<int> nr;\n    nr.reserve(route.size() - 2);\n\n    int P = oid;\n    int D = OFF + oid;\n\n    for (int id : route) {\n        if (id != P && id != D) nr.push_back(id);\n    }\n\n    return nr;\n}\n\nbool twoOptDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int delPos[NORD + 1];\n        for (int i = 0; i <= NORD; i++) delPos[i] = -1;\n\n        for (int i = 0; i < n; i++) {\n            int id = sol.route[i];\n            if (id > OFF) delPos[id - OFF] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        bool timeout = false;\n\n        for (int l = 1; l <= n - 3; l++) {\n            if ((l & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            int minDelivery = INF;\n\n            for (int r = l; r <= n - 2; r++) {\n                int node = sol.route[r];\n\n                if (1 <= node && node <= NORD) {\n                    minDelivery = min(minDelivery, delPos[node]);\n                }\n\n                if (r == l) continue;\n                if (minDelivery <= r) continue;\n\n                int A = sol.route[l - 1];\n                int B = sol.route[l];\n                int C = sol.route[r];\n                int D = sol.route[r + 1];\n\n                int delta = distId(A, C) + distId(B, D) -\n                            distId(A, B) - distId(C, D);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta < 0) {\n            reverse(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSegmentMoveFast(const vector<int>& route, const int pos[], int l, int r, int k) {\n    int oids[8];\n    int cnt = 0;\n\n    for (int i = l; i <= r; i++) {\n        int id = route[i];\n        int oid = (id <= OFF ? id : id - OFF);\n\n        bool exists = false;\n        for (int j = 0; j < cnt; j++) {\n            if (oids[j] == oid) {\n                exists = true;\n                break;\n            }\n        }\n\n        if (!exists) oids[cnt++] = oid;\n    }\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        bool inP = (l <= pp && pp <= r);\n        bool inD = (l <= dd && dd <= r);\n\n        if (inP && !inD) {\n            if (!(k < dd)) return false;\n        } else if (!inP && inD) {\n            if (!(k >= pp)) return false;\n        }\n    }\n\n    return true;\n}\n\nbool orOptDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestL = -1;\n        int bestR = -1;\n        int bestK = -1;\n\n        int checks = 0;\n        bool timeout = false;\n\n        for (int len = 1; len <= maxSegLen; len++) {\n            for (int l = 1; l + len - 1 <= n - 2; l++) {\n                int r = l + len - 1;\n\n                int oldLR = distId(sol.route[l - 1], sol.route[l]) +\n                            distId(sol.route[r], sol.route[r + 1]);\n\n                for (int k = 0; k <= n - 2; k++) {\n                    if (++checks % 8192 == 0 && timer.elapsed() >= deadline) {\n                        timeout = true;\n                        break;\n                    }\n\n                    if (k >= l - 1 && k <= r) continue;\n\n                    int delta =\n                        distId(sol.route[l - 1], sol.route[r + 1]) +\n                        distId(sol.route[k], sol.route[l]) +\n                        distId(sol.route[r], sol.route[k + 1]) -\n                        oldLR -\n                        distId(sol.route[k], sol.route[k + 1]);\n\n                    if (delta >= bestDelta) continue;\n                    if (!validSegmentMoveFast(sol.route, pos, l, r, k)) continue;\n\n                    bestDelta = delta;\n                    bestL = l;\n                    bestR = r;\n                    bestK = k;\n                }\n\n                if (timeout) break;\n            }\n            if (timeout) break;\n        }\n\n        if (bestDelta < 0) {\n            int segLen = bestR - bestL + 1;\n            vector<int> seg(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n\n            if (bestK < bestL) {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                sol.route.insert(sol.route.begin() + bestK + 1, seg.begin(), seg.end());\n            } else {\n                sol.route.erase(sol.route.begin() + bestL, sol.route.begin() + bestR + 1);\n                int ins = bestK - segLen + 1;\n                sol.route.insert(sol.route.begin() + ins, seg.begin(), seg.end());\n            }\n\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool validSwapFast(const vector<int>& route, const int pos[], int i, int j) {\n    int a = route[i];\n    int b = route[j];\n\n    int oids[2];\n    int cnt = 0;\n\n    auto addOid = [&](int id) {\n        int oid = (id <= OFF ? id : id - OFF);\n        for (int z = 0; z < cnt; z++) {\n            if (oids[z] == oid) return;\n        }\n        oids[cnt++] = oid;\n    };\n\n    addOid(a);\n    addOid(b);\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = pos[oid];\n        int dd = pos[OFF + oid];\n\n        if (pp == i) pp = j;\n        else if (pp == j) pp = i;\n\n        if (dd == i) dd = j;\n        else if (dd == j) dd = i;\n\n        if (pp >= dd) return false;\n    }\n\n    return true;\n}\n\nbool swapDescent(Solution& sol, Timer& timer, double deadline) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) pos[sol.route[i]] = i;\n\n        int bestDelta = 0;\n        int bestI = -1;\n        int bestJ = -1;\n\n        bool timeout = false;\n\n        for (int i = 1; i <= n - 3; i++) {\n            if ((i & 7) == 0 && timer.elapsed() >= deadline) {\n                timeout = true;\n                break;\n            }\n\n            for (int j = i + 1; j <= n - 2; j++) {\n                int u = sol.route[i];\n                int v = sol.route[j];\n\n                int delta;\n\n                if (i + 1 == j) {\n                    int A = sol.route[i - 1];\n                    int B = sol.route[j + 1];\n\n                    delta = distId(A, v) + distId(v, u) + distId(u, B)\n                          - distId(A, u) - distId(u, v) - distId(v, B);\n                } else {\n                    int Ai = sol.route[i - 1];\n                    int Bi = sol.route[i + 1];\n                    int Aj = sol.route[j - 1];\n                    int Bj = sol.route[j + 1];\n\n                    delta = distId(Ai, v) + distId(v, Bi) +\n                            distId(Aj, u) + distId(u, Bj) -\n                            distId(Ai, u) - distId(u, Bi) -\n                            distId(Aj, v) - distId(v, Bj);\n                }\n\n                if (delta >= bestDelta) continue;\n                if (!validSwapFast(sol.route, pos, i, j)) continue;\n\n                bestDelta = delta;\n                bestI = i;\n                bestJ = j;\n            }\n        }\n\n        if (bestDelta < 0) {\n            swap(sol.route[bestI], sol.route[bestJ]);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    return any;\n}\n\nbool routeDescent(Solution& sol, Timer& timer, double deadline, int maxSegLen = 3, bool doSwap = false) {\n    bool any = false;\n\n    for (int rep = 0; rep < 5 && timer.elapsed() < deadline; rep++) {\n        bool moved = false;\n\n        if (twoOptDescent(sol, timer, deadline)) moved = true;\n        if (timer.elapsed() >= deadline) break;\n\n        if (orOptDescent(sol, timer, deadline, maxSegLen)) moved = true;\n        if (timer.elapsed() >= deadline) break;\n\n        if (doSwap && swapDescent(sol, timer, deadline)) moved = true;\n\n        if (!moved) break;\n        any = true;\n    }\n\n    sol.len = routeCost(sol.route);\n    return any;\n}\n\nvoid applyBlockSwap(vector<int>& route, int i, int l1, int j, int l2) {\n    int r = i + l1;\n    int s = j + l2;\n\n    vector<int> nr;\n    nr.reserve(route.size());\n\n    nr.insert(nr.end(), route.begin(), route.begin() + i);\n    nr.insert(nr.end(), route.begin() + j, route.begin() + s);\n    nr.insert(nr.end(), route.begin() + r, route.begin() + j);\n    nr.insert(nr.end(), route.begin() + i, route.begin() + r);\n    nr.insert(nr.end(), route.begin() + s, route.end());\n\n    route.swap(nr);\n}\n\nbool validBlockSwapFast(const vector<int>& route, const int pos[], int i, int l1, int j, int l2) {\n    int r = i + l1 - 1;\n    int s = j + l2 - 1;\n\n    int oids[16];\n    int cnt = 0;\n\n    auto addOid = [&](int id) {\n        int oid = (id <= OFF ? id : id - OFF);\n        for (int z = 0; z < cnt; z++) {\n            if (oids[z] == oid) return;\n        }\n        oids[cnt++] = oid;\n    };\n\n    for (int p = i; p <= r; p++) addOid(route[p]);\n    for (int p = j; p <= s; p++) addOid(route[p]);\n\n    auto trans = [&](int p) {\n        if (i <= p && p <= r) {\n            return p + (j - i) + (l2 - l1);\n        }\n        if (j <= p && p <= s) {\n            return i + (p - j);\n        }\n        if (r < p && p < j) {\n            return p + (l2 - l1);\n        }\n        return p;\n    };\n\n    for (int z = 0; z < cnt; z++) {\n        int oid = oids[z];\n\n        int pp = trans(pos[oid]);\n        int dd = trans(pos[OFF + oid]);\n\n        if (pp >= dd) return false;\n    }\n\n    return true;\n}\n\nbool blockSwapDescent(Solution& sol, Timer& timer, double deadline, int maxLen) {\n    bool any = false;\n\n    while (timer.elapsed() < deadline) {\n        int n = (int)sol.route.size();\n\n        int pos[NID];\n        for (int i = 0; i < n; i++) {\n            pos[sol.route[i]] = i;\n        }\n\n        int bestDelta = 0;\n        int bestI = -1;\n        int bestL1 = -1;\n        int bestJ = -1;\n        int bestL2 = -1;\n\n        int checks = 0;\n        bool timeout = false;\n\n        for (int l1 = 1; l1 <= maxLen; l1++) {\n            for (int l2 = 1; l2 <= maxLen; l2++) {\n                if (l1 == 1 && l2 == 1) continue;\n\n                for (int i = 1; i + l1 - 1 <= n - 2; i++) {\n                    int r = i + l1 - 1;\n\n                    for (int j = r + 1; j + l2 - 1 <= n - 2; j++) {\n                        if (++checks % 8192 == 0 && timer.elapsed() >= deadline) {\n                            timeout = true;\n                            break;\n                        }\n\n                        int s = j + l2 - 1;\n                        int delta;\n\n                        if (r + 1 == j) {\n                            int A = sol.route[i - 1];\n                            int S1F = sol.route[i];\n                            int S1L = sol.route[r];\n                            int S2F = sol.route[j];\n                            int S2L = sol.route[s];\n                            int D = sol.route[s + 1];\n\n                            delta =\n                                distId(A, S2F) +\n                                distId(S2L, S1F) +\n                                distId(S1L, D) -\n                                distId(A, S1F) -\n                                distId(S1L, S2F) -\n                                distId(S2L, D);\n                        } else {\n                            int A = sol.route[i - 1];\n                            int S1F = sol.route[i];\n                            int S1L = sol.route[r];\n                            int B = sol.route[r + 1];\n                            int C = sol.route[j - 1];\n                            int S2F = sol.route[j];\n                            int S2L = sol.route[s];\n                            int D = sol.route[s + 1];\n\n                            delta =\n                                distId(A, S2F) +\n                                distId(S2L, B) +\n                                distId(C, S1F) +\n                                distId(S1L, D) -\n                                distId(A, S1F) -\n                                distId(S1L, B) -\n                                distId(C, S2F) -\n                                distId(S2L, D);\n                        }\n\n                        if (delta >= bestDelta) continue;\n                        if (!validBlockSwapFast(sol.route, pos, i, l1, j, l2)) continue;\n\n                        bestDelta = delta;\n                        bestI = i;\n                        bestL1 = l1;\n                        bestJ = j;\n                        bestL2 = l2;\n                    }\n\n                    if (timeout) break;\n                }\n\n                if (timeout) break;\n            }\n\n            if (timeout) break;\n        }\n\n        if (bestDelta < 0) {\n            applyBlockSwap(sol.route, bestI, bestL1, bestJ, bestL2);\n            sol.len += bestDelta;\n            any = true;\n        } else {\n            break;\n        }\n\n        if (timeout) break;\n    }\n\n    sol.len = routeCost(sol.route);\n    return any;\n}\n\nbool findAndApplyBestPairMove(Solution& sol, Timer& timer, double deadline) {\n    int cur = sol.len;\n    vector<int> sel = selectedList(sol);\n\n    int bestNewLen = cur;\n    int bestRem = -1;\n    int bestIns = -1;\n\n    bool stop = false;\n\n    for (int idx = 0; idx < (int)sel.size(); idx++) {\n        if (timer.elapsed() >= deadline) break;\n\n        int rem = sel[idx];\n        vector<int> tmp = removeOrderRoute(sol.route, rem);\n        int lenTmp = routeCost(tmp);\n\n        {\n            InsertRes res = bestInsertion(tmp, rem);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = rem;\n            }\n        }\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if ((oid & 63) == 0 && timer.elapsed() >= deadline) {\n                stop = true;\n                break;\n            }\n\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(tmp, oid);\n            int nl = lenTmp + res.delta;\n\n            if (nl < bestNewLen) {\n                bestNewLen = nl;\n                bestRem = rem;\n                bestIns = oid;\n            }\n        }\n\n        if (stop) break;\n    }\n\n    if (bestRem == -1) return false;\n\n    vector<int> tmp = removeOrderRoute(sol.route, bestRem);\n\n    if (bestIns != bestRem) {\n        sol.selected.reset(bestRem);\n        sol.selected.set(bestIns);\n    }\n\n    InsertRes res = bestInsertion(tmp, bestIns);\n    insertOrder(tmp, bestIns, res);\n\n    sol.route.swap(tmp);\n    sol.len = routeCost(sol.route);\n\n    return sol.len < cur;\n}\n\nvoid localImprove(Solution& sol, Timer& timer, double deadline) {\n    while (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 3, false);\n\n        if (timer.elapsed() >= deadline) break;\n\n        bool moved = findAndApplyBestPairMove(sol, timer, deadline);\n        if (!moved) break;\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nSolution rebuildFixedOrder(const Solution& base, vector<int> orders) {\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    for (int oid : orders) {\n        InsertRes res = bestInsertion(sol.route, oid);\n        insertOrder(sol.route, oid, res);\n        sol.len += res.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildFixedGreedy(const Solution& base) {\n    vector<int> orders = selectedList(base);\n    int m = (int)orders.size();\n\n    Solution sol;\n    sol.route = {0, 0};\n    sol.selected = base.selected;\n    sol.len = 0;\n\n    vector<char> used(m, 0);\n\n    for (int cnt = 0; cnt < m; cnt++) {\n        int bestIdx = -1;\n        InsertRes best{INF, 0, 0};\n\n        for (int i = 0; i < m; i++) {\n            if (used[i]) continue;\n\n            InsertRes res = bestInsertion(sol.route, orders[i]);\n            if (res.delta < best.delta) {\n                best = res;\n                bestIdx = i;\n            }\n        }\n\n        used[bestIdx] = 1;\n        insertOrder(sol.route, orders[bestIdx], best);\n        sol.len += best.delta;\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nSolution rebuildSequentialBeam(const Solution& base, int W, int K) {\n    vector<int> orders = selectedList(base);\n    int M = (int)orders.size();\n    if (M != 50) return base;\n\n    struct State {\n        uint64_t picked;\n        uint64_t delivered;\n        int last;\n        int cost;\n        int eval;\n        vector<int> route;\n    };\n\n    struct Choice {\n        int rank;\n        int node;\n        int idx;\n        int type;\n        int add;\n    };\n\n    uint64_t fullMask = (1ULL << M) - 1ULL;\n\n    vector<State> beam;\n    State init;\n    init.picked = 0;\n    init.delivered = 0;\n    init.last = 0;\n    init.cost = 0;\n    init.eval = 0;\n    init.route = {0};\n    beam.push_back(init);\n\n    for (int step = 0; step < 2 * M; step++) {\n        vector<State> children;\n        children.reserve(beam.size() * K);\n\n        for (const State& st : beam) {\n            Choice top[16];\n            int ts = 0;\n\n            auto consider = [&](int node, int idx, int type) {\n                int add = distId(st.last, node);\n                int rank = add + distId(node, 0) / 6;\n\n                Choice c{rank, node, idx, type, add};\n\n                if (ts < K) {\n                    top[ts++] = c;\n                } else {\n                    int worst = 0;\n                    for (int i = 1; i < ts; i++) {\n                        if (top[i].rank > top[worst].rank) worst = i;\n                    }\n                    if (c.rank < top[worst].rank) top[worst] = c;\n                }\n            };\n\n            for (int j = 0; j < M; j++) {\n                uint64_t bit = 1ULL << j;\n\n                if (!(st.picked & bit)) {\n                    consider(orders[j], j, 0);\n                } else if (!(st.delivered & bit)) {\n                    consider(OFF + orders[j], j, 1);\n                }\n            }\n\n            sort(top, top + ts, [](const Choice& a, const Choice& b) {\n                return a.rank < b.rank;\n            });\n\n            for (int i = 0; i < ts; i++) {\n                State ch = st;\n                uint64_t bit = 1ULL << top[i].idx;\n\n                if (top[i].type == 0) ch.picked |= bit;\n                else ch.delivered |= bit;\n\n                ch.last = top[i].node;\n                ch.cost += top[i].add;\n                ch.eval = ch.cost + distId(ch.last, 0);\n                ch.route.push_back(top[i].node);\n\n                children.push_back(std::move(ch));\n            }\n        }\n\n        sort(children.begin(), children.end(), [](const State& a, const State& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)children.size() > W) children.resize(W);\n        beam.swap(children);\n    }\n\n    int best = -1;\n    int bestCost = INF;\n\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (beam[i].delivered != fullMask) continue;\n\n        int c = beam[i].cost + distId(beam[i].last, 0);\n        if (c < bestCost) {\n            bestCost = c;\n            best = i;\n        }\n    }\n\n    if (best == -1) return base;\n\n    Solution sol;\n    sol.selected = base.selected;\n    sol.route = std::move(beam[best].route);\n    sol.route.push_back(0);\n    sol.len = routeCost(sol.route);\n\n    return sol;\n}\n\nvoid tryRebuilds(Solution& sol, XorShift& rng, Timer& timer, double deadline) {\n    if (timer.elapsed() >= deadline) return;\n\n    {\n        Solution g = rebuildFixedGreedy(sol);\n        routeDescent(g, timer, min(deadline, timer.elapsed() + 0.030), 2, false);\n        if (g.len < sol.len) sol = std::move(g);\n    }\n\n    if (timer.elapsed() < deadline) {\n        Solution b = rebuildSequentialBeam(sol, 60, 6);\n        routeDescent(b, timer, min(deadline, timer.elapsed() + 0.035), 2, false);\n        if (b.len < sol.len) sol = std::move(b);\n    }\n\n    for (int it = 0; it < 2 && timer.elapsed() < deadline; it++) {\n        vector<int> orders = selectedList(sol);\n\n        for (int i = (int)orders.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(orders[i], orders[j]);\n        }\n\n        Solution r = rebuildFixedOrder(sol, orders);\n        routeDescent(r, timer, min(deadline, timer.elapsed() + 0.025), 2, false);\n\n        if (r.len < sol.len) sol = std::move(r);\n    }\n\n    sol.len = routeCost(sol.route);\n}\n\nstruct Cand {\n    int rankCost;\n    int oid;\n    InsertRes res;\n};\n\nSolution ruinRecreate(const Solution& base, int k, XorShift& rng, Timer& timer, double deadline) {\n    Solution sol = base;\n    vector<int> sel = selectedList(base);\n    k = min(k, (int)sel.size());\n\n    vector<char> rem(NORD + 1, 0);\n    vector<int> toRemove;\n\n    int strategy = rng.nextInt(4);\n\n    if (strategy == 0) {\n        vector<pair<int, int>> savings;\n        savings.reserve(sel.size());\n\n        for (int oid : sel) {\n            vector<int> tmp = removeOrderRoute(base.route, oid);\n            int l = routeCost(tmp);\n            savings.push_back({base.len - l, oid});\n        }\n\n        sort(savings.begin(), savings.end(), [](const auto& a, const auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        int topLimit = min(25, (int)savings.size());\n\n        while ((int)toRemove.size() < k) {\n            int idx;\n            if (rng.nextInt(100) < 75) idx = rng.nextInt(topLimit);\n            else idx = rng.nextInt((int)savings.size());\n\n            int oid = savings[idx].second;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 1) {\n        while ((int)toRemove.size() < k) {\n            int oid = sel[rng.nextInt((int)sel.size())];\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else if (strategy == 2) {\n        int pos[NID];\n        for (int i = 0; i < (int)base.route.size(); i++) {\n            pos[base.route[i]] = i;\n        }\n\n        int seed = sel[rng.nextInt((int)sel.size())];\n        int sp = pos[seed];\n        int sd = pos[OFF + seed];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int pp = pos[oid];\n            int dd = pos[OFF + oid];\n\n            int sc = min({\n                abs(pp - sp),\n                abs(pp - sd),\n                abs(dd - sp),\n                abs(dd - sd)\n            });\n\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    } else {\n        int seed = sel[rng.nextInt((int)sel.size())];\n\n        vector<pair<int, int>> near;\n        near.reserve(sel.size());\n\n        for (int oid : sel) {\n            int sc1 = distId(seed, oid) + distId(OFF + seed, OFF + oid);\n            int sc2 = distId(seed, OFF + oid) + distId(OFF + seed, oid);\n            int sc = min(sc1, sc2);\n            near.push_back({sc, oid});\n        }\n\n        sort(near.begin(), near.end());\n\n        for (auto [sc, oid] : near) {\n            if ((int)toRemove.size() >= k) break;\n            if (!rem[oid]) {\n                rem[oid] = 1;\n                toRemove.push_back(oid);\n            }\n        }\n    }\n\n    for (int oid : toRemove) {\n        sol.selected.reset(oid);\n    }\n\n    vector<int> nr;\n    nr.reserve(base.route.size());\n\n    for (int id : base.route) {\n        if (id == 0) {\n            nr.push_back(id);\n        } else {\n            int oid = (id <= OFF ? id : id - OFF);\n            if (!rem[oid]) nr.push_back(id);\n        }\n    }\n\n    sol.route.swap(nr);\n    sol.len = routeCost(sol.route);\n\n    int removedPenalty = 8 + rng.nextInt(45);\n\n    for (int t = 0; t < k; t++) {\n        static constexpr int R = 7;\n        Cand top[R];\n        int topSize = 0;\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            if (sol.selected.test(oid)) continue;\n\n            InsertRes res = bestInsertion(sol.route, oid);\n            int rankCost = res.delta + (rem[oid] ? removedPenalty : 0) + rng.nextInt(7);\n\n            Cand c{rankCost, oid, res};\n\n            if (topSize < R) {\n                top[topSize++] = c;\n            } else {\n                int worst = 0;\n                for (int i = 1; i < R; i++) {\n                    if (top[i].rankCost > top[worst].rankCost) worst = i;\n                }\n                if (c.rankCost < top[worst].rankCost) top[worst] = c;\n            }\n        }\n\n        sort(top, top + topSize, [](const Cand& a, const Cand& b) {\n            return a.rankCost < b.rankCost;\n        });\n\n        int pick = 0;\n        if (topSize > 1) {\n            int roll = rng.nextInt(100);\n            if (roll < 62) pick = 0;\n            else if (roll < 82) pick = min(1, topSize - 1);\n            else if (roll < 93) pick = min(2, topSize - 1);\n            else pick = rng.nextInt(topSize);\n        }\n\n        Cand c = top[pick];\n\n        insertOrder(sol.route, c.oid, c.res);\n        sol.selected.set(c.oid);\n        sol.len += c.res.delta;\n    }\n\n    if (timer.elapsed() < deadline) {\n        routeDescent(sol, timer, deadline, 2, false);\n    }\n\n    sol.len = routeCost(sol.route);\n    return sol;\n}\n\nbool validate(const Solution& sol) {\n    if (selectedCount(sol) != 50) return false;\n    if (sol.route.empty()) return false;\n    if (sol.route.front() != 0 || sol.route.back() != 0) return false;\n\n    vector<int> pp(NORD + 1, -1), dd(NORD + 1, -1);\n\n    for (int i = 0; i < (int)sol.route.size(); i++) {\n        int id = sol.route[i];\n\n        if (id == 0) continue;\n\n        if (1 <= id && id <= NORD) {\n            pp[id] = i;\n        } else if (OFF < id && id <= OFF + NORD) {\n            dd[id - OFF] = i;\n        } else {\n            return false;\n        }\n    }\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (!sol.selected.test(oid)) continue;\n        if (pp[oid] == -1 || dd[oid] == -1) return false;\n        if (pp[oid] >= dd[oid]) return false;\n    }\n\n    return true;\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    for (int i = 1; i <= NORD; i++) {\n        int a, b, c, d;\n        cin >> a >> b >> c >> d;\n\n        X[i] = a;\n        Y[i] = b;\n        X[OFF + i] = c;\n        Y[OFF + i] = d;\n    }\n\n    distMat.assign(NID * NID, 0);\n\n    for (int i = 0; i < NID; i++) {\n        for (int j = 0; j <= i; j++) {\n            int v = abs(X[i] - X[j]) + abs(Y[i] - Y[j]);\n            distMat[i * NID + j] = distMat[j * NID + i] = (unsigned short)v;\n        }\n    }\n\n    vector<pair<int, int>> firstCost;\n    firstCost.reserve(NORD);\n\n    for (int oid = 1; oid <= NORD; oid++) {\n        int dP = distId(0, oid);\n        int dD = distId(0, OFF + oid);\n        int pd = distId(oid, OFF + oid);\n\n        orderCentral[oid] = dP + dD;\n        firstCost.push_back({dP + pd + dD, oid});\n    }\n\n    sort(firstCost.begin(), firstCost.end());\n\n    Timer timer;\n    XorShift rng(1234567891234567ull);\n\n    vector<int> allIds(NORD);\n    iota(allIds.begin(), allIds.end(), 1);\n\n    vector<Solution> candidates;\n\n    auto addCandidate = [&](Solution sol) {\n        if (selectedCount(sol) == 50) {\n            sol.len = routeCost(sol.route);\n            candidates.push_back(std::move(sol));\n        }\n    };\n\n    addCandidate(buildGreedy(firstCost[0].second));\n\n    const double INIT_DEAD = 0.52;\n\n    for (int idx = 1; idx < 10 && timer.elapsed() < 0.22; idx++) {\n        addCandidate(buildGreedy(firstCost[idx].second));\n    }\n\n    if (timer.elapsed() < 0.32) {\n        auto sols = buildBeam(allIds, 8, 4, 0);\n        for (int i = 0; i < (int)sols.size() && i < 4; i++) {\n            addCandidate(std::move(sols[i]));\n        }\n    }\n\n    vector<vector<int>> sortedModes;\n\n    for (int mode = 0; mode < 8; mode++) {\n        vector<pair<int, int>> score;\n        score.reserve(NORD);\n\n        for (int oid = 1; oid <= NORD; oid++) {\n            int dP = distId(0, oid);\n            int dD = distId(0, OFF + oid);\n            int pd = distId(oid, OFF + oid);\n\n            int linf = max({\n                abs(X[oid] - 400),\n                abs(Y[oid] - 400),\n                abs(X[OFF + oid] - 400),\n                abs(Y[OFF + oid] - 400)\n            });\n\n            int mid = abs(X[oid] + X[OFF + oid] - 800) +\n                      abs(Y[oid] + Y[OFF + oid] - 800);\n\n            int dxSpan = abs(X[oid] - X[OFF + oid]);\n            int dySpan = abs(Y[oid] - Y[OFF + oid]);\n\n            int sc;\n\n            if (mode == 0) {\n                sc = dP + dD;\n            } else if (mode == 1) {\n                sc = max(dP, dD) * 2000 + dP + dD;\n            } else if (mode == 2) {\n                sc = dP + dD + pd;\n            } else if (mode == 3) {\n                sc = linf * 2000 + dP + dD;\n            } else if (mode == 4) {\n                sc = max(dP, dD) * 3 + min(dP, dD);\n            } else if (mode == 5) {\n                sc = dP + dD + mid;\n            } else if (mode == 6) {\n                sc = linf * 3000 + pd;\n            } else {\n                sc = dP + dD + max(dxSpan, dySpan);\n            }\n\n            score.push_back({sc, oid});\n        }\n\n        sort(score.begin(), score.end());\n\n        vector<int> ord;\n        ord.reserve(NORD);\n\n        for (auto [sc, oid] : score) ord.push_back(oid);\n        sortedModes.push_back(std::move(ord));\n    }\n\n    vector<int> poolSizes = {55, 70, 90, 130, 200, 300};\n\n    for (int mode = 0; mode < (int)sortedModes.size(); mode++) {\n        for (int ps : poolSizes) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            ps = min(ps, (int)sortedModes[mode].size());\n            vector<int> pool(sortedModes[mode].begin(), sortedModes[mode].begin() + ps);\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    vector<int> centers = {250, 300, 350, 400, 450, 500, 550};\n\n    for (int cx : centers) {\n        for (int cy : centers) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                int lp = abs(X[oid] - cx) + abs(Y[oid] - cy);\n                int ld = abs(X[OFF + oid] - cx) + abs(Y[OFF + oid] - cy);\n\n                int infp = max(abs(X[oid] - cx), abs(Y[oid] - cy));\n                int infd = max(abs(X[OFF + oid] - cx), abs(Y[OFF + oid] - cy));\n\n                int centerPenalty = abs(cx - 400) + abs(cy - 400);\n                int sc = max(infp, infd) * 3000 + max(lp, ld) * 3 + centerPenalty * 20;\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            int ps = 110;\n            vector<int> pool;\n            pool.reserve(ps);\n\n            for (int i = 0; i < ps; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    for (int sx : {-1, 1}) {\n        for (int sy : {-1, 1}) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                auto outsidePoint = [&](int id) {\n                    int px = sx * (X[id] - 400);\n                    int py = sy * (Y[id] - 400);\n                    return max(0, -px) + max(0, -py);\n                };\n\n                int out = outsidePoint(oid) + outsidePoint(OFF + oid);\n                int far = max(distId(0, oid), distId(0, OFF + oid));\n                int sc = out * 10000 + far * 10 + orderCentral[oid];\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            vector<int> pool;\n            for (int i = 0; i < 130; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    for (int axis = 0; axis < 2; axis++) {\n        for (int sgn : {-1, 1}) {\n            if (timer.elapsed() >= INIT_DEAD) break;\n\n            vector<pair<int, int>> score;\n            score.reserve(NORD);\n\n            for (int oid = 1; oid <= NORD; oid++) {\n                auto outsidePoint = [&](int id) {\n                    int v = (axis == 0 ? X[id] - 400 : Y[id] - 400);\n                    return max(0, -sgn * v);\n                };\n\n                int out = outsidePoint(oid) + outsidePoint(OFF + oid);\n                int far = max(distId(0, oid), distId(0, OFF + oid));\n                int sc = out * 10000 + far * 10 + orderCentral[oid];\n\n                score.push_back({sc, oid});\n            }\n\n            sort(score.begin(), score.end());\n\n            vector<int> pool;\n            for (int i = 0; i < 170; i++) pool.push_back(score[i].second);\n\n            addCandidate(buildFromPool(pool));\n        }\n    }\n\n    while (timer.elapsed() < INIT_DEAD && (int)candidates.size() < 65) {\n        if (rng.nextInt(2) == 0) {\n            addCandidate(buildRandomizedGreedy(allIds, rng, 8, 0));\n        } else {\n            int mi = rng.nextInt((int)sortedModes.size());\n            int ps = min(300, (int)sortedModes[mi].size());\n            vector<int> pool(sortedModes[mi].begin(), sortedModes[mi].begin() + ps);\n            addCandidate(buildRandomizedGreedy(pool, rng, 8, 2));\n        }\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    if (candidates.empty()) {\n        candidates.push_back(buildGreedy(firstCost[0].second));\n    }\n\n    const double QUICK_DEAD = 0.72;\n\n    for (int i = 0; i < (int)candidates.size() && i < 14 && timer.elapsed() < QUICK_DEAD; i++) {\n        double sub = min(QUICK_DEAD, timer.elapsed() + 0.020);\n        routeDescent(candidates[i], timer, sub, 2, false);\n    }\n\n    sort(candidates.begin(), candidates.end(), [](const Solution& a, const Solution& b) {\n        return a.len < b.len;\n    });\n\n    Solution bestOverall = candidates[0];\n\n    const double LOCAL_DEAD = 1.40;\n\n    vector<int> startIdx;\n    int nCand = (int)candidates.size();\n\n    int topBase = min(4, nCand);\n    for (int i = 0; i < topBase; i++) {\n        startIdx.push_back(i);\n    }\n\n    if ((int)startIdx.size() < min(5, nCand)) {\n        int lim = min(nCand, 30);\n        int bestDiverse = -1;\n        long long bestScore = LLONG_MIN;\n\n        for (int idx = topBase; idx < lim; idx++) {\n            int minDiff = 10000;\n\n            for (int si : startIdx) {\n                auto diff = candidates[idx].selected ^ candidates[si].selected;\n                minDiff = min(minDiff, (int)diff.count());\n            }\n\n            int excess = candidates[idx].len - candidates[0].len;\n            long long score = (long long)minDiff * 40 - excess;\n\n            if (score > bestScore) {\n                bestScore = score;\n                bestDiverse = idx;\n            }\n        }\n\n        if (bestDiverse != -1) {\n            startIdx.push_back(bestDiverse);\n        }\n    }\n\n    for (int i = 0; i < nCand && (int)startIdx.size() < min(5, nCand); i++) {\n        bool used = false;\n        for (int x : startIdx) {\n            if (x == i) {\n                used = true;\n                break;\n            }\n        }\n        if (!used) startIdx.push_back(i);\n    }\n\n    for (int idx : startIdx) {\n        if (timer.elapsed() >= LOCAL_DEAD) break;\n\n        Solution sol = candidates[idx];\n\n        double sub = min(LOCAL_DEAD, timer.elapsed() + 0.15);\n        localImprove(sol, timer, sub);\n\n        if (sol.len < bestOverall.len) {\n            bestOverall = std::move(sol);\n        }\n    }\n\n    const double REBUILD_DEAD = 1.48;\n\n    if (timer.elapsed() < REBUILD_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, REBUILD_DEAD);\n        localImprove(bestOverall, timer, REBUILD_DEAD);\n    }\n\n    Solution current = bestOverall;\n\n    const double LNS_DEAD = 1.88;\n\n    while (timer.elapsed() < LNS_DEAD) {\n        if (LNS_DEAD - timer.elapsed() < 0.045) break;\n\n        int roll = rng.nextInt(100);\n        int k;\n\n        if (roll < 58) {\n            k = 3 + rng.nextInt(5);\n        } else if (roll < 90) {\n            k = 8 + rng.nextInt(6);\n        } else {\n            k = 14 + rng.nextInt(7);\n        }\n\n        const Solution& base = (rng.nextInt(5) == 0 ? current : bestOverall);\n\n        Solution cand = ruinRecreate(base, k, rng, timer, LNS_DEAD);\n\n        if (cand.len < bestOverall.len) {\n            bestOverall = std::move(cand);\n\n            double sub = min(LNS_DEAD, timer.elapsed() + 0.08);\n            localImprove(bestOverall, timer, sub);\n\n            if (timer.elapsed() < LNS_DEAD) {\n                tryRebuilds(bestOverall, rng, timer, min(LNS_DEAD, timer.elapsed() + 0.04));\n            }\n\n            current = bestOverall;\n        } else {\n            int diff = cand.len - current.len;\n            double progress = min(1.0, timer.elapsed() / LNS_DEAD);\n            double temp = 45.0 * (1.0 - progress) + 3.0;\n\n            if (diff < 0 || rng.nextDouble() < exp(-(double)diff / temp)) {\n                current = std::move(cand);\n            }\n\n            if (current.len > bestOverall.len + 350) {\n                current = bestOverall;\n            }\n        }\n    }\n\n    const double FINAL_DEAD = 1.94;\n\n    if (timer.elapsed() < FINAL_DEAD) {\n        tryRebuilds(bestOverall, rng, timer, min(FINAL_DEAD, timer.elapsed() + 0.045));\n    }\n\n    if (timer.elapsed() < FINAL_DEAD) {\n        routeDescent(bestOverall, timer, min(FINAL_DEAD, timer.elapsed() + 0.030), 4, true);\n    }\n\n    if (timer.elapsed() < FINAL_DEAD) {\n        if (blockSwapDescent(bestOverall, timer, min(FINAL_DEAD, timer.elapsed() + 0.030), 2)) {\n            routeDescent(bestOverall, timer, min(FINAL_DEAD, timer.elapsed() + 0.025), 4, true);\n        }\n    }\n\n    routeDescent(bestOverall, timer, FINAL_DEAD, 4, true);\n\n    bestOverall.len = routeCost(bestOverall.route);\n\n    if (!validate(bestOverall)) {\n        bestOverall = buildGreedy(firstCost[0].second);\n    }\n\n    cout << 50;\n    for (int oid = 1; oid <= NORD; oid++) {\n        if (bestOverall.selected.test(oid)) {\n            cout << ' ' << oid;\n        }\n    }\n    cout << '\\n';\n\n    cout << bestOverall.route.size();\n    for (int id : bestOverall.route) {\n        cout << ' ' << X[id] << ' ' << Y[id];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc007":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int N = 400;\nstatic constexpr int M = 1995;\n\nstatic constexpr int FIRST_SAMPLES = 64;\nstatic constexpr int MAX_SAMPLES = 256;\nstatic constexpr int BLOCK_SIZE = 64;\n\nstatic constexpr int INF = 1e9;\n\nstatic constexpr double BASE_ADAPT_PART = 0.88;\nstatic constexpr double Q_BLEND = 0.12;\n\nstatic constexpr int YMAX = 20000;\n\nstruct DSU {\n    int p[N];\n    int comps;\n\n    void init() {\n        comps = N;\n        for (int i = 0; i < N; i++) p[i] = -1;\n    }\n\n    inline int find(int x) {\n        while (p[x] >= 0) {\n            int y = p[x];\n            if (p[y] >= 0) p[x] = p[y];\n            x = p[x];\n        }\n        return x;\n    }\n\n    inline bool same(int a, int b) {\n        return find(a) == find(b);\n    }\n\n    inline bool unite(int a, int b) {\n        a = find(a);\n        b = find(b);\n        if (a == b) return false;\n        if (p[a] > p[b]) swap(a, b);\n        p[a] += p[b];\n        p[b] = a;\n        comps--;\n        return true;\n    }\n};\n\nstruct SplitMix64 {\n    uint64_t x;\n\n    SplitMix64(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int randint(int l, int r) {\n        return l + int(next() % uint64_t(r - l + 1));\n    }\n};\n\nint X[N], Y[N];\nint U[M], V[M], D[M];\n\nstatic int sampleW[MAX_SAMPLES][M];\nstatic int orderSample[MAX_SAMPLES][M];\nstatic int orderD[M];\n\nstatic double onlineY[YMAX + 1];\n\nstatic inline double online_y_from_offline_mean(double yoff) {\n    if (yoff <= 0.0) return 0.0;\n    if (yoff >= 0.5) return 0.5;\n\n    double k = 1.0 / yoff - 1.0;\n    if (k <= 1.0) return 0.5;\n\n    if (k >= YMAX) {\n        return 2.0 / (k + 3.0);\n    }\n\n    int a = int(floor(k));\n    double f = k - a;\n\n    if (a < 1) return 0.5;\n    if (a + 1 > YMAX) return 2.0 / (k + 3.0);\n\n    return onlineY[a] * (1.0 - f) + onlineY[a + 1] * f;\n}\n\nstatic inline double sample_quantile(const int* vals, int cnt, double p) {\n    static int tmp[MAX_SAMPLES];\n\n    for (int i = 0; i < cnt; i++) tmp[i] = vals[i];\n    sort(tmp, tmp + cnt);\n\n    if (cnt == 1) return tmp[0];\n\n    p = clamp(p, 0.0, 1.0);\n    double pos = p * double(cnt - 1);\n    int a = int(floor(pos));\n    double f = pos - a;\n\n    if (a >= cnt - 1) return tmp[cnt - 1];\n\n    return tmp[a] * (1.0 - f) + tmp[a + 1] * f;\n}\n\nint bottleneck_baseD(int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = orderD[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return D[e];\n        }\n    }\n\n    return INF;\n}\n\nint bottleneck_sample(int s, int cur, int u, int v, const DSU& accepted) {\n    DSU tmp = accepted;\n\n    const int* ord = orderSample[s];\n    const int* w = sampleW[s];\n\n    for (int pos = 0; pos < M; pos++) {\n        int e = ord[pos];\n        if (e <= cur) continue;\n\n        if (tmp.unite(U[e], V[e])) {\n            if (tmp.same(u, v)) return w[e];\n        }\n    }\n\n    return INF;\n}\n\ndouble make_threshold(\n    double mc,\n    double lo,\n    int idx,\n    int acceptedEdges,\n    const int* vals,\n    int cnt\n) {\n    double hi = 3.0 * lo;\n    double range = hi - lo;\n\n    if (mc < lo) mc = lo;\n    if (mc > hi) mc = hi;\n\n    double z = (mc - lo) / range;\n    z = clamp(z, 0.0, 1.0);\n\n    double target = double(idx + 1) * double(N - 1) / double(M);\n    double deficit = target - acceptedEdges;\n\n    double threshold;\n\n    if (z < 0.5) {\n        double adapt = BASE_ADAPT_PART;\n\n        if (deficit > 4.0) {\n            adapt -= min(0.16, 0.012 * (deficit - 4.0));\n        } else if (deficit < -8.0) {\n            adapt += min(0.09, 0.008 * (-deficit - 8.0));\n        }\n\n        adapt = clamp(adapt, 0.70, 0.97);\n\n        double yon = online_y_from_offline_mean(z);\n\n        // Stable fallback:\n        // threshold = mc + 0.22 * (2*lo - mc)\n        // normalized: 0.11 + 0.78*z\n        double linear = 0.11 + 0.78 * z;\n        if (linear > 0.5) linear = 0.5;\n\n        double tnorm = adapt * yon + (1.0 - adapt) * linear;\n        threshold = lo + range * tnorm;\n\n        // Moderate empirical distribution-shape correction.\n        if (cnt >= 16) {\n            double p;\n\n            if (z <= 1e-12 || yon <= 1e-12) {\n                p = 0.865;\n            } else {\n                double kEff = 1.0 / z - 1.0;\n                if (kEff < 1.0) kEff = 1.0;\n\n                double remBase = max(1e-15, 1.0 - yon);\n                double logRemain = kEff * log(remBase);\n\n                if (logRemain < -50.0) p = 1.0;\n                else p = 1.0 - exp(logRemain);\n\n                p = clamp(p, 0.50, 0.875);\n            }\n\n            double q = sample_quantile(vals, cnt, p);\n\n            double qw = Q_BLEND;\n            if (deficit > 4.0) qw *= 0.55;\n            if (deficit < -8.0) qw = min(0.22, qw * 1.25);\n\n            threshold = threshold * (1.0 - qw) + q * qw;\n        }\n    } else {\n        // Scarce-alternative case.  The sampled marginal mean is stable.\n        threshold = mc;\n\n        // Distribution-shape-aware far-ahead correction.\n        // If mean > median, rare bad future samples are inflating mc, so being\n        // slightly more selective is safer.  If median > mean, future is usually\n        // expensive, so weaken the correction.\n        if (deficit < -11.0) {\n            double over = -deficit - 11.0;\n            double down = min(0.020, 0.00130 * over);\n\n            double zfac = 1.0 - 0.45 * clamp((z - 0.70) / 0.30, 0.0, 1.0);\n\n            double shapeFac = 1.0;\n            if (cnt >= 16) {\n                double med = sample_quantile(vals, cnt, 0.50);\n                double diff = (mc - med) / range;\n                shapeFac = clamp(0.85 + 2.50 * diff, 0.35, 1.35);\n            }\n\n            threshold *= (1.0 - down * zfac * shapeFac);\n        }\n    }\n\n    // Safety correction against falling too far behind.\n    if (deficit > 8.0) {\n        double mult = 1.0 + 0.0035 * (deficit - 8.0);\n        if (mult > 1.07) mult = 1.07;\n        threshold *= mult;\n    }\n\n    if (threshold < lo) threshold = lo;\n    if (threshold > hi) threshold = hi;\n\n    return threshold;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    onlineY[1] = 0.5;\n    for (int i = 2; i <= YMAX; i++) {\n        onlineY[i] = onlineY[i - 1] - 0.5 * onlineY[i - 1] * onlineY[i - 1];\n    }\n\n    uint64_t seed = 0x123456789abcdefULL;\n\n    auto mix_seed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n\n    for (int i = 0; i < N; i++) {\n        cin >> X[i] >> Y[i];\n        mix_seed(uint64_t(X[i] + 1009));\n        mix_seed(uint64_t(Y[i] + 9176));\n    }\n\n    for (int i = 0; i < M; i++) {\n        cin >> U[i] >> V[i];\n\n        long long dx = X[U[i]] - X[V[i]];\n        long long dy = Y[U[i]] - Y[V[i]];\n        D[i] = int(sqrt(double(dx * dx + dy * dy)) + 0.5);\n\n        mix_seed(uint64_t(U[i] + 1));\n        mix_seed(uint64_t(V[i] + 1));\n        mix_seed(uint64_t(D[i] + 1));\n    }\n\n    SplitMix64 rng(seed);\n\n    vector<int> perm(BLOCK_SIZE);\n    iota(perm.begin(), perm.end(), 0);\n\n    // Independent stratified samples.\n    for (int e = 0; e < M; e++) {\n        int R = 2 * D[e] + 1;\n\n        for (int block = 0; block < MAX_SAMPLES / BLOCK_SIZE; block++) {\n            iota(perm.begin(), perm.end(), 0);\n\n            for (int i = BLOCK_SIZE - 1; i > 0; i--) {\n                int j = rng.randint(0, i);\n                swap(perm[i], perm[j]);\n            }\n\n            for (int s = 0; s < BLOCK_SIZE; s++) {\n                long long numerator = 1LL * (2 * perm[s] + 1) * R;\n                int k = int(numerator / (2LL * BLOCK_SIZE));\n\n                if (k < 0) k = 0;\n                if (k >= R) k = R - 1;\n\n                sampleW[block * BLOCK_SIZE + s][e] = D[e] + k;\n            }\n        }\n    }\n\n    vector<int> ids(M);\n\n    for (int s = 0; s < MAX_SAMPLES; s++) {\n        iota(ids.begin(), ids.end(), 0);\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (sampleW[s][a] != sampleW[s][b]) return sampleW[s][a] < sampleW[s][b];\n            return a < b;\n        });\n\n        for (int i = 0; i < M; i++) orderSample[s][i] = ids[i];\n    }\n\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (D[a] != D[b]) return D[a] < D[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < M; i++) orderD[i] = ids[i];\n\n    DSU accepted;\n    accepted.init();\n\n    for (int i = 0; i < M; i++) {\n        int l;\n        cin >> l;\n\n        int ans = 0;\n\n        if (!accepted.same(U[i], V[i])) {\n            int base = bottleneck_baseD(i, U[i], V[i], accepted);\n\n            if (base >= INF) {\n                ans = 1;\n            } else {\n                int loInt = base;\n                int hiInt = 3 * base;\n\n                if (l <= loInt) {\n                    ans = 1;\n                } else if (l > hiInt) {\n                    ans = 0;\n                } else {\n                    int vals[MAX_SAMPLES];\n\n                    long long sum = 0;\n                    long long sumsq = 0;\n\n                    for (int s = 0; s < FIRST_SAMPLES; s++) {\n                        int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                        if (b >= INF) b = hiInt;\n\n                        vals[s] = b;\n                        sum += b;\n                        sumsq += 1LL * b * b;\n                    }\n\n                    double mc = double(sum) / FIRST_SAMPLES;\n                    int acceptedEdges = N - accepted.comps;\n\n                    double threshold = make_threshold(\n                        mc,\n                        double(loInt),\n                        i,\n                        acceptedEdges,\n                        vals,\n                        FIRST_SAMPLES\n                    );\n\n                    double var = double(sumsq) / FIRST_SAMPLES - mc * mc;\n                    if (var < 0.0) var = 0.0;\n\n                    double se = sqrt(var / FIRST_SAMPLES);\n\n                    // Extra samples only when the decision is close.\n                    double margin = max(4.0, 2.4 * se + 0.012 * double(loInt));\n\n                    if (fabs(double(l) - threshold) <= margin) {\n                        for (int s = FIRST_SAMPLES; s < MAX_SAMPLES; s++) {\n                            int b = bottleneck_sample(s, i, U[i], V[i], accepted);\n                            if (b >= INF) b = hiInt;\n\n                            vals[s] = b;\n                            sum += b;\n                        }\n\n                        mc = double(sum) / MAX_SAMPLES;\n\n                        threshold = make_threshold(\n                            mc,\n                            double(loInt),\n                            i,\n                            acceptedEdges,\n                            vals,\n                            MAX_SAMPLES\n                        );\n                    }\n\n                    if (double(l) <= threshold) ans = 1;\n                }\n            }\n\n            if (ans) accepted.unite(U[i], V[i]);\n        }\n\n        cout << ans << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc008":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int G = 30;\nconst int INF = 1e9;\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\nchar DIR_CH[4] = {'U', 'D', 'L', 'R'};\n\nint dirId(char ch) {\n    ch = toupper(ch);\n    if (ch == 'U') return 0;\n    if (ch == 'D') return 1;\n    if (ch == 'L') return 2;\n    return 3;\n}\n\nbool inside(int r, int c) {\n    return 0 <= r && r < G && 0 <= c && c < G;\n}\n\nstruct Pet {\n    int r, c, t;\n};\n\npair<int,int> toPhysCoord(int r, int c, int ori) {\n    if (ori == 0) return {r, c};             // corridor = bottom\n    if (ori == 1) return {G - 1 - r, c};     // corridor = top\n    if (ori == 2) return {c, r};             // corridor = right\n    return {c, G - 1 - r};                   // corridor = left\n}\n\npair<int,int> toLogCoord(int pr, int pc, int ori) {\n    if (ori == 0) return {pr, pc};\n    if (ori == 1) return {G - 1 - pr, pc};\n    if (ori == 2) return {pc, pr};\n    return {G - 1 - pc, pr};\n}\n\nint chooseOrientation(const vector<Pet>& petsPhys, const vector<pair<int,int>>& humansPhys) {\n    double best = 1e100;\n    int bestOri = 0;\n\n    for (int ori = 0; ori < 4; ori++) {\n        double cost = 0.0;\n\n        for (auto p : petsPhys) {\n            auto [r, c] = toLogCoord(p.r, p.c, ori);\n            int distCorr = G - 1 - r;\n\n            double w = 1.0;\n            if (p.t == 4) w = 3.0;\n            else if (p.t == 3) w = 1.5;\n            else if (p.t == 5) w = 1.4;\n            else if (p.t == 2) w = 1.2;\n\n            int near = max(0, 12 - distCorr);\n            cost += w * near * near;\n            if (r >= 28) cost += 100.0 * w;\n        }\n\n        for (auto h : humansPhys) {\n            auto [r, c] = toLogCoord(h.first, h.second, ori);\n            int bestStand = 100;\n            for (int s = 2; s <= 26; s += 4) {\n                bestStand = min(bestStand, abs(c - s));\n            }\n            cost += 0.5 * (G - 1 - r) + 0.2 * bestStand;\n        }\n\n        if (cost < best) {\n            best = cost;\n            bestOri = ori;\n        }\n    }\n\n    return bestOri;\n}\n\nstruct Task {\n    int stand;\n    vector<int> walls;\n    int assigned = -1; // -1: free, >=0: human id, -2: finished\n};\n\nstruct HState {\n    int task = -1;\n    int phase = 0;\n    int wait = 0;\n    int home = 0;\n};\n\nclass Solver {\npublic:\n    int N, M, ori;\n    int turnNo = 0;\n\n    vector<Pet> pets;\n    vector<pair<int,int>> humans;\n\n    bool blocked[G][G]{};\n    bool petOcc[G][G]{};\n    bool humanOcc[G][G]{};\n    bool resBuild[G][G]{};\n    bool resMove[G][G]{};\n\n    vector<Task> tasks;\n    vector<HState> hs;\n\n    char logToPhys[256]{};\n    char physToLog[256]{};\n\n    static constexpr int FREE = 0;\n    static constexpr int GO = 1;\n    static constexpr int UP = 2;\n    static constexpr int DOWN = 3;\n    static constexpr int RET = 4;\n\n    static constexpr int ASSIGN_LIMIT = 190;\n    static constexpr int BUILD_LIMIT = 265;\n    static constexpr int WAIT_UNTIL = 230;\n    static constexpr int WAIT_LIMIT = 2;\n\n    Solver(int n,\n           const vector<Pet>& petsPhys,\n           int m,\n           const vector<pair<int,int>>& humansPhys,\n           int orientation)\n        : N(n), M(m), ori(orientation)\n    {\n        initDirectionMaps();\n\n        pets.resize(N);\n        for (int i = 0; i < N; i++) {\n            auto [r, c] = toLogCoord(petsPhys[i].r, petsPhys[i].c, ori);\n            pets[i] = {r, c, petsPhys[i].t};\n        }\n\n        humans.resize(M);\n        for (int i = 0; i < M; i++) {\n            humans[i] = toLogCoord(humansPhys[i].first, humansPhys[i].second, ori);\n        }\n\n        initTasks();\n\n        hs.resize(M);\n        for (int i = 0; i < M; i++) {\n            hs[i].home = (i + 1) * G / (M + 1);\n        }\n    }\n\n    void initDirectionMaps() {\n        memset(logToPhys, 0, sizeof(logToPhys));\n        memset(physToLog, 0, sizeof(physToLog));\n\n        int br = 15, bc = 15;\n        for (char ch : string(\"UDLR\")) {\n            int d = dirId(ch);\n            auto p1 = toPhysCoord(br, bc, ori);\n            auto p2 = toPhysCoord(br + DR[d], bc + DC[d], ori);\n            int rr = p2.first - p1.first;\n            int cc = p2.second - p1.second;\n\n            char pc = '?';\n            if (rr == -1 && cc == 0) pc = 'U';\n            if (rr == 1 && cc == 0) pc = 'D';\n            if (rr == 0 && cc == -1) pc = 'L';\n            if (rr == 0 && cc == 1) pc = 'R';\n\n            logToPhys[(int)ch] = pc;\n            physToLog[(int)pc] = ch;\n        }\n    }\n\n    void initTasks() {\n        // Stable vertical-cage layout.\n        for (int s = 2; s <= 26; s += 4) {\n            Task t;\n            t.stand = s;\n            t.walls = {s - 1, s + 1};\n            tasks.push_back(t);\n        }\n    }\n\n    void buildOcc() {\n        memset(petOcc, 0, sizeof(petOcc));\n        memset(humanOcc, 0, sizeof(humanOcc));\n\n        for (auto &p : pets) {\n            if (inside(p.r, p.c)) petOcc[p.r][p.c] = true;\n        }\n        for (auto &h : humans) {\n            if (inside(h.first, h.second)) humanOcc[h.first][h.second] = true;\n        }\n    }\n\n    void resetReservations() {\n        memset(resBuild, 0, sizeof(resBuild));\n        memset(resMove, 0, sizeof(resMove));\n    }\n\n    bool canBuild(int i, char lowerDir) {\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (petOcc[r][c]) return false;\n        if (humanOcc[r][c]) return false;\n        if (resMove[r][c]) return false;\n\n        for (int k = 0; k < 4; k++) {\n            int nr = r + DR[k], nc = c + DC[k];\n            if (inside(nr, nc) && petOcc[nr][nc]) return false;\n        }\n\n        return true;\n    }\n\n    bool canMove(int i, char upperDir) {\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        if (!inside(r, c)) return false;\n        if (blocked[r][c]) return false;\n        if (resBuild[r][c]) return false;\n        return true;\n    }\n\n    bool issueBuild(int i, char lowerDir, vector<char>& act) {\n        lowerDir = tolower(lowerDir);\n        if (!canBuild(i, lowerDir)) return false;\n\n        int d = dirId(lowerDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = lowerDir;\n        resBuild[r][c] = true;\n        return true;\n    }\n\n    bool issueMove(int i, char upperDir, vector<char>& act) {\n        upperDir = toupper(upperDir);\n        if (!canMove(i, upperDir)) return false;\n\n        int d = dirId(upperDir);\n        int r = humans[i].first + DR[d];\n        int c = humans[i].second + DC[d];\n\n        act[i] = upperDir;\n        resMove[r][c] = true;\n        return true;\n    }\n\n    bool taskComplete(int tid) {\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) return false;\n            }\n        }\n        return true;\n    }\n\n    int countRemainingBuilds(int tid) {\n        int cnt = 0;\n        for (int wc : tasks[tid].walls) {\n            for (int r = 0; r <= 28; r++) {\n                if (!blocked[r][wc]) cnt++;\n            }\n        }\n        return cnt;\n    }\n\n    int shortestDist(pair<int,int> st, pair<int,int> goal) {\n        if (!inside(goal.first, goal.second)) return INF;\n        if (blocked[goal.first][goal.second]) return INF;\n\n        int dist[G][G];\n        for (int r = 0; r < G; r++) {\n            for (int c = 0; c < G; c++) dist[r][c] = -1;\n        }\n\n        queue<pair<int,int>> q;\n        dist[st.first][st.second] = 0;\n        q.push(st);\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            if (r == goal.first && c == goal.second) return dist[r][c];\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (dist[nr][nc] != -1) continue;\n\n                dist[nr][nc] = dist[r][c] + 1;\n                q.push({nr, nc});\n            }\n        }\n\n        return INF;\n    }\n\n    char bfsMove(int i, const vector<pair<int,int>>& goals) {\n        bool goal[G][G]{};\n        int goalCnt = 0;\n\n        for (auto [r, c] : goals) {\n            if (!inside(r, c)) continue;\n            if (blocked[r][c]) continue;\n            if (resBuild[r][c]) continue;\n            if (!goal[r][c]) {\n                goal[r][c] = true;\n                goalCnt++;\n            }\n        }\n\n        if (goalCnt == 0) return '.';\n\n        int sr = humans[i].first;\n        int sc = humans[i].second;\n\n        if (goal[sr][sc]) return '.';\n\n        bool vis[G][G]{};\n        char first[G][G]{};\n\n        queue<pair<int,int>> q;\n        vis[sr][sc] = true;\n        q.push({sr, sc});\n\n        while (!q.empty()) {\n            auto [r, c] = q.front();\n            q.pop();\n\n            for (int d = 0; d < 4; d++) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (!inside(nr, nc)) continue;\n                if (blocked[nr][nc]) continue;\n                if (resBuild[nr][nc]) continue;\n                if (vis[nr][nc]) continue;\n\n                vis[nr][nc] = true;\n                first[nr][nc] = (r == sr && c == sc ? DIR_CH[d] : first[r][c]);\n\n                if (goal[nr][nc]) return first[nr][nc];\n\n                q.push({nr, nc});\n            }\n        }\n\n        return '.';\n    }\n\n    int taskPriority(int tid) {\n        int s = tasks[tid].stand;\n        int pr = 0;\n\n        for (auto &p : pets) {\n            int w = 1;\n            if (p.t == 4) w = 6;\n            else if (p.t == 5) w = 3;\n            else if (p.t == 3) w = 3;\n            else if (p.t == 2) w = 2;\n\n            if (p.r <= 28) {\n                int dc = abs(p.c - s);\n                if (dc <= 2) pr += w * (3 - dc);\n                else if (dc <= 4) pr += 1;\n            } else {\n                if (abs(p.c - s) <= 2) pr += 1;\n            }\n        }\n\n        return pr;\n    }\n\n    void normalizeStates() {\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task == -1) continue;\n\n            int tid = hs[i].task;\n            bool comp = taskComplete(tid);\n\n            if (comp) hs[i].phase = RET;\n            if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n            if (humans[i].first == 29 && hs[i].phase == RET) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n            }\n        }\n    }\n\n    void assignTasks() {\n        if (turnNo > ASSIGN_LIMIT) return;\n\n        while (true) {\n            int bestI = -1, bestT = -1;\n            double bestVal = -1e100;\n\n            for (int i = 0; i < M; i++) {\n                if (hs[i].task != -1) continue;\n\n                for (int tid = 0; tid < (int)tasks.size(); tid++) {\n                    if (tasks[tid].assigned != -1) continue;\n                    if (taskComplete(tid)) continue;\n\n                    int stand = tasks[tid].stand;\n                    if (blocked[28][stand]) continue;\n\n                    int dist = shortestDist(humans[i], {29, stand});\n                    if (dist >= INF) continue;\n\n                    int rem = countRemainingBuilds(tid);\n                    int estimate = dist + rem + 58;\n                    if (turnNo + estimate > BUILD_LIMIT + 8) continue;\n\n                    double val = 50.0 * taskPriority(tid) - dist;\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestI = i;\n                        bestT = tid;\n                    }\n                }\n            }\n\n            if (bestI == -1) break;\n\n            hs[bestI].task = bestT;\n            hs[bestI].phase = GO;\n            hs[bestI].wait = 0;\n            tasks[bestT].assigned = bestI;\n        }\n    }\n\n    array<bool, G> computeDoorTargets() {\n        array<bool, G> need;\n        need.fill(false);\n\n        struct Comp {\n            int area = 0;\n            int pets = 0;\n            bool protect = false;\n            vector<int> doors;\n        };\n\n        int compId[G][G];\n        for (int r = 0; r < G; r++) {\n            for (int c = 0; c < G; c++) compId[r][c] = -1;\n        }\n\n        vector<Comp> comps;\n\n        for (int sr = 0; sr <= 28; sr++) {\n            for (int sc = 0; sc < G; sc++) {\n                if (blocked[sr][sc]) continue;\n                if (compId[sr][sc] != -1) continue;\n\n                int id = (int)comps.size();\n                comps.push_back(Comp());\n\n                queue<pair<int,int>> q;\n                compId[sr][sc] = id;\n                q.push({sr, sc});\n\n                while (!q.empty()) {\n                    auto [r, c] = q.front();\n                    q.pop();\n\n                    comps[id].area++;\n\n                    if (r == 28 && !blocked[29][c]) {\n                        comps[id].doors.push_back(c);\n                    }\n\n                    for (int d = 0; d < 4; d++) {\n                        int nr = r + DR[d], nc = c + DC[d];\n                        if (!inside(nr, nc)) continue;\n                        if (nr == 29) continue;\n                        if (blocked[nr][nc]) continue;\n                        if (compId[nr][nc] != -1) continue;\n\n                        compId[nr][nc] = id;\n                        q.push({nr, nc});\n                    }\n                }\n            }\n        }\n\n        int corridorPets = 0;\n\n        for (auto &p : pets) {\n            if (p.r == 29) {\n                corridorPets++;\n            } else if (0 <= p.r && p.r <= 28) {\n                int id = compId[p.r][p.c];\n                if (id >= 0) comps[id].pets++;\n            }\n        }\n\n        for (auto &h : humans) {\n            if (h.first <= 28) {\n                int id = compId[h.first][h.second];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            int tid = hs[i].task;\n            if (tid == -1) continue;\n            if (hs[i].phase == RET) continue;\n            if (taskComplete(tid)) continue;\n\n            int s = tasks[tid].stand;\n            if (!blocked[28][s]) {\n                int id = compId[28][s];\n                if (id >= 0) comps[id].protect = true;\n            }\n        }\n\n        int baseArea = 0;\n        for (int c = 0; c < G; c++) {\n            if (!blocked[29][c]) baseArea++;\n        }\n\n        int basePets = corridorPets;\n        (void)basePets;\n\n        struct Item {\n            int comp;\n            int area;\n            int pets;\n        };\n\n        vector<Item> items;\n\n        for (int id = 0; id < (int)comps.size(); id++) {\n            auto &cp = comps[id];\n\n            if (cp.doors.empty()) continue;\n\n            if (cp.protect || cp.pets == 0) {\n                baseArea += cp.area;\n                basePets += cp.pets;\n            } else {\n                items.push_back({id, cp.area, cp.pets});\n            }\n        }\n\n        int K = (int)items.size();\n        int maxP = N;\n\n        vector<vector<int>> dp(K + 1, vector<int>(maxP + 1, -INF));\n        vector<vector<int>> pre(K + 1, vector<int>(maxP + 1, -1));\n        vector<vector<char>> take(K + 1, vector<char>(maxP + 1, 0));\n\n        dp[0][0] = baseArea;\n\n        for (int k = 0; k < K; k++) {\n            int a = items[k].area;\n            int p = items[k].pets;\n\n            for (int q = 0; q <= maxP; q++) {\n                if (dp[k][q] < 0) continue;\n\n                if (dp[k][q] > dp[k + 1][q]) {\n                    dp[k + 1][q] = dp[k][q];\n                    pre[k + 1][q] = q;\n                    take[k + 1][q] = 0;\n                }\n\n                if (q + p <= maxP && dp[k][q] + a > dp[k + 1][q + p]) {\n                    dp[k + 1][q + p] = dp[k][q] + a;\n                    pre[k + 1][q + p] = q;\n                    take[k + 1][q + p] = 1;\n                }\n            }\n        }\n\n        int bestQ = 0;\n        double bestScore = -1.0;\n\n        for (int q = 0; q <= maxP; q++) {\n            if (dp[K][q] < 0) continue;\n            double val = ldexp((double)dp[K][q], -q);\n            if (val > bestScore) {\n                bestScore = val;\n                bestQ = q;\n            }\n        }\n\n        vector<bool> include(K, false);\n        int q = bestQ;\n        for (int k = K; k >= 1; k--) {\n            include[k - 1] = take[k][q];\n            q = pre[k][q];\n            if (q < 0) break;\n        }\n\n        for (int k = 0; k < K; k++) {\n            if (include[k]) continue;\n\n            int id = items[k].comp;\n            for (int c : comps[id].doors) {\n                if (!blocked[28][c]) need[c] = true;\n            }\n        }\n\n        return need;\n    }\n\n    double evaluateBottomBarrierMask(const vector<int>& cand, int mask) {\n        bool extra[G]{};\n\n        for (int i = 0; i < (int)cand.size(); i++) {\n            if (mask & (1 << i)) extra[cand[i]] = true;\n        }\n\n        auto isBlocked = [&](int r, int c) -> bool {\n            if (blocked[r][c]) return true;\n            if (r == 29 && extra[c]) return true;\n            return false;\n        };\n\n        double total = 0.0;\n\n        for (auto &h : humans) {\n            if (isBlocked(h.first, h.second)) return -1e100;\n\n            bool vis[G][G]{};\n            queue<pair<int,int>> q;\n\n            vis[h.first][h.second] = true;\n            q.push(h);\n\n            int area = 0;\n\n            while (!q.empty()) {\n                auto [r, c] = q.front();\n                q.pop();\n\n                area++;\n\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + DR[d], nc = c + DC[d];\n                    if (!inside(nr, nc)) continue;\n                    if (isBlocked(nr, nc)) continue;\n                    if (vis[nr][nc]) continue;\n\n                    vis[nr][nc] = true;\n                    q.push({nr, nc});\n                }\n            }\n\n            int pcnt = 0;\n            for (auto &p : pets) {\n                if (inside(p.r, p.c) && vis[p.r][p.c]) pcnt++;\n            }\n\n            total += ldexp((double)area, -min(pcnt, 20));\n        }\n\n        return total / M;\n    }\n\n    vector<int> chooseCorridorBarriers() {\n        if (turnNo < 290) return {};\n\n        int bottomPets = 0;\n        for (auto &p : pets) {\n            if (p.r == 29) bottomPets++;\n        }\n\n        if (bottomPets < 3) return {};\n\n        vector<int> freeIds;\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task == -1) freeIds.push_back(i);\n        }\n        if (freeIds.empty()) return {};\n\n        vector<pair<int,int>> scoredCand;\n\n        for (int c = 1; c <= 27; c += 2) {\n            if (blocked[29][c]) continue;\n            if (humanOcc[29][c]) continue;\n            if (petOcc[29][c]) continue;\n\n            bool adjacentPet = false;\n            for (int d = 0; d < 4; d++) {\n                int nr = 29 + DR[d], nc = c + DC[d];\n                if (inside(nr, nc) && petOcc[nr][nc]) adjacentPet = true;\n            }\n            if (adjacentPet) continue;\n\n            int md = INF;\n            for (auto &p : pets) {\n                if (p.r == 29) md = min(md, abs(c - p.c));\n            }\n            if (md < 2 || md >= INF) continue;\n\n            bool reachable = false;\n            int rem = 299 - turnNo;\n\n            for (int id : freeIds) {\n                if (c - 1 >= 0 && !blocked[29][c - 1]) {\n                    int d = shortestDist(humans[id], {29, c - 1});\n                    if (d <= rem) reachable = true;\n                }\n                if (c + 1 < G && !blocked[29][c + 1]) {\n                    int d = shortestDist(humans[id], {29, c + 1});\n                    if (d <= rem) reachable = true;\n                }\n            }\n\n            if (!reachable) continue;\n\n            scoredCand.push_back({md, c});\n        }\n\n        if (scoredCand.empty()) return {};\n\n        sort(scoredCand.begin(), scoredCand.end());\n\n        vector<int> cand;\n        for (auto [_, c] : scoredCand) {\n            cand.push_back(c);\n            if ((int)cand.size() >= 12) break;\n        }\n\n        double curVal = evaluateBottomBarrierMask(cand, 0);\n        if (curVal > 20.0) return {};\n\n        int K = (int)cand.size();\n        int maxBuild = min(4, max(1, (int)freeIds.size()));\n\n        double bestVal = curVal;\n        int bestMask = 0;\n\n        for (int mask = 1; mask < (1 << K); mask++) {\n            if (__builtin_popcount((unsigned)mask) > maxBuild) continue;\n\n            double val = evaluateBottomBarrierMask(cand, mask);\n            val -= 1.0 * __builtin_popcount((unsigned)mask);\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestMask = mask;\n            }\n        }\n\n        double threshold = max(curVal * 1.8 + 5.0, curVal + 12.0);\n        if (bestMask == 0 || bestVal <= threshold) return {};\n\n        vector<int> ret;\n        for (int i = 0; i < K; i++) {\n            if (bestMask & (1 << i)) ret.push_back(cand[i]);\n        }\n\n        return ret;\n    }\n\n    double evaluateReservedWithExtra(const vector<pair<int,int>>& extra) {\n        bool extraBlock[G][G]{};\n\n        for (auto [r, c] : extra) {\n            if (inside(r, c)) extraBlock[r][c] = true;\n        }\n\n        auto isBlocked = [&](int r, int c) -> bool {\n            if (blocked[r][c]) return true;\n            if (resBuild[r][c]) return true;\n            if (extraBlock[r][c]) return true;\n            return false;\n        };\n\n        double total = 0.0;\n\n        for (auto &h : humans) {\n            if (!inside(h.first, h.second) || isBlocked(h.first, h.second)) {\n                return -1e100;\n            }\n\n            bool vis[G][G]{};\n            queue<pair<int,int>> q;\n\n            vis[h.first][h.second] = true;\n            q.push(h);\n\n            int area = 0;\n\n            while (!q.empty()) {\n                auto [r, c] = q.front();\n                q.pop();\n\n                area++;\n\n                for (int d = 0; d < 4; d++) {\n                    int nr = r + DR[d], nc = c + DC[d];\n                    if (!inside(nr, nc)) continue;\n                    if (isBlocked(nr, nc)) continue;\n                    if (vis[nr][nc]) continue;\n\n                    vis[nr][nc] = true;\n                    q.push({nr, nc});\n                }\n            }\n\n            int pcnt = 0;\n            for (auto &p : pets) {\n                if (inside(p.r, p.c) && vis[p.r][p.c]) pcnt++;\n            }\n\n            total += ldexp((double)area, -min(pcnt, 20));\n        }\n\n        return total / M;\n    }\n\n    void finalImmediateCorridorRescue(vector<char>& act, const array<bool,G>& needDoor) {\n        if (turnNo < 297) return;\n\n        for (int i = 0; i < M; i++) {\n            if (hs[i].task != -1) return;\n        }\n\n        for (char a : act) {\n            if ('A' <= a && a <= 'Z') return;\n        }\n\n        // If a normal door can be closed immediately, prefer the original policy.\n        for (int i = 0; i < M; i++) {\n            if (act[i] != '.') continue;\n            if (hs[i].task != -1) continue;\n\n            int r = humans[i].first;\n            int c = humans[i].second;\n\n            if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c]) {\n                if (canBuild(i, 'u')) return;\n            }\n        }\n\n        double curVal = evaluateReservedWithExtra({});\n        if (curVal > 10.0) return;\n\n        int builtCnt = 0;\n        int maxExtra = 2;\n\n        while (builtCnt < maxExtra) {\n            double bestVal = curVal;\n            int bestHuman = -1;\n            char bestDir = '.';\n            int bestR = -1, bestC = -1;\n\n            for (int i = 0; i < M; i++) {\n                if (act[i] != '.') continue;\n                if (hs[i].task != -1) continue;\n\n                int r = humans[i].first;\n                int c = humans[i].second;\n                if (r != 29) continue;\n\n                for (char dir : string(\"lr\")) {\n                    int d = dirId(dir);\n                    int nr = r + DR[d], nc = c + DC[d];\n\n                    if (!inside(nr, nc)) continue;\n                    if (nr != 29) continue;\n                    if (nc < 1 || nc > 27 || nc % 2 == 0) continue;\n                    if (blocked[nr][nc] || resBuild[nr][nc]) continue;\n                    if (!canBuild(i, dir)) continue;\n\n                    double val = evaluateReservedWithExtra({{nr, nc}});\n\n                    if (val > bestVal) {\n                        bestVal = val;\n                        bestHuman = i;\n                        bestDir = dir;\n                        bestR = nr;\n                        bestC = nc;\n                    }\n                }\n            }\n\n            if (bestHuman == -1) break;\n\n            double threshold = max(curVal + 2.0, curVal * 1.25);\n            if (bestVal <= threshold) break;\n\n            if (!issueBuild(bestHuman, bestDir, act)) break;\n\n            (void)bestR;\n            (void)bestC;\n\n            curVal = bestVal;\n            builtCnt++;\n\n            if (curVal > 15.0) break;\n        }\n    }\n\n    int tryBuildCurrentRow(int i, int tid, vector<char>& act) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (!(0 <= r && r <= 28)) return 0;\n        if (c != stand) return 0;\n\n        bool anyUnbuilt = false;\n\n        for (int wc : tasks[tid].walls) {\n            if (blocked[r][wc]) continue;\n\n            anyUnbuilt = true;\n            char low = (wc < stand ? 'l' : 'r');\n\n            if (!resBuild[r][wc] && canBuild(i, low)) {\n                issueBuild(i, low, act);\n                return 1;\n            }\n        }\n\n        return anyUnbuilt ? -1 : 0;\n    }\n\n    void moveToGoals(int i, const vector<pair<int,int>>& goals, vector<char>& act) {\n        char mv = bfsMove(i, goals);\n        if (mv != '.') issueMove(i, mv, act);\n    }\n\n    void actBuilder(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int tid = hs[i].task;\n\n        if (tid == -1) {\n            actFree(i, act, needDoor);\n            return;\n        }\n\n        bool comp = taskComplete(tid);\n        if (comp) hs[i].phase = RET;\n        if (turnNo >= BUILD_LIMIT && !comp) hs[i].phase = RET;\n\n        int r = humans[i].first;\n        int c = humans[i].second;\n        int stand = tasks[tid].stand;\n\n        if (hs[i].phase == RET) {\n            if (r == 29) {\n                if (comp) tasks[tid].assigned = -2;\n                else tasks[tid].assigned = -1;\n\n                hs[i].task = -1;\n                hs[i].phase = FREE;\n                hs[i].wait = 0;\n                actFree(i, act, needDoor);\n                return;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col = 0; col < G; col++) {\n                if (!blocked[29][col]) goals.push_back({29, col});\n            }\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        if (hs[i].phase == GO) {\n            if (!(r == 29 && c == stand)) {\n                moveToGoals(i, {{29, stand}}, act);\n                return;\n            }\n            hs[i].phase = UP;\n        }\n\n        if (c != stand) {\n            hs[i].phase = GO;\n            moveToGoals(i, {{29, stand}}, act);\n            return;\n        }\n\n        if (hs[i].phase == UP) {\n            if (r == 29) {\n                hs[i].wait = 0;\n                issueMove(i, 'U', act);\n                return;\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r > 0) {\n                issueMove(i, 'U', act);\n                return;\n            } else {\n                hs[i].phase = DOWN;\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n\n        if (hs[i].phase == DOWN) {\n            if (r == 29) {\n                if (taskComplete(tid)) {\n                    hs[i].phase = RET;\n                    actBuilder(i, act, needDoor);\n                    return;\n                } else {\n                    hs[i].phase = UP;\n                    issueMove(i, 'U', act);\n                    return;\n                }\n            }\n\n            int res = tryBuildCurrentRow(i, tid, act);\n            if (res == 1) {\n                hs[i].wait = 0;\n                return;\n            }\n\n            if (res == -1 && turnNo < WAIT_UNTIL && hs[i].wait < WAIT_LIMIT) {\n                hs[i].wait++;\n                return;\n            }\n\n            hs[i].wait = 0;\n\n            if (r < 28) {\n                issueMove(i, 'D', act);\n                return;\n            } else {\n                issueMove(i, 'D', act);\n                return;\n            }\n        }\n    }\n\n    void actFree(int i, vector<char>& act, const array<bool,G>& needDoor) {\n        int r = humans[i].first;\n        int c = humans[i].second;\n\n        if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c]) {\n            if (canBuild(i, 'u')) {\n                issueBuild(i, 'u', act);\n                return;\n            }\n        }\n\n        vector<int> cols;\n        for (int col = 0; col < G; col++) {\n            if (needDoor[col] && !blocked[28][col] && !resBuild[28][col]) {\n                cols.push_back(col);\n            }\n        }\n\n        if (!cols.empty()) {\n            bool curIllegal = false;\n            if (r == 29 && needDoor[c] && !blocked[28][c] && !resBuild[28][c] && !canBuild(i, 'u')) {\n                curIllegal = true;\n            }\n\n            vector<pair<int,int>> goals;\n            for (int col : cols) {\n                if (curIllegal && col == c && cols.size() >= 2) continue;\n                goals.push_back({29, col});\n            }\n\n            if (goals.empty()) goals.push_back({29, c});\n\n            moveToGoals(i, goals, act);\n            return;\n        }\n\n        moveToGoals(i, {{29, hs[i].home}}, act);\n    }\n\n    void handleCorridorBarriers(vector<char>& act, const vector<int>& targets) {\n        if (targets.empty()) return;\n\n        auto isTarget = [&](int c) -> bool {\n            return find(targets.begin(), targets.end(), c) != targets.end();\n        };\n\n        for (int i = 0; i < M; i++) {\n            if (act[i] != '.') continue;\n            if (hs[i].task != -1) continue;\n\n            int r = humans[i].first;\n            int c = humans[i].second;\n\n            if (r != 29) continue;\n\n            if (c - 1 >= 0 && isTarget(c - 1) &&\n                !blocked[29][c - 1] && !resBuild[29][c - 1]) {\n                if (issueBuild(i, 'l', act)) continue;\n            }\n\n            if (c + 1 < G && isTarget(c + 1) &&\n                !blocked[29][c + 1] && !resBuild[29][c + 1]) {\n                if (issueBuild(i, 'r', act)) continue;\n            }\n        }\n\n        vector<pair<int,int>> goals;\n\n        for (int t : targets) {\n            if (blocked[29][t] || resBuild[29][t]) continue;\n\n            if (t - 1 >= 0 && !blocked[29][t - 1]) goals.push_back({29, t - 1});\n            if (t + 1 < G && !blocked[29][t + 1]) goals.push_back({29, t + 1});\n        }\n\n        if (goals.empty()) return;\n\n        for (int i = 0; i < M; i++) {\n            if (act[i] != '.') continue;\n            if (hs[i].task != -1) continue;\n\n            moveToGoals(i, goals, act);\n        }\n    }\n\n    string decideActions() {\n        buildOcc();\n        resetReservations();\n\n        normalizeStates();\n        assignTasks();\n\n        auto needDoor = computeDoorTargets();\n        vector<int> corridorTargets = chooseCorridorBarriers();\n\n        vector<char> act(M, '.');\n\n        vector<int> order;\n        for (int i = 0; i < M; i++) if (hs[i].task != -1) order.push_back(i);\n        for (int i = 0; i < M; i++) if (hs[i].task == -1) order.push_back(i);\n\n        for (int i : order) {\n            if (hs[i].task != -1) actBuilder(i, act, needDoor);\n        }\n\n        handleCorridorBarriers(act, corridorTargets);\n\n        if (corridorTargets.empty()) {\n            finalImmediateCorridorRescue(act, needDoor);\n        }\n\n        for (int i : order) {\n            if (hs[i].task == -1 && act[i] == '.') actFree(i, act, needDoor);\n        }\n\n        string s;\n        s.reserve(M);\n        for (int i = 0; i < M; i++) s.push_back(act[i]);\n        return s;\n    }\n\n    char convertAction(char ch) {\n        if (ch == '.') return '.';\n\n        bool low = islower((unsigned char)ch);\n        char up = toupper(ch);\n        char p = logToPhys[(int)up];\n\n        if (low) p = tolower(p);\n        return p;\n    }\n\n    string toPhysicalOutput(const string& logAct) {\n        string out;\n        out.reserve(logAct.size());\n\n        for (char ch : logAct) {\n            out.push_back(convertAction(ch));\n        }\n\n        return out;\n    }\n\n    void applyActions(const string& logAct) {\n        auto oldHumans = humans;\n        auto newHumans = humans;\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('a' <= a && a <= 'z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) blocked[r][c] = true;\n            }\n        }\n\n        for (int i = 0; i < M; i++) {\n            char a = logAct[i];\n\n            if ('A' <= a && a <= 'Z') {\n                int d = dirId(a);\n                int r = oldHumans[i].first + DR[d];\n                int c = oldHumans[i].second + DC[d];\n\n                if (inside(r, c)) newHumans[i] = {r, c};\n            }\n        }\n\n        humans = newHumans;\n    }\n\n    bool readPetMovesAndUpdate() {\n        for (int i = 0; i < N; i++) {\n            string s;\n            if (!(cin >> s)) return false;\n\n            if (s == \".\") continue;\n\n            for (char pc : s) {\n                if (pc == '.') continue;\n\n                char lc = physToLog[(int)pc];\n                int d = dirId(lc);\n\n                pets[i].r += DR[d];\n                pets[i].c += DC[d];\n            }\n        }\n\n        return true;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N;\n    cin >> N;\n\n    vector<Pet> petsPhys(N);\n    for (int i = 0; i < N; i++) {\n        cin >> petsPhys[i].r >> petsPhys[i].c >> petsPhys[i].t;\n        petsPhys[i].r--;\n        petsPhys[i].c--;\n    }\n\n    int M;\n    cin >> M;\n\n    vector<pair<int,int>> humansPhys(M);\n    for (int i = 0; i < M; i++) {\n        cin >> humansPhys[i].first >> humansPhys[i].second;\n        humansPhys[i].first--;\n        humansPhys[i].second--;\n    }\n\n    int ori = chooseOrientation(petsPhys, humansPhys);\n    Solver solver(N, petsPhys, M, humansPhys, ori);\n\n    for (int turn = 0; turn < 300; turn++) {\n        solver.turnNo = turn;\n\n        string logAct = solver.decideActions();\n        string out = solver.toPhysicalOutput(logAct);\n\n        cout << out << endl;\n        cout.flush();\n\n        solver.applyActions(logAct);\n\n        if (!solver.readPetMovesAndUpdate()) return 0;\n    }\n\n    return 0;\n}","ahc009":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic constexpr int H = 20;\nstatic constexpr int W = 20;\nstatic constexpr int N = 400;\nstatic constexpr int MAXL = 200;\nstatic constexpr int MAXD = 400;\n\nint si_, sj_, ti_, tj_;\nint SID, TID;\ndouble pForget, qRemember;\n\nstring hwall[H], vwall[H - 1];\n\nint goTo[4][N]; // U D L R\nint distT[N], distS[N];\n\ndouble pot[MAXL + 1][MAXD + 1];\ndouble adaptVal[MAXL + 1][N];\n\ndouble pref[MAXL + 1][N];\ndouble suff[MAXL + 1][N];\ndouble prefScore[MAXL + 1];\n\nchrono::steady_clock::time_point startTime;\n\nconst double HARD_LIMIT = 1.88;\nconst double EPS = 1e-10;\nconst string DIRS = \"UDLR\";\n\nenum FillMode {\n    F_LAST = 0,\n    F_GREEDY = 1\n};\n\ninline int id(int i, int j) {\n    return i * W + j;\n}\n\ninline double elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n}\n\nvoid buildGo() {\n    for (int i = 0; i < H; i++) {\n        for (int j = 0; j < W; j++) {\n            int x = id(i, j);\n            goTo[0][x] = (i > 0 && vwall[i - 1][j] == '0') ? id(i - 1, j) : x;\n            goTo[1][x] = (i + 1 < H && vwall[i][j] == '0') ? id(i + 1, j) : x;\n            goTo[2][x] = (j > 0 && hwall[i][j - 1] == '0') ? id(i, j - 1) : x;\n            goTo[3][x] = (j + 1 < W && hwall[i][j] == '0') ? id(i, j + 1) : x;\n        }\n    }\n}\n\nvoid bfsDistFrom(int st, int* dist) {\n    fill(dist, dist + N, -1);\n    queue<int> que;\n    dist[st] = 0;\n    que.push(st);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n            if (dist[y] == -1) {\n                dist[y] = dist[x] + 1;\n                que.push(y);\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (dist[i] < 0) dist[i] = MAXD;\n    }\n}\n\nvoid buildPotential() {\n    for (int d = 0; d <= MAXD; d++) pot[MAXL][d] = 0.0;\n    pot[MAXL][0] = 401 - MAXL;\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        pot[l][0] = 401 - l;\n        for (int d = 1; d <= MAXD; d++) {\n            pot[l][d] = qRemember * pot[l + 1][d - 1] + pForget * pot[l + 1][d];\n        }\n    }\n}\n\nvoid buildAdaptiveValue() {\n    fill(adaptVal[MAXL], adaptVal[MAXL] + N, 0.0);\n\n    for (int l = MAXL - 1; l >= 0; l--) {\n        double reward = 400 - l;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                adaptVal[l][v] = 0.0;\n                continue;\n            }\n\n            double best = 0.0;\n            for (int a = 0; a < 4; a++) {\n                int u = goTo[a][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * adaptVal[l + 1][v];\n                } else if (u == v) {\n                    val = adaptVal[l + 1][v];\n                } else {\n                    val = pForget * adaptVal[l + 1][v] + qRemember * adaptVal[l + 1][u];\n                }\n\n                best = max(best, val);\n            }\n\n            adaptVal[l][v] = best;\n        }\n    }\n}\n\ndouble evaluate(const vector<int>& seq) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    double score = 0.0;\n    int L = (int)seq.size();\n\n    for (int k = 0; k < L; k++) {\n        fill(ndp, ndp + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = dp[v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                ndp[v] += m * pForget;\n            } else if (u == v) {\n                ndp[v] += m;\n            } else {\n                ndp[v] += m * pForget;\n                ndp[u] += m * qRemember;\n            }\n        }\n\n        score += reward * hit;\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return score;\n}\n\nvoid applyActionDist(const double* dp, double* ndp, int a) {\n    fill(ndp, ndp + N, 0.0);\n\n    for (int v = 0; v < N; v++) {\n        double m = dp[v];\n        if (m == 0.0) continue;\n\n        int u = goTo[a][v];\n\n        if (u == TID) {\n            ndp[v] += m * pForget;\n        } else if (u == v) {\n            ndp[v] += m;\n        } else {\n            ndp[v] += m * pForget;\n            ndp[u] += m * qRemember;\n        }\n    }\n}\n\nvoid computePrefixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(pref[0], pref[0] + N, 0.0);\n    pref[0][SID] = 1.0;\n    prefScore[0] = 0.0;\n\n    for (int k = 0; k < L; k++) {\n        fill(pref[k + 1], pref[k + 1] + N, 0.0);\n\n        int a = seq[k];\n        double hit = 0.0;\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            double m = pref[k][v];\n            if (m == 0.0) continue;\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                hit += m * qRemember;\n                pref[k + 1][v] += m * pForget;\n            } else if (u == v) {\n                pref[k + 1][v] += m;\n            } else {\n                pref[k + 1][v] += m * pForget;\n                pref[k + 1][u] += m * qRemember;\n            }\n        }\n\n        prefScore[k + 1] = prefScore[k] + reward * hit;\n    }\n}\n\nvoid computeSuffixOnly(const vector<int>& seq) {\n    int L = (int)seq.size();\n\n    fill(suff[L], suff[L] + N, 0.0);\n\n    for (int k = L - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - k;\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                suff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                suff[k][v] = qRemember * reward + pForget * suff[k + 1][v];\n            } else if (u == v) {\n                suff[k][v] = suff[k + 1][v];\n            } else {\n                suff[k][v] = pForget * suff[k + 1][v] + qRemember * suff[k + 1][u];\n            }\n        }\n    }\n}\n\nvoid computePrefixSuffix(const vector<int>& seq) {\n    computePrefixOnly(seq);\n    computeSuffixOnly(seq);\n}\n\ninline double heuristicFuture(int mode, int pos, int state) {\n    if (mode == 0) return adaptVal[pos][state];\n    if (mode == 1) return pot[pos][distT[state]];\n    return 0.55 * adaptVal[pos][state] + 0.45 * pot[pos][distT[state]];\n}\n\nvoid completeGreedy(vector<int>& seq) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n    if ((int)seq.size() == MAXL) return;\n\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    int len = (int)seq.size();\n\n    for (int k = 0; k < len; k++) {\n        applyActionDist(dp, ndp, seq[k]);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    for (int k = len; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * adaptVal[k + 1][v]);\n                } else if (u == v) {\n                    val += m * adaptVal[k + 1][v];\n                } else {\n                    val += m * (pForget * adaptVal[k + 1][v] + qRemember * adaptVal[k + 1][u]);\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n}\n\nvector<int> greedySequenceMode(int mode) {\n    static double dp[N], ndp[N];\n\n    fill(dp, dp + N, 0.0);\n    dp[SID] = 1.0;\n\n    vector<int> seq;\n    seq.reserve(MAXL);\n\n    for (int k = 0; k < MAXL; k++) {\n        double bestVal = -1.0;\n        int bestA = 0;\n        double reward = 400 - k;\n\n        for (int a = 0; a < 4; a++) {\n            double val = 0.0;\n\n            for (int v = 0; v < N; v++) {\n                double m = dp[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    val += m * (qRemember * reward + pForget * heuristicFuture(mode, k + 1, v));\n                } else if (u == v) {\n                    val += m * heuristicFuture(mode, k + 1, v);\n                } else {\n                    val += m * (pForget * heuristicFuture(mode, k + 1, v)\n                              + qRemember * heuristicFuture(mode, k + 1, u));\n                }\n            }\n\n            if (val > bestVal) {\n                bestVal = val;\n                bestA = a;\n            }\n        }\n\n        seq.push_back(bestA);\n        applyActionDist(dp, ndp, bestA);\n        memcpy(dp, ndp, sizeof(double) * N);\n    }\n\n    return seq;\n}\n\nstruct Candidate {\n    vector<int> seq;\n    double score;\n};\n\nvoid fillLast(vector<int>& seq) {\n    if (seq.empty()) seq.push_back(1);\n    while ((int)seq.size() < MAXL) seq.push_back(seq.back());\n}\n\nvoid addCandidate(vector<Candidate>& cands, vector<int> seq, int mode = F_GREEDY) {\n    if ((int)seq.size() > MAXL) seq.resize(MAXL);\n\n    if ((int)seq.size() < MAXL) {\n        if (mode == F_GREEDY) completeGreedy(seq);\n        else fillLast(seq);\n    }\n\n    for (const auto& c : cands) {\n        if (c.seq == seq) return;\n    }\n\n    double sc = evaluate(seq);\n    cands.push_back({move(seq), sc});\n}\n\nvoid pruneCands(vector<Candidate>& cands, int limit) {\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        return a.score > b.score;\n    });\n\n    if ((int)cands.size() > limit) cands.resize(limit);\n}\n\nint repCost(int d, double z) {\n    if (d <= 0) return 0;\n\n    double val = d / qRemember + z * sqrt(max(0.0, d * pForget)) / qRemember;\n    int r = (int)ceil(val - 1e-9);\n\n    r = max(r, d);\n    r = max(r, 1);\n\n    return r;\n}\n\nint cappedRep(int d, double z) {\n    if (d <= 0) return 0;\n    return min(18, repCost(d, z));\n}\n\nvoid appendRun(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt && (int)s.size() < MAXL; i++) {\n        s.push_back(a);\n    }\n}\n\nvoid appendRunRaw(vector<int>& s, int a, int cnt) {\n    for (int i = 0; i < cnt; i++) s.push_back(a);\n}\n\nvector<int> bfsPath(int start, int goal, const array<int, 4>& order) {\n    if (start == goal) return {};\n\n    vector<int> par(N, -1), parA(N, -1);\n    queue<int> que;\n\n    par[start] = start;\n    que.push(start);\n\n    while (!que.empty()) {\n        int x = que.front();\n        que.pop();\n\n        if (x == goal) break;\n\n        for (int a : order) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            if (par[y] == -1) {\n                par[y] = x;\n                parA[y] = a;\n                que.push(y);\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != start) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> randomPathTo(int goal, int seed, int noise, int biasAway) {\n    mt19937 rng(seed);\n\n    int wgt[4][N];\n\n    for (int a = 0; a < 4; a++) {\n        for (int v = 0; v < N; v++) {\n            if (goTo[a][v] == v) {\n                wgt[a][v] = INT_MAX / 4;\n            } else {\n                int pen = (a == 0 || a == 2) ? biasAway : 0;\n                wgt[a][v] = 1000 + pen + (int)(rng() % max(1, noise));\n            }\n        }\n    }\n\n    const int INF = 1 << 29;\n    vector<int> dist(N, INF), par(N, -1), parA(N, -1);\n    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;\n\n    dist[SID] = 0;\n    pq.push({0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd != dist[x]) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            int y = goTo[a][x];\n            if (y == x) continue;\n\n            int nd = cd + wgt[a][x];\n            if (nd < dist[y]) {\n                dist[y] = nd;\n                par[y] = x;\n                parA[y] = a;\n                pq.push({nd, y});\n            }\n        }\n    }\n\n    vector<int> path;\n\n    if (par[goal] == -1) return path;\n\n    int x = goal;\n    while (x != SID) {\n        path.push_back(parA[x]);\n        x = par[x];\n    }\n\n    reverse(path.begin(), path.end());\n    return path;\n}\n\nvector<int> makeCyclePath(const vector<int>& path) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    s.reserve(MAXL);\n    for (int i = 0; i < MAXL; i++) {\n        s.push_back(path[i % path.size()]);\n    }\n\n    return s;\n}\n\nvector<int> repeatEachPathOriginal(const vector<int>& path, int rep) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    for (int a : path) {\n        for (int r = 0; r < rep && (int)s.size() < MAXL; r++) {\n            s.push_back(a);\n        }\n\n        if ((int)s.size() >= MAXL) break;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(path[ptr % path.size()]);\n        ptr++;\n    }\n\n    return s;\n}\n\nvector<int> syncRunPath(const vector<int>& path, double z, int extraUnsynced = 0) {\n    vector<int> s;\n\n    if (path.empty()) return s;\n\n    int cell = SID;\n\n    for (int i = 0; i < (int)path.size();) {\n        int a = path[i];\n        int j = i;\n\n        while (j < (int)path.size() && path[j] == a) j++;\n\n        int d = j - i;\n        int end = cell;\n\n        for (int k = 0; k < d; k++) {\n            end = goTo[a][end];\n        }\n\n        bool synced = (end == TID || goTo[a][end] == end);\n        int r = synced ? repCost(d, z) : d + extraUnsynced;\n        r = max(r, d);\n\n        appendRun(s, a, r);\n\n        cell = end;\n\n        if ((int)s.size() >= MAXL) break;\n\n        i = j;\n    }\n\n    return s;\n}\n\npair<int, int> slideResult(int cell, int a) {\n    int c = cell;\n    int d = 0;\n\n    while (true) {\n        int u = goTo[a][c];\n        if (u == c) break;\n\n        c = u;\n        d++;\n\n        if (c == TID) break;\n    }\n\n    return {c, d};\n}\n\nvector<int> slidePathToGoal(int goal, double z) {\n    if (goal == SID) return {};\n\n    const double INF = 1e100;\n\n    vector<double> dc(N, INF);\n    vector<int> pre(N, -1), preA(N, -1), preD(N, 0);\n\n    priority_queue<pair<double, int>, vector<pair<double, int>>, greater<pair<double, int>>> pq;\n\n    dc[SID] = 0.0;\n    pq.push({0.0, SID});\n\n    while (!pq.empty()) {\n        auto [cd, x] = pq.top();\n        pq.pop();\n\n        if (cd > dc[x] + 1e-9) continue;\n        if (x == goal) break;\n\n        for (int a = 0; a < 4; a++) {\n            auto [to, d] = slideResult(x, a);\n            if (d == 0) continue;\n\n            double nd = cd + repCost(d, z);\n\n            if (nd < dc[to]) {\n                dc[to] = nd;\n                pre[to] = x;\n                preA[to] = a;\n                preD[to] = d;\n                pq.push({nd, to});\n            }\n        }\n    }\n\n    if (pre[goal] == -1) return {};\n\n    vector<pair<int, int>> segs;\n\n    int x = goal;\n    while (x != SID) {\n        segs.push_back({preA[x], preD[x]});\n        x = pre[x];\n    }\n\n    reverse(segs.begin(), segs.end());\n\n    vector<int> seq;\n\n    for (auto [a, d] : segs) {\n        appendRun(seq, a, repCost(d, z));\n        if ((int)seq.size() >= MAXL) break;\n    }\n\n    return seq;\n}\n\nvector<int> slideCandidate(double z) {\n    return slidePathToGoal(TID, z);\n}\n\nvoid addPathCandidatesOriginal(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, F_LAST);\n    addCandidate(cands, makeCyclePath(path), F_LAST);\n\n    for (int rep : {2, 3, 4}) {\n        addCandidate(cands, repeatEachPathOriginal(path, rep), F_LAST);\n    }\n}\n\nvoid addLightPathCandidates(vector<Candidate>& cands, const vector<int>& path) {\n    if (path.empty()) return;\n\n    addCandidate(cands, path, F_GREEDY);\n    addCandidate(cands, makeCyclePath(path), F_LAST);\n    addCandidate(cands, syncRunPath(path, 0.9, 0), F_GREEDY);\n\n    int r = max(2, (int)ceil(1.0 / qRemember));\n    addCandidate(cands, repeatEachPathOriginal(path, r), F_GREEDY);\n}\n\nvector<int> patternFromRuns(const vector<pair<int, int>>& runs) {\n    vector<int> pat;\n\n    for (auto [a, c] : runs) {\n        if (c <= 0) continue;\n        appendRunRaw(pat, a, c);\n    }\n\n    return pat;\n}\n\nvoid addPatternCandidate(vector<Candidate>& cands, const vector<int>& prefix, const vector<int>& pattern) {\n    vector<int> s = prefix;\n\n    if ((int)s.size() > MAXL) s.resize(MAXL);\n\n    if (pattern.empty()) {\n        addCandidate(cands, s, F_GREEDY);\n        return;\n    }\n\n    int ptr = 0;\n    while ((int)s.size() < MAXL) {\n        s.push_back(pattern[ptr]);\n        ptr++;\n        if (ptr == (int)pattern.size()) ptr = 0;\n    }\n\n    addCandidate(cands, s, F_LAST);\n}\n\nvoid addLineCandidates(vector<Candidate>& cands, int goal, int toward, int back, int offset) {\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<vector<int>> prefixes;\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPath(SID, goal, ord);\n        if (goal != SID && path.empty()) continue;\n\n        prefixes.push_back(path);\n\n        vector<int> sp = syncRunPath(path, 0.8, 0);\n        prefixes.push_back(sp);\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    if (offset == 0) {\n        for (auto& pre : prefixes) {\n            addCandidate(cands, pre, F_GREEDY);\n        }\n        return;\n    }\n\n    vector<int> counts = {\n        offset,\n        max(offset, (int)ceil(offset / qRemember)),\n        cappedRep(offset, 0.7),\n        min(18, max(offset, 5))\n    };\n\n    sort(counts.begin(), counts.end());\n    counts.erase(unique(counts.begin(), counts.end()), counts.end());\n\n    for (auto& pre : prefixes) {\n        for (int c : counts) {\n            vector<int> pat = patternFromRuns({{toward, c}, {back, c}});\n            addPatternCandidate(cands, pre, pat);\n        }\n    }\n}\n\nvoid addSweepCandidates(vector<Candidate>& cands) {\n    vector<vector<int>> patterns;\n\n    vector<int> cs = {\n        4,\n        max(4, (int)round(4.0 / qRemember)),\n        min(14, repCost(4, 0.7)),\n        min(18, repCost(4, 1.4))\n    };\n\n    sort(cs.begin(), cs.end());\n    cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n    for (int c : cs) {\n        patterns.push_back(patternFromRuns({{0, c}, {2, c}, {1, c}, {3, c}}));\n        patterns.push_back(patternFromRuns({{2, c}, {0, c}, {3, c}, {1, c}}));\n    }\n\n    int up = 19 - ti_;\n    int left = 19 - tj_;\n\n    for (double z : {0.0, 0.8, 1.5}) {\n        int ru = cappedRep(up, z);\n        int rl = cappedRep(left, z);\n\n        if (ru + rl > 0) {\n            patterns.push_back(patternFromRuns({{0, ru}, {2, rl}, {1, ru}, {3, rl}}));\n            patterns.push_back(patternFromRuns({{2, rl}, {0, ru}, {3, rl}, {1, ru}}));\n        }\n    }\n\n    vector<vector<int>> prefixes;\n\n    for (double z : {0.0, 1.0}) {\n        int big = min(75, repCost(19, z));\n\n        vector<int> s1;\n        appendRun(s1, 1, big);\n        appendRun(s1, 3, big);\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        appendRun(s2, 3, big);\n        appendRun(s2, 1, big);\n        prefixes.push_back(s2);\n    }\n\n    for (int chunk : {max(5, (int)round(7.0 / qRemember)), max(8, (int)round(11.0 / qRemember))}) {\n        vector<int> s1;\n        while ((int)s1.size() < 115) {\n            appendRun(s1, 1, chunk);\n            appendRun(s1, 3, chunk);\n        }\n        prefixes.push_back(s1);\n\n        vector<int> s2;\n        while ((int)s2.size() < 115) {\n            appendRun(s2, 3, chunk);\n            appendRun(s2, 1, chunk);\n        }\n        prefixes.push_back(s2);\n    }\n\n    array<int, 4> drOrder{1, 3, 0, 2};\n    vector<int> cornerPath = bfsPath(SID, id(19, 19), drOrder);\n\n    if (!cornerPath.empty()) {\n        prefixes.push_back(cornerPath);\n        prefixes.push_back(syncRunPath(cornerPath, 0.8, 0));\n        prefixes.push_back(syncRunPath(cornerPath, 1.6, 0));\n    }\n\n    sort(prefixes.begin(), prefixes.end());\n    prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n    int used = 0;\n\n    for (auto& pre : prefixes) {\n        for (auto& pat : patterns) {\n            addPatternCandidate(cands, pre, pat);\n            used++;\n            if (used >= 60) break;\n        }\n        if (used >= 60) break;\n    }\n\n    addLineCandidates(cands, id(ti_, 19), 2, 3, 19 - tj_);\n    addLineCandidates(cands, id(19, tj_), 0, 1, 19 - ti_);\n}\n\nvoid addNearTargetCandidates(vector<Candidate>& cands) {\n    vector<int> cells;\n\n    for (int v = 0; v < N; v++) {\n        if (v == TID) continue;\n        if (distT[v] <= 4) cells.push_back(v);\n    }\n\n    sort(cells.begin(), cells.end(), [&](int a, int b) {\n        int ca = distS[a] + 5 * distT[a];\n        int cb = distS[b] + 5 * distT[b];\n        return ca < cb;\n    });\n\n    if ((int)cells.size() > 10) cells.resize(10);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    for (int v : cells) {\n        for (auto ord : orders) {\n            vector<int> path = bfsPath(SID, v, ord);\n            if (v != SID && path.empty()) continue;\n\n            addCandidate(cands, path, F_GREEDY);\n\n            vector<int> sp = syncRunPath(path, 0.8, 0);\n            addCandidate(cands, sp, F_GREEDY);\n        }\n    }\n}\n\nstruct RayInfo {\n    int cell;\n    int action;\n    int d;\n    int rank;\n};\n\nvoid addTargetRayCandidates(vector<Candidate>& cands) {\n    vector<RayInfo> rays;\n\n    for (int a = 0; a < 4; a++) {\n        for (int c = 0; c < N; c++) {\n            if (c == TID) continue;\n\n            int x = c;\n\n            for (int d = 1; d <= 25; d++) {\n                int y = goTo[a][x];\n                if (y == x) break;\n\n                x = y;\n\n                if (x == TID) {\n                    int rank = distS[c] + repCost(d, 1.0);\n                    rays.push_back({c, a, d, rank});\n                    break;\n                }\n            }\n        }\n    }\n\n    sort(rays.begin(), rays.end(), [](const RayInfo& a, const RayInfo& b) {\n        if (a.rank != b.rank) return a.rank < b.rank;\n        return a.d < b.d;\n    });\n\n    if ((int)rays.size() > 16) rays.resize(16);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2}\n    };\n\n    vector<double> zs = {0.0, 1.0};\n    if (pForget >= 0.25) zs.push_back(1.8);\n\n    for (const auto& r : rays) {\n        for (auto ord : orders) {\n            vector<int> path = bfsPath(SID, r.cell, ord);\n            if (r.cell != SID && path.empty()) continue;\n\n            vector<vector<int>> prefixes;\n            prefixes.push_back(path);\n            prefixes.push_back(syncRunPath(path, 0.8, 0));\n\n            sort(prefixes.begin(), prefixes.end());\n            prefixes.erase(unique(prefixes.begin(), prefixes.end()), prefixes.end());\n\n            for (auto pre : prefixes) {\n                for (double z : zs) {\n                    vector<int> s = pre;\n                    appendRun(s, r.action, repCost(r.d, z));\n                    addCandidate(cands, s, F_GREEDY);\n                }\n            }\n        }\n\n        for (double pz : {0.5, 1.2}) {\n            vector<int> pre = slidePathToGoal(r.cell, pz);\n            if (r.cell != SID && pre.empty()) continue;\n\n            for (double z : zs) {\n                vector<int> s = pre;\n                appendRun(s, r.action, repCost(r.d, z));\n                addCandidate(cands, s, F_GREEDY);\n            }\n        }\n    }\n}\n\nstruct BeamNode {\n    float prob[N];\n    double score;\n    double est;\n    unsigned char seq[MAXL];\n\n    BeamNode() {}\n};\n\nvector<vector<int>> beamSearchMode(int topCount, int initialWidth, int mode) {\n    int width = initialWidth;\n\n    vector<BeamNode> cur, nxt, selected;\n    vector<int> idx;\n\n    cur.reserve(initialWidth);\n    nxt.reserve(initialWidth * 4);\n    selected.reserve(initialWidth);\n    idx.reserve(initialWidth * 4);\n\n    BeamNode root;\n    fill(root.prob, root.prob + N, 0.0f);\n    root.prob[SID] = 1.0f;\n    root.score = 0.0;\n\n    if (mode == 0) {\n        root.est = pot[0][distT[SID]];\n    } else {\n        root.est = 0.75 * adaptVal[0][SID] + 0.25 * pot[0][distT[SID]];\n    }\n\n    cur.push_back(root);\n\n    for (int l = 0; l < MAXL; l++) {\n        if ((l % 5) == 0) {\n            double e = elapsedSec();\n\n            if (e > 1.55) width = min(width, 35);\n            else if (e > 1.42) width = min(width, 70);\n            else if (e > 1.28) width = min(width, 120);\n            else if (e > 1.12 && mode != 0) width = min(width, 120);\n        }\n\n        nxt.clear();\n\n        for (const BeamNode& par : cur) {\n            for (int a = 0; a < 4; a++) {\n                BeamNode& ch = nxt.emplace_back();\n\n                fill(ch.prob, ch.prob + N, 0.0f);\n\n                if (l > 0) memcpy(ch.seq, par.seq, l * sizeof(unsigned char));\n                ch.seq[l] = (unsigned char)a;\n\n                double hit = 0.0;\n                double future = 0.0;\n                const double* drow = pot[l + 1];\n                const double* vrow = adaptVal[l + 1];\n\n                for (int v = 0; v < N; v++) {\n                    float mf = par.prob[v];\n                    if (mf == 0.0f) continue;\n\n                    double m = mf;\n                    int u = goTo[a][v];\n\n                    auto addFuture = [&](int state, double mass) {\n                        if (mode == 0) {\n                            future += mass * drow[distT[state]];\n                        } else {\n                            future += mass * (0.75 * vrow[state] + 0.25 * drow[distT[state]]);\n                        }\n                    };\n\n                    if (u == TID) {\n                        double stay = m * pForget;\n                        hit += m * qRemember;\n                        ch.prob[v] += (float)stay;\n                        addFuture(v, stay);\n                    } else if (u == v) {\n                        ch.prob[v] += mf;\n                        addFuture(v, m);\n                    } else {\n                        double stay = m * pForget;\n                        double mv = m * qRemember;\n\n                        ch.prob[v] += (float)stay;\n                        ch.prob[u] += (float)mv;\n\n                        addFuture(v, stay);\n                        addFuture(u, mv);\n                    }\n                }\n\n                ch.score = par.score + (400 - l) * hit;\n                ch.est = ch.score + future;\n            }\n        }\n\n        int n = (int)nxt.size();\n\n        if (n > width) {\n            idx.resize(n);\n            iota(idx.begin(), idx.end(), 0);\n\n            auto cmp = [&](int x, int y) {\n                if (nxt[x].est != nxt[y].est) return nxt[x].est > nxt[y].est;\n                return nxt[x].score > nxt[y].score;\n            };\n\n            nth_element(idx.begin(), idx.begin() + width, idx.end(), cmp);\n\n            selected.clear();\n\n            for (int i = 0; i < width; i++) {\n                selected.push_back(nxt[idx[i]]);\n            }\n\n            cur.swap(selected);\n        } else {\n            cur.swap(nxt);\n        }\n    }\n\n    vector<vector<int>> res;\n    int n = (int)cur.size();\n\n    idx.resize(n);\n    iota(idx.begin(), idx.end(), 0);\n\n    sort(idx.begin(), idx.end(), [&](int x, int y) {\n        return cur[x].score > cur[y].score;\n    });\n\n    int take = min(topCount, n);\n\n    for (int r = 0; r < take; r++) {\n        vector<int> s(MAXL);\n        const BeamNode& node = cur[idx[r]];\n\n        for (int k = 0; k < MAXL; k++) {\n            s[k] = node.seq[k];\n        }\n\n        res.push_back(move(s));\n    }\n\n    return res;\n}\n\nvector<int> bestCrossoverSeq(const vector<int>& A, const vector<int>& B) {\n    computeSuffixOnly(B);\n    computePrefixOnly(A);\n\n    double best = -1.0;\n    int bestK = 0;\n\n    for (int k = 0; k <= MAXL; k++) {\n        double total = prefScore[k];\n\n        for (int v = 0; v < N; v++) {\n            total += pref[k][v] * suff[k][v];\n        }\n\n        if (total > best) {\n            best = total;\n            bestK = k;\n        }\n    }\n\n    vector<int> s;\n    s.reserve(MAXL);\n\n    for (int i = 0; i < bestK; i++) s.push_back(A[i]);\n    for (int i = bestK; i < MAXL; i++) s.push_back(B[i]);\n\n    return s;\n}\n\nvoid addCrossovers(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>((int)cands.size(), 14));\n\n    int m = min<int>(8, cands.size());\n    vector<vector<int>> top;\n\n    for (int i = 0; i < m; i++) top.push_back(cands[i].seq);\n\n    for (int i = 0; i < m; i++) {\n        for (int j = 0; j < m; j++) {\n            if (i == j) continue;\n\n            if (elapsedSec() > 1.60) return;\n\n            vector<int> s = bestCrossoverSeq(top[i], top[j]);\n            addCandidate(cands, s, F_LAST);\n        }\n    }\n}\n\nvoid addGreedyTailCandidates(vector<Candidate>& cands) {\n    pruneCands(cands, min<int>((int)cands.size(), 12));\n\n    vector<vector<int>> top;\n    int m = min<int>(6, cands.size());\n\n    for (int i = 0; i < m; i++) top.push_back(cands[i].seq);\n\n    vector<int> cuts = {0, 25, 50, 75, 100, 125, 150, 175};\n\n    for (auto& base : top) {\n        for (int k : cuts) {\n            if (elapsedSec() > 1.55) return;\n\n            vector<int> s(base.begin(), base.begin() + k);\n            addCandidate(cands, s, F_GREEDY);\n        }\n    }\n}\n\nbool tryWindow(vector<int>& seq, int win, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    int masks = 1 << (2 * win);\n\n    static double buf1[N], buf2[N];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 3) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        for (int mask = 0; mask < masks; mask++) {\n            if (mask == curMask) continue;\n\n            memcpy(buf1, pref[k], sizeof(double) * N);\n\n            double* dp = buf1;\n            double* ndp = buf2;\n            double sc = prefScore[k];\n\n            int mm = mask;\n\n            for (int r = 0; r < win; r++) {\n                int a = mm & 3;\n                mm >>= 2;\n\n                fill(ndp, ndp + N, 0.0);\n\n                double hit = 0.0;\n                double reward = 400 - (k + r);\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        ndp[v] += m * pForget;\n                    } else if (u == v) {\n                        ndp[v] += m;\n                    } else {\n                        ndp[v] += m * pForget;\n                        ndp[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp, ndp);\n            }\n\n            double total = sc;\n            const double* sw = suff[k + win];\n\n            for (int v = 0; v < N; v++) {\n                total += dp[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = mask;\n            }\n        }\n    }\n\n    if (bestK != -1) {\n        int mm = bestMask;\n\n        for (int r = 0; r < win; r++) {\n            seq[bestK + r] = mm & 3;\n            mm >>= 2;\n        }\n\n        newScore = best;\n        return true;\n    }\n\n    return false;\n}\n\nbool tryShiftDP(vector<int>& seq, double currentScore, double& newScore) {\n    int L = (int)seq.size();\n    if (L != MAXL) return false;\n\n    static double insSuff[MAXL + 1][N];\n    static double delSuff[4][MAXL + 1][N];\n\n    fill(insSuff[L - 1], insSuff[L - 1] + N, 0.0);\n\n    for (int k = L - 2; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 399 - k;\n        const double* nxt = insSuff[k + 1];\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                insSuff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                insSuff[k][v] = qRemember * reward + pForget * nxt[v];\n            } else if (u == v) {\n                insSuff[k][v] = nxt[v];\n            } else {\n                insSuff[k][v] = pForget * nxt[v] + qRemember * nxt[u];\n            }\n        }\n    }\n\n    double finalReward = 400 - (L - 1);\n\n    for (int c = 0; c < 4; c++) {\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                delSuff[c][L][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[c][v];\n            delSuff[c][L][v] = (u == TID ? qRemember * finalReward : 0.0);\n        }\n\n        for (int k = L - 1; k >= 1; k--) {\n            int a = seq[k];\n            double reward = 401 - k;\n            const double* nxt = delSuff[c][k + 1];\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    delSuff[c][k][v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    delSuff[c][k][v] = qRemember * reward + pForget * nxt[v];\n                } else if (u == v) {\n                    delSuff[c][k][v] = nxt[v];\n                } else {\n                    delSuff[c][k][v] = pForget * nxt[v] + qRemember * nxt[u];\n                }\n            }\n        }\n    }\n\n    double best = currentScore;\n    int bestType = -1;\n    int bestI = -1;\n    int bestC = -1;\n\n    for (int i = 0; i < L; i++) {\n        const double* row = pref[i];\n        double base = prefScore[i];\n        double reward = 400 - i;\n        const double* tail = insSuff[i];\n\n        for (int c = 0; c < 4; c++) {\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                double m = row[v];\n                if (m == 0.0) continue;\n\n                int u = goTo[c][v];\n                double val;\n\n                if (u == TID) {\n                    val = qRemember * reward + pForget * tail[v];\n                } else if (u == v) {\n                    val = tail[v];\n                } else {\n                    val = pForget * tail[v] + qRemember * tail[u];\n                }\n\n                total += m * val;\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 0;\n                bestI = i;\n                bestC = c;\n            }\n        }\n    }\n\n    for (int i = 0; i < L; i++) {\n        const double* row = pref[i];\n        double base = prefScore[i];\n\n        for (int c = 0; c < 4; c++) {\n            const double* tail = delSuff[c][i + 1];\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                total += row[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 1;\n                bestI = i;\n                bestC = c;\n            }\n        }\n    }\n\n    if (bestType == -1) return false;\n\n    vector<int> ns(L);\n\n    if (bestType == 0) {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n        ns[bestI] = bestC;\n        for (int k = bestI + 1; k < L; k++) ns[k] = seq[k - 1];\n    } else {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n        for (int k = bestI; k < L - 1; k++) ns[k] = seq[k + 1];\n        ns[L - 1] = bestC;\n    }\n\n    seq.swap(ns);\n    newScore = best;\n    return true;\n}\n\nbool tryShiftAnyBlock(vector<int>& seq, int b, double currentScore, double& newScore, double deadline) {\n    int L = (int)seq.size();\n    if (L != MAXL || b < 2 || b > 3) return false;\n\n    int masks = 1 << (2 * b);\n\n    static double insSuff[MAXL + 1][N];\n    static double delSuff[64][MAXL + 1][N];\n    static double dp1[N], dp2[N];\n    static double tmp1[N], tmp2[N];\n\n    fill(insSuff[L - b], insSuff[L - b] + N, 0.0);\n\n    for (int k = L - b - 1; k >= 0; k--) {\n        int a = seq[k];\n        double reward = 400 - (k + b);\n        const double* nxt = insSuff[k + 1];\n\n        for (int v = 0; v < N; v++) {\n            if (v == TID) {\n                insSuff[k][v] = 0.0;\n                continue;\n            }\n\n            int u = goTo[a][v];\n\n            if (u == TID) {\n                insSuff[k][v] = qRemember * reward + pForget * nxt[v];\n            } else if (u == v) {\n                insSuff[k][v] = nxt[v];\n            } else {\n                insSuff[k][v] = pForget * nxt[v] + qRemember * nxt[u];\n            }\n        }\n    }\n\n    for (int mask = 0; mask < masks; mask++) {\n        fill(tmp1, tmp1 + N, 0.0);\n\n        for (int r = b - 1; r >= 0; r--) {\n            int a = (mask >> (2 * r)) & 3;\n            double reward = 400 - (L - b + r);\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    tmp2[v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    tmp2[v] = qRemember * reward + pForget * tmp1[v];\n                } else if (u == v) {\n                    tmp2[v] = tmp1[v];\n                } else {\n                    tmp2[v] = pForget * tmp1[v] + qRemember * tmp1[u];\n                }\n            }\n\n            memcpy(tmp1, tmp2, sizeof(double) * N);\n        }\n\n        memcpy(delSuff[mask][L], tmp1, sizeof(double) * N);\n\n        for (int k = L - 1; k >= b; k--) {\n            int a = seq[k];\n            double reward = 400 - (k - b);\n            const double* nxt = delSuff[mask][k + 1];\n\n            for (int v = 0; v < N; v++) {\n                if (v == TID) {\n                    delSuff[mask][k][v] = 0.0;\n                    continue;\n                }\n\n                int u = goTo[a][v];\n\n                if (u == TID) {\n                    delSuff[mask][k][v] = qRemember * reward + pForget * nxt[v];\n                } else if (u == v) {\n                    delSuff[mask][k][v] = nxt[v];\n                } else {\n                    delSuff[mask][k][v] = pForget * nxt[v] + qRemember * nxt[u];\n                }\n            }\n        }\n    }\n\n    double best = currentScore;\n    int bestType = -1;\n    int bestI = -1;\n    int bestMask = 0;\n\n    for (int i = 0; i <= L - b; i++) {\n        if ((i & 7) == 0 && elapsedSec() > deadline - 0.006) goto finish_search;\n\n        const double* row = pref[i];\n        double base = prefScore[i];\n        const double* tail = insSuff[i];\n\n        for (int mask = 0; mask < masks; mask++) {\n            memcpy(dp1, row, sizeof(double) * N);\n            double sc = base;\n\n            for (int r = 0; r < b; r++) {\n                int a = (mask >> (2 * r)) & 3;\n\n                fill(dp2, dp2 + N, 0.0);\n\n                double reward = 400 - (i + r);\n                double hit = 0.0;\n\n                for (int v = 0; v < N; v++) {\n                    double m = dp1[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[a][v];\n\n                    if (u == TID) {\n                        hit += m * qRemember;\n                        dp2[v] += m * pForget;\n                    } else if (u == v) {\n                        dp2[v] += m;\n                    } else {\n                        dp2[v] += m * pForget;\n                        dp2[u] += m * qRemember;\n                    }\n                }\n\n                sc += reward * hit;\n                swap(dp1, dp2);\n            }\n\n            double total = sc;\n\n            for (int v = 0; v < N; v++) {\n                total += dp1[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 0;\n                bestI = i;\n                bestMask = mask;\n            }\n        }\n    }\n\n    for (int i = 0; i <= L - b; i++) {\n        if ((i & 7) == 0 && elapsedSec() > deadline - 0.006) goto finish_search;\n\n        const double* row = pref[i];\n        double base = prefScore[i];\n\n        for (int mask = 0; mask < masks; mask++) {\n            const double* tail = delSuff[mask][i + b];\n            double total = base;\n\n            for (int v = 0; v < N; v++) {\n                total += row[v] * tail[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestType = 1;\n                bestI = i;\n                bestMask = mask;\n            }\n        }\n    }\n\nfinish_search:\n\n    if (bestType == -1) return false;\n\n    vector<int> ns(L);\n\n    if (bestType == 0) {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n\n        for (int r = 0; r < b; r++) {\n            ns[bestI + r] = (bestMask >> (2 * r)) & 3;\n        }\n\n        for (int k = bestI + b; k < L; k++) {\n            ns[k] = seq[k - b];\n        }\n    } else {\n        for (int k = 0; k < bestI; k++) ns[k] = seq[k];\n\n        for (int k = bestI; k < L - b; k++) {\n            ns[k] = seq[k + b];\n        }\n\n        for (int r = 0; r < b; r++) {\n            ns[L - b + r] = (bestMask >> (2 * r)) & 3;\n        }\n    }\n\n    seq.swap(ns);\n    newScore = best;\n    return true;\n}\n\nstruct BlockNode {\n    double prob[N];\n    double sc;\n    double key;\n    int mask;\n};\n\nbool tryWindowBeam(vector<int>& seq, int win, int beamW, double currentScore, double deadline, double& newScore) {\n    int L = (int)seq.size();\n    if (win <= 0 || win > 10) return false;\n\n    beamW = min(beamW, 30);\n\n    static BlockNode cur[32], nxt[128], sel[32];\n    static int idx[128];\n\n    double best = currentScore;\n    int bestK = -1;\n    int bestMask = 0;\n\n    for (int k = 0; k + win <= L; k++) {\n        if ((k & 1) == 0 && elapsedSec() > deadline) break;\n\n        int curMask = 0;\n        for (int r = 0; r < win; r++) {\n            curMask |= (seq[k + r] << (2 * r));\n        }\n\n        int curN = 1;\n        memcpy(cur[0].prob, pref[k], sizeof(double) * N);\n        cur[0].sc = 0.0;\n        cur[0].key = 0.0;\n        cur[0].mask = 0;\n\n        for (int r = 0; r < win; r++) {\n            int nn = 0;\n            int pos = k + r;\n            double reward = 400 - pos;\n            const double* vrow = adaptVal[pos + 1];\n            const double* drow = pot[pos + 1];\n\n            for (int bi = 0; bi < curN; bi++) {\n                const BlockNode& par = cur[bi];\n\n                for (int a = 0; a < 4; a++) {\n                    BlockNode& ch = nxt[nn++];\n                    fill(ch.prob, ch.prob + N, 0.0);\n\n                    double hit = 0.0;\n                    double future = 0.0;\n\n                    for (int v = 0; v < N; v++) {\n                        double m = par.prob[v];\n                        if (m == 0.0) continue;\n\n                        int u = goTo[a][v];\n\n                        if (u == TID) {\n                            double stay = m * pForget;\n                            hit += m * qRemember;\n                            ch.prob[v] += stay;\n                            future += stay * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                        } else if (u == v) {\n                            ch.prob[v] += m;\n                            future += m * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                        } else {\n                            double stay = m * pForget;\n                            double mv = m * qRemember;\n                            ch.prob[v] += stay;\n                            ch.prob[u] += mv;\n                            future += stay * (0.65 * vrow[v] + 0.35 * drow[distT[v]]);\n                            future += mv * (0.65 * vrow[u] + 0.35 * drow[distT[u]]);\n                        }\n                    }\n\n                    ch.sc = par.sc + reward * hit;\n                    ch.key = ch.sc + future;\n                    ch.mask = par.mask | (a << (2 * r));\n                }\n            }\n\n            if (nn > beamW) {\n                iota(idx, idx + nn, 0);\n                nth_element(idx, idx + beamW, idx + nn, [&](int x, int y) {\n                    return nxt[x].key > nxt[y].key;\n                });\n\n                for (int i = 0; i < beamW; i++) {\n                    sel[i] = nxt[idx[i]];\n                }\n\n                curN = beamW;\n                for (int i = 0; i < curN; i++) {\n                    cur[i] = sel[i];\n                }\n            } else {\n                curN = nn;\n                for (int i = 0; i < curN; i++) {\n                    cur[i] = nxt[i];\n                }\n            }\n        }\n\n        const double* sw = suff[k + win];\n\n        for (int bi = 0; bi < curN; bi++) {\n            if (cur[bi].mask == curMask) continue;\n\n            double total = prefScore[k] + cur[bi].sc;\n\n            for (int v = 0; v < N; v++) {\n                total += cur[bi].prob[v] * sw[v];\n            }\n\n            if (total > best + EPS) {\n                best = total;\n                bestK = k;\n                bestMask = cur[bi].mask;\n            }\n        }\n    }\n\n    if (bestK == -1) return false;\n\n    int mm = bestMask;\n    for (int r = 0; r < win; r++) {\n        seq[bestK + r] = mm & 3;\n        mm >>= 2;\n    }\n\n    newScore = best;\n    return true;\n}\n\ndouble improve(vector<int>& seq, double deadline, int maxWindow, bool useShift, bool useLarge, bool useAnyBlock = false) {\n    int L = (int)seq.size();\n    double curScore = evaluate(seq);\n\n    while (elapsedSec() < deadline) {\n        computePrefixSuffix(seq);\n        curScore = prefScore[L];\n\n        double bestScore = curScore;\n        int bestK = -1;\n        int bestC = -1;\n\n        for (int k = 0; k < L; k++) {\n            const double* row = pref[k];\n            const double* sw = suff[k + 1];\n            double base = prefScore[k];\n            double reward = 400 - k;\n\n            for (int c = 0; c < 4; c++) {\n                if (c == seq[k]) continue;\n\n                double total = base;\n\n                for (int v = 0; v < N; v++) {\n                    double m = row[v];\n                    if (m == 0.0) continue;\n\n                    int u = goTo[c][v];\n                    double val;\n\n                    if (u == TID) {\n                        val = qRemember * reward + pForget * sw[v];\n                    } else if (u == v) {\n                        val = sw[v];\n                    } else {\n                        val = pForget * sw[v] + qRemember * sw[u];\n                    }\n\n                    total += m * val;\n                }\n\n                if (total > bestScore + EPS) {\n                    bestScore = total;\n                    bestK = k;\n                    bestC = c;\n                }\n            }\n        }\n\n        if (bestK != -1) {\n            seq[bestK] = bestC;\n            curScore = bestScore;\n            continue;\n        }\n\n        bool changed = false;\n\n        for (int w = 2; w <= maxWindow; w++) {\n            if (elapsedSec() > deadline - 0.01) break;\n\n            double ns;\n            if (tryWindow(seq, w, curScore, deadline, ns)) {\n                curScore = ns;\n                changed = true;\n                break;\n            }\n        }\n\n        if (changed) continue;\n\n        if (useShift && elapsedSec() < deadline - 0.005) {\n            double ns;\n            if (tryShiftDP(seq, curScore, ns)) {\n                curScore = ns;\n                continue;\n            }\n        }\n\n        if (useLarge && elapsedSec() < deadline - 0.05) {\n            double ns;\n            int bw = (pForget >= 0.35 ? 14 : 12);\n\n            if (tryWindowBeam(seq, 7, bw, curScore, deadline, ns)) {\n                curScore = ns;\n                continue;\n            }\n\n            if (elapsedSec() < deadline - 0.06 && tryWindowBeam(seq, 10, 8, curScore, deadline, ns)) {\n                curScore = ns;\n                continue;\n            }\n        }\n\n        if (useAnyBlock && elapsedSec() < deadline - 0.055) {\n            double ns;\n\n            if (tryShiftAnyBlock(seq, 2, curScore, ns, deadline)) {\n                curScore = ns;\n                continue;\n            }\n\n            if (pForget >= 0.30 && elapsedSec() < deadline - 0.12) {\n                if (tryShiftAnyBlock(seq, 3, curScore, ns, deadline)) {\n                    curScore = ns;\n                    continue;\n                }\n            }\n        }\n\n        break;\n    }\n\n    return evaluate(seq);\n}\n\nvector<int> recompleteFromCut(const vector<int>& seq, int cut) {\n    cut = min(cut, (int)seq.size());\n    vector<int> s(seq.begin(), seq.begin() + cut);\n    completeGreedy(s);\n    return s;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> si_ >> sj_ >> ti_ >> tj_ >> pForget;\n    qRemember = 1.0 - pForget;\n\n    for (int i = 0; i < H; i++) cin >> hwall[i];\n    for (int i = 0; i < H - 1; i++) cin >> vwall[i];\n\n    SID = id(si_, sj_);\n    TID = id(ti_, tj_);\n\n    startTime = chrono::steady_clock::now();\n\n    buildGo();\n    bfsDistFrom(TID, distT);\n    bfsDistFrom(SID, distS);\n    buildPotential();\n    buildAdaptiveValue();\n\n    vector<Candidate> cands;\n\n    addCandidate(cands, vector<int>{}, F_GREEDY);\n\n    for (int mode = 0; mode < 3; mode++) {\n        addCandidate(cands, greedySequenceMode(mode), F_LAST);\n    }\n\n    array<int, 4> originalOrder{0, 1, 2, 3};\n    vector<int> spOriginal = bfsPath(SID, TID, originalOrder);\n    addPathCandidatesOriginal(cands, spOriginal);\n\n    vector<array<int, 4>> orders = {\n        array<int, 4>{1, 3, 0, 2},\n        array<int, 4>{3, 1, 0, 2},\n        array<int, 4>{1, 3, 2, 0},\n        array<int, 4>{3, 1, 2, 0},\n        array<int, 4>{0, 1, 3, 2},\n        array<int, 4>{2, 3, 1, 0}\n    };\n\n    for (auto ord : orders) {\n        vector<int> path = bfsPath(SID, TID, ord);\n        addLightPathCandidates(cands, path);\n    }\n\n    for (int r = 0; r < 4; r++) {\n        int noise = 350 + 100 * r;\n        int bias = (r % 2 == 0 ? 120 : 0);\n        addLightPathCandidates(cands, randomPathTo(TID, 10000 + r * 97, noise, bias));\n    }\n\n    addNearTargetCandidates(cands);\n    addTargetRayCandidates(cands);\n    addSweepCandidates(cands);\n\n    for (double z : {0.0, 0.5, 1.0, 1.5, 2.2}) {\n        vector<int> s = slideCandidate(z);\n        if (!s.empty()) {\n            addCandidate(cands, s, F_LAST);\n            addCandidate(cands, s, F_GREEDY);\n        }\n    }\n\n    pruneCands(cands, 90);\n\n    vector<vector<int>> distBeamSeqs;\n    distBeamSeqs = beamSearchMode(8, 430, 0);\n\n    for (auto& s : distBeamSeqs) {\n        addCandidate(cands, s, F_LAST);\n    }\n\n    if (elapsedSec() < 1.20) {\n        vector<vector<int>> adapBeamSeqs = beamSearchMode(5, 170, 1);\n        for (auto& s : adapBeamSeqs) {\n            addCandidate(cands, s, F_LAST);\n        }\n    }\n\n    pruneCands(cands, 100);\n\n    if (elapsedSec() < 1.45) {\n        addGreedyTailCandidates(cands);\n    }\n\n    if (elapsedSec() < 1.50) {\n        addCrossovers(cands);\n    }\n\n    if (cands.empty()) {\n        addCandidate(cands, vector<int>{}, F_GREEDY);\n    }\n\n    pruneCands(cands, 100);\n\n    vector<int> bestSeq = cands[0].seq;\n    double bestScore = cands[0].score;\n\n    vector<vector<int>> localStarts;\n\n    auto addStart = [&](const vector<int>& s) {\n        if ((int)s.size() != MAXL) return;\n\n        for (auto& t : localStarts) {\n            if (t == s) return;\n        }\n\n        localStarts.push_back(s);\n    };\n\n    addStart(cands[0].seq);\n\n    if (!distBeamSeqs.empty()) {\n        addStart(distBeamSeqs[0]);\n        if ((int)distBeamSeqs.size() >= 2) addStart(distBeamSeqs[1]);\n    }\n\n    int topStarts = min<int>(8, cands.size());\n    for (int i = 1; i < topStarts; i++) {\n        addStart(cands[i].seq);\n    }\n\n    for (int i = 0; i < (int)localStarts.size(); i++) {\n        if (elapsedSec() > HARD_LIMIT - 0.22) break;\n\n        vector<int> seq = localStarts[i];\n\n        double budget;\n        if (i == 0) budget = 0.22;\n        else if (i <= 2) budget = 0.20;\n        else budget = 0.10;\n\n        double dl = min(HARD_LIMIT - 0.12, elapsedSec() + budget);\n        if (dl <= elapsedSec() + 0.01) break;\n\n        int mw = (i <= 2 ? 3 : 2);\n        bool useShift = (i <= 3);\n        double sc = improve(seq, dl, mw, useShift, false, false);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    // Main final search, with a small reserved time for the late timing refinement.\n    double finalMainDeadline = HARD_LIMIT - 0.065;\n    if (elapsedSec() < finalMainDeadline - 0.005) {\n        vector<int> seq = bestSeq;\n        double sc = improve(seq, finalMainDeadline, 4, true, true, false);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    // Late exact block timing refinement.\n    if (elapsedSec() < HARD_LIMIT - 0.055) {\n        vector<int> seq = bestSeq;\n        double sc = improve(seq, HARD_LIMIT, 2, true, false, true);\n\n        if (sc > bestScore + EPS) {\n            bestScore = sc;\n            bestSeq = move(seq);\n        }\n    }\n\n    // Spare-time adaptive greedy suffix recompletion.\n    if (elapsedSec() < HARD_LIMIT - 0.08) {\n        vector<int> cuts = {40, 60, 80, 100, 120, 140, 160};\n\n        for (int cut : cuts) {\n            if (elapsedSec() > HARD_LIMIT - 0.055) break;\n\n            vector<int> s = recompleteFromCut(bestSeq, cut);\n            double sc = evaluate(s);\n\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = move(s);\n            }\n        }\n\n        if (elapsedSec() < HARD_LIMIT - 0.035) {\n            vector<int> seq = bestSeq;\n            double sc = improve(seq, HARD_LIMIT, 2, true, false, true);\n\n            if (sc > bestScore + EPS) {\n                bestScore = sc;\n                bestSeq = move(seq);\n            }\n        }\n    }\n\n    if ((int)bestSeq.size() > MAXL) bestSeq.resize(MAXL);\n    if ((int)bestSeq.size() < MAXL) completeGreedy(bestSeq);\n\n    string out;\n    out.reserve(MAXL);\n\n    for (int a : bestSeq) {\n        out.push_back(DIRS[a]);\n    }\n\n    cout << out << '\\n';\n\n    return 0;\n}","ahc010":"#include <bits/stdc++.h>\nusing namespace std;\n\n#pragma GCC optimize(\"O3,unroll-loops\")\n\nconstexpr int N = 30;\nconstexpr int CELLS = N * N;\nconstexpr int PORTS = CELLS * 4;\nconstexpr int MAXLEN = 1800;\nconstexpr int MAXCOMP = 4005;\nconstexpr int BITWORDS = (CELLS + 63) / 64;\n\nusing StateArr = array<unsigned char, CELLS>;\n\nint pairDir[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\nint maskState[8];\nint segCnt[8];\nint segA[8][2], segB[8][2];\n\nint adjPort[PORTS];\nint neighCell[CELLS][4];\n\nint baseTile[CELLS];\nint optCnt[CELLS];\nint optState[CELLS][4];\n\nint moveCnt[PORTS];\nint moveNextState[PORTS][2];\nvector<int> validMoveStates;\n\nint di[4] = {0, -1, 0, 1};\nint dj[4] = {-1, 0, 1, 0};\n\nbool STRICT_FINAL = false;\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 RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) {\n        x = seed ? seed : 88172645463325252ULL;\n        for (int i = 0; i < 20; i++) next();\n    }\n    inline uint64_t next() {\n        x ^= x << 13;\n        x ^= x >> 7;\n        x ^= x << 17;\n        return x;\n    }\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct BIT {\n    int bit[MAXLEN + 2];\n    int total;\n\n    void reset() {\n        memset(bit, 0, sizeof(bit));\n        total = 0;\n    }\n\n    void add(int idx, int delta) {\n        if (idx <= 0) return;\n        total += delta;\n        for (int i = idx; i <= MAXLEN; i += i & -i) bit[i] += delta;\n    }\n\n    int kth(int k) const {\n        int idx = 0;\n        for (int pw = 2048; pw; pw >>= 1) {\n            int ni = idx + pw;\n            if (ni <= MAXLEN && bit[ni] < k) {\n                idx = ni;\n                k -= bit[ni];\n            }\n        }\n        return idx + 1;\n    }\n};\n\nstruct Stats {\n    int l1 = 0, l2 = 0;\n    int c1 = 0, c2 = 0;\n    int loops = 0;\n    int broken = 0;\n    long long score = 0;\n    long long loopSq = 0;\n};\n\nstruct Manager {\n    unsigned char st[CELLS];\n\n    int comp[PORTS];\n    vector<int> ports[MAXCOMP];\n    bool alive[MAXCOMP];\n    int compLen[MAXCOMP];\n    int compBroken[MAXCOMP];\n\n    int nextId = 0;\n    vector<int> freeIds;\n\n    BIT compBIT, loopBIT;\n    long long loopSq = 0;\n    int brokenTotal = 0;\n\n    int stackBuf[PORTS];\n\n    Manager() {\n        freeIds.reserve(MAXCOMP);\n        memset(alive, 0, sizeof(alive));\n    }\n\n    inline bool active(int p) const {\n        return pairDir[st[p >> 2]][p & 3] >= 0;\n    }\n\n    inline int internalPort(int p) const {\n        return (p & ~3) | pairDir[st[p >> 2]][p & 3];\n    }\n\n    int allocId() {\n        int id;\n        if (!freeIds.empty()) {\n            id = freeIds.back();\n            freeIds.pop_back();\n        } else {\n            id = nextId++;\n        }\n        alive[id] = true;\n        ports[id].clear();\n        return id;\n    }\n\n    void addStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, 1);\n        brokenTotal += br;\n\n        if (br == 0) {\n            loopBIT.add(len, 1);\n            loopSq += 1LL * len * len;\n        }\n    }\n\n    void removeStats(int id) {\n        int len = compLen[id];\n        int br = compBroken[id];\n\n        compBIT.add(len, -1);\n        brokenTotal -= br;\n\n        if (br == 0) {\n            loopBIT.add(len, -1);\n            loopSq -= 1LL * len * len;\n        }\n    }\n\n    void removeComp(int id) {\n        if (id < 0 || !alive[id]) return;\n\n        removeStats(id);\n\n        for (int p : ports[id]) comp[p] = -1;\n        ports[id].clear();\n        alive[id] = false;\n        freeIds.push_back(id);\n    }\n\n    void addComponent(int start) {\n        int id = allocId();\n\n        int top = 0;\n        stackBuf[top++] = start;\n        comp[start] = id;\n        ports[id].push_back(start);\n\n        int broken = 0;\n\n        while (top) {\n            int p = stackBuf[--top];\n\n            int q = internalPort(p);\n            if (comp[q] == -1) {\n                comp[q] = id;\n                ports[id].push_back(q);\n                stackBuf[top++] = q;\n            }\n\n            int e = adjPort[p];\n            if (e != -1 && active(e)) {\n                if (comp[e] == -1) {\n                    comp[e] = id;\n                    ports[id].push_back(e);\n                    stackBuf[top++] = e;\n                }\n            } else {\n                broken++;\n            }\n        }\n\n        compLen[id] = (int)ports[id].size() / 2;\n        compBroken[id] = broken;\n        addStats(id);\n    }\n\n    void build(const StateArr &arr) {\n        for (int i = 0; i < nextId; i++) {\n            ports[i].clear();\n            alive[i] = false;\n        }\n\n        nextId = 0;\n        freeIds.clear();\n\n        compBIT.reset();\n        loopBIT.reset();\n        loopSq = 0;\n        brokenTotal = 0;\n\n        for (int i = 0; i < CELLS; i++) st[i] = arr[i];\n        fill(comp, comp + PORTS, -1);\n\n        for (int p = 0; p < PORTS; p++) {\n            if (active(p) && comp[p] == -1) addComponent(p);\n        }\n    }\n\n    void updateCell(int cell, int newState) {\n        if (st[cell] == newState) return;\n\n        int ids[20];\n        int cnt = 0;\n\n        auto addId = [&](int id) {\n            if (id < 0 || !alive[id]) return;\n            for (int k = 0; k < cnt; k++) {\n                if (ids[k] == id) return;\n            }\n            ids[cnt++] = id;\n        };\n\n        int base = cell * 4;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            addId(comp[p]);\n            int e = adjPort[p];\n            if (e != -1) addId(comp[e]);\n        }\n\n        for (int k = 0; k < cnt; k++) removeComp(ids[k]);\n\n        st[cell] = (unsigned char)newState;\n\n        for (int d = 0; d < 4; d++) {\n            int p = base + d;\n            if (active(p) && comp[p] == -1) addComponent(p);\n\n            int e = adjPort[p];\n            if (e != -1 && active(e) && comp[e] == -1) addComponent(e);\n        }\n    }\n\n    Stats getStats() const {\n        Stats s;\n\n        s.loops = loopBIT.total;\n\n        if (loopBIT.total >= 1) s.l1 = loopBIT.kth(loopBIT.total);\n        if (loopBIT.total >= 2) s.l2 = loopBIT.kth(loopBIT.total - 1);\n\n        if (compBIT.total >= 1) s.c1 = compBIT.kth(compBIT.total);\n        if (compBIT.total >= 2) s.c2 = compBIT.kth(compBIT.total - 1);\n\n        s.score = 1LL * s.l1 * s.l2;\n        s.loopSq = loopSq;\n        s.broken = brokenTotal;\n\n        return s;\n    }\n\n    void exportState(StateArr &out) const {\n        for (int i = 0; i < CELLS; i++) out[i] = st[i];\n    }\n};\n\nvoid initGlobals() {\n    for (int t = 0; t < 8; t++) {\n        maskState[t] = 0;\n        segCnt[t] = 0;\n\n        for (int d = 0; d < 4; d++) {\n            if (pairDir[t][d] != -1) maskState[t] |= 1 << d;\n        }\n\n        for (int d = 0; d < 4; d++) {\n            int e = pairDir[t][d];\n            if (e != -1 && d < e) {\n                int k = segCnt[t]++;\n                segA[t][k] = d;\n                segB[t][k] = e;\n            }\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d], nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                    neighCell[id][d] = -1;\n                    adjPort[id * 4 + d] = -1;\n                } else {\n                    int nb = ni * N + nj;\n                    neighCell[id][d] = nb;\n                    adjPort[id * 4 + d] = nb * 4 + (d ^ 2);\n                }\n            }\n        }\n    }\n}\n\nvoid buildMoveTransitions() {\n    validMoveStates.clear();\n\n    for (int s = 0; s < PORTS; s++) {\n        moveCnt[s] = 0;\n\n        int c = s >> 2;\n        int d = s & 3;\n\n        if (neighCell[c][d] == -1) continue;\n\n        if (baseTile[c] >= 6) {\n            int out = d ^ 2;\n            int nb = neighCell[c][out];\n            if (nb != -1) {\n                moveNextState[s][moveCnt[s]++] = nb * 4 + (out ^ 2);\n            }\n        } else {\n            int out1 = (d + 1) & 3;\n            int out2 = (d + 3) & 3;\n\n            int nb1 = neighCell[c][out1];\n            if (nb1 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb1 * 4 + (out1 ^ 2);\n            }\n\n            int nb2 = neighCell[c][out2];\n            if (nb2 != -1) {\n                moveNextState[s][moveCnt[s]++] = nb2 * 4 + (out2 ^ 2);\n            }\n        }\n\n        if (moveCnt[s] > 0) validMoveStates.push_back(s);\n    }\n}\n\nint stateForPair(int base, int a, int b) {\n    if (a > b) swap(a, b);\n\n    if (base < 4) {\n        if (a == 0 && b == 1) return 0;\n        if (a == 0 && b == 3) return 1;\n        if (a == 2 && b == 3) return 2;\n        if (a == 1 && b == 2) return 3;\n        return -1;\n    } else if (base < 6) {\n        if ((a == 0 && b == 1) || (a == 2 && b == 3)) return 4;\n        if ((a == 0 && b == 3) || (a == 1 && b == 2)) return 5;\n        return -1;\n    } else {\n        if (a == 0 && b == 2) return 6;\n        if (a == 1 && b == 3) return 7;\n        return -1;\n    }\n}\n\nint localQuality(const unsigned char *arr, int id, int candState) {\n    bool nbAct[4];\n\n    for (int d = 0; d < 4; d++) {\n        int nb = neighCell[id][d];\n        nbAct[d] = false;\n\n        if (nb != -1) {\n            int ns = arr[nb];\n            nbAct[d] = (maskState[ns] >> (d ^ 2)) & 1;\n        }\n    }\n\n    int cm = maskState[candState];\n    int q = 0;\n\n    for (int d = 0; d < 4; d++) {\n        bool ca = (cm >> d) & 1;\n        bool na = nbAct[d];\n\n        if (ca && na) q += 6;\n        else if (ca || na) q -= 4;\n    }\n\n    for (int k = 0; k < segCnt[candState]; k++) {\n        int a = segA[candState][k];\n        int b = segB[candState][k];\n\n        int c = (nbAct[a] ? 1 : 0) + (nbAct[b] ? 1 : 0);\n\n        if (c == 2) q += 20;\n        else if (c == 1) q -= 3;\n        else q -= 8;\n    }\n\n    return q;\n}\n\nvoid greedyImprove(StateArr &cand, RNG &rng, int sweeps, const char *fixed = nullptr) {\n    int steps = sweeps * CELLS;\n\n    for (int it = 0; it < steps; it++) {\n        int id = rng.nextInt(CELLS);\n        if (fixed && fixed[id]) continue;\n\n        int bestSt = cand[id];\n        int bestQ = -1000000000;\n        int ties = 0;\n\n        for (int k = 0; k < optCnt[id]; k++) {\n            int s = optState[id][k];\n            int q = localQuality(cand.data(), id, s);\n\n            if (q > bestQ) {\n                bestQ = q;\n                bestSt = s;\n                ties = 1;\n            } else if (q == bestQ) {\n                ties++;\n                if (rng.nextInt(ties) == 0) bestSt = s;\n            }\n        }\n\n        cand[id] = (unsigned char)bestSt;\n    }\n}\n\nlong long startValue(const Stats &s) {\n    long long compProd = 1LL * s.c1 * s.c2;\n    return s.score * 1500LL + s.loopSq * 25LL + compProd * 6LL - 120LL * s.broken;\n}\n\nlong long energyValue(const Stats &s, double progress) {\n    long long compProd = 1LL * s.c1 * s.c2;\n\n    if (progress < 0.60) {\n        return s.score * 500LL\n             + s.loopSq * 30LL\n             + compProd * 8LL\n             + 1LL * s.l1 * s.l1 * 10LL\n             + 1LL * s.l2 * s.l2 * 10LL\n             - 110LL * s.broken;\n    } else {\n        return s.score * 2500LL\n             + s.loopSq * 5LL\n             + 1LL * s.l1 * s.l1 * 3LL\n             + 1LL * s.l2 * s.l2 * 3LL\n             + compProd / 3LL\n             - 4LL * s.broken;\n    }\n}\n\nlong long finalValue(const Stats &s) {\n    if (STRICT_FINAL) {\n        return s.score * 1000000000LL\n             + 1LL * s.l1 * 100000LL\n             + 1LL * s.l2 * 1000LL\n             + s.loopSq\n             - s.broken;\n    }\n\n    long long compProd = 1LL * s.c1 * s.c2;\n\n    return s.score * 1000000LL\n         + 1LL * s.l1 * 2000LL\n         + 1LL * s.l2 * 1000LL\n         + s.loopSq\n         + compProd / 4LL\n         - 20LL * s.broken;\n}\n\nbool betterStats(const Stats &s, long long bestScore, int bestL1, int bestL2) {\n    if (s.score != bestScore) return s.score > bestScore;\n    return s.l1 + s.l2 > bestL1 + bestL2;\n}\n\nvoid updateBestWithState(\n    const StateArr &arr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        bestState = arr;\n    }\n}\n\nvoid updateBestWithManager(\n    const Manager &mgr,\n    const Stats &s,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    if (betterStats(s, bestScore, bestL1, bestL2)) {\n        bestScore = s.score;\n        bestL1 = s.l1;\n        bestL2 = s.l2;\n        mgr.exportState(bestState);\n    }\n}\n\nstruct Cycle {\n    int len = 0;\n    uint64_t hash = 0;\n    array<uint64_t, BITWORDS> bits{};\n    array<unsigned char, CELLS> pmask{};\n    array<unsigned char, CELLS> cstate{};\n    vector<int> cells;\n    vector<unsigned char> states;\n    vector<unsigned char> masks;\n};\n\nbool incompatibleCycle(const Cycle &a, const Cycle &b) {\n    for (int w = 0; w < BITWORDS; w++) {\n        uint64_t x = a.bits[w] & b.bits[w];\n\n        while (x) {\n            int bit = __builtin_ctzll(x);\n            int c = w * 64 + bit;\n            x &= x - 1;\n\n            if (c >= CELLS) continue;\n\n            if (!(baseTile[c] >= 4 && baseTile[c] < 6)) return true;\n            if (a.cstate[c] != b.cstate[c]) return true;\n            if (a.pmask[c] & b.pmask[c]) return true;\n        }\n    }\n\n    return false;\n}\n\nstruct CycleSampler {\n    static constexpr int MIN_LEN = 16;\n    static constexpr int KEEP = 1300;\n\n    vector<Cycle> cycles;\n\n    int stateSeen[PORTS];\n    int statePos[PORTS];\n\n    int cellSeen[CELLS];\n    int cellCnt[CELLS];\n\n    int tmpSeen[CELLS];\n    unsigned char tmpState[CELLS];\n    unsigned char tmpMask[CELLS];\n\n    int stamp = 1;\n    int tmpStamp = 1;\n    int minStored = MIN_LEN;\n\n    vector<int> path;\n    vector<int> tmpCells;\n\n    CycleSampler() {\n        memset(stateSeen, 0, sizeof(stateSeen));\n        memset(cellSeen, 0, sizeof(cellSeen));\n        memset(tmpSeen, 0, sizeof(tmpSeen));\n        cycles.reserve(KEEP);\n        path.reserve(PORTS);\n        tmpCells.reserve(MAXLEN);\n    }\n\n    void markState(int s) {\n        int pos = (int)path.size();\n        path.push_back(s);\n\n        stateSeen[s] = stamp;\n        statePos[s] = pos;\n\n        int c = s >> 2;\n        if (cellSeen[c] != stamp) {\n            cellSeen[c] = stamp;\n            cellCnt[c] = 0;\n        }\n        cellCnt[c]++;\n    }\n\n    bool canVisitState(int s) const {\n        if (stateSeen[s] == stamp) return false;\n\n        int c = s >> 2;\n\n        if (cellSeen[c] != stamp) return true;\n\n        return baseTile[c] >= 4 && baseTile[c] < 6 && cellCnt[c] < 2;\n    }\n\n    void recomputeMin() {\n        if ((int)cycles.size() < KEEP) {\n            minStored = MIN_LEN;\n            return;\n        }\n\n        minStored = 1000000;\n        for (const auto &c : cycles) minStored = min(minStored, c.len);\n    }\n\n    uint64_t calcHash(const Cycle &cy) {\n        uint64_t h = 1469598103934665603ULL ^ (uint64_t)cy.len;\n\n        for (uint64_t x : cy.bits) {\n            h ^= x + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n\n        for (int i = 0; i < (int)cy.cells.size(); i++) {\n            uint64_t v = (uint64_t)cy.cells[i] * 1315423911ULL\n                       + (uint64_t)cy.states[i] * 911382323ULL\n                       + (uint64_t)cy.masks[i] * 972663749ULL;\n            h ^= v + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2);\n        }\n\n        return h;\n    }\n\n    void storeCycle(Cycle &&cy) {\n        for (const auto &ex : cycles) {\n            if (ex.len != cy.len || ex.hash != cy.hash) continue;\n            if (ex.cells == cy.cells && ex.states == cy.states && ex.masks == cy.masks) {\n                return;\n            }\n        }\n\n        if ((int)cycles.size() < KEEP) {\n            cycles.push_back(std::move(cy));\n            if ((int)cycles.size() == KEEP) recomputeMin();\n            return;\n        }\n\n        int mi = 0;\n        for (int i = 1; i < KEEP; i++) {\n            if (cycles[i].len < cycles[mi].len) mi = i;\n        }\n\n        if (cy.len > cycles[mi].len) {\n            cycles[mi] = std::move(cy);\n            recomputeMin();\n        }\n    }\n\n    void addCycle(int idx) {\n        int end = (int)path.size();\n        int len = end - idx;\n\n        if (len < MIN_LEN || len > MAXLEN) return;\n        if ((int)cycles.size() >= KEEP && len < minStored) return;\n\n        tmpStamp++;\n        if (tmpStamp == INT_MAX) {\n            memset(tmpSeen, 0, sizeof(tmpSeen));\n            tmpStamp = 1;\n        }\n\n        tmpCells.clear();\n\n        for (int p = idx; p < end; p++) {\n            int s = path[p];\n            int nxt = (p + 1 < end ? path[p + 1] : path[idx]);\n\n            int c = s >> 2;\n            int in = s & 3;\n            int out = (nxt & 3) ^ 2;\n\n            int st = stateForPair(baseTile[c], in, out);\n            if (st < 0) return;\n\n            unsigned char pm = (unsigned char)((1 << in) | (1 << out));\n\n            if (tmpSeen[c] != tmpStamp) {\n                tmpSeen[c] = tmpStamp;\n                tmpState[c] = (unsigned char)st;\n                tmpMask[c] = pm;\n                tmpCells.push_back(c);\n            } else {\n                if (!(baseTile[c] >= 4 && baseTile[c] < 6)) return;\n                if (tmpState[c] != st) return;\n                if (tmpMask[c] & pm) return;\n                tmpMask[c] |= pm;\n            }\n        }\n\n        Cycle cy;\n        cy.len = len;\n        cy.bits.fill(0);\n        cy.pmask.fill(0);\n        cy.cstate.fill((unsigned char)255);\n\n        sort(tmpCells.begin(), tmpCells.end());\n\n        cy.cells.reserve(tmpCells.size());\n        cy.states.reserve(tmpCells.size());\n        cy.masks.reserve(tmpCells.size());\n\n        for (int c : tmpCells) {\n            cy.bits[c >> 6] |= 1ULL << (c & 63);\n            cy.pmask[c] = tmpMask[c];\n            cy.cstate[c] = tmpState[c];\n\n            cy.cells.push_back(c);\n            cy.states.push_back(tmpState[c]);\n            cy.masks.push_back(tmpMask[c]);\n        }\n\n        cy.hash = calcHash(cy);\n        storeCycle(std::move(cy));\n    }\n\n    int onwardDegree(int ns) {\n        int deg = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) deg++;\n            } else if (canVisitState(nn)) {\n                deg++;\n            }\n        }\n\n        return deg;\n    }\n\n    int onwardScore(int ns, RNG &rng) {\n        int sc = 0;\n\n        for (int k = 0; k < moveCnt[ns]; k++) {\n            int nn = moveNextState[ns][k];\n\n            if (stateSeen[nn] == stamp) {\n                int len = (int)path.size() + 1 - statePos[nn];\n                if (len >= MIN_LEN) sc += 20 + min(50, len / 8);\n            } else if (canVisitState(nn)) {\n                sc += 3;\n            }\n        }\n\n        int c = ns >> 2;\n        int i = c / N;\n        int j = c % N;\n        int border = min(min(i, N - 1 - i), min(j, N - 1 - j));\n        sc += border / 4;\n\n        return sc + rng.nextInt(4);\n    }\n\n    void sample(Timer &timer, double endTime, RNG &rng) {\n        if (validMoveStates.empty()) return;\n\n        while (timer.elapsed() < endTime) {\n            stamp++;\n\n            if (stamp == INT_MAX) {\n                memset(stateSeen, 0, sizeof(stateSeen));\n                memset(cellSeen, 0, sizeof(cellSeen));\n                stamp = 1;\n            }\n\n            path.clear();\n\n            int start = validMoveStates[rng.nextInt((int)validMoveStates.size())];\n            markState(start);\n\n            int mode = rng.nextInt(3);\n            int inner = 0;\n\n            while ((int)path.size() < MAXLEN) {\n                int cur = path.back();\n                int cnt = moveCnt[cur];\n\n                if (cnt == 0) break;\n\n                int cont[2];\n                int cc = 0;\n\n                for (int k = 0; k < cnt; k++) {\n                    int ns = moveNextState[cur][k];\n\n                    if (stateSeen[ns] == stamp) {\n                        int idx = statePos[ns];\n                        int len = (int)path.size() - idx;\n                        if (len >= MIN_LEN) addCycle(idx);\n                    } else if (canVisitState(ns)) {\n                        cont[cc++] = ns;\n                    }\n                }\n\n                if (cc == 0) break;\n\n                int chosen;\n\n                if (cc == 1) {\n                    chosen = cont[0];\n                } else if (mode == 2) {\n                    chosen = cont[rng.nextInt(2)];\n                } else if (mode == 1) {\n                    int d0 = onwardDegree(cont[0]);\n                    int d1 = onwardDegree(cont[1]);\n\n                    if (d0 == 0 && d1 > 0) {\n                        chosen = cont[1];\n                    } else if (d1 == 0 && d0 > 0) {\n                        chosen = cont[0];\n                    } else if (d0 == d1) {\n                        chosen = cont[rng.nextInt(2)];\n                    } else if (d0 < d1) {\n                        chosen = (rng.nextInt(4) ? cont[0] : cont[1]);\n                    } else {\n                        chosen = (rng.nextInt(4) ? cont[1] : cont[0]);\n                    }\n                } else {\n                    int s0 = onwardScore(cont[0], rng);\n                    int s1 = onwardScore(cont[1], rng);\n\n                    if (s0 == s1) {\n                        chosen = cont[rng.nextInt(2)];\n                    } else if (s0 > s1) {\n                        chosen = (rng.nextInt(5) ? cont[0] : cont[1]);\n                    } else {\n                        chosen = (rng.nextInt(5) ? cont[1] : cont[0]);\n                    }\n                }\n\n                markState(chosen);\n\n                inner++;\n                if ((inner & 255) == 0 && timer.elapsed() >= endTime) break;\n            }\n        }\n    }\n};\n\nvoid runSA(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    double startTime = timer.elapsed();\n    if (endTime - startTime < 0.01) return;\n\n    Stats initS = mgr.getStats();\n    updateBestWithManager(mgr, initS, bestState, bestScore, bestL1, bestL2);\n\n    int iter = 0;\n    double now = startTime;\n    double progress = 0.0;\n    double temp = 6e6;\n\n    while (true) {\n        if ((iter & 127) == 0) {\n            now = timer.elapsed();\n            if (now >= endTime) break;\n\n            progress = (now - startTime) / (endTime - startTime);\n            progress = min(1.0, max(0.0, progress));\n            temp = 6e6 * pow(2000.0 / 6e6, progress);\n        }\n\n        int ids[4];\n        int oldSt[4];\n        int newSt[4];\n        int m = 1;\n\n        int rr = rng.nextInt(100);\n\n        if (progress < 0.65 && rr < 6) {\n            m = 4;\n            int i = rng.nextInt(N - 1);\n            int j = rng.nextInt(N - 1);\n\n            ids[0] = i * N + j;\n            ids[1] = i * N + j + 1;\n            ids[2] = (i + 1) * N + j;\n            ids[3] = (i + 1) * N + j + 1;\n        } else if (progress < 0.85 && rr < 22) {\n            m = 2;\n            ids[0] = rng.nextInt(CELLS);\n\n            int d0 = rng.nextInt(4);\n            int nb = -1;\n\n            for (int a = 0; a < 4; a++) {\n                int d = (d0 + a) & 3;\n                if (neighCell[ids[0]][d] != -1) {\n                    nb = neighCell[ids[0]][d];\n                    break;\n                }\n            }\n\n            ids[1] = nb;\n        } else {\n            m = 1;\n            ids[0] = rng.nextInt(CELLS);\n        }\n\n        bool changed = false;\n\n        for (int x = 0; x < m; x++) {\n            int id = ids[x];\n            int cur = mgr.st[id];\n            oldSt[x] = cur;\n\n            int ns = cur;\n            int smartProb = (m == 1 ? 25 : 45);\n\n            if (rng.nextInt(100) < smartProb) {\n                int bestQ = -1000000000;\n                int ties = 0;\n\n                for (int k = 0; k < optCnt[id]; k++) {\n                    int s = optState[id][k];\n                    if (s == cur) continue;\n\n                    int q = localQuality(mgr.st, id, s);\n\n                    if (q > bestQ) {\n                        bestQ = q;\n                        ns = s;\n                        ties = 1;\n                    } else if (q == bestQ) {\n                        ties++;\n                        if (rng.nextInt(ties) == 0) ns = s;\n                    }\n                }\n            } else {\n                do {\n                    ns = optState[id][rng.nextInt(optCnt[id])];\n                } while (ns == cur);\n            }\n\n            newSt[x] = ns;\n            if (ns != cur) changed = true;\n        }\n\n        if (!changed) {\n            iter++;\n            continue;\n        }\n\n        Stats oldS = mgr.getStats();\n        long long oldE = energyValue(oldS, progress);\n\n        for (int x = 0; x < m; x++) mgr.updateCell(ids[x], newSt[x]);\n\n        Stats newS = mgr.getStats();\n        long long newE = energyValue(newS, progress);\n\n        updateBestWithManager(mgr, newS, bestState, bestScore, bestL1, bestL2);\n\n        long long diff = newE - oldE;\n        bool accept = false;\n\n        if (diff >= 0) {\n            accept = true;\n        } else {\n            double x = (double)diff / temp;\n            if (x > -30.0 && rng.nextDouble() < exp(x)) accept = true;\n        }\n\n        if (!accept) {\n            for (int x = m - 1; x >= 0; x--) mgr.updateCell(ids[x], oldSt[x]);\n        }\n\n        iter++;\n    }\n}\n\nbool trySingleMove(\n    Manager &mgr,\n    int id,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    int cur = mgr.st[id];\n\n    Stats baseS = mgr.getStats();\n    long long bestVal = finalValue(baseS);\n    int bestSt = cur;\n\n    for (int k = 0; k < optCnt[id]; k++) {\n        int s = optState[id][k];\n        if (s == cur) continue;\n\n        mgr.updateCell(id, s);\n        Stats ns = mgr.getStats();\n        long long v = finalValue(ns);\n        mgr.updateCell(id, cur);\n\n        if (v > bestVal) {\n            bestVal = v;\n            bestSt = s;\n        }\n    }\n\n    if (bestSt != cur) {\n        mgr.updateCell(id, bestSt);\n        Stats s = mgr.getStats();\n        updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n        return true;\n    }\n\n    return false;\n}\n\nbool tryMultiMove(\n    Manager &mgr,\n    const int *ids,\n    int m,\n    int prodLimit,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    for (int a = 0; a < m; a++) {\n        for (int b = 0; b < a; b++) {\n            if (ids[a] == ids[b]) return false;\n        }\n    }\n\n    int old[10];\n    int prod = 1;\n\n    for (int x = 0; x < m; x++) {\n        old[x] = mgr.st[ids[x]];\n        prod *= optCnt[ids[x]];\n        if (prod > prodLimit) return false;\n    }\n\n    Stats baseS = mgr.getStats();\n    long long bestVal = finalValue(baseS);\n\n    int bestS[10];\n    int ns[10];\n\n    for (int x = 0; x < m; x++) bestS[x] = old[x];\n\n    for (int code = 0; code < prod; code++) {\n        int tmp = code;\n        bool same = true;\n\n        for (int x = 0; x < m; x++) {\n            int id = ids[x];\n            int k = tmp % optCnt[id];\n            tmp /= optCnt[id];\n            ns[x] = optState[id][k];\n            if (ns[x] != old[x]) same = false;\n        }\n\n        if (same) continue;\n\n        for (int x = 0; x < m; x++) {\n            if (ns[x] != old[x]) mgr.updateCell(ids[x], ns[x]);\n        }\n\n        Stats st = mgr.getStats();\n        long long v = finalValue(st);\n\n        for (int x = m - 1; x >= 0; x--) {\n            if (ns[x] != old[x]) mgr.updateCell(ids[x], old[x]);\n        }\n\n        if (v > bestVal) {\n            bestVal = v;\n            for (int x = 0; x < m; x++) bestS[x] = ns[x];\n        }\n    }\n\n    bool changed = false;\n    for (int x = 0; x < m; x++) {\n        if (bestS[x] != old[x]) changed = true;\n    }\n\n    if (changed) {\n        for (int x = 0; x < m; x++) {\n            if (bestS[x] != old[x]) mgr.updateCell(ids[x], bestS[x]);\n        }\n\n        Stats s = mgr.getStats();\n        updateBestWithManager(mgr, s, bestState, bestScore, bestL1, bestL2);\n        return true;\n    }\n\n    return false;\n}\n\ninline int clampInt(int x, int lo, int hi) {\n    return min(hi, max(lo, x));\n}\n\nvoid addHot(vector<int> &hot, int c, int w) {\n    if (c < 0 || c >= CELLS) return;\n    while (w-- && (int)hot.size() < 15000) hot.push_back(c);\n}\n\nvoid collectHotCells(Manager &mgr, vector<int> &hot) {\n    hot.clear();\n\n    Stats s = mgr.getStats();\n    int pathTh = max(24, s.l2 / 2);\n    int loopTh = max(40, s.l2);\n\n    for (int id = 0; id < mgr.nextId; id++) {\n        if (!mgr.alive[id]) continue;\n\n        int len = mgr.compLen[id];\n        int br = mgr.compBroken[id];\n\n        if (br > 0 && len >= pathTh) {\n            for (int p : mgr.ports[id]) {\n                int e = adjPort[p];\n                int c = p >> 2;\n\n                if (e == -1 || !mgr.active(e)) {\n                    addHot(hot, c, 5);\n\n                    for (int d = 0; d < 4; d++) {\n                        int nb = neighCell[c][d];\n                        if (nb != -1) {\n                            addHot(hot, nb, 3);\n                            int nb2 = neighCell[nb][d];\n                            if (nb2 != -1) addHot(hot, nb2, 1);\n                        }\n                    }\n                }\n\n                if (len >= loopTh && ((p & 1) == 0)) {\n                    addHot(hot, c, 1);\n                }\n\n                if ((int)hot.size() >= 15000) return;\n            }\n        } else if (br == 0 && len >= loopTh) {\n            for (int p : mgr.ports[id]) {\n                int c = p >> 2;\n                addHot(hot, c, 1);\n\n                if ((p & 1) == 0) {\n                    for (int d = 0; d < 4; d++) {\n                        int nb = neighCell[c][d];\n                        if (nb != -1) addHot(hot, nb, 1);\n                    }\n                }\n\n                if ((int)hot.size() >= 15000) return;\n            }\n        }\n    }\n}\n\nvoid runHillClimb(\n    Manager &mgr,\n    Timer &timer,\n    double endTime,\n    RNG &rng,\n    StateArr &bestState,\n    long long &bestScore,\n    int &bestL1,\n    int &bestL2\n) {\n    double mainEnd = endTime - 0.020;\n\n    mgr.build(bestState);\n\n    array<int, CELLS> order;\n    for (int i = 0; i < CELLS; i++) order[i] = i;\n    for (int i = CELLS - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(order[i], order[j]);\n    }\n\n    for (int oi = 0; oi < CELLS; oi++) {\n        if ((oi & 31) == 0 && timer.elapsed() >= mainEnd) break;\n        trySingleMove(mgr, order[oi], bestState, bestScore, bestL1, bestL2);\n    }\n\n    constexpr int BLOCKS = (N - 1) * (N - 1);\n    array<int, BLOCKS> blocks;\n    for (int i = 0; i < BLOCKS; i++) blocks[i] = i;\n    for (int i = BLOCKS - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(blocks[i], blocks[j]);\n    }\n\n    for (int bi = 0; bi < BLOCKS; bi++) {\n        if ((bi & 7) == 0 && timer.elapsed() >= mainEnd - 0.10) break;\n\n        int b = blocks[bi];\n        int i = b / (N - 1);\n        int j = b % (N - 1);\n\n        int ids[10] = {\n            i * N + j,\n            i * N + j + 1,\n            (i + 1) * N + j,\n            (i + 1) * N + j + 1\n        };\n\n        tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n    }\n\n    for (int i = CELLS - 1; i > 0; i--) {\n        int j = rng.nextInt(i + 1);\n        swap(order[i], order[j]);\n    }\n\n    for (int oi = 0; oi < CELLS; oi++) {\n        if ((oi & 31) == 0 && timer.elapsed() >= mainEnd - 0.075) break;\n        trySingleMove(mgr, order[oi], bestState, bestScore, bestL1, bestL2);\n    }\n\n    vector<int> hot;\n    collectHotCells(mgr, hot);\n\n    auto pickCell = [&](int hotProb) -> int {\n        if (!hot.empty() && rng.nextInt(100) < hotProb) {\n            return hot[rng.nextInt((int)hot.size())];\n        }\n        return rng.nextInt(CELLS);\n    };\n\n    auto pickNeighbor = [&](int c) -> int {\n        int d0 = rng.nextInt(4);\n        for (int a = 0; a < 4; a++) {\n            int d = (d0 + a) & 3;\n            if (neighCell[c][d] != -1) return neighCell[c][d];\n        }\n        return -1;\n    };\n\n    auto makeLine = [&](int len, int ids[10]) {\n        bool horiz = rng.nextInt(2) == 0;\n        int c = pickCell(40);\n        int i = c / N;\n        int j = c % N;\n\n        if (horiz) {\n            int sj = clampInt(j - rng.nextInt(len), 0, N - len);\n            for (int k = 0; k < len; k++) ids[k] = i * N + sj + k;\n        } else {\n            int si = clampInt(i - rng.nextInt(len), 0, N - len);\n            for (int k = 0; k < len; k++) ids[k] = (si + k) * N + j;\n        }\n    };\n\n    auto makeBlock = [&](int h, int w, int ids[10]) {\n        int c = pickCell(50);\n        int i = c / N;\n        int j = c % N;\n\n        int si = clampInt(i - rng.nextInt(h), 0, N - h);\n        int sj = clampInt(j - rng.nextInt(w), 0, N - w);\n\n        int t = 0;\n        for (int a = 0; a < h; a++) {\n            for (int b = 0; b < w; b++) {\n                ids[t++] = (si + a) * N + (sj + b);\n            }\n        }\n    };\n\n    auto makeL3 = [&](int ids[10]) {\n        int c = pickCell(55);\n        int i = c / N;\n        int j = c % N;\n\n        int si = clampInt(i - rng.nextInt(2), 0, N - 2);\n        int sj = clampInt(j - rng.nextInt(2), 0, N - 2);\n\n        int all[4] = {\n            si * N + sj,\n            si * N + sj + 1,\n            (si + 1) * N + sj,\n            (si + 1) * N + sj + 1\n        };\n\n        int omit = rng.nextInt(4);\n        int t = 0;\n        for (int k = 0; k < 4; k++) {\n            if (k != omit) ids[t++] = all[k];\n        }\n    };\n\n    auto makeT4 = [&](int ids[10]) {\n        int c = pickCell(55);\n        int i = clampInt(c / N, 1, N - 2);\n        int j = clampInt(c % N, 1, N - 2);\n\n        ids[0] = i * N + j;\n\n        int omit = rng.nextInt(4);\n        int t = 1;\n\n        for (int d = 0; d < 4; d++) {\n            if (d == omit) continue;\n            int nb = (i + di[d]) * N + (j + dj[d]);\n            ids[t++] = nb;\n        }\n    };\n\n    auto makePlus5 = [&](int ids[10]) {\n        int c = pickCell(60);\n        int i = clampInt(c / N, 1, N - 2);\n        int j = clampInt(c % N, 1, N - 2);\n\n        ids[0] = i * N + j;\n        for (int d = 0; d < 4; d++) {\n            ids[d + 1] = (i + di[d]) * N + (j + dj[d]);\n        }\n    };\n\n    auto makeTwoPairs = [&](int ids[10]) -> bool {\n        for (int rep = 0; rep < 8; rep++) {\n            int a = pickCell(70);\n            int b = pickNeighbor(a);\n            int c = pickCell(70);\n            int d = pickNeighbor(c);\n\n            if (b == -1 || d == -1) continue;\n\n            ids[0] = a;\n            ids[1] = b;\n            ids[2] = c;\n            ids[3] = d;\n\n            bool ok = true;\n            for (int x = 0; x < 4; x++) {\n                for (int y = 0; y < x; y++) {\n                    if (ids[x] == ids[y]) ok = false;\n                }\n            }\n\n            if (ok) return true;\n        }\n\n        return false;\n    };\n\n    auto makeThreePairs = [&](int ids[10]) -> bool {\n        for (int rep = 0; rep < 10; rep++) {\n            bool ok = true;\n\n            for (int k = 0; k < 3; k++) {\n                int a = pickCell(75);\n                int b = pickNeighbor(a);\n\n                if (b == -1) {\n                    ok = false;\n                    break;\n                }\n\n                ids[2 * k] = a;\n                ids[2 * k + 1] = b;\n            }\n\n            if (!ok) continue;\n\n            for (int x = 0; x < 6; x++) {\n                for (int y = 0; y < x; y++) {\n                    if (ids[x] == ids[y]) ok = false;\n                }\n            }\n\n            if (ok) return true;\n        }\n\n        return false;\n    };\n\n    for (int rep = 0; rep < 180; rep++) {\n        if ((rep & 7) == 0 && timer.elapsed() >= mainEnd - 0.06) break;\n\n        int ids[10];\n        int t = rep % 7;\n\n        if (t == 0) {\n            int id = pickCell(80);\n            trySingleMove(mgr, id, bestState, bestScore, bestL1, bestL2);\n        } else if (t == 1) {\n            makeBlock(2, 2, ids);\n            tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n        } else if (t == 2) {\n            makeLine(4, ids);\n            tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n        } else if (t == 3) {\n            makeT4(ids);\n            tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n        } else if (t == 4) {\n            makeLine(5, ids);\n            tryMultiMove(mgr, ids, 5, 512, bestState, bestScore, bestL1, bestL2);\n        } else if (t == 5) {\n            if (makeTwoPairs(ids)) {\n                tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        } else {\n            if (makeThreePairs(ids)) {\n                tryMultiMove(mgr, ids, 6, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        }\n    }\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 7) == 0) {\n            if (timer.elapsed() >= mainEnd) break;\n        }\n\n        if ((iter & 47) == 0) {\n            collectHotCells(mgr, hot);\n        }\n\n        int mt = rng.nextInt(100);\n\n        if (mt < 20) {\n            int id = pickCell(45);\n            trySingleMove(mgr, id, bestState, bestScore, bestL1, bestL2);\n        } else if (mt < 33) {\n            int ids[10];\n            ids[0] = pickCell(45);\n            ids[1] = pickNeighbor(ids[0]);\n\n            if (ids[1] != -1) {\n                tryMultiMove(mgr, ids, 2, 64, bestState, bestScore, bestL1, bestL2);\n            }\n        } else if (mt < 39) {\n            int ids[10];\n            if (makeTwoPairs(ids)) {\n                tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        } else if (mt < 42) {\n            int ids[10];\n            if (makeThreePairs(ids)) {\n                tryMultiMove(mgr, ids, 6, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        } else if (mt < 51) {\n            int ids[10];\n            makeLine(3, ids);\n            tryMultiMove(mgr, ids, 3, 128, bestState, bestScore, bestL1, bestL2);\n        } else if (mt < 60) {\n            int ids[10];\n            makeL3(ids);\n            tryMultiMove(mgr, ids, 3, 128, bestState, bestScore, bestL1, bestL2);\n        } else if (mt < 67) {\n            int ids[10];\n            makeLine(4, ids);\n            tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n        } else if (mt < 72) {\n            int ids[10];\n            makeLine(5, ids);\n            tryMultiMove(mgr, ids, 5, 512, bestState, bestScore, bestL1, bestL2);\n        } else if (mt < 83) {\n            if (timer.elapsed() < mainEnd - 0.006) {\n                int ids[10];\n                makeBlock(2, 2, ids);\n                tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        } else if (mt < 90) {\n            if (timer.elapsed() < mainEnd - 0.008) {\n                int ids[10];\n                makeT4(ids);\n                tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        } else if (mt < 95) {\n            if (timer.elapsed() < mainEnd - 0.012) {\n                int ids[10];\n                makePlus5(ids);\n                tryMultiMove(mgr, ids, 5, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        } else if (mt < 98) {\n            if (timer.elapsed() < mainEnd - 0.018) {\n                int ids[10];\n\n                if (rng.nextInt(2) == 0) {\n                    makeBlock(2, 3, ids);\n                } else {\n                    makeBlock(3, 2, ids);\n                }\n\n                tryMultiMove(mgr, ids, 6, 256, bestState, bestScore, bestL1, bestL2);\n            }\n        } else {\n            if (timer.elapsed() < mainEnd - 0.03) {\n                int ids[10];\n                makeBlock(3, 3, ids);\n                tryMultiMove(mgr, ids, 9, 512, bestState, bestScore, bestL1, bestL2);\n            }\n        }\n\n        iter++;\n    }\n\n    if (timer.elapsed() < endTime) {\n        STRICT_FINAL = true;\n\n        mgr.build(bestState);\n        collectHotCells(mgr, hot);\n\n        int piter = 0;\n\n        while (timer.elapsed() < endTime) {\n            if ((piter & 31) == 0) collectHotCells(mgr, hot);\n\n            int mt = rng.nextInt(100);\n            int ids[10];\n\n            if (mt < 38) {\n                int id = pickCell(55);\n                trySingleMove(mgr, id, bestState, bestScore, bestL1, bestL2);\n            } else if (mt < 58) {\n                ids[0] = pickCell(55);\n                ids[1] = pickNeighbor(ids[0]);\n\n                if (ids[1] != -1) {\n                    tryMultiMove(mgr, ids, 2, 64, bestState, bestScore, bestL1, bestL2);\n                }\n            } else if (mt < 78) {\n                if (timer.elapsed() < endTime - 0.004) {\n                    makeBlock(2, 2, ids);\n                    tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n                }\n            } else if (mt < 90) {\n                makeLine(3, ids);\n                tryMultiMove(mgr, ids, 3, 128, bestState, bestScore, bestL1, bestL2);\n            } else {\n                if (timer.elapsed() < endTime - 0.006) {\n                    makeT4(ids);\n                    tryMultiMove(mgr, ids, 4, 512, bestState, bestScore, bestL1, bestL2);\n                }\n            }\n\n            piter++;\n        }\n\n        STRICT_FINAL = false;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initGlobals();\n\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        string row;\n        cin >> row;\n\n        for (int j = 0; j < N; j++) {\n            int id = i * N + j;\n            int t = row[j] - '0';\n\n            baseTile[id] = t;\n            seed = seed * 1000003ULL + (uint64_t)(t + 17);\n        }\n    }\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n\n        if (b < 4) {\n            optCnt[id] = 4;\n            for (int k = 0; k < 4; k++) optState[id][k] = k;\n        } else if (b < 6) {\n            optCnt[id] = 2;\n            optState[id][0] = 4;\n            optState[id][1] = 5;\n        } else {\n            optCnt[id] = 2;\n            optState[id][0] = 6;\n            optState[id][1] = 7;\n        }\n    }\n\n    buildMoveTransitions();\n\n    Timer timer;\n    RNG rng(seed);\n\n    Manager mgr;\n\n    StateArr bestState{};\n    long long bestScore = -1;\n    int bestL1 = 0;\n    int bestL2 = 0;\n\n    vector<pair<long long, StateArr>> topStarts;\n\n    auto insertTop = [&](long long val, const StateArr &s) {\n        topStarts.push_back({val, s});\n\n        sort(topStarts.begin(), topStarts.end(),\n             [](const auto &a, const auto &b) {\n                 return a.first > b.first;\n             });\n\n        if ((int)topStarts.size() > 12) topStarts.pop_back();\n    };\n\n    auto evalCandidate = [&](const StateArr &cand) {\n        mgr.build(cand);\n        Stats s = mgr.getStats();\n\n        updateBestWithState(cand, s, bestState, bestScore, bestL1, bestL2);\n        insertTop(startValue(s), cand);\n    };\n\n    StateArr baseArr;\n    for (int id = 0; id < CELLS; id++) baseArr[id] = baseTile[id];\n    evalCandidate(baseArr);\n\n    CycleSampler sampler;\n    sampler.sample(timer, 0.31, rng);\n\n    auto &cycles = sampler.cycles;\n\n    sort(cycles.begin(), cycles.end(),\n         [](const Cycle &a, const Cycle &b) {\n             return a.len > b.len;\n         });\n\n    vector<tuple<long long, int, int>> topPairs;\n\n    auto insertPair = [&](long long prod, int a, int b) {\n        topPairs.emplace_back(prod, a, b);\n\n        sort(topPairs.begin(), topPairs.end(),\n             [](const auto &x, const auto &y) {\n                 return get<0>(x) > get<0>(y);\n             });\n\n        if ((int)topPairs.size() > 16) topPairs.pop_back();\n    };\n\n    int C = (int)cycles.size();\n\n    if (C > 0) {\n        for (int i = 0; i < C; i++) {\n            if ((int)topPairs.size() >= 16 &&\n                1LL * cycles[i].len * cycles[0].len <= get<0>(topPairs.back())) {\n                break;\n            }\n\n            for (int j = i + 1; j < C; j++) {\n                long long prod = 1LL * cycles[i].len * cycles[j].len;\n\n                if ((int)topPairs.size() >= 16 && prod <= get<0>(topPairs.back())) {\n                    break;\n                }\n\n                if (!incompatibleCycle(cycles[i], cycles[j])) {\n                    insertPair(prod, i, j);\n                }\n            }\n        }\n    }\n\n    auto applyCycle = [&](const Cycle &cy, StateArr &cand, array<char, CELLS> &fixed) {\n        for (int c : cy.cells) {\n            cand[c] = cy.cstate[c];\n            fixed[c] = 1;\n        }\n    };\n\n    for (int p = 0; p < (int)topPairs.size(); p++) {\n        if (timer.elapsed() > 0.48) break;\n\n        int a = get<1>(topPairs[p]);\n        int b = get<2>(topPairs[p]);\n\n        for (int var = 0; var < 2; var++) {\n            if (timer.elapsed() > 0.50) break;\n\n            StateArr cand;\n            array<char, CELLS> fixed{};\n            fixed.fill(0);\n\n            if (var == 0) {\n                for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n            } else {\n                for (int id = 0; id < CELLS; id++) {\n                    cand[id] = optState[id][rng.nextInt(optCnt[id])];\n                }\n            }\n\n            applyCycle(cycles[a], cand, fixed);\n            applyCycle(cycles[b], cand, fixed);\n\n            greedyImprove(cand, rng, 7 + var, fixed.data());\n            evalCandidate(cand);\n        }\n    }\n\n    for (int sidx = 0; sidx < min(5, C); sidx++) {\n        if (timer.elapsed() > 0.51) break;\n\n        StateArr cand;\n        array<char, CELLS> fixed{};\n        fixed.fill(0);\n\n        for (int id = 0; id < CELLS; id++) {\n            cand[id] = optState[id][rng.nextInt(optCnt[id])];\n        }\n\n        applyCycle(cycles[sidx], cand, fixed);\n        greedyImprove(cand, rng, 7, fixed.data());\n        evalCandidate(cand);\n    }\n\n    constexpr int CAND_LIMIT = 50;\n    constexpr double START_END = 0.54;\n\n    for (int c = 0; c < CAND_LIMIT; c++) {\n        if (c > 4 && timer.elapsed() > START_END) break;\n\n        StateArr cand;\n\n        if (c == 0) {\n            for (int id = 0; id < CELLS; id++) cand[id] = baseTile[id];\n        } else {\n            for (int id = 0; id < CELLS; id++) {\n                cand[id] = optState[id][rng.nextInt(optCnt[id])];\n            }\n        }\n\n        int sweeps = 7 + (c % 4);\n        greedyImprove(cand, rng, sweeps);\n\n        evalCandidate(cand);\n    }\n\n    vector<StateArr> starts;\n\n    auto addUniqueStart = [&](const StateArr &s) {\n        for (const auto &t : starts) {\n            if (t == s) return;\n        }\n        starts.push_back(s);\n    };\n\n    addUniqueStart(bestState);\n\n    for (auto &p : topStarts) addUniqueStart(p.second);\n\n    if (starts.empty()) {\n        StateArr init;\n        for (int id = 0; id < CELLS; id++) init[id] = baseTile[id];\n        starts.push_back(init);\n        bestState = init;\n    }\n\n    double SA_END = 1.58;\n    double HILL_END = 1.965;\n\n    int runs = min(4, (int)starts.size());\n\n    for (int r = 0; r < runs; r++) {\n        double now = timer.elapsed();\n\n        if (now >= SA_END) break;\n\n        double endTime = now + (SA_END - now) / (runs - r);\n\n        mgr.build(starts[r]);\n        runSA(mgr, timer, endTime, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    if (timer.elapsed() < HILL_END) {\n        runHillClimb(mgr, timer, HILL_END, rng, bestState, bestScore, bestL1, bestL2);\n    }\n\n    string ans;\n    ans.reserve(CELLS);\n\n    for (int id = 0; id < CELLS; id++) {\n        int b = baseTile[id];\n        int f = bestState[id];\n        int r;\n\n        if (b < 4) {\n            r = (f - b + 4) % 4;\n        } else {\n            r = (f == b ? 0 : 1);\n        }\n\n        ans.push_back(char('0' + r));\n    }\n\n    cout << ans << '\\n';\n    return 0;\n}","ahc011":"#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\nint N, T, NN, M;\nvector<int> initBoard;\nint initBlank;\nint invCnt[16];\nint nbCell[105][4];\nint nearDistMask[16][105];\n\nconst int DR[4] = {-1, 1, 0, 0};\nconst int DC[4] = {0, 0, -1, 1};\nconst char DCH[4] = {'U', 'D', 'L', 'R'};\nconst int OPP[4] = {1, 0, 3, 2};\n\nstruct Shape {\n    int h, w, ori;\n};\n\nint hexVal(char c) {\n    if ('0' <= c && c <= '9') return c - '0';\n    return c - 'a' + 10;\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\nint bitForDir(int d) {\n    if (d == 0) return 2;\n    if (d == 1) return 8;\n    if (d == 2) return 1;\n    return 4;\n}\n\nint manhattanCell(int a, int b) {\n    return abs(a / N - b / N) + abs(a % N - b % N);\n}\n\nint transToAct(int tid, int ori) {\n    int r = tid / N, c = tid % N;\n    if (ori == 0) return r * N + c;\n    if (ori == 1) return r * N + (N - 1 - c);\n    if (ori == 2) return (N - 1 - r) * N + c;\n    return (N - 1 - r) * N + (N - 1 - c);\n}\n\nint actToTrans(int aid, int ori) {\n    int r = aid / N, c = aid % N;\n    if (ori == 0) return r * N + c;\n    if (ori == 1) return r * N + (N - 1 - c);\n    if (ori == 2) return (N - 1 - r) * N + c;\n    return (N - 1 - r) * N + (N - 1 - c);\n}\n\nint mapDirTransToAct(int d, int ori) {\n    static int mp[4][4] = {\n        {0, 1, 2, 3},\n        {0, 1, 3, 2},\n        {1, 0, 2, 3},\n        {1, 0, 3, 2},\n    };\n    return mp[ori][d];\n}\n\nbool inRegionCell(int aid, const Shape& s) {\n    int tid = actToTrans(aid, s.ori);\n    int r = tid / N, c = tid % N;\n    return !(r >= N - s.h && c >= N - s.w);\n}\n\nint shapeArea(const Shape& s) {\n    return s.h * s.w;\n}\n\nint freeBlankCell(const Shape& s) {\n    return transToAct((N - 1) * N + (N - 1), s.ori);\n}\n\nvector<int> freeCellsOf(const Shape& s) {\n    vector<int> cells;\n    for (int r = N - s.h; r < N; r++) {\n        for (int c = N - s.w; c < N; c++) {\n            cells.push_back(transToAct(r * N + c, s.ori));\n        }\n    }\n    return cells;\n}\n\nstruct FastDSU {\n    int p[105], sz[105];\n\n    void init(int n) {\n        for (int i = 0; i < n; i++) {\n            p[i] = i;\n            sz[i] = 1;\n        }\n    }\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\n    void unite(int a, int b) {\n        a = find(a);\n        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 Eval {\n    int S;\n    int edges;\n    int maxComp;\n};\n\nEval evalBoard(const vector<int>& bd) {\n    FastDSU dsu;\n    dsu.init(NN);\n\n    pair<int, int> edges[220];\n    int ec = 0;\n\n    for (int r = 0; r < N; r++) {\n        for (int c = 0; c < N; c++) {\n            int id = r * N + c;\n            int v = bd[id];\n            if (v == 0) continue;\n\n            if (c + 1 < N) {\n                int j = id + 1;\n                if (bd[j] != 0 && (v & 4) && (bd[j] & 1)) {\n                    dsu.unite(id, j);\n                    edges[ec++] = {id, j};\n                }\n            }\n\n            if (r + 1 < N) {\n                int j = id + N;\n                if (bd[j] != 0 && (v & 8) && (bd[j] & 2)) {\n                    dsu.unite(id, j);\n                    edges[ec++] = {id, j};\n                }\n            }\n        }\n    }\n\n    int vcnt[105] = {};\n    int ecnt[105] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (bd[i] != 0) vcnt[dsu.find(i)]++;\n    }\n    for (int i = 0; i < ec; i++) {\n        ecnt[dsu.find(edges[i].first)]++;\n    }\n\n    int best = 0;\n    int mx = 0;\n\n    for (int i = 0; i < NN; i++) {\n        if (dsu.find(i) == i && vcnt[i] > 0) {\n            mx = max(mx, vcnt[i]);\n            if (ecnt[i] == vcnt[i] - 1) best = max(best, vcnt[i]);\n        }\n    }\n\n    return {best, ec, mx};\n}\n\nlong long scoreFromEval(const Eval& e, int K) {\n    if (e.S == M) {\n        return llround(500000.0 * (2.0 - (double)K / T));\n    } else {\n        return llround(500000.0 * (double)e.S / M);\n    }\n}\n\nbool applyDir(vector<int>& bd, int& blank, int d) {\n    int nb = nbCell[blank][d];\n    if (nb < 0) return false;\n    swap(bd[blank], bd[nb]);\n    blank = nb;\n    return true;\n}\n\nvector<int> simulateMoves(const string& moves) {\n    vector<int> bd = initBoard;\n    int blank = initBlank;\n\n    for (char ch : moves) {\n        int d = dirIndex(ch);\n        if (!applyDir(bd, blank, d)) break;\n    }\n\n    return bd;\n}\n\nstring simplifyMoves(const string& s) {\n    string res;\n\n    for (char ch : s) {\n        int d = dirIndex(ch);\n        if (!res.empty() && dirIndex(res.back()) == OPP[d]) {\n            res.pop_back();\n        } else {\n            res.push_back(ch);\n        }\n    }\n\n    return res;\n}\n\nstruct BestAns {\n    string moves;\n    long long score = -1;\n    int S = 0;\n};\n\nvoid updateBestKnownBoard(BestAns& best, const string& mv0, const vector<int>& bd) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n\n    Eval e = evalBoard(bd);\n    long long sc = scoreFromEval(e, (int)mv.size());\n\n    if (sc > best.score || (sc == best.score && mv.size() < best.moves.size())) {\n        best.score = sc;\n        best.moves = mv;\n        best.S = e.S;\n    }\n}\n\nvoid updateBest(BestAns& best, const string& mv0) {\n    string mv = simplifyMoves(mv0);\n    if ((int)mv.size() > T) return;\n\n    vector<int> bd = simulateMoves(mv);\n    updateBestKnownBoard(best, mv, bd);\n}\n\nuint64_t hashRegionMask(const vector<int>& mask, const Shape& s) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)(s.h * 100 + s.w * 10 + s.ori);\n    h *= 1099511628211ULL;\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) {\n            h ^= (uint64_t)(mask[i] + 17);\n            h *= 1099511628211ULL;\n        }\n    }\n\n    return h;\n}\n\nint rectHungarian(const vector<int>& targets, const vector<int>& sources) {\n    int n = (int)targets.size();\n    int m = (int)sources.size();\n\n    if (n == 0) return 0;\n    if (n > m) return 1000000000;\n\n    const int INF = 1000000000;\n    vector<vector<int>> cost(n, vector<int>(m));\n\n    for (int i = 0; i < n; i++) {\n        int tr = targets[i] / N;\n        int tc = targets[i] % N;\n\n        for (int j = 0; j < m; j++) {\n            int sr = sources[j] / N;\n            int sc = sources[j] % N;\n            cost[i][j] = abs(tr - sr) + abs(tc - sc);\n        }\n    }\n\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\n        vector<int> minv(m + 1, INF);\n        vector<char> used(m + 1, false);\n\n        do {\n            used[j0] = true;\n            int i0 = p[j0];\n            int delta = INF;\n            int j1 = 0;\n\n            for (int j = 1; j <= m; j++) {\n                if (used[j]) continue;\n\n                int cur = cost[i0 - 1][j - 1] - u[i0] - v[j];\n\n                if (cur < minv[j]) {\n                    minv[j] = cur;\n                    way[j] = j0;\n                }\n\n                if (minv[j] < delta) {\n                    delta = minv[j];\n                    j1 = j;\n                }\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\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);\n    }\n\n    return -v[0];\n}\n\nint partialMatchingCost(const vector<int>& target, const Shape& s) {\n    int total = 0;\n\n    for (int m = 1; m < 16; m++) {\n        vector<int> A;\n        vector<int> S;\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, s) && target[i] == m) A.push_back(i);\n            if (initBoard[i] == m) S.push_back(i);\n        }\n\n        if (A.size() > S.size()) return 1000000000;\n        total += rectHungarian(A, S);\n    }\n\n    return total;\n}\n\nint kindRank(int kind) {\n    if (kind == 1) return 0;\n    if (kind == 0) return 1;\n    return 2;\n}\n\nstruct Candidate {\n    vector<int> target;\n    Shape s;\n    int expectedS;\n    int estCost;\n    int kind;\n    uint64_t hash;\n};\n\nlong long candidateValue(const Candidate& c) {\n    return (long long)c.expectedS * 1000000LL\n         - (long long)(c.estCost + kindRank(c.kind) * 40) * 1000LL\n         - (long long)shapeArea(c.s) * 100LL;\n}\n\nvoid addPartialCandidate(vector<Candidate>& cands, const vector<int>& regionMask, const Shape& s, int kind) {\n    int cnt[16] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (!inRegionCell(i, s)) continue;\n        int m = regionMask[i];\n        if (m <= 0 || m >= 16) return;\n        cnt[m]++;\n    }\n\n    for (int m = 0; m < 16; m++) {\n        if (cnt[m] > invCnt[m]) return;\n    }\n\n    vector<int> freeCells = freeCellsOf(s);\n    vector<int> target(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) target[i] = regionMask[i];\n    }\n\n    int blankCell = freeBlankCell(s);\n    target[blankCell] = 0;\n\n    vector<int> remCnt(16);\n    int remSum = 0;\n\n    for (int m = 1; m < 16; m++) {\n        remCnt[m] = invCnt[m] - cnt[m];\n        remSum += remCnt[m];\n    }\n\n    if (remSum != (int)freeCells.size() - 1) return;\n\n    int ptr = 1;\n\n    for (int id : freeCells) {\n        if (id == blankCell) continue;\n\n        while (ptr < 16 && remCnt[ptr] == 0) ptr++;\n        if (ptr >= 16) return;\n\n        target[id] = ptr;\n        remCnt[ptr]--;\n    }\n\n    vector<int> ideal(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) ideal[i] = regionMask[i];\n    }\n\n    Eval e = evalBoard(ideal);\n    int est = partialMatchingCost(target, s);\n\n    if (est >= 1000000000) return;\n\n    uint64_t h = hashRegionMask(regionMask, s);\n\n    for (auto& c : cands) {\n        if (c.hash == h && c.s.h == s.h && c.s.w == s.w && c.s.ori == s.ori) {\n            if (kindRank(kind) < kindRank(c.kind)) c.kind = kind;\n            return;\n        }\n    }\n\n    Candidate nc{target, s, e.S, est, kind, h};\n\n    const int MAX_CANDS = 840;\n\n    if ((int)cands.size() < MAX_CANDS) {\n        cands.push_back(nc);\n    } else {\n        int worst = 0;\n\n        for (int i = 1; i < (int)cands.size(); i++) {\n            if (candidateValue(cands[i]) < candidateValue(cands[worst])) {\n                worst = i;\n            }\n        }\n\n        if (candidateValue(nc) > candidateValue(cands[worst])) {\n            cands[worst] = nc;\n        }\n    }\n}\n\nint outwardToFreeBits(int id, const Shape& s) {\n    int bits = 0;\n\n    for (int d = 0; d < 4; d++) {\n        int nb = nbCell[id][d];\n\n        if (nb >= 0 && !inRegionCell(nb, s)) {\n            bits |= bitForDir(d);\n        }\n    }\n\n    return bits;\n}\n\nvoid adjustAndAddCandidate(vector<Candidate>& cands, vector<int> regMask, const Shape& s) {\n    int cnt[16] = {};\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) cnt[regMask[i]]++;\n    }\n\n    vector<int> cur(NN, 0);\n\n    for (int i = 0; i < NN; i++) {\n        if (inRegionCell(i, s)) cur[i] = regMask[i];\n    }\n\n    int guard = 0;\n\n    while (guard++ < 260) {\n        int over = -1;\n\n        for (int m = 1; m < 16; m++) {\n            if (cnt[m] > invCnt[m]) {\n                over = m;\n                break;\n            }\n        }\n\n        if (over == -1) break;\n\n        vector<int> deficits;\n\n        for (int m = 1; m < 16; m++) {\n            if (cnt[m] < invCnt[m]) deficits.push_back(m);\n        }\n\n        if (deficits.empty()) break;\n\n        int bestCell = -1;\n        int bestNew = -1;\n        long long bestVal = LLONG_MIN;\n\n        for (int id = 0; id < NN; id++) {\n            if (!inRegionCell(id, s) || cur[id] != over) continue;\n\n            int old = cur[id];\n\n            for (int nm : deficits) {\n                cur[id] = nm;\n                Eval e = evalBoard(cur);\n\n                int outPenalty = __builtin_popcount((unsigned)(nm & outwardToFreeBits(id, s)));\n\n                long long val =\n                    (long long)e.S * 1000000LL +\n                    (long long)e.maxComp * 5000LL +\n                    (long long)e.edges * 100LL -\n                    (long long)outPenalty * 250000LL -\n                    (long long)nearDistMask[nm][id] * 240LL -\n                    (long long)__builtin_popcount((unsigned)(nm ^ old)) * 60LL;\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestCell = id;\n                    bestNew = nm;\n                }\n            }\n\n            cur[id] = old;\n        }\n\n        if (bestCell < 0) break;\n\n        int old = cur[bestCell];\n        cur[bestCell] = bestNew;\n        cnt[old]--;\n        cnt[bestNew]++;\n    }\n\n    for (int m = 0; m < 16; m++) {\n        if (cnt[m] > invCnt[m]) return;\n    }\n\n    addPartialCandidate(cands, cur, s, 0);\n}\n\nvector<int> canonicalTreeMask(const Shape& s) {\n    vector<int> mask(NN, 0);\n    int root = 0;\n\n    for (int tid = 0; tid < NN; tid++) {\n        int aid = transToAct(tid, s.ori);\n\n        if (!inRegionCell(aid, s) || tid == root) continue;\n\n        int r = tid / N;\n        int c = tid % N;\n        int parentTid = -1;\n        int childTransDir = -1;\n\n        if (r > 0 && inRegionCell(transToAct(tid - N, s.ori), s)) {\n            parentTid = tid - N;\n            childTransDir = 0;\n        } else if (c > 0 && inRegionCell(transToAct(tid - 1, s.ori), s)) {\n            parentTid = tid - 1;\n            childTransDir = 2;\n        }\n\n        if (parentTid < 0) continue;\n\n        int pid = transToAct(parentTid, s.ori);\n        int childActualDir = mapDirTransToAct(childTransDir, s.ori);\n        int parentActualDir = OPP[childActualDir];\n\n        mask[aid] |= bitForDir(childActualDir);\n        mask[pid] |= bitForDir(parentActualDir);\n    }\n\n    return mask;\n}\n\nstruct Edge {\n    int a, b;\n    int ba, bb;\n};\n\nconst int OVER_W = 120000;\nconst int DIST_W = 95;\nconst int POS_W = 12;\n\nstruct Change {\n    int vc = 0;\n    int verts[4];\n    int oldm[4];\n    int newm[4];\n    int dcnt[16];\n    int overD = 0;\n    int distD = 0;\n    int posD = 0;\n    int energyD = 0;\n};\n\nstruct RegionTreeState {\n    Shape s;\n    vector<char> inReg;\n    vector<int> verts;\n    vector<Edge> edges;\n    int E;\n\n    vector<char> inTree;\n    vector<vector<int>> adj;\n    vector<int> mask;\n\n    int cnt[16];\n    int overflow = 0;\n    int distCost = 0;\n    int posCost = 0;\n\n    vector<int> par;\n    vector<int> pare;\n    vector<int> qbuf;\n    vector<int> path;\n\n    RegionTreeState(const Shape& s_) : s(s_) {\n        inReg.assign(NN, 0);\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, s)) {\n                inReg[i] = 1;\n                verts.push_back(i);\n            }\n        }\n\n        for (int tid = 0; tid < NN; tid++) {\n            int aid = transToAct(tid, s.ori);\n            if (!inReg[aid]) continue;\n\n            int r = tid / N;\n            int c = tid % N;\n\n            if (c + 1 < N) {\n                int ntid = tid + 1;\n                int bid = transToAct(ntid, s.ori);\n\n                if (inReg[bid]) {\n                    int d = mapDirTransToAct(3, s.ori);\n                    edges.push_back({aid, bid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n\n            if (r + 1 < N) {\n                int ntid = tid + N;\n                int bid = transToAct(ntid, s.ori);\n\n                if (inReg[bid]) {\n                    int d = mapDirTransToAct(1, s.ori);\n                    edges.push_back({aid, bid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n        }\n\n        E = (int)edges.size();\n\n        inTree.assign(E, 0);\n        adj.assign(NN, {});\n        mask.assign(NN, 0);\n\n        par.resize(NN);\n        pare.resize(NN);\n        qbuf.reserve(NN);\n        path.reserve(NN);\n    }\n\n    int other(int eid, int v) const {\n        const Edge& e = edges[eid];\n        return e.a == v ? e.b : e.a;\n    }\n\n    void addInitialEdge(int eid) {\n        const Edge& e = edges[eid];\n\n        inTree[eid] = 1;\n        adj[e.a].push_back(eid);\n        adj[e.b].push_back(eid);\n        mask[e.a] |= e.ba;\n        mask[e.b] |= e.bb;\n    }\n\n    int calcOverflow() const {\n        int ov = 0;\n        for (int m = 0; m < 16; m++) ov += max(0, cnt[m] - invCnt[m]);\n        return ov;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(inTree.begin(), inTree.end(), 0);\n\n        for (auto& a : adj) a.clear();\n        fill(mask.begin(), mask.end(), 0);\n\n        vector<pair<long long, int>> ord;\n        ord.reserve(E);\n\n        for (int i = 0; i < E; i++) {\n            const Edge& e = edges[i];\n            int w = 0;\n\n            if (mode > 0) {\n                if (initBoard[e.a] & e.ba) w += 4;\n                else w -= 1;\n\n                if (initBoard[e.b] & e.bb) w += 4;\n                else w -= 1;\n\n                if (nearDistMask[e.ba][e.a] == 0) w++;\n                if (nearDistMask[e.bb][e.b] == 0) w++;\n\n                if (mode == 2) w += (int)(rng() % 7) - 3;\n            }\n\n            long long noise = ((long long)rng() << 32) ^ rng();\n            long long key = noise - (long long)w * (mode == 1 ? 950000000LL : 260000000LL);\n            if (mode == 0) key = noise;\n            ord.push_back({key, i});\n        }\n\n        sort(ord.begin(), ord.end());\n\n        FastDSU dsu;\n        dsu.init(NN);\n\n        int selected = 0;\n\n        for (auto [key, id] : ord) {\n            (void)key;\n\n            const Edge& e = edges[id];\n\n            if (dsu.find(e.a) != dsu.find(e.b)) {\n                dsu.unite(e.a, e.b);\n                addInitialEdge(id);\n                selected++;\n\n                if (selected == (int)verts.size() - 1) break;\n            }\n        }\n\n        memset(cnt, 0, sizeof(cnt));\n\n        overflow = 0;\n        distCost = 0;\n        posCost = 0;\n\n        for (int v : verts) {\n            cnt[mask[v]]++;\n            distCost += nearDistMask[mask[v]][v];\n            posCost += __builtin_popcount((unsigned)(mask[v] ^ initBoard[v]));\n        }\n\n        overflow = calcOverflow();\n    }\n\n    void getPath(int s0, int t0) {\n        fill(par.begin(), par.end(), -1);\n        qbuf.clear();\n        path.clear();\n\n        int head = 0;\n        par[s0] = s0;\n        qbuf.push_back(s0);\n\n        while (head < (int)qbuf.size()) {\n            int v = qbuf[head++];\n\n            if (v == t0) break;\n\n            for (int eid : adj[v]) {\n                if (!inTree[eid]) continue;\n\n                int u = other(eid, v);\n\n                if (par[u] == -1) {\n                    par[u] = v;\n                    pare[u] = eid;\n                    qbuf.push_back(u);\n                }\n            }\n        }\n\n        if (par[t0] == -1) return;\n\n        int cur = t0;\n        while (cur != s0) {\n            path.push_back(pare[cur]);\n            cur = par[cur];\n        }\n    }\n\n    Change makeChange(int addId, int remId) const {\n        Change ch;\n        memset(ch.dcnt, 0, sizeof(ch.dcnt));\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < ch.vc; i++) {\n                if (ch.verts[i] == v) return i;\n            }\n\n            int idx = ch.vc++;\n            ch.verts[idx] = v;\n            ch.oldm[idx] = mask[v];\n            ch.newm[idx] = mask[v];\n            return idx;\n        };\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        int ia = getIdx(ea.a);\n        ch.newm[ia] |= ea.ba;\n\n        int ib = getIdx(ea.b);\n        ch.newm[ib] |= ea.bb;\n\n        int ra = getIdx(er.a);\n        ch.newm[ra] &= ~er.ba;\n\n        int rb = getIdx(er.b);\n        ch.newm[rb] &= ~er.bb;\n\n        for (int i = 0; i < ch.vc; i++) {\n            if (ch.oldm[i] == ch.newm[i]) continue;\n\n            int v = ch.verts[i];\n\n            ch.dcnt[ch.oldm[i]]--;\n            ch.dcnt[ch.newm[i]]++;\n\n            ch.distD += nearDistMask[ch.newm[i]][v] - nearDistMask[ch.oldm[i]][v];\n            ch.posD += __builtin_popcount((unsigned)(ch.newm[i] ^ initBoard[v]))\n                     - __builtin_popcount((unsigned)(ch.oldm[i] ^ initBoard[v]));\n        }\n\n        for (int m = 0; m < 16; m++) {\n            if (ch.dcnt[m]) {\n                ch.overD += max(0, cnt[m] + ch.dcnt[m] - invCnt[m])\n                          - max(0, cnt[m] - invCnt[m]);\n            }\n        }\n\n        ch.energyD = ch.overD * OVER_W + ch.distD * DIST_W + ch.posD * POS_W;\n        return ch;\n    }\n\n    void removeAdj(int v, int eid) {\n        auto& a = adj[v];\n\n        for (int i = 0; i < (int)a.size(); i++) {\n            if (a[i] == eid) {\n                a[i] = a.back();\n                a.pop_back();\n                return;\n            }\n        }\n    }\n\n    void applySwap(int addId, int remId, const Change& ch) {\n        for (int m = 0; m < 16; m++) cnt[m] += ch.dcnt[m];\n\n        overflow += ch.overD;\n        distCost += ch.distD;\n        posCost += ch.posD;\n\n        for (int i = 0; i < ch.vc; i++) {\n            mask[ch.verts[i]] = ch.newm[i];\n        }\n\n        const Edge& ea = edges[addId];\n        const Edge& er = edges[remId];\n\n        inTree[addId] = 1;\n        inTree[remId] = 0;\n\n        adj[ea.a].push_back(addId);\n        adj[ea.b].push_back(addId);\n\n        removeAdj(er.a, remId);\n        removeAdj(er.b, remId);\n    }\n\n    void step(mt19937& rng, double temp) {\n        if (E <= (int)verts.size() - 1) return;\n\n        int addId = -1;\n\n        for (int tries = 0; tries < E * 3 + 10; tries++) {\n            int x = (int)(rng() % E);\n            if (!inTree[x]) {\n                addId = x;\n                break;\n            }\n        }\n\n        if (addId < 0) return;\n\n        const Edge& e = edges[addId];\n        getPath(e.a, e.b);\n\n        if (path.empty()) return;\n\n        int remId = -1;\n        Change bestCh;\n        int bestDelta = INT_MAX;\n\n        bool chooseBest = (rng() % 100) < 90;\n\n        if (chooseBest) {\n            for (int pe : path) {\n                Change ch = makeChange(addId, pe);\n\n                if (ch.energyD < bestDelta) {\n                    bestDelta = ch.energyD;\n                    bestCh = ch;\n                    remId = pe;\n                }\n            }\n        } else {\n            remId = path[rng() % path.size()];\n            bestCh = makeChange(addId, remId);\n            bestDelta = bestCh.energyD;\n        }\n\n        bool accept = false;\n\n        if (bestDelta <= 0) {\n            accept = true;\n        } else if (bestDelta < temp * 70.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-(double)bestDelta / temp);\n        }\n\n        if (accept) applySwap(addId, remId, bestCh);\n    }\n};\n\nvoid runPartialSearch(const Shape& s, double endTime, Timer& timer, mt19937& rng, vector<Candidate>& cands) {\n    int bestOver = INT_MAX;\n    int bestDist = INT_MAX;\n    vector<int> bestMask;\n\n    int restart = 0;\n\n    while (timer.elapsed() < endTime) {\n        RegionTreeState st(s);\n\n        int mode = restart % 3;\n        st.initRandom(mode, rng);\n\n        if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n            bestOver = st.overflow;\n            bestDist = st.distCost;\n            bestMask = st.mask;\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 2);\n\n        int maxIter = 21000 + N * 1400;\n        if (shapeArea(s) >= 20) maxIter = 16000 + N * 1000;\n\n        int bestZeroDist = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n\n            double p = (double)it / maxIter;\n            double temp = 90000.0 * pow(80.0 / 90000.0, p);\n\n            st.step(rng, temp);\n\n            if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n                bestOver = st.overflow;\n                bestDist = st.distCost;\n                bestMask = st.mask;\n            }\n\n            if (st.overflow == 0) {\n                if (st.distCost + 4 < bestZeroDist || (it & 4095) == 0) {\n                    addPartialCandidate(cands, st.mask, s, 2);\n                    bestZeroDist = min(bestZeroDist, st.distCost);\n                }\n            }\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 2);\n        restart++;\n    }\n\n    if (!bestMask.empty()) adjustAndAddCandidate(cands, bestMask, s);\n}\n\nstruct ParOpt {\n    int parent;\n    int cb;\n    int pb;\n};\n\nstruct MonoTreeState {\n    Shape s;\n    vector<int> nodes;\n    vector<vector<ParOpt>> opts;\n    vector<int> choice;\n    vector<int> flex;\n    vector<int> mask;\n    int cnt[16];\n    int overflow = 0;\n    int distCost = 0;\n    int posCost = 0;\n\n    MonoTreeState(const Shape& s_) : s(s_) {\n        mask.assign(NN, 0);\n\n        int rootTid = 0;\n\n        for (int tid = 0; tid < NN; tid++) {\n            int aid = transToAct(tid, s.ori);\n            if (!inRegionCell(aid, s) || tid == rootTid) continue;\n\n            int r = tid / N, c = tid % N;\n            vector<ParOpt> v;\n\n            if (r > 0) {\n                int ptid = tid - N;\n                int pid = transToAct(ptid, s.ori);\n                if (inRegionCell(pid, s)) {\n                    int d = mapDirTransToAct(0, s.ori);\n                    v.push_back({pid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n            if (c > 0) {\n                int ptid = tid - 1;\n                int pid = transToAct(ptid, s.ori);\n                if (inRegionCell(pid, s)) {\n                    int d = mapDirTransToAct(2, s.ori);\n                    v.push_back({pid, bitForDir(d), bitForDir(OPP[d])});\n                }\n            }\n\n            if (v.empty()) continue;\n\n            int idx = (int)nodes.size();\n            nodes.push_back(aid);\n            opts.push_back(v);\n            if (v.size() >= 2) flex.push_back(idx);\n        }\n\n        choice.assign(nodes.size(), 0);\n    }\n\n    int calcOverflow() const {\n        int ov = 0;\n        for (int m = 0; m < 16; m++) ov += max(0, cnt[m] - invCnt[m]);\n        return ov;\n    }\n\n    void initRandom(int mode, mt19937& rng) {\n        fill(mask.begin(), mask.end(), 0);\n\n        for (int i = 0; i < (int)nodes.size(); i++) {\n            int ch = nodes[i];\n\n            if (mode == 0 || opts[i].size() == 1) {\n                choice[i] = rng() % opts[i].size();\n            } else {\n                int best = 0;\n                int bestScore = -1000000;\n\n                for (int j = 0; j < (int)opts[i].size(); j++) {\n                    const ParOpt& o = opts[i][j];\n                    int sc = 0;\n                    sc += (initBoard[ch] & o.cb) ? 5 : -1;\n                    sc += (initBoard[o.parent] & o.pb) ? 5 : -1;\n                    sc -= nearDistMask[o.cb][ch];\n                    sc -= nearDistMask[o.pb][o.parent];\n                    if (mode == 2) sc += (int)(rng() % 7) - 3;\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        best = j;\n                    }\n                }\n\n                choice[i] = best;\n            }\n\n            const ParOpt& o = opts[i][choice[i]];\n            mask[ch] |= o.cb;\n            mask[o.parent] |= o.pb;\n        }\n\n        memset(cnt, 0, sizeof(cnt));\n        overflow = 0;\n        distCost = 0;\n        posCost = 0;\n\n        for (int v = 0; v < NN; v++) {\n            if (!inRegionCell(v, s)) continue;\n            cnt[mask[v]]++;\n            distCost += nearDistMask[mask[v]][v];\n            posCost += __builtin_popcount((unsigned)(mask[v] ^ initBoard[v]));\n        }\n\n        overflow = calcOverflow();\n    }\n\n    Change makeChangeNode(int idx, int newChoice) const {\n        Change chg;\n        memset(chg.dcnt, 0, sizeof(chg.dcnt));\n\n        int child = nodes[idx];\n        const ParOpt& old = opts[idx][choice[idx]];\n        const ParOpt& nw = opts[idx][newChoice];\n\n        auto getIdx = [&](int v) mutable -> int {\n            for (int i = 0; i < chg.vc; i++) {\n                if (chg.verts[i] == v) return i;\n            }\n            int k = chg.vc++;\n            chg.verts[k] = v;\n            chg.oldm[k] = mask[v];\n            chg.newm[k] = mask[v];\n            return k;\n        };\n\n        int ic = getIdx(child);\n        chg.newm[ic] &= ~old.cb;\n        chg.newm[ic] |= nw.cb;\n\n        int io = getIdx(old.parent);\n        chg.newm[io] &= ~old.pb;\n\n        int in = getIdx(nw.parent);\n        chg.newm[in] |= nw.pb;\n\n        for (int i = 0; i < chg.vc; i++) {\n            if (chg.oldm[i] == chg.newm[i]) continue;\n\n            int v = chg.verts[i];\n\n            chg.dcnt[chg.oldm[i]]--;\n            chg.dcnt[chg.newm[i]]++;\n\n            chg.distD += nearDistMask[chg.newm[i]][v] - nearDistMask[chg.oldm[i]][v];\n            chg.posD += __builtin_popcount((unsigned)(chg.newm[i] ^ initBoard[v]))\n                      - __builtin_popcount((unsigned)(chg.oldm[i] ^ initBoard[v]));\n        }\n\n        for (int m = 0; m < 16; m++) {\n            if (chg.dcnt[m]) {\n                chg.overD += max(0, cnt[m] + chg.dcnt[m] - invCnt[m])\n                           - max(0, cnt[m] - invCnt[m]);\n            }\n        }\n\n        chg.energyD = chg.overD * OVER_W + chg.distD * DIST_W + chg.posD * POS_W;\n        return chg;\n    }\n\n    void applyNode(int idx, int newChoice, const Change& chg) {\n        for (int m = 0; m < 16; m++) cnt[m] += chg.dcnt[m];\n\n        overflow += chg.overD;\n        distCost += chg.distD;\n        posCost += chg.posD;\n\n        for (int i = 0; i < chg.vc; i++) {\n            mask[chg.verts[i]] = chg.newm[i];\n        }\n\n        choice[idx] = newChoice;\n    }\n\n    void step(mt19937& rng, double temp) {\n        if (flex.empty()) return;\n\n        int idx = flex[rng() % flex.size()];\n        int cur = choice[idx];\n        int nc = cur;\n\n        if (opts[idx].size() == 2) {\n            nc = 1 - cur;\n        } else {\n            while (nc == cur) nc = rng() % opts[idx].size();\n        }\n\n        Change chg = makeChangeNode(idx, nc);\n        int delta = chg.energyD;\n\n        bool accept = false;\n\n        if (delta <= 0) {\n            accept = true;\n        } else if (delta < temp * 70.0) {\n            double r = (rng() + 0.5) * (1.0 / 4294967296.0);\n            accept = r < exp(-(double)delta / temp);\n        }\n\n        if (accept) applyNode(idx, nc, chg);\n    }\n};\n\nvoid runMonoSearch(const Shape& s, double endTime, Timer& timer, mt19937& rng, vector<Candidate>& cands) {\n    int bestOver = INT_MAX;\n    int bestDist = INT_MAX;\n    vector<int> bestMask;\n\n    int restart = 0;\n\n    while (timer.elapsed() < endTime) {\n        MonoTreeState st(s);\n\n        int mode = restart % 3;\n        st.initRandom(mode, rng);\n\n        if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n            bestOver = st.overflow;\n            bestDist = st.distCost;\n            bestMask = st.mask;\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 1);\n\n        int maxIter = 32000 + N * 1200;\n        int bestZeroDist = INT_MAX;\n\n        for (int it = 0; it < maxIter; it++) {\n            if ((it & 255) == 0 && timer.elapsed() >= endTime) break;\n\n            double p = (double)it / maxIter;\n            double temp = 90000.0 * pow(80.0 / 90000.0, p);\n\n            st.step(rng, temp);\n\n            if (st.overflow < bestOver || (st.overflow == bestOver && st.distCost < bestDist)) {\n                bestOver = st.overflow;\n                bestDist = st.distCost;\n                bestMask = st.mask;\n            }\n\n            if (st.overflow == 0) {\n                if (st.distCost + 4 < bestZeroDist || (it & 4095) == 0) {\n                    addPartialCandidate(cands, st.mask, s, 1);\n                    bestZeroDist = min(bestZeroDist, st.distCost);\n                }\n            }\n        }\n\n        if (st.overflow == 0) addPartialCandidate(cands, st.mask, s, 1);\n        restart++;\n    }\n\n    if (!bestMask.empty()) adjustAndAddCandidate(cands, bestMask, s);\n}\n\nstruct SolveResult {\n    string bestMoves;\n    int bestS;\n    bool completed;\n};\n\nstruct PathRes {\n    bool ok;\n    vector<int> path;\n};\n\nstruct SlidingSolver {\n    vector<int> board;\n    vector<int> target;\n    vector<char> fixed;\n    string ops;\n\n    int blank;\n    Shape s;\n    int variant;\n    int baseVar;\n    bool adaptive;\n    bool freeBeam;\n\n    Timer& timer;\n    double timeLimit;\n    int cap;\n\n    string localBestMoves;\n    long long localBestScore = -1;\n    int localBestS = 0;\n\n    vector<int> dirOrder;\n    vector<int> parent;\n    vector<unsigned char> pdir;\n    vector<int> que;\n\n    SlidingSolver(const vector<int>& tgt, const Shape& s_, int var, Timer& tm, double lim, int cp)\n        : board(initBoard),\n          target(tgt),\n          fixed(NN, 0),\n          blank(initBlank),\n          s(s_),\n          variant(var),\n          baseVar(var & 15),\n          adaptive((var & 16) != 0),\n          freeBeam((var & 32) != 0),\n          timer(tm),\n          timeLimit(lim),\n          cap(cp) {\n        static const int perms[8][4] = {\n            {0, 1, 2, 3},\n            {2, 3, 0, 1},\n            {1, 0, 3, 2},\n            {3, 2, 1, 0},\n            {0, 2, 1, 3},\n            {2, 0, 3, 1},\n            {1, 3, 0, 2},\n            {3, 1, 2, 0},\n        };\n\n        int pm = baseVar % 8;\n        dirOrder.assign(perms[pm], perms[pm] + 4);\n\n        parent.resize(NN * NN);\n        pdir.resize(NN * NN);\n        que.reserve(NN * NN);\n    }\n\n    void considerLocal() {\n        if ((int)ops.size() > T) return;\n\n        Eval e = evalBoard(board);\n        long long sc = scoreFromEval(e, (int)ops.size());\n\n        if (sc > localBestScore || (sc == localBestScore && ops.size() < localBestMoves.size())) {\n            localBestScore = sc;\n            localBestMoves = ops;\n            localBestS = e.S;\n        }\n    }\n\n    bool doDir(int d) {\n        int nb = nbCell[blank][d];\n        if (nb < 0) return false;\n\n        swap(board[blank], board[nb]);\n        blank = nb;\n        ops.push_back(DCH[d]);\n        return true;\n    }\n\n    PathRes findPathTo(int qcell) {\n        int desired = target[qcell];\n\n        if (desired == 0) return {false, {}};\n\n        vector<int> sources;\n        sources.reserve(NN);\n\n        for (int i = 0; i < NN; i++) {\n            if (!fixed[i] && i != blank && board[i] == desired) {\n                sources.push_back(i);\n            }\n        }\n\n        if (sources.empty()) return {false, {}};\n\n        sort(sources.begin(), sources.end(), [&](int a, int b) {\n            int ka = manhattanCell(a, qcell);\n            int kb = manhattanCell(b, qcell);\n            if (a == qcell) ka -= 100;\n            if (b == qcell) kb -= 100;\n            if (baseVar & 1) return ka < kb;\n            return ka > kb;\n        });\n\n        fill(parent.begin(), parent.end(), -1);\n        que.clear();\n\n        int goal = -1;\n\n        for (int i : sources) {\n            int id = i * NN + blank;\n\n            if (parent[id] == -1) {\n                parent[id] = -2;\n                que.push_back(id);\n\n                if (i == qcell) goal = id;\n            }\n        }\n\n        int head = 0;\n\n        while (goal == -1 && head < (int)que.size()) {\n            int id = que[head++];\n            int tile = id / NN;\n            int emp = id % NN;\n\n            for (int d : dirOrder) {\n                int nb = nbCell[emp][d];\n\n                if (nb < 0 || fixed[nb]) continue;\n\n                int ntile = tile;\n                int nemp = nb;\n\n                if (nb == tile) {\n                    ntile = emp;\n                    nemp = nb;\n                }\n\n                int nid = ntile * NN + nemp;\n\n                if (parent[nid] != -1) continue;\n\n                parent[nid] = id;\n                pdir[nid] = (unsigned char)d;\n\n                if (ntile == qcell) {\n                    goal = nid;\n                    break;\n                }\n\n                que.push_back(nid);\n            }\n        }\n\n        if (goal == -1) return {false, {}};\n\n        vector<int> path;\n\n        for (int cur = goal; parent[cur] != -2; cur = parent[cur]) {\n            path.push_back((int)pdir[cur]);\n        }\n\n        reverse(path.begin(), path.end());\n        return {true, path};\n    }\n\n    bool executePath(const vector<int>& path) {\n        for (int d : path) {\n            if ((int)ops.size() >= cap) return false;\n            if (!doDir(d)) return false;\n\n            if (((int)ops.size() & 7) == 0) {\n                considerLocal();\n                if (timer.elapsed() > timeLimit) return false;\n            }\n        }\n\n        return true;\n    }\n\n    bool placeTile(int qcell) {\n        PathRes res = findPathTo(qcell);\n        if (!res.ok) return false;\n        if (!executePath(res.path)) return false;\n        if (board[qcell] != target[qcell]) return false;\n        fixed[qcell] = 1;\n        return true;\n    }\n\n    bool readyAdaptiveCell(int aid) const {\n        int tid = actToTrans(aid, s.ori);\n        int r = tid / N;\n        int c = tid % N;\n\n        if (r > 0) {\n            int u = transToAct(tid - N, s.ori);\n            if (inRegionCell(u, s) && !fixed[u]) return false;\n        }\n\n        if (c > 0) {\n            int l = transToAct(tid - 1, s.ori);\n            if (inRegionCell(l, s) && !fixed[l]) return false;\n        }\n\n        return true;\n    }\n\n    void optimizeCells(const vector<int>& cells) {\n        int rem = cap - (int)ops.size();\n        if (rem <= 0 || timer.elapsed() > timeLimit) return;\n\n        vector<int> idx(NN, -1);\n        for (int i = 0; i < (int)cells.size(); i++) idx[cells[i]] = i;\n\n        int L = (int)cells.size();\n        int startBlankK = (blank >= 0 ? idx[blank] : -1);\n        if (startBlankK < 0 || L <= 1 || L > 36) return;\n\n        if (L <= 10) {\n            auto getVal = [&](uint64_t code, int k) -> int {\n                return (int)((code >> (4 * k)) & 15ULL);\n            };\n\n            auto swapBlank = [&](uint64_t code, int bk, int nk) -> uint64_t {\n                int v = getVal(code, nk);\n                uint64_t mb = 15ULL << (4 * bk);\n                uint64_t mn = 15ULL << (4 * nk);\n                code &= ~mb;\n                code &= ~mn;\n                code |= (uint64_t)v << (4 * bk);\n                return code;\n            };\n\n            array<array<int, 4>, 36> adjK;\n            for (auto& a : adjK) a.fill(-1);\n\n            for (int k = 0; k < L; k++) {\n                int cell = cells[k];\n                for (int d = 0; d < 4; d++) {\n                    int nb = nbCell[cell][d];\n                    if (nb >= 0 && idx[nb] >= 0) adjK[k][d] = idx[nb];\n                }\n            }\n\n            uint64_t start = 0;\n            for (int k = 0; k < L; k++) {\n                start |= (uint64_t)board[cells[k]] << (4 * k);\n            }\n\n            int stateCap = (L <= 6 ? 100000 : (L <= 8 ? 120000 : 155000));\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(stateCap * 2);\n            mp.max_load_factor(0.7);\n\n            vector<uint64_t> states;\n            vector<int> par;\n            vector<unsigned char> mv;\n            vector<unsigned char> blanks;\n            vector<unsigned short> dep;\n\n            states.reserve(stateCap);\n            par.reserve(stateCap);\n            mv.reserve(stateCap);\n            blanks.reserve(stateCap);\n            dep.reserve(stateCap);\n\n            mp[start] = 0;\n            states.push_back(start);\n            par.push_back(-1);\n            mv.push_back(0);\n            blanks.push_back((unsigned char)startBlankK);\n            dep.push_back(0);\n\n            int bestIdx = -1;\n            long long bestScore = localBestScore;\n            int bestS = localBestS;\n            int bestLen = (int)localBestMoves.size();\n\n            vector<int> tmp = board;\n\n            for (int head = 0; head < (int)states.size(); head++) {\n                if ((head & 1023) == 0 && timer.elapsed() > timeLimit) break;\n                if (dep[head] >= rem) continue;\n\n                int bk = blanks[head];\n\n                for (int d = 0; d < 4; d++) {\n                    int nk = adjK[bk][d];\n                    if (nk < 0) continue;\n\n                    uint64_t nc = swapBlank(states[head], bk, nk);\n                    if (mp.find(nc) != mp.end()) continue;\n                    if ((int)states.size() >= stateCap) continue;\n\n                    int ni = (int)states.size();\n                    mp[nc] = ni;\n                    states.push_back(nc);\n                    par.push_back(head);\n                    mv.push_back((unsigned char)d);\n                    blanks.push_back((unsigned char)nk);\n                    dep.push_back(dep[head] + 1);\n\n                    tmp = board;\n                    for (int k = 0; k < L; k++) tmp[cells[k]] = getVal(nc, k);\n\n                    Eval e = evalBoard(tmp);\n                    int mvLen = (int)ops.size() + dep[ni];\n                    long long sc = scoreFromEval(e, mvLen);\n\n                    if (sc > bestScore || (sc == bestScore && mvLen < bestLen)) {\n                        bestScore = sc;\n                        bestIdx = ni;\n                        bestS = e.S;\n                        bestLen = mvLen;\n                    }\n                }\n            }\n\n            if (bestIdx != -1) {\n                string add;\n                for (int cur = bestIdx; par[cur] != -1; cur = par[cur]) {\n                    add.push_back(DCH[mv[cur]]);\n                }\n                reverse(add.begin(), add.end());\n\n                localBestScore = bestScore;\n                localBestMoves = ops + add;\n                localBestS = bestS;\n            }\n\n            return;\n        }\n\n        struct Node {\n            array<unsigned char, 36> val;\n            int blankK;\n            int last;\n            string path;\n            int key;\n        };\n\n        auto hashNode = [&](const Node& nd) {\n            uint64_t h = 1469598103934665603ULL;\n            for (int i = 0; i < L; i++) {\n                h ^= (uint64_t)(nd.val[i] + 1);\n                h *= 1099511628211ULL;\n            }\n            h ^= (uint64_t)(nd.blankK + 123);\n            h *= 1099511628211ULL;\n            return h;\n        };\n\n        Node st;\n        st.val.fill(0);\n        for (int i = 0; i < L; i++) st.val[i] = (unsigned char)board[cells[i]];\n        st.blankK = startBlankK;\n        st.last = -1;\n        st.path.clear();\n        st.key = 0;\n\n        vector<Node> beam;\n        beam.push_back(st);\n\n        int width = (L <= 16 ? 170 : 100);\n        int depthLimit = min(rem, 45 + max(s.h, s.w) * 8);\n        vector<int> tmp = board;\n\n        for (int depth = 0; depth < depthLimit; depth++) {\n            if ((depth & 7) == 0 && timer.elapsed() > timeLimit) break;\n\n            vector<Node> nxt;\n            nxt.reserve(beam.size() * 3);\n\n            unordered_map<uint64_t, int> seen;\n            seen.reserve(beam.size() * 5 + 10);\n            seen.max_load_factor(0.7);\n\n            for (const Node& nd : beam) {\n                int globalBlank = cells[nd.blankK];\n\n                for (int d = 0; d < 4; d++) {\n                    if (nd.last != -1 && d == OPP[nd.last]) continue;\n\n                    int nb = nbCell[globalBlank][d];\n                    if (nb < 0 || idx[nb] < 0) continue;\n\n                    int nk = idx[nb];\n\n                    Node ch = nd;\n                    swap(ch.val[ch.blankK], ch.val[nk]);\n                    ch.blankK = nk;\n                    ch.last = d;\n                    ch.path.push_back(DCH[d]);\n\n                    tmp = board;\n                    for (int k = 0; k < L; k++) tmp[cells[k]] = ch.val[k];\n\n                    Eval e = evalBoard(tmp);\n                    int mvLen = (int)ops.size() + (int)ch.path.size();\n\n                    if (mvLen <= T) {\n                        long long sc = scoreFromEval(e, mvLen);\n                        if (sc > localBestScore ||\n                            (sc == localBestScore && ops.size() + ch.path.size() < localBestMoves.size())) {\n                            localBestScore = sc;\n                            localBestMoves = ops + ch.path;\n                            localBestS = e.S;\n                        }\n                    }\n\n                    ch.key =\n                        e.S * 1000000 +\n                        e.maxComp * 7000 +\n                        e.edges * 200 -\n                        depth * 5 -\n                        (int)ch.path.size() * 2;\n\n                    uint64_t h = hashNode(ch);\n                    auto it = seen.find(h);\n\n                    if (it == seen.end()) {\n                        seen[h] = (int)nxt.size();\n                        nxt.push_back(std::move(ch));\n                    } else {\n                        int pos = it->second;\n                        if (ch.key > nxt[pos].key) nxt[pos] = std::move(ch);\n                    }\n                }\n            }\n\n            if (nxt.empty()) break;\n\n            if ((int)nxt.size() > width) {\n                nth_element(nxt.begin(), nxt.begin() + width, nxt.end(),\n                            [](const Node& a, const Node& b) { return a.key > b.key; });\n                nxt.resize(width);\n            }\n\n            beam.swap(nxt);\n        }\n    }\n\n    void optimizeFreeBlock() {\n        optimizeCells(freeCellsOf(s));\n    }\n\n    void optimizeMovableBlock() {\n        vector<int> cells;\n        cells.reserve(NN);\n        for (int i = 0; i < NN; i++) {\n            if (!fixed[i]) cells.push_back(i);\n        }\n        if ((int)cells.size() <= 36) optimizeCells(cells);\n    }\n\n    SolveResult runAdaptive() {\n        considerLocal();\n\n        int total = 0;\n\n        for (int i = 0; i < NN; i++) {\n            if (inRegionCell(i, s) && target[i] != 0) total++;\n        }\n\n        bool completed = true;\n\n        for (int placed = 0; placed < total; placed++) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                completed = false;\n                break;\n            }\n\n            int bestQ = -1;\n            int bestKey = INT_MAX;\n            vector<int> bestPath;\n\n            for (int q = 0; q < NN; q++) {\n                if (!inRegionCell(q, s) || fixed[q] || target[q] == 0) continue;\n                if (!readyAdaptiveCell(q)) continue;\n\n                PathRes res = findPathTo(q);\n                if (!res.ok) continue;\n\n                int key = (int)res.path.size() * 100;\n                if (board[q] == target[q]) key -= 80;\n                key += nearDistMask[target[q]][q] * 2;\n                key += manhattanCell(blank, q);\n\n                if (key < bestKey) {\n                    bestKey = key;\n                    bestQ = q;\n                    bestPath = std::move(res.path);\n                }\n            }\n\n            if (bestQ < 0) {\n                completed = false;\n                break;\n            }\n\n            if (!executePath(bestPath)) {\n                completed = false;\n                break;\n            }\n\n            if (board[bestQ] != target[bestQ]) {\n                completed = false;\n                break;\n            }\n\n            fixed[bestQ] = 1;\n            considerLocal();\n        }\n\n        considerLocal();\n\n        if (freeBeam && timer.elapsed() < timeLimit) {\n            if (completed) optimizeFreeBlock();\n            else optimizeMovableBlock();\n        }\n\n        considerLocal();\n        return {localBestMoves, localBestS, completed};\n    }\n\n    SolveResult runStatic() {\n        considerLocal();\n\n        int rowMode = baseVar % 3;\n        int colMode = (baseVar / 3) % 4;\n\n        vector<int> order;\n        order.reserve(NN);\n\n        for (int r = 0; r < N - s.h; r++) {\n            bool rev = false;\n            if (rowMode == 1) rev = true;\n            if (rowMode == 2 && (r & 1)) rev = true;\n\n            if (!rev) {\n                for (int c = 0; c < N; c++) order.push_back(transToAct(r * N + c, s.ori));\n            } else {\n                for (int c = N - 1; c >= 0; c--) order.push_back(transToAct(r * N + c, s.ori));\n            }\n        }\n\n        for (int c = 0; c < N - s.w; c++) {\n            vector<int> rows;\n            for (int r = N - s.h; r < N; r++) rows.push_back(r);\n\n            if (colMode == 1) {\n                reverse(rows.begin(), rows.end());\n            } else if (colMode == 2 && (c & 1)) {\n                reverse(rows.begin(), rows.end());\n            } else if (colMode == 3 && s.h > 1) {\n                rotate(rows.begin(), rows.begin() + (baseVar % s.h), rows.end());\n            }\n\n            for (int r : rows) order.push_back(transToAct(r * N + c, s.ori));\n        }\n\n        bool completed = true;\n\n        for (int q : order) {\n            if (timer.elapsed() > timeLimit || (int)ops.size() >= cap) {\n                completed = false;\n                break;\n            }\n\n            if (target[q] == 0) continue;\n\n            if (!placeTile(q)) {\n                completed = false;\n                break;\n            }\n\n            considerLocal();\n        }\n\n        considerLocal();\n\n        if (freeBeam && timer.elapsed() < timeLimit) {\n            if (completed) optimizeFreeBlock();\n            else optimizeMovableBlock();\n        }\n\n        considerLocal();\n        return {localBestMoves, localBestS, completed};\n    }\n\n    SolveResult run() {\n        if (adaptive) return runAdaptive();\n        return runStatic();\n    }\n};\n\nSolveResult solveCandidate(const Candidate& cand, int variant, Timer& timer, double limit) {\n    SlidingSolver solver(cand.target, cand.s, variant, timer, limit, T);\n    return solver.run();\n}\n\nvoid greedyImprove(BestAns& best, double endTime, Timer& timer, mt19937& rng) {\n    while (timer.elapsed() < endTime) {\n        vector<int> bd = initBoard;\n        int blank = initBlank;\n        string mv;\n        int last = -1;\n\n        for (int step = 0; step < T && timer.elapsed() < endTime; step++) {\n            vector<int> opts;\n\n            for (int d = 0; d < 4; d++) {\n                if (nbCell[blank][d] >= 0 && (last == -1 || d != OPP[last])) {\n                    opts.push_back(d);\n                }\n            }\n\n            if (opts.empty()) {\n                for (int d = 0; d < 4; d++) {\n                    if (nbCell[blank][d] >= 0) opts.push_back(d);\n                }\n            }\n\n            int bestD = opts[0];\n            long long bestVal = LLONG_MIN;\n            Eval chosenEval{0, 0, 0};\n\n            for (int d : opts) {\n                int oldBlank = blank;\n                int nb = nbCell[blank][d];\n\n                swap(bd[blank], bd[nb]);\n                blank = nb;\n\n                Eval e = evalBoard(bd);\n\n                long long val =\n                    (long long)e.S * 1000000LL +\n                    (long long)e.maxComp * 8000LL +\n                    (long long)e.edges * 300LL +\n                    (long long)(rng() % 1000);\n\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestD = d;\n                    chosenEval = e;\n                }\n\n                swap(bd[oldBlank], bd[blank]);\n                blank = oldBlank;\n            }\n\n            applyDir(bd, blank, bestD);\n            mv.push_back(DCH[bestD]);\n            last = bestD;\n\n            if (chosenEval.S >= best.S || (step & 15) == 0) {\n                updateBestKnownBoard(best, mv, bd);\n            }\n        }\n\n        updateBestKnownBoard(best, mv, bd);\n    }\n}\n\nvoid addShape(vector<pair<int,int>>& v, int h, int w) {\n    if (h < 1 || w < 1 || h > N || w > N) return;\n    if (h == N && w == N) return;\n    if (h * w > 36) return;\n    if (h * w <= 1) return;\n    for (auto p : v) if (p.first == h && p.second == w) return;\n    v.push_back({h, w});\n}\n\nvector<pair<int,int>> preferredShapes() {\n    vector<pair<int,int>> v;\n\n    if (N == 6) {\n        addShape(v, 2, 2);\n        addShape(v, 1, 4);\n        addShape(v, 4, 1);\n        addShape(v, 1, 5);\n        addShape(v, 5, 1);\n        addShape(v, 2, 3);\n        addShape(v, 3, 2);\n        addShape(v, 1, 6);\n        addShape(v, 6, 1);\n        addShape(v, 3, 3);\n    } else if (N == 7) {\n        addShape(v, 2, 3);\n        addShape(v, 3, 2);\n        addShape(v, 1, 5);\n        addShape(v, 5, 1);\n        addShape(v, 2, 2);\n        addShape(v, 1, 6);\n        addShape(v, 6, 1);\n        addShape(v, 1, 7);\n        addShape(v, 7, 1);\n        addShape(v, 3, 3);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 4, 4);\n    } else if (N == 8) {\n        addShape(v, 2, 3);\n        addShape(v, 3, 2);\n        addShape(v, 1, 6);\n        addShape(v, 6, 1);\n        addShape(v, 2, 2);\n        addShape(v, 1, 7);\n        addShape(v, 7, 1);\n        addShape(v, 1, 8);\n        addShape(v, 8, 1);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 3, 3);\n        addShape(v, 3, 4);\n        addShape(v, 4, 3);\n        addShape(v, 4, 4);\n    } else if (N == 9) {\n        addShape(v, 3, 4);\n        addShape(v, 4, 3);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 1, 7);\n        addShape(v, 7, 1);\n        addShape(v, 1, 8);\n        addShape(v, 8, 1);\n        addShape(v, 1, 9);\n        addShape(v, 9, 1);\n        addShape(v, 3, 3);\n        addShape(v, 2, 5);\n        addShape(v, 5, 2);\n        addShape(v, 4, 4);\n        addShape(v, 4, 5);\n        addShape(v, 5, 4);\n    } else {\n        addShape(v, 3, 4);\n        addShape(v, 4, 3);\n        addShape(v, 2, 4);\n        addShape(v, 4, 2);\n        addShape(v, 1, 8);\n        addShape(v, 8, 1);\n        addShape(v, 1, 9);\n        addShape(v, 9, 1);\n        addShape(v, 1, 10);\n        addShape(v, 10, 1);\n        addShape(v, 2, 5);\n        addShape(v, 5, 2);\n        addShape(v, 3, 3);\n        addShape(v, 4, 4);\n        addShape(v, 3, 5);\n        addShape(v, 5, 3);\n        addShape(v, 4, 5);\n        addShape(v, 5, 4);\n        addShape(v, 5, 5);\n        addShape(v, 6, 6);\n    }\n\n    return v;\n}\n\nvector<int> orientationOrder(int h, int w) {\n    vector<int> os = {0, 1, 2, 3};\n    sort(os.begin(), os.end(), [&](int a, int b) {\n        Shape sa{h, w, a};\n        Shape sb{h, w, b};\n        int da = manhattanCell(initBlank, freeBlankCell(sa));\n        int db = manhattanCell(initBlank, freeBlankCell(sb));\n        return da < db;\n    });\n    return os;\n}\n\nbool sameHW(const Candidate& c, pair<int,int> p) {\n    return c.s.h == p.first && c.s.w == p.second;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> T;\n\n    NN = N * N;\n    M = NN - 1;\n\n    initBoard.assign(NN, 0);\n    memset(invCnt, 0, sizeof(invCnt));\n\n    for (int r = 0; r < N; r++) {\n        string s;\n        cin >> s;\n\n        for (int c = 0; c < N; c++) {\n            int v = hexVal(s[c]);\n            int id = r * N + c;\n\n            initBoard[id] = v;\n\n            if (v == 0) initBlank = id;\n            else invCnt[v]++;\n        }\n    }\n\n    for (int id = 0; id < NN; id++) {\n        int r = id / N;\n        int c = id % N;\n\n        for (int d = 0; d < 4; d++) {\n            int nr = r + DR[d];\n            int nc = c + DC[d];\n\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                nbCell[id][d] = -1;\n            } else {\n                nbCell[id][d] = nr * N + nc;\n            }\n        }\n    }\n\n    for (int m = 0; m < 16; m++) {\n        for (int v = 0; v < NN; v++) {\n            nearDistMask[m][v] = 2 * N + 5;\n        }\n    }\n\n    for (int v = 0; v < NN; v++) nearDistMask[0][v] = 0;\n\n    for (int m = 1; m < 16; m++) {\n        vector<int> pos;\n\n        for (int i = 0; i < NN; i++) {\n            if (initBoard[i] == m) pos.push_back(i);\n        }\n\n        if (pos.empty()) continue;\n\n        for (int v = 0; v < NN; v++) {\n            int best = 2 * N + 5;\n            for (int p : pos) best = min(best, manhattanCell(v, p));\n            nearDistMask[m][v] = best;\n        }\n    }\n\n    Timer timer;\n\n    uint64_t seed = 88172645463393265ULL;\n    for (int x : initBoard) {\n        seed = seed * 1315423911ULL + x + 1;\n    }\n    seed ^= (uint64_t)N * 1000003ULL;\n\n    mt19937 rng((uint32_t)(seed ^ (seed >> 32)));\n\n    BestAns best;\n    updateBest(best, \"\");\n\n    if (best.S == M) {\n        cout << \"\\n\";\n        return 0;\n    }\n\n    vector<Candidate> cands;\n    vector<pair<int,int>> prefs = preferredShapes();\n\n    for (auto [h, w] : prefs) {\n        for (int ori = 0; ori < 4; ori++) {\n            Shape s{h, w, ori};\n            vector<int> can = canonicalTreeMask(s);\n            adjustAndAddCandidate(cands, can, s);\n        }\n    }\n\n    auto runMonoAll = [&](pair<int,int> hw, double until, double slice) {\n        int h = hw.first, w = hw.second;\n        vector<int> os = orientationOrder(h, w);\n        int ptr = 0;\n\n        while (timer.elapsed() < until) {\n            int ori = os[ptr % 4];\n            ptr++;\n            Shape s{h, w, ori};\n            double nxt = min(until, timer.elapsed() + slice);\n            runMonoSearch(s, nxt, timer, rng, cands);\n        }\n    };\n\n    auto runArbAll = [&](pair<int,int> hw, double until, double slice) {\n        int h = hw.first, w = hw.second;\n        vector<int> os = orientationOrder(h, w);\n        int ptr = 0;\n\n        while (timer.elapsed() < until) {\n            int ori = os[ptr % 4];\n            ptr++;\n            Shape s{h, w, ori};\n            double nxt = min(until, timer.elapsed() + slice);\n            runPartialSearch(s, nxt, timer, rng, cands);\n        }\n    };\n\n    vector<double> monoUntil = {0.38, 0.62, 0.82, 0.98, 1.10, 1.20};\n    for (int i = 0; i < (int)prefs.size() && i < (int)monoUntil.size(); i++) {\n        runMonoAll(prefs[i], monoUntil[i], (i < 2 ? 0.055 : 0.045));\n    }\n\n    vector<double> arbUntil = {1.30, 1.40, 1.48, 1.55};\n    for (int i = 0; i < (int)prefs.size() && i < (int)arbUntil.size(); i++) {\n        runArbAll(prefs[i], arbUntil[i], (i < 2 ? 0.065 : 0.055));\n    }\n\n    sort(cands.begin(), cands.end(), [](const Candidate& a, const Candidate& b) {\n        if (a.expectedS != b.expectedS) return a.expectedS > b.expectedS;\n        if (kindRank(a.kind) != kindRank(b.kind)) return kindRank(a.kind) < kindRank(b.kind);\n        int aa = a.estCost + kindRank(a.kind) * 40;\n        int bb = b.estCost + kindRank(b.kind) * 40;\n        if (aa != bb) return aa < bb;\n        if (shapeArea(a.s) != shapeArea(b.s)) return shapeArea(a.s) < shapeArea(b.s);\n        return a.s.ori < b.s.ori;\n    });\n\n    vector<vector<int>> groups(prefs.size());\n    vector<int> otherIdx;\n\n    for (int i = 0; i < (int)cands.size(); i++) {\n        bool found = false;\n        for (int pi = 0; pi < (int)prefs.size(); pi++) {\n            if (sameHW(cands[i], prefs[pi])) {\n                groups[pi].push_back(i);\n                found = true;\n                break;\n            }\n        }\n        if (!found) otherIdx.push_back(i);\n    }\n\n    vector<int> orderIdx;\n    vector<char> used(cands.size(), 0);\n\n    int active = min((int)prefs.size(), 7);\n    for (int round = 0; round < 7; round++) {\n        for (int pi = 0; pi < active; pi++) {\n            if (round < (int)groups[pi].size()) {\n                int idx = groups[pi][round];\n                if (!used[idx]) {\n                    orderIdx.push_back(idx);\n                    used[idx] = 1;\n                }\n            }\n        }\n    }\n\n    for (int pi = 0; pi < (int)prefs.size(); pi++) {\n        int takeLimit = (pi == 0 ? 22 : 13);\n        int take = 0;\n        for (int idx : groups[pi]) {\n            if (take >= takeLimit) break;\n            if (!used[idx]) {\n                orderIdx.push_back(idx);\n                used[idx] = 1;\n                take++;\n            }\n        }\n    }\n\n    for (int i = 0; i < (int)cands.size(); i++) {\n        if (!used[i]) orderIdx.push_back(i);\n    }\n\n    int attemptRank = 0;\n\n    for (int idx : orderIdx) {\n        if (timer.elapsed() > 2.80) break;\n\n        const Candidate& cand = cands[idx];\n\n        if (attemptRank > 15 && cand.expectedS + 2 <= best.S) continue;\n\n        vector<int> vars;\n\n        if (attemptRank < 4) {\n            vars = {48, 49, 50, 51, 52, 53, 54, 55, 16, 17, 0, 1};\n        } else if (attemptRank < 14) {\n            vars = {48, 49, 50, 51, 16, 17, 0, 1};\n        } else if (attemptRank < 32) {\n            vars = {48, 49, 16, 17, 50};\n        } else {\n            vars = {16, 0};\n        }\n\n        for (int v : vars) {\n            if (timer.elapsed() > 2.83) break;\n\n            SolveResult res = solveCandidate(cand, v, timer, 2.85);\n            updateBest(best, res.bestMoves);\n\n            if (res.completed && best.S >= cand.expectedS + min(2, shapeArea(cand.s) - 1)) break;\n            if (best.S == M) break;\n        }\n\n        attemptRank++;\n        if (best.S == M) break;\n    }\n\n    if (best.S < NN - 9 && timer.elapsed() < 2.86) {\n        greedyImprove(best, 2.87, timer, rng);\n    }\n\n    if ((int)best.moves.size() > T) best.moves.resize(T);\n\n    cout << best.moves << \"\\n\";\n    return 0;\n}","ahc012":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint N, K_input, MAX_CUTS;\nint targetA[11];\nvector<int> Xs, Ys;\nint M_attendees;\n\nchrono::steady_clock::time_point START_TIME;\nconst double STOP_START_TIME = 2.52;\nconst double HARD_TIME_LIMIT = 2.92;\n\nconst ll SCORE_W = 1000000000000LL;\nconst ll OVER_W = 5000LL;\nconst ll OVERSQ_W = 20LL;\nconst ll SURPLUS_W = 10000LL;\n\ndouble elapsed_time() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t state = 1;\n    uint64_t next() {\n        uint64_t z = (state += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int l, int r) {\n        if (l > r) swap(l, r);\n        return l + (int)(next() % (uint64_t)(r - l + 1));\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\nRNG rng;\n\nstruct Key {\n    uint64_t lo, hi;\n    bool operator==(const Key& o) const {\n        return lo == o.lo && hi == o.hi;\n    }\n};\n\nstruct KeyHash {\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    size_t operator()(const Key& k) const {\n        return (size_t)(splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1));\n    }\n};\n\nstruct Proj {\n    ll s;\n    int idx;\n    bool operator<(const Proj& o) const {\n        if (s != o.s) return s < o.s;\n        return idx < o.idx;\n    }\n};\n\nstruct Line {\n    ll A, B, C;\n    shared_ptr<vector<Proj>> ord;\n};\n\nstruct LineOut {\n    ll A, B, C;\n};\n\nvector<LineOut> bestLines;\nint bestScore = -1;\nll bestValue = LLONG_MIN;\n\ninline bool getBit(const Key& k, int j) {\n    if (j < 64) return (k.lo >> j) & 1ULL;\n    return (k.hi >> (j - 64)) & 1ULL;\n}\n\ninline void flipBit(Key& k, int j) {\n    if (j < 64) k.lo ^= (1ULL << j);\n    else k.hi ^= (1ULL << (j - 64));\n}\n\ninline Key clearedBit(Key k, int j) {\n    if (j < 64) k.lo &= ~(1ULL << j);\n    else k.hi &= ~(1ULL << (j - 64));\n    return k;\n}\n\ninline int overPart(int c) {\n    return c > 10 ? c : 0;\n}\n\ninline ll overSqPart(int c) {\n    if (c <= 10) return 0;\n    ll e = c - 10;\n    return e * e;\n}\n\nshared_ptr<vector<Proj>> computeOrder(ll A, ll B) {\n    auto ord = make_shared<vector<Proj>>();\n    ord->reserve(N);\n    for (int i = 0; i < N; i++) {\n        ll s = A * (ll)Xs[i] + B * (ll)Ys[i];\n        ord->push_back({s, i});\n    }\n    sort(ord->begin(), ord->end());\n    return ord;\n}\n\nll thresholdAtRank(const vector<Proj>& ord, int rank) {\n    int n = (int)ord.size();\n    if (rank <= 0) return ord[0].s - 1;\n    if (rank >= n) return ord[n - 1].s + 1;\n\n    for (int d = 0; d <= n; d++) {\n        int b = rank - d;\n        if (0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n        b = rank + d;\n        if (d != 0 && 0 < b && b < n) {\n            ll l = ord[b - 1].s, r = ord[b].s;\n            if (r - l >= 2) return l + (r - l) / 2;\n        }\n    }\n    return (rank < n / 2 ? ord[0].s - 1 : ord[n - 1].s + 1);\n}\n\npair<ll,ll> primitive(ll A, ll B) {\n    if (A == 0 && B == 0) return {1, 0};\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) g = 1;\n    A /= g;\n    B /= g;\n    return {A, B};\n}\n\npair<ll,ll> normalFromAngle(long double theta) {\n    static const long double PI = acosl(-1.0L);\n    theta = fmodl(theta, PI);\n    if (theta < 0) theta += PI;\n\n    const long double S = 1000000.0L;\n    ll A = llround(cosl(theta) * S);\n    ll B = llround(sinl(theta) * S);\n    if (A == 0 && B == 0) A = 1;\n    return primitive(A, B);\n}\n\nlong long cellCountFormula(const vector<int>& c) {\n    long long cells = 1;\n    int sum = 0;\n    for (int x : c) sum += x;\n    cells += sum;\n    for (int i = 0; i < (int)c.size(); i++) {\n        for (int j = i + 1; j < (int)c.size(); j++) {\n            cells += 1LL * c[i] * c[j];\n        }\n    }\n    return cells;\n}\n\nvector<int> bestCounts(int G, int T) {\n    vector<int> best(G, 0), cur(G, 0);\n    long long bestCost = LLONG_MAX;\n\n    auto eval = [&]() {\n        int sum = 0, mn = 1e9, mx = -1;\n        for (int x : cur) {\n            sum += x;\n            mn = min(mn, x);\n            mx = max(mx, x);\n        }\n        if (sum > MAX_CUTS) return;\n\n        long long cells = cellCountFormula(cur);\n        long long diff = llabs(cells - T);\n        long long cost = diff * 100000LL + (cells < T ? 1000LL : 0LL)\n                       + (mx - mn) * 100LL + sum;\n\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = cur;\n        }\n    };\n\n    if (G == 2) {\n        for (int a = 0; a <= MAX_CUTS; a++) {\n            for (int b = 0; a + b <= MAX_CUTS; b++) {\n                cur[0] = a;\n                cur[1] = b;\n                eval();\n            }\n        }\n        return best;\n    }\n\n    if (G <= 4) {\n        long double denom = max(1, G * (G - 1));\n        int base = (int)round(sqrt((2.0L * T) / denom));\n        int R = (G == 4 ? 10 : 12);\n        int lo = max(0, base - R);\n        int hi = min(MAX_CUTS, base + R);\n\n        function<void(int,int)> dfs = [&](int pos, int sum) {\n            if (pos == G) {\n                eval();\n                return;\n            }\n            for (int v = lo; v <= hi; v++) {\n                if (sum + v <= MAX_CUTS) {\n                    cur[pos] = v;\n                    dfs(pos + 1, sum + v);\n                }\n            }\n        };\n        dfs(0, 0);\n    } else {\n        for (int sum = 0; sum <= MAX_CUTS; sum++) {\n            for (int h = 0; h <= sum; h++) {\n                cur[0] = h;\n                int rem = sum - h;\n                int q = rem / (G - 1);\n                int r = rem % (G - 1);\n                for (int i = 1; i < G; i++) cur[i] = q + (i - 1 < r);\n                eval();\n            }\n        }\n    }\n\n    if (bestCost == LLONG_MAX) {\n        int v = min(MAX_CUTS / G, 1);\n        fill(best.begin(), best.end(), v);\n    }\n    return best;\n}\n\nvector<Line> makeGroup(int G, const vector<int>& counts, long double baseAngle, int initMode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n\n    for (int g = 0; g < G; g++) {\n        int m = counts[g];\n        if (m <= 0) continue;\n\n        auto [A, B] = normalFromAngle(baseAngle + PI * g / G);\n        auto ord = computeOrder(A, B);\n\n        vector<int> ranks;\n        ranks.reserve(m);\n\n        if (initMode == 0) {\n            for (int t = 1; t <= m; t++) {\n                ranks.push_back((int)((long long)t * N / (m + 1)));\n            }\n        } else if (initMode == 1) {\n            int low = N / 20;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            for (int t = 0; t < m; t++) ranks.push_back(rng.nextInt(low, high));\n            sort(ranks.begin(), ranks.end());\n        } else {\n            for (int t = 1; t <= m; t++) {\n                long double u = (long double)t + (rng.nextDouble() - 0.5L) * 0.9L;\n                int rank = (int)llround(u * N / (m + 1));\n                rank = max(0, min(N, rank));\n                ranks.push_back(rank);\n            }\n            sort(ranks.begin(), ranks.end());\n        }\n\n        for (int rank : ranks) {\n            Line L;\n            L.A = A;\n            L.B = B;\n            L.ord = ord;\n            L.C = thresholdAtRank(*L.ord, rank);\n            res.push_back(std::move(L));\n        }\n    }\n\n    if ((int)res.size() > MAX_CUTS) res.resize(MAX_CUTS);\n    return res;\n}\n\nint kForCells(int T) {\n    for (int k = 0; k <= MAX_CUTS; k++) {\n        if (1LL + 1LL * k * (k + 1) / 2 >= T) return k;\n    }\n    return MAX_CUTS;\n}\n\nvector<Line> makeGeneral(int k, int mode) {\n    static const long double PI = acosl(-1.0L);\n    vector<Line> res;\n    res.reserve(k);\n\n    long double base = (k > 0 ? rng.nextDouble() * PI / k : 0);\n\n    for (int i = 0; i < k; i++) {\n        long double theta;\n        if (mode == 0) {\n            theta = base + ((long double)i + 0.5L + (rng.nextDouble() - 0.5L) * 0.8L) * PI / k;\n        } else {\n            theta = rng.nextDouble() * PI;\n        }\n\n        auto [A, B] = normalFromAngle(theta);\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.ord = computeOrder(A, B);\n\n        int low = N / 20;\n        int high = N - low;\n        if (low > high) {\n            low = 0;\n            high = N;\n        }\n        int rank = rng.nextInt(low, high);\n        L.C = thresholdAtRank(*L.ord, rank);\n\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nstruct Config {\n    int k;\n    vector<Line> lines;\n    vector<Key> pat;\n    unordered_map<Key, int, KeyHash> mp;\n    int hist[11];\n    int overStraw = 0;\n    ll overSq = 0;\n\n    Config(vector<Line>&& ls) : k((int)ls.size()), lines(std::move(ls)), pat(N) {\n        memset(hist, 0, sizeof(hist));\n    }\n\n    inline void removeEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]--;\n        else if (c > 10) {\n            overStraw -= c;\n            overSq -= overSqPart(c);\n        }\n    }\n\n    inline void addEffect(int c) {\n        if (1 <= c && c <= 10) hist[c]++;\n        else if (c > 10) {\n            overStraw += c;\n            overSq += overSqPart(c);\n        }\n    }\n\n    void build() {\n        mp.clear();\n        mp.reserve(N * 4 + 100);\n        mp.max_load_factor(0.7);\n        memset(hist, 0, sizeof(hist));\n        overStraw = 0;\n        overSq = 0;\n\n        for (int i = 0; i < N; i++) {\n            Key key{0, 0};\n            for (int j = 0; j < k; j++) {\n                ll s = lines[j].A * (ll)Xs[i] + lines[j].B * (ll)Ys[i];\n                if (s > lines[j].C) {\n                    if (j < 64) key.lo |= (1ULL << j);\n                    else key.hi |= (1ULL << (j - 64));\n                }\n            }\n            pat[i] = key;\n            mp[key]++;\n        }\n\n        for (auto& kv : mp) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) hist[c]++;\n            else if (c > 10) {\n                overStraw += c;\n                overSq += overSqPart(c);\n            }\n        }\n    }\n\n    void decKey(const Key& key) {\n        auto it = mp.find(key);\n        int old = it->second;\n        removeEffect(old);\n        int nw = old - 1;\n        addEffect(nw);\n        if (nw == 0) mp.erase(it);\n        else it->second = nw;\n    }\n\n    void incKey(const Key& key) {\n        auto it = mp.find(key);\n        if (it == mp.end()) {\n            addEffect(1);\n            mp.emplace(key, 1);\n        } else {\n            int old = it->second;\n            removeEffect(old);\n            int nw = old + 1;\n            addEffect(nw);\n            it->second = nw;\n        }\n    }\n\n    inline void flipPoint(int idx, int j) {\n        Key old = pat[idx];\n        Key nw = old;\n        flipBit(nw, j);\n        decKey(old);\n        incKey(nw);\n        pat[idx] = nw;\n    }\n\n    int score() const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], hist[d]);\n        return sc;\n    }\n\n    int surplus() const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (hist[d] > targetA[d]) s += hist[d] - targetA[d];\n        }\n        return s;\n    }\n\n    int scoreOfHist(const int h[11]) const {\n        int sc = 0;\n        for (int d = 1; d <= 10; d++) sc += min(targetA[d], h[d]);\n        return sc;\n    }\n\n    int surplusOfHist(const int h[11]) const {\n        int s = 0;\n        for (int d = 1; d <= 10; d++) {\n            if (h[d] > targetA[d]) s += h[d] - targetA[d];\n        }\n        return s;\n    }\n\n    ll value() const {\n        return (ll)score() * SCORE_W\n             - (ll)overStraw * OVER_W\n             - overSq * OVERSQ_W\n             - (ll)surplus() * SURPLUS_W;\n    }\n\n    ll tempValue(const int h[11], int over, ll osq) const {\n        int sc = scoreOfHist(h);\n        int surp = surplusOfHist(h);\n        return (ll)sc * SCORE_W\n             - (ll)over * OVER_W\n             - osq * OVERSQ_W\n             - (ll)surp * SURPLUS_W;\n    }\n\n    int rankForC(int j) const {\n        const auto& ord = *lines[j].ord;\n        int l = 0, r = N;\n        ll C = lines[j].C;\n        while (l < r) {\n            int m = (l + r) >> 1;\n            if (ord[m].s <= C) l = m + 1;\n            else r = m;\n        }\n        return l;\n    }\n\n    void sweepLine(int j) {\n        const auto& ord = *lines[j].ord;\n\n        ll origVal = value();\n        int bestIdx = rankForC(j);\n        ll bestC = lines[j].C;\n        ll bestVal = origVal;\n\n        for (int i = 0; i < N; i++) {\n            if (!getBit(pat[i], j)) flipPoint(i, j);\n        }\n\n        ll valAll = value();\n        if (valAll > bestVal) {\n            bestVal = valAll;\n            bestIdx = 0;\n            bestC = ord[0].s - 1;\n        }\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = ord[idx].s;\n            while (idx < N && ord[idx].s == v) {\n                flipPoint(ord[idx].idx, j);\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = ord[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = value();\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestIdx = idx;\n                    bestC = candC;\n                }\n            }\n        }\n\n        for (int t = bestIdx; t < N; t++) {\n            flipPoint(ord[t].idx, j);\n        }\n        lines[j].C = bestC;\n    }\n\n    void optimize(int passes) {\n        if (k == 0) return;\n        vector<int> order(k);\n        iota(order.begin(), order.end(), 0);\n\n        for (int p = 0; p < passes; p++) {\n            for (int i = k - 1; i > 0; i--) {\n                int j = rng.nextInt(0, i);\n                swap(order[i], order[j]);\n            }\n\n            ll before = value();\n\n            for (int t = 0; t < k; t++) {\n                sweepLine(order[t]);\n                if ((t & 7) == 0 && elapsed_time() > HARD_TIME_LIMIT) return;\n            }\n\n            if (value() <= before) break;\n        }\n    }\n\n    int cellBadScoreGeneric(int c, const int hUse[11]) const {\n        if (c <= 1) return 0;\n\n        int def[11];\n        for (int d = 1; d <= 10; d++) def[d] = max(0, targetA[d] - hUse[d]);\n\n        int loss = 0;\n        if (1 <= c && c <= 10 && hUse[c] <= targetA[c]) loss = 1;\n\n        int best = -loss;\n\n        auto evalSplit = [&](int t) {\n            if (t <= 0 || t >= c) return;\n            int u = c - t;\n            int cnt[11] = {};\n            if (1 <= t && t <= 10) cnt[t]++;\n            if (1 <= u && u <= 10) cnt[u]++;\n            int gain = -loss;\n            for (int d = 1; d <= 10; d++) gain += min(cnt[d], def[d]);\n            best = max(best, gain);\n        };\n\n        for (int t = 1; t <= min(c - 1, 10); t++) evalSplit(t);\n        for (int t = max(1, c - 10); t <= c - 1; t++) evalSplit(t);\n\n        if (best > 0) return 100 * best + min(c, 60);\n        if (c > 10) return 15 + min(c, 50);\n        if (hUse[c] > targetA[c]) return 8 + min(hUse[c] - targetA[c], 25);\n        return 0;\n    }\n\n    int cellBadScore(int c) const {\n        return cellBadScoreGeneric(c, hist);\n    }\n\n    int chooseSplitSmallRank(int c, const int hUse[11]) const {\n        if (c <= 1) return 1;\n\n        vector<int> cand;\n        auto addCand = [&](int t) {\n            if (1 <= t && t < c) cand.push_back(t);\n        };\n\n        if (c <= 28) {\n            for (int t = 1; t < c; t++) addCand(t);\n        } else {\n            for (int t = 1; t <= 10; t++) addCand(t);\n            for (int t = c - 10; t < c; t++) addCand(t);\n            addCand(c / 2);\n            addCand((c + 1) / 2);\n            addCand(c / 3);\n            addCand(2 * c / 3);\n        }\n\n        for (int d = 1; d <= 10; d++) {\n            if (targetA[d] > hUse[d]) {\n                addCand(d);\n                addCand(c - d);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int beforeScore = scoreOfHist(hUse);\n        int beforeSur = surplusOfHist(hUse);\n        int beforeOver = overPart(c);\n        ll beforeSq = overSqPart(c);\n\n        ll bestVal = LLONG_MIN;\n        int bestT = cand.empty() ? c / 2 : cand[0];\n\n        for (int t : cand) {\n            int u = c - t;\n            int afterH[11];\n            memcpy(afterH, hUse, sizeof(int) * 11);\n\n            if (1 <= c && c <= 10) afterH[c]--;\n            if (1 <= t && t <= 10) afterH[t]++;\n            if (1 <= u && u <= 10) afterH[u]++;\n\n            int afterScore = scoreOfHist(afterH);\n            int afterSur = surplusOfHist(afterH);\n            int afterOver = overPart(t) + overPart(u);\n            ll afterSq = overSqPart(t) + overSqPart(u);\n\n            ll delta = (ll)(afterScore - beforeScore) * SCORE_W\n                     - (ll)(afterOver - beforeOver) * OVER_W\n                     - (afterSq - beforeSq) * OVERSQ_W\n                     - (ll)(afterSur - beforeSur) * SURPLUS_W;\n\n            if (delta > bestVal) {\n                bestVal = delta;\n                bestT = t;\n            }\n        }\n\n        int r = min(bestT, c - bestT);\n        r = max(1, min(c - 1, r));\n        return r;\n    }\n\n    long double thetaFromPoints(const vector<int>& pts) const {\n        static const long double PI = acosl(-1.0L);\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        int bestA = pts[0], bestB = pts[1];\n        ll bestD = -1;\n        int samples = min(45, max(8, (int)pts.size() * 2));\n\n        for (int s = 0; s < samples; s++) {\n            int a = pts[rng.nextInt(0, (int)pts.size() - 1)];\n            int b = pts[rng.nextInt(0, (int)pts.size() - 1)];\n            if (a == b) continue;\n            ll dx = (ll)Xs[a] - Xs[b];\n            ll dy = (ll)Ys[a] - Ys[b];\n            ll dist = dx * dx + dy * dy;\n            if (dist > bestD) {\n                bestD = dist;\n                bestA = a;\n                bestB = b;\n            }\n        }\n\n        long double dx = (long double)Xs[bestA] - Xs[bestB];\n        long double dy = (long double)Ys[bestA] - Ys[bestB];\n        if (dx == 0 && dy == 0) return rng.nextDouble() * PI;\n\n        long double th = atan2l(dy, dx);\n        th += (rng.nextDouble() - 0.5L) * 0.32L;\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    long double thetaBySplitGap(const vector<int>& pts, int smallRank) const {\n        static const long double PI = acosl(-1.0L);\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        vector<int> sample;\n        if ((int)pts.size() <= 240) {\n            sample = pts;\n        } else {\n            sample.reserve(240);\n            for (int i = 0; i < 240; i++) sample.push_back(pts[rng.nextInt(0, (int)pts.size() - 1)]);\n        }\n\n        int m = (int)sample.size();\n        int r = (int)llround((long double)smallRank * m / max(1, (int)pts.size()));\n        r = max(1, min(m - 1, r));\n\n        vector<long double> angles;\n        angles.reserve(16);\n\n        angles.push_back(thetaFromPoints(sample));\n\n        for (int s = 0; s < 6; s++) {\n            int a = sample[rng.nextInt(0, m - 1)];\n            int b = sample[rng.nextInt(0, m - 1)];\n            if (a != b) {\n                long double dx = (long double)Xs[a] - Xs[b];\n                long double dy = (long double)Ys[a] - Ys[b];\n                if (dx != 0 || dy != 0) {\n                    long double th = atan2l(dy, dx);\n                    th = fmodl(th, PI);\n                    if (th < 0) th += PI;\n                    angles.push_back(th);\n                }\n            }\n        }\n\n        for (int s = 0; s < 5; s++) angles.push_back(rng.nextDouble() * PI);\n\n        long double bestGap = -1;\n        long double bestTheta = angles[0];\n\n        vector<long double> proj;\n        proj.reserve(m);\n\n        for (long double th : angles) {\n            long double cs = cosl(th), sn = sinl(th);\n            proj.clear();\n            for (int idx : sample) {\n                proj.push_back(cs * (long double)Xs[idx] + sn * (long double)Ys[idx]);\n            }\n            sort(proj.begin(), proj.end());\n            long double gap = proj[r] - proj[r - 1];\n            if (gap > bestGap) {\n                bestGap = gap;\n                bestTheta = th;\n            }\n        }\n\n        bestTheta += (rng.nextDouble() - 0.5L) * 0.10L;\n        bestTheta = fmodl(bestTheta, PI);\n        if (bestTheta < 0) bestTheta += PI;\n        return bestTheta;\n    }\n\n    long double targetedTheta() const {\n        static const long double PI = acosl(-1.0L);\n\n        Key chosen{0, 0};\n        bool has = false;\n        int chosenC = 0;\n        double total = 0.0;\n\n        for (const auto& kv : mp) {\n            int w = cellBadScore(kv.second);\n            if (w <= 0) continue;\n            double dw = (double)w;\n            total += dw;\n            if (rng.nextDouble() * total < dw) {\n                chosen = kv.first;\n                chosenC = kv.second;\n                has = true;\n            }\n        }\n\n        if (!has) {\n            for (int attempt = 0; attempt < 10; attempt++) {\n                int i = rng.nextInt(0, N - 1);\n                auto it = mp.find(pat[i]);\n                if (it != mp.end() && it->second >= 2) {\n                    chosen = pat[i];\n                    chosenC = it->second;\n                    has = true;\n                    break;\n                }\n            }\n        }\n\n        if (!has) return rng.nextDouble() * PI;\n\n        vector<int> pts;\n        pts.reserve(min(chosenC, 256));\n        for (int i = 0; i < N; i++) {\n            if (pat[i] == chosen) pts.push_back(i);\n        }\n\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        if (rng.nextDouble() < 0.70) {\n            int r = chooseSplitSmallRank((int)pts.size(), hist);\n            return thetaBySplitGap(pts, r);\n        } else {\n            return thetaFromPoints(pts);\n        }\n    }\n\n    long double targetedThetaWithoutLine(int j) const {\n        static const long double PI = acosl(-1.0L);\n        if (j < 0 || j >= k) return targetedTheta();\n\n        unordered_map<Key, int, KeyHash> cnt;\n        cnt.reserve(N * 2 + 10);\n        cnt.max_load_factor(0.7);\n\n        for (int i = 0; i < N; i++) {\n            cnt[clearedBit(pat[i], j)]++;\n        }\n\n        int h2[11] = {};\n        for (auto& kv : cnt) {\n            int c = kv.second;\n            if (1 <= c && c <= 10) h2[c]++;\n        }\n\n        Key chosen{0, 0};\n        bool has = false;\n        int chosenC = 0;\n        double total = 0.0;\n\n        for (const auto& kv : cnt) {\n            int w = cellBadScoreGeneric(kv.second, h2);\n            if (w <= 0) continue;\n            double dw = (double)w;\n            total += dw;\n            if (rng.nextDouble() * total < dw) {\n                chosen = kv.first;\n                chosenC = kv.second;\n                has = true;\n            }\n        }\n\n        if (!has) {\n            for (int attempt = 0; attempt < 10; attempt++) {\n                int i = rng.nextInt(0, N - 1);\n                Key ck = clearedBit(pat[i], j);\n                auto it = cnt.find(ck);\n                if (it != cnt.end() && it->second >= 2) {\n                    chosen = ck;\n                    chosenC = it->second;\n                    has = true;\n                    break;\n                }\n            }\n        }\n\n        if (!has) return rng.nextDouble() * PI;\n\n        vector<int> pts;\n        pts.reserve(min(chosenC, 256));\n        for (int i = 0; i < N; i++) {\n            if (clearedBit(pat[i], j) == chosen) pts.push_back(i);\n        }\n\n        if ((int)pts.size() < 2) return rng.nextDouble() * PI;\n\n        if (rng.nextDouble() < 0.75) {\n            int r = chooseSplitSmallRank((int)pts.size(), h2);\n            return thetaBySplitGap(pts, r);\n        } else {\n            return thetaFromPoints(pts);\n        }\n    }\n\n    bool trySetLineThetaFast(int j, long double theta, bool isAdd) {\n        if (elapsed_time() > HARD_TIME_LIMIT - 0.02) return false;\n        if (isAdd && k >= MAX_CUTS) return false;\n        if (!isAdd && (j < 0 || j >= k)) return false;\n\n        auto [A, B] = normalFromAngle(theta);\n        if (!isAdd && A == lines[j].A && B == lines[j].B) return false;\n\n        auto ord = computeOrder(A, B);\n        ll oldVal = value();\n\n        int bit = isAdd ? k : j;\n\n        unordered_map<Key, int, KeyHash> id;\n        id.reserve(N * 2 + 10);\n        id.max_load_factor(0.7);\n\n        vector<int> baseId(N);\n        vector<int> totalCnt;\n        totalCnt.reserve(mp.size() + 8);\n\n        for (int i = 0; i < N; i++) {\n            Key key = pat[i];\n            if (!isAdd) key = clearedBit(key, bit);\n\n            auto it = id.find(key);\n            if (it == id.end()) {\n                int nid = (int)totalCnt.size();\n                id.emplace(key, nid);\n                baseId[i] = nid;\n                totalCnt.push_back(1);\n            } else {\n                baseId[i] = it->second;\n                totalCnt[it->second]++;\n            }\n        }\n\n        int h2[11] = {};\n        int over2 = 0;\n        ll overSq2 = 0;\n\n        auto addCnt = [&](int c) {\n            if (1 <= c && c <= 10) h2[c]++;\n            else if (c > 10) {\n                over2 += c;\n                overSq2 += overSqPart(c);\n            }\n        };\n        auto remCnt = [&](int c) {\n            if (1 <= c && c <= 10) h2[c]--;\n            else if (c > 10) {\n                over2 -= c;\n                overSq2 -= overSqPart(c);\n            }\n        };\n\n        for (int c : totalCnt) addCnt(c);\n\n        vector<int> leftCnt(totalCnt.size(), 0);\n\n        ll bestVal = tempValue(h2, over2, overSq2);\n        ll bestC = (*ord)[0].s - 1;\n\n        int idx = 0;\n        while (idx < N) {\n            ll v = (*ord)[idx].s;\n\n            while (idx < N && (*ord)[idx].s == v) {\n                int p = (*ord)[idx].idx;\n                int cid = baseId[p];\n                int l = leftCnt[cid];\n                int r = totalCnt[cid] - l;\n\n                remCnt(l);\n                remCnt(r);\n\n                leftCnt[cid]++;\n                l++;\n                r--;\n\n                addCnt(l);\n                addCnt(r);\n\n                idx++;\n            }\n\n            bool valid = true;\n            ll candC;\n            if (idx == N) {\n                candC = v + 1;\n            } else {\n                ll nxt = (*ord)[idx].s;\n                if (nxt - v >= 2) candC = v + (nxt - v) / 2;\n                else valid = false;\n            }\n\n            if (valid) {\n                ll val = tempValue(h2, over2, overSq2);\n                if (val > bestVal) {\n                    bestVal = val;\n                    bestC = candC;\n                }\n            }\n        }\n\n        if (bestVal <= oldVal) return false;\n\n        Line L;\n        L.A = A;\n        L.B = B;\n        L.C = bestC;\n        L.ord = ord;\n\n        if (isAdd) {\n            lines.push_back(std::move(L));\n            k++;\n        } else {\n            lines[j] = std::move(L);\n        }\n\n        build();\n        return true;\n    }\n\n    bool tryReplaceLineTheta(int j, long double theta) {\n        return trySetLineThetaFast(j, theta, false);\n    }\n\n    bool tryAddLineTheta(long double theta) {\n        return trySetLineThetaFast(k, theta, true);\n    }\n\n    int addLineSearch(int trials, int maxAccept) {\n        static const long double PI = acosl(-1.0L);\n        int acc = 0;\n        for (int t = 0; t < trials && acc < maxAccept && k < MAX_CUTS; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n            long double theta;\n            if (rng.nextDouble() < 0.82) theta = targetedTheta();\n            else theta = rng.nextDouble() * PI;\n\n            if (tryAddLineTheta(theta)) acc++;\n        }\n        return acc;\n    }\n\n    int chooseReplaceLine() const {\n        if (k <= 0) return -1;\n        if (rng.nextDouble() < 0.28) {\n            vector<int> cand;\n            cand.reserve(k);\n            for (int i = 0; i < k; i++) {\n                int r = rankForC(i);\n                if (r == 0 || r == N) cand.push_back(i);\n            }\n            if (!cand.empty()) return cand[rng.nextInt(0, (int)cand.size() - 1)];\n        }\n        return rng.nextInt(0, k - 1);\n    }\n\n    long double lineTheta(int j) const {\n        static const long double PI = acosl(-1.0L);\n        long double th = atan2l((long double)lines[j].B, (long double)lines[j].A);\n        th = fmodl(th, PI);\n        if (th < 0) th += PI;\n        return th;\n    }\n\n    int angleOptimize(int trials) {\n        static const long double PI = acosl(-1.0L);\n        if (k == 0) return 0;\n        int acc = 0;\n\n        for (int t = 0; t < trials; t++) {\n            if (elapsed_time() > HARD_TIME_LIMIT - 0.03) break;\n\n            int j = chooseReplaceLine();\n            if (j < 0) break;\n\n            long double theta;\n            double r = rng.nextDouble();\n\n            if (r < 0.24) {\n                theta = targetedThetaWithoutLine(j);\n            } else if (r < 0.48) {\n                long double scale = 0.04L + 0.32L * rng.nextDouble();\n                theta = lineTheta(j) + (rng.nextDouble() * 2.0L - 1.0L) * scale;\n            } else if (r < 0.85) {\n                theta = targetedTheta();\n            } else {\n                theta = rng.nextDouble() * PI;\n            }\n\n            if (tryReplaceLineTheta(j, theta)) acc++;\n        }\n\n        return acc;\n    }\n};\n\nvoid updateBest(const Config& cfg) {\n    int sc = cfg.score();\n    ll val = cfg.value();\n\n    if (sc > bestScore || (sc == bestScore && val > bestValue)) {\n        bestScore = sc;\n        bestValue = val;\n        bestLines.clear();\n        for (const auto& L : cfg.lines) {\n            bestLines.push_back({L.A, L.B, L.C});\n        }\n    }\n}\n\nvoid runCandidate(vector<Line> lines, int passes) {\n    if ((int)lines.size() > MAX_CUTS) lines.resize(MAX_CUTS);\n    if (elapsed_time() > STOP_START_TIME) return;\n\n    Config cfg(std::move(lines));\n    cfg.build();\n    cfg.optimize(passes);\n    updateBest(cfg);\n}\n\nvector<Line> rebuildLinesFromOut(const vector<LineOut>& outs) {\n    vector<Line> res;\n    res.reserve(outs.size());\n    for (auto O : outs) {\n        Line L;\n        L.A = O.A;\n        L.B = O.B;\n        L.C = O.C;\n        L.ord = computeOrder(L.A, L.B);\n        res.push_back(std::move(L));\n    }\n    return res;\n}\n\nvoid finalPolish() {\n    if (bestLines.empty()) return;\n    if (elapsed_time() > HARD_TIME_LIMIT - 0.08) return;\n\n    auto ls = rebuildLinesFromOut(bestLines);\n    Config cfg(std::move(ls));\n    cfg.build();\n\n    cfg.optimize(5);\n    updateBest(cfg);\n\n    int loops = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.06 && cfg.score() < M_attendees) {\n        cfg.addLineSearch(22, 4);\n        cfg.angleOptimize(26);\n        cfg.optimize(1);\n        updateBest(cfg);\n        loops++;\n        if (loops > 45) break;\n    }\n\n    int shakeAttempts = 0;\n    while (elapsed_time() < HARD_TIME_LIMIT - 0.04 && shakeAttempts < 8) {\n        vector<Line> sl = cfg.lines;\n        if (sl.empty()) break;\n\n        int changes = max(1, (int)sl.size() / 6);\n        for (int c = 0; c < changes; c++) {\n            int j = rng.nextInt(0, (int)sl.size() - 1);\n            int low = N / 25;\n            int high = N - low;\n            if (low > high) {\n                low = 0;\n                high = N;\n            }\n            int rank = rng.nextInt(low, high);\n            sl[j].C = thresholdAtRank(*sl[j].ord, rank);\n        }\n\n        Config tmp(std::move(sl));\n        tmp.build();\n        tmp.optimize(2);\n        tmp.addLineSearch(8, 2);\n        tmp.angleOptimize(10);\n        tmp.optimize(1);\n        updateBest(tmp);\n\n        if (tmp.value() > cfg.value()) {\n            cfg = std::move(tmp);\n        }\n\n        shakeAttempts++;\n    }\n}\n\nll extgcd(ll a, ll b, ll& x, ll& y) {\n    if (b == 0) {\n        x = 1;\n        y = 0;\n        return a;\n    }\n    ll x1, y1;\n    ll g = extgcd(b, a % b, x1, y1);\n    x = y1;\n    y = x1 - (a / b) * y1;\n    return g;\n}\n\narray<ll,4> fallbackLine() {\n    return {1000000000LL, 1000000000LL, 999999999LL, 1000000000LL};\n}\n\narray<ll,4> endpoints(LineOut L) {\n    ll A = L.A, B = L.B, C = L.C;\n    ll g = std::gcd(llabs(A), llabs(B));\n    if (g == 0) return fallbackLine();\n    if (C % g != 0) return fallbackLine();\n    A /= g;\n    B /= g;\n    C /= g;\n\n    auto inside = [](ll v) {\n        return -1000000000LL <= v && v <= 1000000000LL;\n    };\n\n    if (B == 0) {\n        if (A == 0 || C % A != 0) return fallbackLine();\n        ll x = C / A;\n        if (!inside(x)) return fallbackLine();\n        return {x, 0, x, 1};\n    }\n    if (A == 0) {\n        if (B == 0 || C % B != 0) return fallbackLine();\n        ll y = C / B;\n        if (!inside(y)) return fallbackLine();\n        return {0, y, 1, y};\n    }\n\n    ll xg, yg;\n    extgcd(llabs(A), llabs(B), xg, yg);\n\n    __int128 x0 = (__int128)xg * (A >= 0 ? 1 : -1) * C;\n    __int128 y0 = (__int128)yg * (B >= 0 ? 1 : -1) * C;\n\n    ll dx = B;\n    ll dy = -A;\n\n    long double dot = (long double)x0 * (long double)dx + (long double)y0 * (long double)dy;\n    long double den = (long double)dx * dx + (long double)dy * dy;\n    ll t0 = llround(-dot / den);\n\n    __int128 bestNorm = -1;\n    __int128 bx = x0, by = y0;\n\n    for (ll dt = -6; dt <= 6; dt++) {\n        ll t = t0 + dt;\n        __int128 x = x0 + (__int128)dx * t;\n        __int128 y = y0 + (__int128)dy * t;\n        __int128 norm = x * x + y * y;\n        if (bestNorm < 0 || norm < bestNorm) {\n            bestNorm = norm;\n            bx = x;\n            by = y;\n        }\n    }\n\n    __int128 qx = bx + dx;\n    __int128 qy = by + dy;\n\n    if (bx < -1000000000LL || bx > 1000000000LL ||\n        by < -1000000000LL || by > 1000000000LL ||\n        qx < -1000000000LL || qx > 1000000000LL ||\n        qy < -1000000000LL || qy > 1000000000LL) {\n        return fallbackLine();\n    }\n\n    ll px = (ll)bx, py = (ll)by;\n    ll rx = (ll)qx, ry = (ll)qy;\n    if (px == rx && py == ry) return fallbackLine();\n    return {px, py, rx, ry};\n}\n\nLineOut canonical(LineOut L) {\n    ll g = std::gcd(llabs(L.A), llabs(L.B));\n    if (g > 0 && L.C % g == 0) {\n        L.A /= g;\n        L.B /= g;\n        L.C /= g;\n    }\n    if (L.A < 0 || (L.A == 0 && L.B < 0)) {\n        L.A = -L.A;\n        L.B = -L.B;\n        L.C = -L.C;\n    }\n    return L;\n}\n\ndouble clampd(double x, double l, double r) {\n    return max(l, min(r, x));\n}\n\ndouble poissonFactorEstimate() {\n    int maxCells = min(5051, max(50, (int)ceil(M_attendees * 4.0)));\n    int minCells = max(20, (int)floor(M_attendees * 0.40));\n\n    double bestVal = -1e100;\n    int bestT = max(1, M_attendees);\n\n    for (int T = minCells; T <= maxCells; T++) {\n        double lambda = (double)N / T;\n        double p = exp(-lambda);\n        double approx = 0.0;\n        for (int d = 1; d <= 10; d++) {\n            p *= lambda / d;\n            double bd = T * p;\n            approx += min((double)targetA[d], bd);\n        }\n\n        double factor = (double)T / max(1, M_attendees);\n        double penalty = 0.04 * abs(factor - 1.25);\n        double val = approx - penalty;\n        if (val > bestVal) {\n            bestVal = val;\n            bestT = T;\n        }\n    }\n\n    return (double)bestT / max(1, M_attendees);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> K_input;\n    MAX_CUTS = min(K_input, 100);\n\n    M_attendees = 0;\n    for (int d = 1; d <= 10; d++) {\n        cin >> targetA[d];\n        M_attendees += targetA[d];\n    }\n\n    Xs.resize(N);\n    Ys.resize(N);\n    for (int i = 0; i < N; i++) cin >> Xs[i] >> Ys[i];\n\n    uint64_t seed = 0x123456789abcdefULL;\n    auto mixSeed = [&](uint64_t v) {\n        seed ^= v + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n    };\n    mixSeed(N);\n    mixSeed(K_input);\n    for (int d = 1; d <= 10; d++) mixSeed(targetA[d]);\n    for (int i = 0; i < N; i++) {\n        mixSeed((uint64_t)(Xs[i] + 20000) * 40009ULL + (uint64_t)(Ys[i] + 20000));\n    }\n    rng.state = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    double avgD = (double)N / max(1, M_attendees);\n    double smallRatio = (targetA[1] + targetA[2] + targetA[3]) / (double)M_attendees;\n    double largeRatio = (targetA[8] + targetA[9] + targetA[10]) / (double)M_attendees;\n\n    double centerFactor = 1.25 + 0.95 * (smallRatio - largeRatio) + 0.10 * (5.5 - avgD);\n    centerFactor = clampd(centerFactor, 0.70, 2.05);\n\n    double poissonFactor = poissonFactorEstimate();\n    poissonFactor = clampd(poissonFactor, 0.55, 3.20);\n\n    auto normFactor = [&](double f) {\n        return clampd(f, 0.45, 4.00);\n    };\n\n    auto tryGroup = [&](int G, double factor, int initMode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        auto counts = bestCounts(G, T);\n        long double PI = acosl(-1.0L);\n        long double base = rng.nextDouble() * PI / G;\n        auto lines = makeGroup(G, counts, base, initMode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    auto tryGeneral = [&](double factor, int mode, int passes) {\n        if (elapsed_time() > STOP_START_TIME) return;\n        int T = max(1, (int)llround(M_attendees * normFactor(factor)));\n        int k = kForCells(T);\n        auto lines = makeGeneral(k, mode);\n        runCandidate(std::move(lines), passes);\n    };\n\n    tryGroup(2, centerFactor, 0, 4);\n    tryGroup(3, centerFactor, 0, 4);\n    tryGroup(4, centerFactor, 0, 3);\n    tryGroup(5, centerFactor, 0, 3);\n    tryGeneral(centerFactor, 0, 3);\n\n    tryGroup(2, centerFactor * 1.28, 2, 3);\n    tryGroup(3, centerFactor * 0.88, 2, 3);\n    tryGroup(4, centerFactor * 1.18, 2, 3);\n    tryGroup(6, centerFactor * 1.05, 0, 3);\n    tryGeneral(centerFactor * 1.28, 1, 3);\n\n    tryGroup(2, poissonFactor, 0, 3);\n    tryGroup(3, poissonFactor * 1.05, 2, 3);\n    tryGroup(7, (centerFactor + poissonFactor) * 0.5, 0, 2);\n    tryGroup(8, (centerFactor + poissonFactor) * 0.5, 2, 2);\n    tryGeneral(poissonFactor, 0, 2);\n\n    int iter = 0;\n    while (elapsed_time() < STOP_START_TIME) {\n        int typ = iter % 9;\n\n        double baseF;\n        double rbase = rng.nextDouble();\n        if (rbase < 0.45) baseF = centerFactor;\n        else if (rbase < 0.80) baseF = poissonFactor;\n        else baseF = 0.5 * (centerFactor + poissonFactor);\n\n        double mult;\n        if (rng.nextDouble() < 0.16) mult = 0.50 + 2.15 * rng.nextDouble();\n        else mult = 0.68 + 1.05 * rng.nextDouble();\n\n        double factor = normFactor(baseF * mult);\n        int initMode = rng.nextInt(0, 2);\n\n        if (typ == 0) tryGroup(2, factor, initMode, 2);\n        else if (typ == 1) tryGroup(3, factor, initMode, 2);\n        else if (typ == 2) tryGroup(4, factor, initMode, 2);\n        else if (typ == 3) tryGroup(5, factor, initMode, 2);\n        else if (typ == 4) tryGroup(6, factor, initMode, 2);\n        else if (typ == 5) tryGroup(7, factor, initMode, 2);\n        else if (typ == 6) tryGroup(8, factor, initMode, 2);\n        else tryGeneral(factor, rng.nextInt(0, 1), 2);\n\n        iter++;\n    }\n\n    finalPolish();\n\n    vector<LineOut> outputLines;\n    vector<LineOut> seen;\n    for (auto L : bestLines) {\n        LineOut C = canonical(L);\n        bool dup = false;\n        for (auto S : seen) {\n            if (S.A == C.A && S.B == C.B && S.C == C.C) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) {\n            seen.push_back(C);\n            outputLines.push_back(L);\n        }\n        if ((int)outputLines.size() == MAX_CUTS) break;\n    }\n\n    cout << outputLines.size() << '\\n';\n    for (auto L : outputLines) {\n        auto e = endpoints(L);\n        cout << e[0] << ' ' << e[1] << ' ' << e[2] << ' ' << e[3] << '\\n';\n    }\n\n    return 0;\n}","ahc014":"#pragma GCC optimize(\"O3,unroll-loops\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nconst int MAXN = 61;\nconst int MAXC = MAXN * MAXN;\nconst int MAXTOP = 128;\n\nint N, M, C;\nint PX[MAXC], PY[MAXC];\nint WT[MAXC];\nint maxWeight = 0;\n\nunsigned char initDot[MAXC];\ndouble priorityVal[MAXC];\nlong long initialSum = 0;\n\nint initMinX, initMaxX, initMinY, initMaxY;\n\nint initDotsArr[MAXC], initDotCnt = 0;\nint initEmptiesArr[MAXC], initEmptyCnt = 0;\nint initEmptyPos[MAXC];\n\nuint64_t RM[MAXN][MAXN];\n\nconst int DX[8] = {1, 0, -1, 0, 1, -1, -1, 1};\nconst int DY[8] = {0, 1, 0, -1, 1, 1, -1, -1};\nconst int OPP[8] = {2, 3, 0, 1, 6, 7, 4, 5};\n\nconst int PA[8] = {0, 1, 2, 3, 4, 5, 6, 7};\nconst int PB[8] = {1, 2, 3, 0, 5, 6, 7, 4};\n\nint startPts[8][2 * MAXN];\nint startLen[8][2 * MAXN];\nint startCnt[8];\nint STEP_DIR[8];\nint PREV_DIR[8][MAXC];\n\ninline int pid(int x, int y) {\n    return x * N + y;\n}\n\ninline bool inside(int x, int y) {\n    return 0 <= x && x < N && 0 <= y && y < N;\n}\n\ninline uint64_t rangeMask(int l, int r) {\n    return RM[l][r];\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 RNG {\n    uint64_t x;\n\n    RNG(uint64_t seed = 1) {\n        x = splitmix64(seed);\n        if (x == 0) x = 88172645463325252ULL;\n    }\n\n    inline uint64_t next() {\n        x ^= x >> 12;\n        x ^= x << 25;\n        x ^= x >> 27;\n        return x * 2685821657736338717ULL;\n    }\n\n    inline int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    inline double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n\n    inline double nextSigned() {\n        return nextDouble() * 2.0 - 1.0;\n    }\n};\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n\n    Timer() {\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\nstruct Op {\n    int p1, p2, p3, p4;\n};\n\nstruct Candidate {\n    int p1, p2, p3, p4;\n    int lenSum;\n    int area;\n    int ord;\n};\n\nstruct Node {\n    double key;\n    int ord;\n    Candidate cand;\n};\n\ninline bool nodeWorse(const Node& a, const Node& b) {\n    if (a.key != b.key) return a.key < b.key;\n    return a.ord > b.ord;\n}\n\ninline void heapSiftUp(Node h[], int i) {\n    while (i > 0) {\n        int p = (i - 1) >> 1;\n        if (!nodeWorse(h[i], h[p])) break;\n        swap(h[p], h[i]);\n        i = p;\n    }\n}\n\ninline void heapSiftDown(Node h[], int n, int i = 0) {\n    while (true) {\n        int l = i * 2 + 1;\n        int r = l + 1;\n        int m = i;\n\n        if (l < n && nodeWorse(h[l], h[m])) m = l;\n        if (r < n && nodeWorse(h[r], h[m])) m = r;\n\n        if (m == i) break;\n\n        swap(h[i], h[m]);\n        i = m;\n    }\n}\n\ninline void heapPushTop(Node h[], int& n, int K, const Node& nd) {\n    if (n < K) {\n        h[n] = nd;\n        heapSiftUp(h, n);\n        ++n;\n    } else if (nodeWorse(h[0], nd)) {\n        h[0] = nd;\n        heapSiftDown(h, n, 0);\n    }\n}\n\nstruct Params {\n    double wcoef;\n    double perim;\n    double area;\n    double outAvg;\n    double outOpp;\n    double frontier;\n    int topK;\n    double rankPower;\n    double noise;\n};\n\nstruct State {\n    unsigned char dot[MAXC];\n    int nearestDot[8][MAXC];\n\n    uint64_t H[MAXN], V[MAXN], DPm[2 * MAXN], DMm[2 * MAXN];\n\n    int dotsArr[MAXC];\n    int dotCnt;\n\n    int emptiesArr[MAXC];\n    int emptyCnt;\n    int emptyPos[MAXC];\n\n    vector<Op> ops;\n\n    long long sumW = 0;\n    bool dirtyNearest = true;\n\n    int minX, maxX, minY, maxY;\n\n    void reset() {\n        memcpy(dot, initDot, C * sizeof(unsigned char));\n        memcpy(emptyPos, initEmptyPos, C * sizeof(int));\n\n        memset(H, 0, sizeof(H));\n        memset(V, 0, sizeof(V));\n        memset(DPm, 0, sizeof(DPm));\n        memset(DMm, 0, sizeof(DMm));\n\n        dotCnt = initDotCnt;\n        memcpy(dotsArr, initDotsArr, dotCnt * sizeof(int));\n\n        emptyCnt = initEmptyCnt;\n        memcpy(emptiesArr, initEmptiesArr, emptyCnt * sizeof(int));\n\n        ops.clear();\n        sumW = initialSum;\n        dirtyNearest = true;\n\n        minX = initMinX;\n        maxX = initMaxX;\n        minY = initMinY;\n        maxY = initMaxY;\n    }\n\n    void buildNearest() {\n        for (int d = 0; d < 8; ++d) {\n            int step = STEP_DIR[d];\n\n            for (int si = 0; si < startCnt[d]; ++si) {\n                int p = startPts[d][si];\n                int len = startLen[d][si];\n                int cur = -1;\n\n                for (int k = 0; k < len; ++k) {\n                    nearestDot[d][p] = cur;\n                    if (dot[p]) cur = p;\n                    p -= step;\n                }\n            }\n        }\n\n        dirtyNearest = false;\n    }\n\n    void updateNearestAfterAdd(int p) {\n        for (int d = 0; d < 8; ++d) {\n            int q = PREV_DIR[d][p];\n\n            while (q >= 0) {\n                nearestDot[d][q] = p;\n\n                if (dot[q]) break;\n\n                q = PREV_DIR[d][q];\n            }\n        }\n    }\n\n    bool sideFree(int a, int b) const {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            return (V[x1] & rangeMask(y1, y2)) == 0;\n        }\n\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            return (H[y1] & rangeMask(x1, x2)) == 0;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (abs(dx) != abs(dy)) return false;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 - y1 + N - 1;\n            return (DPm[line] & rangeMask(x1, x2)) == 0;\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 + y1;\n            return (DMm[line] & rangeMask(x1, x2)) == 0;\n        }\n    }\n\n    void markSide(int a, int b) {\n        int x1 = PX[a], y1 = PY[a];\n        int x2 = PX[b], y2 = PY[b];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            V[x1] |= rangeMask(y1, y2);\n            return;\n        }\n\n        if (y1 == y2) {\n            if (x1 > x2) swap(x1, x2);\n            H[y1] |= rangeMask(x1, x2);\n            return;\n        }\n\n        int dx = x2 - x1;\n        int dy = y2 - y1;\n\n        if (dx == dy) {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 - y1 + N - 1;\n            DPm[line] |= rangeMask(x1, x2);\n        } else {\n            if (x1 > x2) {\n                swap(x1, x2);\n                swap(y1, y2);\n            }\n\n            int line = x1 + y1;\n            DMm[line] |= rangeMask(x1, x2);\n        }\n    }\n\n    inline void removeEmptyPoint(int p) {\n        int pos = emptyPos[p];\n        if (pos < 0) return;\n\n        --emptyCnt;\n        int last = emptiesArr[emptyCnt];\n\n        emptiesArr[pos] = last;\n        emptyPos[last] = pos;\n        emptyPos[p] = -1;\n    }\n\n    void applyOp(const Op& op, bool updateNearest) {\n        markSide(op.p1, op.p2);\n        markSide(op.p2, op.p3);\n        markSide(op.p3, op.p4);\n        markSide(op.p4, op.p1);\n\n        dot[op.p1] = 1;\n        removeEmptyPoint(op.p1);\n        dotsArr[dotCnt++] = op.p1;\n\n        sumW += WT[op.p1];\n        ops.push_back(op);\n\n        int x = PX[op.p1];\n        int y = PY[op.p1];\n\n        if (x < minX) minX = x;\n        if (x > maxX) maxX = x;\n        if (y < minY) minY = y;\n        if (y > maxY) maxY = y;\n\n        if (updateNearest && !dirtyNearest) {\n            updateNearestAfterAdd(op.p1);\n        } else {\n            dirtyNearest = true;\n        }\n    }\n\n    inline bool canReplay(const Op& op) const {\n        return !dot[op.p1] && dot[op.p2] && dot[op.p3] && dot[op.p4];\n    }\n\n    bool chooseCandidate(const Params& par, RNG& rng, Candidate& res) {\n        if (dirtyNearest) buildNearest();\n\n        int K = par.topK;\n        if (K < 1) K = 1;\n        if (K > MAXTOP) K = MAXTOP;\n\n        bool found = false;\n        double bestKey = -1e100;\n        int bestLen = INT_MAX;\n        int bestOrd = INT_MAX;\n        Candidate bestCand{};\n\n        Node heap[MAXTOP];\n        int hsz = 0;\n\n        auto processCandidate = [&](int p1, int p2, int p3, int p4, int t, int x1, int y1) {\n            if (!sideFree(p1, p2)) return;\n            if (!sideFree(p2, p3)) return;\n            if (!sideFree(p3, p4)) return;\n            if (!sideFree(p4, p1)) return;\n\n            int len1 = max(abs(PX[p2] - x1), abs(PY[p2] - y1));\n            int len2 = max(abs(PX[p4] - x1), abs(PY[p4] - y1));\n            int lenSum = len1 + len2;\n            int area = len1 * len2;\n\n            int ext = 0;\n\n            if (x1 < minX) ext += minX - x1;\n            else if (x1 > maxX) ext += x1 - maxX;\n\n            if (y1 < minY) ext += minY - y1;\n            else if (y1 > maxY) ext += y1 - maxY;\n\n            double avgOther = (WT[p2] + WT[p3] + WT[p4]) / 3.0;\n\n            double key =\n                priorityVal[p1]\n                + par.outAvg * (WT[p1] - avgOther)\n                + par.outOpp * (WT[p1] - WT[p3])\n                + par.frontier * ext\n                - par.perim * lenSum\n                - par.area * area;\n\n            int ord = p1 * 8 + t;\n            Candidate cand{p1, p2, p3, p4, lenSum, area, ord};\n\n            if (K == 1) {\n                if (!found || key > bestKey ||\n                    (key == bestKey &&\n                     (lenSum < bestLen || (lenSum == bestLen && ord < bestOrd)))) {\n                    found = true;\n                    bestKey = key;\n                    bestLen = lenSum;\n                    bestOrd = ord;\n                    bestCand = cand;\n                }\n            } else {\n                Node nd{key, ord, cand};\n                heapPushTop(heap, hsz, K, nd);\n            }\n        };\n\n        if (dotCnt <= emptyCnt) {\n            for (int ii = 0; ii < dotCnt; ++ii) {\n                int p3 = dotsArr[ii];\n                int x3 = PX[p3];\n                int y3 = PY[p3];\n\n                for (int t = 0; t < 8; ++t) {\n                    int d1 = PA[t];\n                    int d2 = PB[t];\n\n                    int p2 = nearestDot[OPP[d2]][p3];\n                    if (p2 < 0) continue;\n\n                    int p4 = nearestDot[OPP[d1]][p3];\n                    if (p4 < 0) continue;\n\n                    int x1 = PX[p2] + PX[p4] - x3;\n                    int y1 = PY[p2] + PY[p4] - y3;\n\n                    if ((unsigned)x1 >= (unsigned)N || (unsigned)y1 >= (unsigned)N) continue;\n\n                    int p1 = pid(x1, y1);\n                    if (dot[p1]) continue;\n\n                    if (nearestDot[d1][p1] != p2) continue;\n                    if (nearestDot[d2][p1] != p4) continue;\n\n                    processCandidate(p1, p2, p3, p4, t, x1, y1);\n                }\n            }\n        } else {\n            for (int ii = 0; ii < emptyCnt; ++ii) {\n                int p1 = emptiesArr[ii];\n\n                int x1 = PX[p1];\n                int y1 = PY[p1];\n\n                for (int t = 0; t < 8; ++t) {\n                    int d1 = PA[t];\n                    int d2 = PB[t];\n\n                    int p2 = nearestDot[d1][p1];\n                    if (p2 < 0) continue;\n\n                    int p4 = nearestDot[d2][p1];\n                    if (p4 < 0) continue;\n\n                    int x3 = PX[p2] + PX[p4] - x1;\n                    int y3 = PY[p2] + PY[p4] - y1;\n\n                    if ((unsigned)x3 >= (unsigned)N || (unsigned)y3 >= (unsigned)N) continue;\n\n                    int p3 = pid(x3, y3);\n                    if (!dot[p3]) continue;\n\n                    if (nearestDot[d2][p2] != p3) continue;\n                    if (nearestDot[d1][p4] != p3) continue;\n\n                    processCandidate(p1, p2, p3, p4, t, x1, y1);\n                }\n            }\n        }\n\n        if (K == 1) {\n            if (!found) return false;\n            res = bestCand;\n            return true;\n        } else {\n            if (hsz == 0) return false;\n\n            sort(heap, heap + hsz, [](const Node& a, const Node& b) {\n                if (a.key != b.key) return a.key > b.key;\n                return a.ord < b.ord;\n            });\n\n            int idx = 0;\n\n            if (hsz > 1) {\n                if (par.rankPower <= 0.0) {\n                    idx = rng.nextInt(hsz);\n                } else {\n                    double z = pow(rng.nextDouble(), par.rankPower);\n                    idx = (int)(z * hsz);\n                    if (idx >= hsz) idx = hsz - 1;\n                }\n            }\n\n            res = heap[idx].cand;\n            return true;\n        }\n    }\n};\n\nParams randomParam(RNG& rng) {\n    static const double wcoefs[] = {\n        0.0, 0.15, 0.35, 0.65, 0.9, 1.0, 1.0, 1.25, 1.6, 2.1\n    };\n\n    static const double perims[] = {\n        -1.4, -0.8, -0.4, -0.1, 0.0, 0.4, 0.9, 1.6, 2.7, 4.2, 6.5, 9.0\n    };\n\n    static const double areas[] = {\n        -0.025, -0.010, -0.003, 0.0, 0.0, 0.006, 0.016, 0.035, 0.070\n    };\n\n    Params p;\n\n    p.wcoef = wcoefs[rng.nextInt((int)(sizeof(wcoefs) / sizeof(wcoefs[0])))];\n\n    p.perim = perims[rng.nextInt((int)(sizeof(perims) / sizeof(perims[0])))]\n              + (rng.nextDouble() - 0.5) * 0.45;\n\n    p.area = areas[rng.nextInt((int)(sizeof(areas) / sizeof(areas[0])))];\n\n    p.outAvg = 0.0;\n    p.outOpp = 0.0;\n\n    if (rng.nextInt(100) < 60) p.outAvg = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 50) p.outOpp = rng.nextDouble() * 1.35;\n    if (rng.nextInt(100) < 10) p.outOpp += rng.nextDouble() * 1.8;\n\n    p.frontier = 0.0;\n\n    if (rng.nextInt(100) < 45) p.frontier = rng.nextDouble() * 35.0;\n\n    if (M < 2 * N && rng.nextInt(100) < 35) {\n        p.perim -= 1.0 + rng.nextDouble() * 2.0;\n        p.area -= rng.nextDouble() * 0.025;\n        p.frontier += rng.nextDouble() * 25.0;\n    }\n\n    if (M > N * N / 18 && rng.nextInt(100) < 35) {\n        p.perim += rng.nextDouble() * 4.0;\n        p.area += rng.nextDouble() * 0.040;\n        p.wcoef *= 0.7;\n    }\n\n    int r = rng.nextInt(100);\n\n    if (r < 18) {\n        p.topK = 1;\n    } else if (r < 72) {\n        p.topK = 3 + rng.nextInt(25);\n    } else {\n        p.topK = 30 + rng.nextInt(90);\n    }\n\n    if (p.topK > MAXTOP) p.topK = MAXTOP;\n\n    if (p.topK == 1) {\n        p.rankPower = 1.0;\n    } else {\n        int q = rng.nextInt(100);\n\n        if (q < 18) p.rankPower = 1.0;\n        else if (q < 84) p.rankPower = 1.5 + rng.nextDouble() * 3.2;\n        else p.rankPower = 0.45 + rng.nextDouble() * 0.65;\n    }\n\n    if (rng.nextInt(100) < 50) p.noise = rng.nextDouble() * 0.14;\n    else p.noise = rng.nextDouble() * 0.38;\n\n    if (rng.nextInt(100) < 5) p.noise = rng.nextDouble() * 0.75;\n\n    return p;\n}\n\nvoid preparePriority(const Params& par, RNG& rng) {\n    double amp = par.noise * maxWeight;\n\n    for (int i = 0; i < C; ++i) {\n        priorityVal[i] = par.wcoef * WT[i];\n\n        if (amp > 1e-12) {\n            priorityVal[i] += amp * rng.nextSigned();\n        }\n    }\n}\n\nvoid runGreedy(\n    State& st,\n    const Params& par,\n    RNG& rng,\n    const Timer& timer,\n    double TL\n) {\n    Candidate cand;\n\n    while (timer.elapsed() < TL) {\n        if (!st.chooseCandidate(par, rng, cand)) break;\n\n        Op op{cand.p1, cand.p2, cand.p3, cand.p4};\n        st.applyOp(op, true);\n    }\n}\n\nvoid replayDestroyed(State& st, const vector<Op>& base, RNG& rng) {\n    st.reset();\n\n    int K = (int)base.size();\n    if (K == 0) return;\n\n    int mode = rng.nextInt(100);\n\n    int cut = K;\n    int l = 0, r = 0;\n    int cx = 0, cy = 0, rad2 = 0, rx = 0, ry = 0;\n    bool circle = true;\n    double pdrop = 0.0, extra = 0.0;\n    bool dropLow = true;\n\n    if (mode < 20) {\n        int lim = min(K, 50 + rng.nextInt(950));\n        int drop = 1 + rng.nextInt(lim);\n        cut = K - drop;\n    } else if (mode < 45) {\n        pdrop = 0.01 + pow(rng.nextDouble(), 2.0) * 0.30;\n\n        if (rng.nextInt(100) < 10) {\n            pdrop = 0.30 + rng.nextDouble() * 0.35;\n        }\n    } else if (mode < 65) {\n        double frac = 0.02 + 0.55 * rng.nextDouble() * rng.nextDouble();\n        int maxLen = max(1, min(K, 1 + (int)(K * frac)));\n        int len = 1 + rng.nextInt(maxLen);\n\n        l = rng.nextInt(K - len + 1);\n        r = l + len;\n    } else if (mode < 85) {\n        const Op& op = base[rng.nextInt(K)];\n\n        cx = PX[op.p1];\n        cy = PY[op.p1];\n\n        circle = rng.nextInt(2) == 0;\n\n        if (circle) {\n            int rad = 2 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            rad2 = rad * rad;\n        } else {\n            rx = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n            ry = 1 + (int)(pow(rng.nextDouble(), 2.0) * (N / 2 + 1));\n        }\n    } else {\n        pdrop = 0.01 + rng.nextDouble() * 0.08;\n        extra = 0.05 + rng.nextDouble() * 0.32;\n        dropLow = rng.nextInt(2) == 0;\n    }\n\n    for (int i = 0; i < K; ++i) {\n        const Op& op = base[i];\n        bool keep = true;\n\n        if (mode < 20) {\n            keep = i < cut;\n        } else if (mode < 45) {\n            keep = rng.nextDouble() >= pdrop;\n        } else if (mode < 65) {\n            keep = !(l <= i && i < r);\n        } else if (mode < 85) {\n            int x = PX[op.p1];\n            int y = PY[op.p1];\n\n            bool inRegion;\n\n            if (circle) {\n                int dx = x - cx;\n                int dy = y - cy;\n                inRegion = dx * dx + dy * dy <= rad2;\n            } else {\n                inRegion = abs(x - cx) <= rx && abs(y - cy) <= ry;\n            }\n\n            keep = !inRegion;\n        } else {\n            double norm = (double)WT[op.p1] / maxWeight;\n            double pd = pdrop + extra * (dropLow ? (1.0 - norm) : norm);\n\n            if (pd > 0.80) pd = 0.80;\n\n            keep = rng.nextDouble() >= pd;\n        }\n\n        if (keep && st.canReplay(op)) {\n            st.applyOp(op, false);\n        }\n    }\n}\n\nstruct Solution {\n    long long sum;\n    vector<Op> ops;\n};\n\nvoid considerSolution(\n    const State& st,\n    vector<Solution>& pool,\n    vector<Op>& bestOps,\n    long long& bestSum\n) {\n    if (st.sumW > bestSum) {\n        bestSum = st.sumW;\n        bestOps = st.ops;\n    }\n\n    const int POOL_SIZE = 10;\n\n    if ((int)pool.size() >= POOL_SIZE && st.sumW <= pool.back().sum) return;\n\n    for (const auto& s : pool) {\n        if (s.sum == st.sumW && s.ops.size() == st.ops.size()) return;\n    }\n\n    Solution sol;\n    sol.sum = st.sumW;\n    sol.ops = st.ops;\n\n    pool.push_back(move(sol));\n\n    sort(pool.begin(), pool.end(), [](const Solution& a, const Solution& b) {\n        if (a.sum != b.sum) return a.sum > b.sum;\n        return a.ops.size() > b.ops.size();\n    });\n\n    if ((int)pool.size() > POOL_SIZE) pool.pop_back();\n}\n\ninline void appendInt(string& s, int v) {\n    if (v == 0) {\n        s.push_back('0');\n        return;\n    }\n\n    char buf[16];\n    int n = 0;\n\n    while (v > 0) {\n        buf[n++] = char('0' + (v % 10));\n        v /= 10;\n    }\n\n    while (n--) s.push_back(buf[n]);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    C = N * N;\n\n    for (int l = 0; l < MAXN; ++l) {\n        for (int r = 0; r < MAXN; ++r) {\n            if (r > l) RM[l][r] = ((1ULL << (r - l)) - 1ULL) << l;\n            else RM[l][r] = 0ULL;\n        }\n    }\n\n    fill(initDot, initDot + MAXC, 0);\n\n    int c = N / 2;\n\n    for (int x = 0; x < N; ++x) {\n        for (int y = 0; y < N; ++y) {\n            int p = pid(x, y);\n            PX[p] = x;\n            PY[p] = y;\n\n            int dx = x - c;\n            int dy = y - c;\n\n            WT[p] = dx * dx + dy * dy + 1;\n            maxWeight = max(maxWeight, WT[p]);\n        }\n    }\n\n    for (int d = 0; d < 8; ++d) {\n        STEP_DIR[d] = DX[d] * N + DY[d];\n\n        for (int p = 0; p < C; ++p) {\n            int nx = PX[p] - DX[d];\n            int ny = PY[p] - DY[d];\n\n            if (inside(nx, ny)) PREV_DIR[d][p] = pid(nx, ny);\n            else PREV_DIR[d][p] = -1;\n        }\n\n        startCnt[d] = 0;\n\n        for (int p = 0; p < C; ++p) {\n            int x = PX[p];\n            int y = PY[p];\n\n            if (!inside(x + DX[d], y + DY[d])) {\n                int q = p;\n                int len = 0;\n\n                while (q >= 0) {\n                    ++len;\n                    q = PREV_DIR[d][q];\n                }\n\n                int idx = startCnt[d]++;\n                startPts[d][idx] = p;\n                startLen[d][idx] = len;\n            }\n        }\n    }\n\n    initMinX = N;\n    initMaxX = -1;\n    initMinY = N;\n    initMaxY = -1;\n\n    uint64_t seed = splitmix64(((uint64_t)N << 32) ^ (uint64_t)M);\n\n    vector<int> tmpInitialDots;\n    tmpInitialDots.reserve(M);\n\n    for (int i = 0; i < M; ++i) {\n        int x, y;\n        cin >> x >> y;\n\n        int p = pid(x, y);\n        initDot[p] = 1;\n        tmpInitialDots.push_back(p);\n\n        initMinX = min(initMinX, x);\n        initMaxX = max(initMaxX, x);\n        initMinY = min(initMinY, y);\n        initMaxY = max(initMaxY, y);\n\n        seed ^= splitmix64(((uint64_t)(i + 1) << 40) ^ ((uint64_t)x << 20) ^ (uint64_t)y);\n    }\n\n    sort(tmpInitialDots.begin(), tmpInitialDots.end());\n\n    initDotCnt = (int)tmpInitialDots.size();\n    for (int i = 0; i < initDotCnt; ++i) {\n        initDotsArr[i] = tmpInitialDots[i];\n    }\n\n    initialSum = 0;\n    initEmptyCnt = 0;\n\n    for (int p = 0; p < C; ++p) {\n        if (initDot[p]) {\n            initialSum += WT[p];\n            initEmptyPos[p] = -1;\n        } else {\n            initEmptyPos[p] = initEmptyCnt;\n            initEmptiesArr[initEmptyCnt++] = p;\n        }\n    }\n\n    RNG rng(seed);\n\n    vector<Params> presets = {\n        {1.0,  0.0,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  0.6,  0.000, 0.0, 0.0,  0.0,  1, 1.0, 0.00},\n        {1.0,  2.8,  0.015, 0.8, 0.2,  0.0,  1, 1.0, 0.00},\n        {1.0, -0.4, -0.004, 0.4, 0.0,  0.0,  8, 2.0, 0.00},\n        {1.0,  0.5,  0.000, 1.0, 0.0,  0.0, 16, 1.7, 0.00},\n        {1.0,  4.5,  0.050, 0.0, 0.0,  0.0, 24, 2.5, 0.00},\n        {0.0,  6.0,  0.040, 0.0, 0.0,  0.0,  8, 2.2, 0.01},\n        {0.25, 3.5,  0.020, 0.2, 0.0,  0.0, 12, 2.0, 0.02},\n        {0.8,  0.0,  0.000, 0.0, 0.8, 25.0, 20, 2.2, 0.04}\n    };\n\n    State st;\n    st.ops.reserve(C);\n\n    vector<Op> bestOps;\n    bestOps.reserve(C);\n\n    long long bestSum = initialSum;\n\n    vector<Solution> pool;\n    pool.reserve(12);\n\n    Timer timer;\n\n    // Buffered output makes this slightly more comfortable.\n    // Large boards keep more margin; small boards can use a bit more.\n    double TL = 4.965 + (61 - N) * 0.0007;\n    if (TL > 4.985) TL = 4.985;\n    if (TL < 4.965) TL = 4.965;\n\n    int trial = 0;\n\n    while (timer.elapsed() < TL) {\n        Params par;\n        bool useLNS = false;\n\n        if (trial < (int)presets.size()) {\n            par = presets[trial];\n        } else {\n            par = randomParam(rng);\n\n            if (!pool.empty() && rng.nextInt(100) < 78) {\n                useLNS = true;\n            }\n        }\n\n        preparePriority(par, rng);\n\n        if (useLNS) {\n            int ps = (int)pool.size();\n            double u = rng.nextDouble();\n            int idx = (int)(u * u * ps);\n\n            if (idx >= ps) idx = ps - 1;\n\n            replayDestroyed(st, pool[idx].ops, rng);\n        } else {\n            st.reset();\n        }\n\n        runGreedy(st, par, rng, timer, TL);\n        considerSolution(st, pool, bestOps, bestSum);\n\n        ++trial;\n    }\n\n    string out;\n    out.reserve(16 + bestOps.size() * 40);\n\n    appendInt(out, (int)bestOps.size());\n    out.push_back('\\n');\n\n    for (const auto& op : bestOps) {\n        appendInt(out, PX[op.p1]); out.push_back(' ');\n        appendInt(out, PY[op.p1]); out.push_back(' ');\n        appendInt(out, PX[op.p2]); out.push_back(' ');\n        appendInt(out, PY[op.p2]); out.push_back(' ');\n        appendInt(out, PX[op.p3]); out.push_back(' ');\n        appendInt(out, PY[op.p3]); out.push_back(' ');\n        appendInt(out, PX[op.p4]); out.push_back(' ');\n        appendInt(out, PY[op.p4]); out.push_back('\\n');\n    }\n\n    fwrite(out.data(), 1, out.size(), stdout);\n\n    return 0;\n}","ahc015":"#include <bits/stdc++.h>\nusing namespace std;\n\nusing ll = long long;\n\nint flav[100];\nint totalCnt[4];\nint remAfter[100][4];\n\nint neighs[100][4], degs_[100];\nint rightCell[100], downCell[100];\nuint8_t manhDist[100][100];\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n\n    uint64_t next64() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next64() % (uint64_t)n);\n    }\n};\n\nstruct Board {\n    uint8_t a[100];\n    int n;\n\n    Board() { clear(); }\n\n    void clear() {\n        memset(a, 0, sizeof(a));\n        n = 0;\n    }\n\n    void placeRank(int rk, int fl) {\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) {\n                if (rk == 0) {\n                    a[i] = (uint8_t)fl;\n                    n++;\n                    return;\n                }\n                rk--;\n            }\n        }\n    }\n\n    void placeCell(int pos, int fl) {\n        a[pos] = (uint8_t)fl;\n        n++;\n    }\n\n    int getEmpties(int emp[]) const {\n        int m = 0;\n        for (int i = 0; i < 100; i++) {\n            if (a[i] == 0) emp[m++] = i;\n        }\n        return m;\n    }\n\n    void tilt(int dir) {\n        if (dir == 0) { // F\n            for (int c = 0; c < 10; c++) {\n                int w = 0;\n                for (int r = 0; r < 10; r++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w++ * 10 + c] = v;\n                }\n                for (int r = w; r < 10; r++) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 1) { // B\n            for (int c = 0; c < 10; c++) {\n                int w = 9;\n                for (int r = 9; r >= 0; r--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[w-- * 10 + c] = v;\n                }\n                for (int r = w; r >= 0; r--) a[r * 10 + c] = 0;\n            }\n        } else if (dir == 2) { // L\n            for (int r = 0; r < 10; r++) {\n                int w = 0;\n                for (int c = 0; c < 10; c++) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w++] = v;\n                }\n                for (int c = w; c < 10; c++) a[r * 10 + c] = 0;\n            }\n        } else { // R\n            for (int r = 0; r < 10; r++) {\n                int w = 9;\n                for (int c = 9; c >= 0; c--) {\n                    uint8_t v = a[r * 10 + c];\n                    if (v) a[r * 10 + w--] = v;\n                }\n                for (int c = w; c >= 0; c--) a[r * 10 + c] = 0;\n            }\n        }\n    }\n};\n\nstruct Layout {\n    uint8_t target[100];\n    uint8_t dist[4][100];\n};\n\nvector<Layout> layouts;\nunordered_set<string> seenLayouts;\n\nvoid initTables() {\n    for (int i = 0; i < 100; i++) {\n        degs_[i] = 0;\n        rightCell[i] = downCell[i] = -1;\n    }\n\n    for (int r = 0; r < 10; r++) {\n        for (int c = 0; c < 10; c++) {\n            int id = r * 10 + c;\n\n            if (r > 0) neighs[id][degs_[id]++] = (r - 1) * 10 + c;\n            if (r < 9) neighs[id][degs_[id]++] = (r + 1) * 10 + c;\n            if (c > 0) neighs[id][degs_[id]++] = r * 10 + c - 1;\n            if (c < 9) neighs[id][degs_[id]++] = r * 10 + c + 1;\n\n            if (c < 9) rightCell[id] = id + 1;\n            if (r < 9) downCell[id] = id + 10;\n        }\n    }\n\n    for (int i = 0; i < 100; i++) {\n        int r1 = i / 10, c1 = i % 10;\n        for (int j = 0; j < 100; j++) {\n            int r2 = j / 10, c2 = j % 10;\n            manhDist[i][j] = (uint8_t)(abs(r1 - r2) + abs(c1 - c2));\n        }\n    }\n}\n\nll finalScoreNum(const Board& b) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    ll res = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        int head = 0, tail = 0;\n        int sz = 0;\n\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        res += 1LL * sz * sz;\n    }\n\n    return res;\n}\n\nll evalBoard(const Board& b, int step, const Layout& L) {\n    uint8_t vis[100];\n    memset(vis, 0, sizeof(vis));\n\n    int q[100];\n    int maxComp[4] = {};\n    int sumSq = 0;\n    int comps = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int fl = b.a[i];\n        if (fl == 0 || vis[i]) continue;\n\n        comps++;\n\n        int head = 0, tail = 0;\n        int sz = 0;\n\n        vis[i] = 1;\n        q[tail++] = i;\n\n        while (head < tail) {\n            int v = q[head++];\n            sz++;\n\n            for (int k = 0; k < degs_[v]; k++) {\n                int to = neighs[v][k];\n                if (!vis[to] && b.a[to] == fl) {\n                    vis[to] = 1;\n                    q[tail++] = to;\n                }\n            }\n        }\n\n        sumSq += sz * sz;\n        maxComp[fl] = max(maxComp[fl], sz);\n    }\n\n    int adj = 0;\n    int distCost = 0;\n    int match = 0;\n\n    for (int i = 0; i < 100; i++) {\n        int v = b.a[i];\n        if (!v) continue;\n\n        int r = rightCell[i];\n        if (r != -1 && b.a[r] == v) adj++;\n\n        int d = downCell[i];\n        if (d != -1 && b.a[d] == v) adj++;\n\n        distCost += L.dist[v][i];\n        if (L.target[i] == v) match++;\n    }\n\n    ll compPot = sumSq;\n    for (int f = 1; f <= 3; f++) {\n        compPot += 2LL * maxComp[f] * remAfter[step][f];\n    }\n\n    int future = 99 - step;\n\n    ll val = 0;\n    val += compPot * 1000LL;\n    val += adj * 200LL;\n    val -= comps * 50LL;\n    val += match * (30LL + future);\n    val -= distCost * (20LL + 3LL * future);\n\n    return val;\n}\n\nint greedyDir(const Board& b, int step, const Layout& L) {\n    int offset = ((step + 1) * 17 + flav[step] * 31) & 3;\n\n    int bestD = 0;\n    ll bestV = LLONG_MIN;\n\n    for (int k = 0; k < 4; k++) {\n        int d = (offset + k) & 3;\n\n        Board nb = b;\n        nb.tilt(d);\n\n        ll v = evalBoard(nb, step, L);\n\n        if (v > bestV) {\n            bestV = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nvoid computeLayoutDist(Layout& L) {\n    for (int f = 0; f < 4; f++) {\n        for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n    }\n\n    for (int f = 1; f <= 3; f++) {\n        vector<int> cells;\n\n        for (int i = 0; i < 100; i++) {\n            if (L.target[i] == f) cells.push_back(i);\n        }\n\n        if (cells.empty()) {\n            for (int i = 0; i < 100; i++) L.dist[f][i] = 0;\n            continue;\n        }\n\n        for (int i = 0; i < 100; i++) {\n            int best = 100;\n\n            for (int p : cells) {\n                best = min(best, (int)manhDist[i][p]);\n            }\n\n            L.dist[f][i] = (uint8_t)best;\n        }\n    }\n}\n\nvoid addLayout(const array<uint8_t, 100>& tar) {\n    string key;\n    key.resize(100);\n\n    for (int i = 0; i < 100; i++) {\n        key[i] = char('0' + tar[i]);\n    }\n\n    if (!seenLayouts.insert(key).second) return;\n\n    Layout L;\n    memset(&L, 0, sizeof(L));\n\n    for (int i = 0; i < 100; i++) L.target[i] = tar[i];\n\n    computeLayoutDist(L);\n    layouts.push_back(L);\n}\n\npair<int, int> transformCoord(int r, int c, int s) {\n    if (s == 0) return {r, c};\n    if (s == 1) return {r, 9 - c};\n    if (s == 2) return {9 - r, c};\n    if (s == 3) return {9 - r, 9 - c};\n    if (s == 4) return {c, r};\n    if (s == 5) return {c, 9 - r};\n    if (s == 6) return {9 - c, r};\n    return {9 - c, 9 - r};\n}\n\nstruct PQNode {\n    int dist;\n    int tie;\n    int f;\n    int pos;\n};\n\nstruct PQCmp {\n    bool operator()(const PQNode& a, const PQNode& b) const {\n        if (a.dist != b.dist) return a.dist > b.dist;\n        if (a.tie != b.tie) return a.tie > b.tie;\n        return a.f > b.f;\n    }\n};\n\nint tieValue(int pos, int f, int seed) {\n    return (pos * 37 + f * 101 + seed * 17) & 1023;\n}\n\narray<uint8_t, 100> makeCornerLayout(const int seeds[4]) {\n    array<uint8_t, 100> tar;\n    tar.fill(0);\n\n    int cap[4];\n    for (int f = 1; f <= 3; f++) cap[f] = totalCnt[f];\n\n    priority_queue<PQNode, vector<PQNode>, PQCmp> pq;\n\n    for (int f = 1; f <= 3; f++) {\n        if (cap[f] > 0) {\n            int p = seeds[f];\n            pq.push({0, tieValue(p, f, seeds[f]), f, p});\n        }\n    }\n\n    int assigned = 0;\n\n    while (assigned < 100 && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n\n        int f = cur.f;\n        int p = cur.pos;\n\n        if (cap[f] <= 0 || tar[p] != 0) continue;\n\n        tar[p] = (uint8_t)f;\n        cap[f]--;\n        assigned++;\n\n        if (cap[f] > 0) {\n            for (int k = 0; k < degs_[p]; k++) {\n                int to = neighs[p][k];\n\n                if (tar[to] == 0) {\n                    pq.push({cur.dist + 1, tieValue(to, f, seeds[f]), f, to});\n                }\n            }\n        }\n    }\n\n    if (assigned < 100) {\n        for (int p = 0; p < 100; p++) {\n            if (tar[p] != 0) continue;\n\n            int bestF = -1;\n            int bestCost = 1e9;\n\n            for (int f = 1; f <= 3; f++) {\n                if (cap[f] <= 0) continue;\n\n                int cost = manhDist[p][seeds[f]];\n\n                bool adj = false;\n                for (int k = 0; k < degs_[p]; k++) {\n                    if (tar[neighs[p][k]] == f) adj = true;\n                }\n\n                if (adj) cost -= 20;\n\n                if (cost < bestCost) {\n                    bestCost = cost;\n                    bestF = f;\n                }\n            }\n\n            if (bestF == -1) {\n                for (int f = 1; f <= 3; f++) {\n                    if (cap[f] > 0) {\n                        bestF = f;\n                        break;\n                    }\n                }\n            }\n\n            tar[p] = (uint8_t)bestF;\n            cap[bestF]--;\n            assigned++;\n        }\n    }\n\n    return tar;\n}\n\nvoid generateLayouts() {\n    layouts.clear();\n    seenLayouts.clear();\n\n    layouts.reserve(128);\n    seenLayouts.reserve(256);\n\n    {\n        Layout neutral;\n        memset(&neutral, 0, sizeof(neutral));\n        layouts.push_back(neutral);\n        seenLayouts.insert(string(100, '0'));\n    }\n\n    vector<int> basePath;\n    basePath.reserve(100);\n\n    for (int r = 0; r < 10; r++) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < 10; c++) basePath.push_back(r * 10 + c);\n        } else {\n            for (int c = 9; c >= 0; c--) basePath.push_back(r * 10 + c);\n        }\n    }\n\n    for (int sym = 0; sym < 8; sym++) {\n        vector<int> path;\n        path.reserve(100);\n\n        bool used[100] = {};\n        bool ok = true;\n\n        for (int id : basePath) {\n            int r = id / 10;\n            int c = id % 10;\n\n            auto [nr, nc] = transformCoord(r, c, sym);\n            int p = nr * 10 + nc;\n\n            if (used[p]) ok = false;\n            used[p] = true;\n\n            path.push_back(p);\n        }\n\n        if (!ok) continue;\n\n        array<int, 3> perm = {1, 2, 3};\n\n        do {\n            array<uint8_t, 100> tar;\n            tar.fill(0);\n\n            int idx = 0;\n\n            for (int k = 0; k < 3; k++) {\n                int f = perm[k];\n\n                for (int cnt = 0; cnt < totalCnt[f]; cnt++) {\n                    tar[path[idx++]] = (uint8_t)f;\n                }\n            }\n\n            addLayout(tar);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    int corners[4] = {0, 9, 90, 99};\n\n    for (int a = 0; a < 4; a++) {\n        for (int b = 0; b < 4; b++) if (b != a) {\n            for (int c = 0; c < 4; c++) if (c != a && c != b) {\n                int seeds[4] = {};\n                seeds[1] = corners[a];\n                seeds[2] = corners[b];\n                seeds[3] = corners[c];\n\n                addLayout(makeCornerLayout(seeds));\n            }\n        }\n    }\n}\n\n// Affine Latin-hypercube style rank samples.\nvoid makeLatinSamples(uint8_t ranks[][100], int R, int startS, RNG& rng) {\n    if (startS >= 100) return;\n\n    int offset[100];\n    int mul[100];\n    int add[100];\n\n    for (int s = startS; s < 100; s++) {\n        int m = 100 - s;\n\n        offset[s] = rng.nextInt(m);\n        mul[s] = 0;\n        add[s] = 0;\n\n        if (R > 1) {\n            int a;\n\n            do {\n                a = 1 + rng.nextInt(R - 1);\n            } while (std::gcd(a, R) != 1);\n\n            mul[s] = a;\n            add[s] = rng.nextInt(R);\n        }\n    }\n\n    for (int it = 0; it < R; it++) {\n        for (int s = startS; s < 100; s++) {\n            int m = 100 - s;\n\n            int j = 0;\n            if (R > 1) {\n                j = (mul[s] * it + add[s]) % R;\n            }\n\n            int base = (int)((long long)j * m / R);\n            ranks[it][s] = (uint8_t)((offset[s] + base) % m);\n        }\n    }\n}\n\nint chooseLayout() {\n    constexpr int K = 3;\n\n    uint64_t seed = 0x123456789abcdefULL;\n\n    for (int i = 0; i < 100; i++) {\n        seed = seed * 1000003ULL + flav[i] * 97ULL + i;\n    }\n\n    RNG rng(seed);\n\n    uint8_t ranks[K][100];\n    makeLatinSamples(ranks, K, 0, rng);\n\n    int bestIdx = 0;\n    ll bestScore = LLONG_MIN;\n\n    for (int li = 0; li < (int)layouts.size(); li++) {\n        ll total = 0;\n\n        for (int k = 0; k < K; k++) {\n            Board b;\n\n            for (int s = 0; s < 100; s++) {\n                b.placeRank(ranks[k][s], flav[s]);\n\n                if (s == 99) break;\n\n                int d = greedyDir(b, s, layouts[li]);\n                b.tilt(d);\n            }\n\n            total += finalScoreNum(b);\n        }\n\n        if (total > bestScore) {\n            bestScore = total;\n            bestIdx = li;\n        }\n    }\n\n    return bestIdx;\n}\n\ndouble exactValue(const Board& b, int step);\n\ndouble exactDirValue(const Board& b, int step, int dir) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    Board bb = b;\n    bb.tilt(dir);\n\n    int emp[100];\n    int m = bb.getEmpties(emp);\n\n    if (m == 0) return (double)finalScoreNum(bb);\n\n    double sum = 0.0;\n\n    for (int i = 0; i < m; i++) {\n        Board nb = bb;\n        nb.placeCell(emp[i], flav[step + 1]);\n        sum += exactValue(nb, step + 1);\n    }\n\n    return sum / m;\n}\n\ndouble exactValue(const Board& b, int step) {\n    if (step >= 99) return (double)finalScoreNum(b);\n\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        best = max(best, exactDirValue(b, step, d));\n    }\n\n    return best;\n}\n\nint exactBestDir(const Board& b, int step) {\n    int bestD = 0;\n    double best = -1e100;\n\n    for (int d = 0; d < 4; d++) {\n        double v = exactDirValue(b, step, d);\n\n        if (v > best) {\n            best = v;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nstruct BeamNode {\n    Board b;\n    ll val;\n};\n\nvoid addBeamCandidate(BeamNode next[], int& cnt, int BW, const Board& b, ll val) {\n    if (cnt < BW) {\n        next[cnt].b = b;\n        next[cnt].val = val;\n        cnt++;\n        return;\n    }\n\n    int worst = 0;\n\n    for (int i = 1; i < BW; i++) {\n        if (next[i].val < next[worst].val) worst = i;\n    }\n\n    if (val > next[worst].val) {\n        next[worst].b = b;\n        next[worst].val = val;\n    }\n}\n\nll simulateBeam(const Board& start, int step, const uint8_t ranks[], const Layout& L, int BW) {\n    BeamNode beam[2], nxt[2];\n\n    int bc = 1;\n    beam[0].b = start;\n    beam[0].val = 0;\n\n    for (int s = step + 1; s < 100; s++) {\n        int nc = 0;\n        ll bestFinal = -1;\n\n        for (int i = 0; i < bc; i++) {\n            Board placed = beam[i].b;\n            placed.placeRank(ranks[s], flav[s]);\n\n            if (s == 99) {\n                bestFinal = max(bestFinal, finalScoreNum(placed));\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    Board nb = placed;\n                    nb.tilt(d);\n\n                    ll v = evalBoard(nb, s, L);\n                    addBeamCandidate(nxt, nc, BW, nb, v);\n                }\n            }\n        }\n\n        if (s == 99) return bestFinal;\n\n        bc = nc;\n        for (int i = 0; i < bc; i++) beam[i] = nxt[i];\n    }\n\n    return finalScoreNum(start);\n}\n\nint runRolloutBatchMask(\n    const Board first[4],\n    int step,\n    const Layout& L,\n    int BW,\n    int R,\n    RNG& rng,\n    ll scores[4],\n    int counts[4],\n    int mask,\n    double hardLimit\n) {\n    if (R <= 0 || mask == 0) return 0;\n\n    uint8_t ranks[64][100];\n    makeLatinSamples(ranks, R, step + 1, rng);\n\n    int done = 0;\n\n    for (int it = 0; it < R; it++) {\n        if (it > 0 && (it & 3) == 0 && elapsedSec() > hardLimit) break;\n\n        for (int d = 0; d < 4; d++) {\n            if ((mask >> d) & 1) {\n                scores[d] += simulateBeam(first[d], step, ranks[it], L, BW);\n                counts[d]++;\n            }\n        }\n\n        done++;\n    }\n\n    return done;\n}\n\nvoid getBestSecondAvg(\n    const ll scores[4],\n    const int counts[4],\n    int& bestD,\n    int& secondD,\n    long double& bestAvg,\n    long double& secondAvg\n) {\n    bestD = 0;\n    secondD = 1;\n    bestAvg = -1e100L;\n    secondAvg = -1e100L;\n\n    for (int d = 0; d < 4; d++) {\n        long double avg = (long double)scores[d] / max(1, counts[d]);\n\n        if (avg > bestAvg) {\n            secondAvg = bestAvg;\n            secondD = bestD;\n            bestAvg = avg;\n            bestD = d;\n        } else if (avg > secondAvg) {\n            secondAvg = avg;\n            secondD = d;\n        }\n    }\n}\n\nint makeCandidateMask(const ll scores[4], const int counts[4], long double width) {\n    int bestD, secondD;\n    long double bestAvg, secondAvg;\n    getBestSecondAvg(scores, counts, bestD, secondD, bestAvg, secondAvg);\n\n    int mask = 0;\n    for (int d = 0; d < 4; d++) {\n        long double avg = (long double)scores[d] / max(1, counts[d]);\n        if (bestAvg - avg <= width) mask |= (1 << d);\n    }\n    return mask;\n}\n\nint decideMove(const Board& b, int step, const Layout& L, RNG& rng) {\n    if (step >= 99) return 0;\n\n    int rem = 99 - step;\n    double el = elapsedSec();\n\n    // rem<=4 exact search is cheap, so allow it slightly later.\n    if ((rem == 5 && el < 1.72) || (rem <= 4 && el < 1.88)) {\n        return exactBestDir(b, step);\n    }\n\n    if (el > 1.84) {\n        return greedyDir(b, step, L);\n    }\n\n    Board first[4];\n\n    for (int d = 0; d < 4; d++) {\n        first[d] = b;\n        first[d].tilt(d);\n    }\n\n    int BW = (rem <= 25 ? 2 : 1);\n    int work = (BW == 1 ? 520 : 360);\n    int R = max(4, min(60, work / max(1, rem)));\n\n    if (el > 1.70) {\n        R = max(2, R / 3);\n    } else if (el > 1.50) {\n        R = max(3, R / 2);\n    }\n\n    ll scores[4] = {};\n    int counts[4] = {};\n\n    int done = runRolloutBatchMask(first, step, L, BW, R, rng, scores, counts, 15, 1.86);\n\n    if (done == 0) {\n        return greedyDir(b, step, L);\n    }\n\n    // Successful refinement: all-direction extra batch for close decisions.\n    if (rem > 18 && elapsedSec() < 1.38) {\n        int bestD, secondD;\n        long double bestAvg, secondAvg;\n        getBestSecondAvg(scores, counts, bestD, secondD, bestAvg, secondAvg);\n\n        if (bestAvg - secondAvg < 25.0L) {\n            int extraR = max(2, min(10, R / 2 + 1));\n            runRolloutBatchMask(first, step, L, BW, extraR, rng, scores, counts, 15, 1.78);\n        }\n    }\n\n    // Candidate-only refinement for early/mid decisions.\n    if (rem > 25 && elapsedSec() < 1.50) {\n        int bestD, secondD;\n        long double bestAvg, secondAvg;\n        getBestSecondAvg(scores, counts, bestD, secondD, bestAvg, secondAvg);\n\n        if (bestAvg - secondAvg < 22.0L) {\n            int mask = makeCandidateMask(scores, counts, 34.0L);\n\n            if (__builtin_popcount((unsigned)mask) >= 2) {\n                int extraR = max(3, min(12, R));\n                runRolloutBatchMask(first, step, L, BW, extraR, rng, scores, counts, mask, 1.72);\n            }\n        }\n    } else if (rem > 18 && elapsedSec() < 1.52) {\n        int bestD, secondD;\n        long double bestAvg, secondAvg;\n        getBestSecondAvg(scores, counts, bestD, secondD, bestAvg, secondAvg);\n\n        if (bestAvg - secondAvg < 14.0L) {\n            int mask = makeCandidateMask(scores, counts, 24.0L);\n\n            if (__builtin_popcount((unsigned)mask) >= 2) {\n                int extraR = max(2, min(6, R / 2 + 1));\n                runRolloutBatchMask(first, step, L, BW, extraR, rng, scores, counts, mask, 1.74);\n            }\n        }\n    }\n\n    // One more very small pass if the top directions are still nearly tied.\n    if (rem > 25 && elapsedSec() < 1.56) {\n        int bestD, secondD;\n        long double bestAvg, secondAvg;\n        getBestSecondAvg(scores, counts, bestD, secondD, bestAvg, secondAvg);\n\n        if (bestAvg - secondAvg < 12.0L) {\n            int mask = makeCandidateMask(scores, counts, 22.0L);\n\n            if (__builtin_popcount((unsigned)mask) >= 2) {\n                int extraR = max(2, min(8, R / 2 + 1));\n                runRolloutBatchMask(first, step, L, BW, extraR, rng, scores, counts, mask, 1.76);\n            }\n        }\n    }\n\n    int bestD = 0;\n    long double bestAvg = -1e100L;\n    ll bestHeur = LLONG_MIN;\n\n    for (int d = 0; d < 4; d++) {\n        long double avg = (long double)scores[d] / max(1, counts[d]);\n        ll h = evalBoard(first[d], step, L);\n\n        if (avg > bestAvg + 1e-12L ||\n            (fabsl(avg - bestAvg) <= 1e-12L && h > bestHeur)) {\n            bestAvg = avg;\n            bestHeur = h;\n            bestD = d;\n        }\n    }\n\n    return bestD;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    initTables();\n\n    for (int i = 0; i < 100; i++) {\n        if (!(cin >> flav[i])) return 0;\n        totalCnt[flav[i]]++;\n    }\n\n    int suf[4] = {};\n\n    for (int i = 99; i >= 0; i--) {\n        for (int f = 1; f <= 3; f++) remAfter[i][f] = suf[f];\n        suf[flav[i]]++;\n    }\n\n    generateLayouts();\n\n    int layoutIdx = chooseLayout();\n    Layout layout = layouts[layoutIdx];\n\n    uint64_t seed = 0x9e3779b97f4a7c15ULL;\n\n    for (int i = 0; i < 100; i++) {\n        seed ^= (uint64_t)(flav[i] + 1237 * i);\n        seed *= 0xbf58476d1ce4e5b9ULL;\n    }\n\n    RNG rng(seed ^ 0xdeadbeefcafebabeULL);\n\n    Board board;\n\n    const char dc[4] = {'F', 'B', 'L', 'R'};\n\n    for (int t = 0; t < 100; t++) {\n        int p;\n        if (!(cin >> p)) return 0;\n\n        board.placeRank(p - 1, flav[t]);\n\n        int dir;\n\n        if (t == 99) {\n            dir = 0;\n        } else {\n            dir = decideMove(board, t, layout, rng);\n        }\n\n        board.tilt(dir);\n\n        cout << dc[dir] << '\\n' << flush;\n    }\n\n    return 0;\n}","ahc016":"#pragma GCC optimize(\"O3\")\n\n#include <bits/stdc++.h>\nusing namespace std;\n\nusing ull = unsigned long long;\nconst int MAXN = 100;\nusing Row = array<ull, 2>;\n\nint M;\ndouble EPS, QV;\n\nint Ncur, Bcur, Lcur, Fcur;\nint POSBIN[MAXN];\nint FIDX[10][10];\nvector<int> PAIRCNT;\n\ndouble PMF[MAXN][MAXN];\ndouble NEGLOGP[MAXN][MAXN];\ndouble edgePenalty = 0.0;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsedSec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct Candidate {\n    uint32_t mask = 0;\n    array<unsigned char, MAXN> deg;\n    int sum = 0;\n};\n\nstruct Codeword {\n    uint32_t mask = 0;\n    array<unsigned char, MAXN> deg;\n    vector<Row> rows;\n    array<double, MAXN> mixNeg;\n    vector<int> blockCnt;\n    string out;\n};\n\nstruct QueryFeat {\n    array<int, MAXN> degSorted;\n    array<int, MAXN> hist;\n    vector<Row> rows;\n    vector<int> blockCnt;\n};\n\nstruct Config {\n    double alpha;\n    double wb;\n    double we;\n};\n\nstruct LocalMode {\n    double dg = 0.0;\n    double eg = 0.0;\n    double baseW = 0.0;\n    int topK = 0;\n    int passes = 0;\n    int window = 0;\n};\n\nstruct TrainResult {\n    Config cfg;\n    int err;\n    int samples;\n};\n\nstruct Solution {\n    int N = 0;\n    int B = 0;\n    int Lfeat = 10;\n    vector<Codeword> codes;\n    Config cfg{0.5, 0.0, 0.0};\n    int trainErr = 0;\n    int trainSamples = 0;\n    string name;\n\n    int mode = 0;\n    LocalMode local;\n};\n\nstruct EvalResult {\n    int err = 0;\n    int samples = 0;\n};\n\nvector<Codeword> codes;\nConfig bestCfg{0.5, 0.0, 0.0};\n\nint predMode = 0;\nLocalMode curLocal;\n\ninline int thresholdBit(uint32_t mask, int idx, int B, int N) {\n    int b = (long long)idx * B / N;\n    return (mask >> b) & 1u;\n}\n\ninline void setEdge(vector<Row>& rows, int i, int j) {\n    rows[i][j >> 6] |= 1ULL << (j & 63);\n    rows[j][i >> 6] |= 1ULL << (i & 63);\n}\n\ninline bool getEdge(const vector<Row>& rows, int i, int j) {\n    return (rows[i][j >> 6] >> (j & 63)) & 1ULL;\n}\n\ninline double rnd01(mt19937_64& rng) {\n    return (rng() >> 11) * (1.0 / 9007199254740992.0);\n}\n\nint minimalNForM() {\n    int n = 4;\n    while (n < 100 && (1LL << (n - 1)) < M) n++;\n    return n;\n}\n\nstring graphStringRows(const vector<Row>& rows) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(getEdge(rows, i, j) ? '1' : '0');\n        }\n    }\n    return s;\n}\n\nstring thresholdGraphString(uint32_t mask) {\n    string s;\n    s.reserve(Ncur * (Ncur - 1) / 2);\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            s.push_back(thresholdBit(mask, j, Bcur, Ncur) ? '1' : '0');\n        }\n    }\n    return s;\n}\n\nvoid thresholdDegrees(uint32_t mask, int B, int N, array<int, MAXN>& degOrig) {\n    degOrig.fill(0);\n    int cnt = 0;\n    for (int i = N - 1; i >= 0; --i) {\n        int bit = thresholdBit(mask, i, B, N);\n        if (bit) degOrig[i] = i + cnt;\n        else degOrig[i] = cnt;\n        if (bit) cnt++;\n    }\n}\n\nbool makeCandidate(uint32_t mask, int N, int B, Candidate& c) {\n    array<int, MAXN> dorig{};\n    thresholdDegrees(mask, B, N, dorig);\n\n    c.mask = mask;\n    c.deg.fill(0);\n    c.sum = 0;\n\n    for (int i = 0; i < N; ++i) {\n        c.deg[i] = (unsigned char)dorig[i];\n        c.sum += dorig[i];\n    }\n\n    sort(c.deg.begin(), c.deg.begin() + N);\n    return true;\n}\n\nvector<Candidate> buildPool(int N, int B) {\n    vector<Candidate> pool;\n    int total = 1 << B;\n    pool.reserve(total);\n\n    unordered_set<string> seen;\n    seen.reserve(total * 2);\n\n    for (uint32_t mask = 0; mask < (uint32_t)total; ++mask) {\n        Candidate c;\n        makeCandidate(mask, N, B, c);\n\n        string key;\n        key.resize(N);\n        for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n        if (seen.insert(key).second) pool.push_back(c);\n    }\n\n    return pool;\n}\n\ninline int dist2Deg(const array<unsigned char, MAXN>& a,\n                    const array<unsigned char, MAXN>& b,\n                    int N) {\n    int s = 0;\n    for (int i = 0; i < N; ++i) {\n        int d = (int)a[i] - (int)b[i];\n        s += d * d;\n    }\n    return s;\n}\n\nstruct Selection {\n    vector<int> idx;\n    int minD2 = 0;\n};\n\nSelection selectFarthest(const vector<Candidate>& pool, int N, int m, int improveIters) {\n    int P = (int)pool.size();\n\n    Selection res;\n    if (P < m) return res;\n\n    vector<int> selected;\n    vector<int> minDist(P, INT_MAX);\n    vector<char> used(P, 0);\n\n    int start = 0;\n    for (int i = 1; i < P; ++i) {\n        if (pool[i].sum < pool[start].sum) start = i;\n    }\n\n    for (int it = 0; it < m; ++it) {\n        int id;\n\n        if (it == 0) {\n            id = start;\n        } else {\n            id = -1;\n            int best = -1;\n\n            for (int i = 0; i < P; ++i) {\n                if (!used[i] && minDist[i] > best) {\n                    best = minDist[i];\n                    id = i;\n                }\n            }\n        }\n\n        used[id] = 1;\n        selected.push_back(id);\n\n        for (int i = 0; i < P; ++i) {\n            if (!used[i]) {\n                int d = dist2Deg(pool[i].deg, pool[id].deg, N);\n                if (d < minDist[i]) minDist[i] = d;\n            }\n        }\n    }\n\n    for (int rep = 0; rep < improveIters; ++rep) {\n        vector<int> near(m, INT_MAX);\n        int curMin = INT_MAX;\n        int worstPos = -1;\n\n        for (int i = 0; i < m; ++i) {\n            for (int j = 0; j < m; ++j) if (i != j) {\n                int d = dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N);\n                near[i] = min(near[i], d);\n            }\n\n            if (near[i] < curMin) {\n                curMin = near[i];\n                worstPos = i;\n            }\n        }\n\n        int bestP = -1;\n        int bestMd = curMin;\n\n        for (int p = 0; p < P; ++p) if (!used[p]) {\n            int md = INT_MAX;\n\n            for (int i = 0; i < m; ++i) {\n                if (i == worstPos) continue;\n\n                int d = dist2Deg(pool[p].deg, pool[selected[i]].deg, N);\n                md = min(md, d);\n\n                if (md <= curMin) break;\n            }\n\n            if (md > bestMd) {\n                bestMd = md;\n                bestP = p;\n            }\n        }\n\n        if (bestP == -1) break;\n\n        used[selected[worstPos]] = 0;\n        selected[worstPos] = bestP;\n        used[bestP] = 1;\n    }\n\n    int md2 = INT_MAX;\n    for (int i = 0; i < m; ++i) {\n        for (int j = i + 1; j < m; ++j) {\n            md2 = min(md2, dist2Deg(pool[selected[i]].deg, pool[selected[j]].deg, N));\n        }\n    }\n\n    res.idx = selected;\n    res.minD2 = md2;\n    return res;\n}\n\nvoid setupBlocks(int N, int Lfeat = 10) {\n    Lcur = min(Lfeat, N);\n    Fcur = 0;\n\n    for (int i = 0; i < 10; ++i) {\n        for (int j = 0; j < 10; ++j) FIDX[i][j] = -1;\n    }\n\n    for (int a = 0; a < Lcur; ++a) {\n        for (int b = a; b < Lcur; ++b) {\n            FIDX[a][b] = FIDX[b][a] = Fcur++;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        POSBIN[i] = (long long)i * Lcur / N;\n        if (POSBIN[i] >= Lcur) POSBIN[i] = Lcur - 1;\n    }\n\n    PAIRCNT.assign(Fcur, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            int f = FIDX[POSBIN[i]][POSBIN[j]];\n            PAIRCNT[f]++;\n        }\n    }\n}\n\nvector<double> binomDist(int n, double p) {\n    vector<double> d(n + 1, 0.0);\n\n    if (n == 0) {\n        d[0] = 1.0;\n        return d;\n    }\n    if (p < 1e-15) {\n        d[0] = 1.0;\n        return d;\n    }\n    if (1.0 - p < 1e-15) {\n        d[n] = 1.0;\n        return d;\n    }\n\n    double q = 1.0 - p;\n    d[0] = pow(q, n);\n\n    for (int k = 0; k < n; ++k) {\n        d[k + 1] = d[k] * (double)(n - k) / (double)(k + 1) * p / q;\n    }\n\n    return d;\n}\n\nvoid setupPMF(int N) {\n    vector<vector<double>> keep(N), flip(N);\n\n    for (int n = 0; n <= N - 1; ++n) {\n        keep[n] = binomDist(n, 1.0 - EPS);\n        flip[n] = binomDist(n, EPS);\n    }\n\n    for (int d = 0; d <= N - 1; ++d) {\n        for (int x = 0; x <= N - 1; ++x) PMF[d][x] = 0.0;\n\n        int absent = N - 1 - d;\n\n        for (int y = 0; y <= d; ++y) {\n            for (int z = 0; z <= absent; ++z) {\n                PMF[d][y + z] += keep[d][y] * flip[absent][z];\n            }\n        }\n\n        for (int x = 0; x <= N - 1; ++x) {\n            double p = max(PMF[d][x], 1e-300);\n            NEGLOGP[d][x] = -log(p);\n        }\n    }\n}\n\nvector<int> computeBlockCounts(const vector<Row>& rows) {\n    vector<int> cnt(Fcur, 0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, i, j)) {\n                int f = FIDX[POSBIN[i]][POSBIN[j]];\n                cnt[f]++;\n            }\n        }\n    }\n\n    return cnt;\n}\n\nvoid finalizeCodeword(Codeword& c) {\n    c.mixNeg.fill(0.0);\n\n    for (int x = 0; x < Ncur; ++x) {\n        double p = 0.0;\n\n        for (int i = 0; i < Ncur; ++i) {\n            p += PMF[(int)c.deg[i]][x];\n        }\n\n        p /= Ncur;\n        c.mixNeg[x] = -log(max(p, 1e-300));\n    }\n\n    c.blockCnt = computeBlockCounts(c.rows);\n}\n\nCodeword buildThresholdCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = cand.mask;\n    c.deg = cand.deg;\n\n    c.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : c.rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> dorig{};\n    thresholdDegrees(c.mask, Bcur, Ncur, dorig);\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (dorig[a] != dorig[b]) return dorig[a] < dorig[b];\n        return a < b;\n    });\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            int u = ord[a], v = ord[b];\n            int later = max(u, v);\n\n            if (thresholdBit(c.mask, later, Bcur, Ncur)) {\n                setEdge(c.rows, a, b);\n            }\n        }\n    }\n\n    c.out = thresholdGraphString(c.mask);\n    finalizeCodeword(c);\n    return c;\n}\n\nbool isGraphicalDeg(const vector<int>& degAsc, int N) {\n    vector<int> d(degAsc.begin(), degAsc.begin() + N);\n    sort(d.begin(), d.end(), greater<int>());\n\n    long long sum = 0;\n    for (int x : d) {\n        if (x < 0 || x >= N) return false;\n        sum += x;\n    }\n\n    if (sum & 1LL) return false;\n\n    vector<long long> pref(N + 1, 0);\n    for (int i = 0; i < N; ++i) pref[i + 1] = pref[i] + d[i];\n\n    for (int k = 1; k <= N; ++k) {\n        long long left = pref[k];\n\n        int l = k, r = N;\n        while (l < r) {\n            int mid = (l + r) >> 1;\n            if (d[mid] >= k) l = mid + 1;\n            else r = mid;\n        }\n\n        int p = l;\n        long long right = 1LL * k * (k - 1)\n                        + 1LL * (p - k) * k\n                        + (pref[N] - pref[p]);\n\n        if (left > right) return false;\n    }\n\n    return true;\n}\n\nbool constructGraphHH(const array<unsigned char, MAXN>& deg, vector<Row>& rows) {\n    rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    vector<pair<int, int>> v;\n    v.reserve(Ncur);\n\n    for (int i = 0; i < Ncur; ++i) v.push_back({(int)deg[i], i});\n\n    while (true) {\n        sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n            if (a.first != b.first) return a.first > b.first;\n            return a.second < b.second;\n        });\n\n        if (v.empty() || v[0].first == 0) break;\n\n        int d = v[0].first;\n        int u = v[0].second;\n        v.erase(v.begin());\n\n        if (d > (int)v.size()) return false;\n\n        for (int i = 0; i < d; ++i) {\n            if (v[i].first <= 0) return false;\n\n            v[i].first--;\n            setEdge(rows, u, v[i].second);\n\n            if (v[i].first < 0) return false;\n        }\n    }\n\n    return true;\n}\n\nCodeword buildDegreeCodeword(const Candidate& cand) {\n    Codeword c;\n    c.mask = 0;\n    c.deg = cand.deg;\n\n    bool ok = constructGraphHH(c.deg, c.rows);\n    if (!ok) {\n        c.rows.assign(Ncur, Row{0ULL, 0ULL});\n        for (auto& r : c.rows) r = {0ULL, 0ULL};\n    }\n\n    c.out = graphStringRows(c.rows);\n    finalizeCodeword(c);\n    return c;\n}\n\nvoid addDegreeCandidate(vector<Candidate>& pool,\n                        unordered_set<string>& seen,\n                        vector<int> d) {\n    int N = Ncur;\n    if ((int)d.size() != N) return;\n\n    for (int& x : d) {\n        if (x < 0) x = 0;\n        if (x > N - 1) x = N - 1;\n    }\n\n    sort(d.begin(), d.end());\n\n    long long sum = 0;\n    for (int x : d) sum += x;\n\n    if (sum & 1LL) {\n        bool changed = false;\n\n        for (int i = N - 1; i >= 0; --i) {\n            if (d[i] < N - 1) {\n                d[i]++;\n                changed = true;\n                break;\n            }\n        }\n\n        if (!changed) {\n            for (int i = 0; i < N; ++i) {\n                if (d[i] > 0) {\n                    d[i]--;\n                    changed = true;\n                    break;\n                }\n            }\n        }\n\n        if (!changed) return;\n        sort(d.begin(), d.end());\n    }\n\n    if (!isGraphicalDeg(d, N)) return;\n\n    Candidate c;\n    c.mask = 0;\n    c.deg.fill(0);\n    c.sum = 0;\n\n    for (int i = 0; i < N; ++i) {\n        c.deg[i] = (unsigned char)d[i];\n        c.sum += d[i];\n    }\n\n    string key;\n    key.resize(N);\n    for (int i = 0; i < N; ++i) key[i] = char(c.deg[i]);\n\n    if (seen.insert(key).second) pool.push_back(c);\n}\n\nvector<Candidate> buildDegreePool(int N, int target) {\n    Ncur = N;\n\n    vector<Candidate> pool;\n    pool.reserve(target + 1000);\n\n    unordered_set<string> seen;\n    seen.reserve(target * 3);\n\n    auto addCand = [&](const Candidate& c0) {\n        vector<int> d(N);\n        for (int i = 0; i < N; ++i) d[i] = c0.deg[i];\n        addDegreeCandidate(pool, seen, d);\n    };\n\n    int baseB = min(N, (N >= 70 ? 14 : (N >= 35 ? 13 : 12)));\n    vector<Candidate> th = buildPool(N, baseB);\n    for (const auto& c : th) addCand(c);\n\n    for (int r = 0; r < N; ++r) {\n        vector<int> d(N, r);\n        addDegreeCandidate(pool, seen, d);\n    }\n\n    vector<double> gammas = {0.25, 0.35, 0.5, 0.7, 1.0, 1.4, 2.0, 3.0, 4.5};\n\n    int step = max(1, N / 6);\n    for (int lo = 0; lo < N; lo += step) {\n        for (int hi = lo; hi < N; hi += step) {\n            for (double g : gammas) {\n                vector<int> d(N);\n\n                for (int i = 0; i < N; ++i) {\n                    double x = (N == 1 ? 0.0 : (double)i / (N - 1));\n                    int val = (int)llround(lo + (hi - lo) * pow(x, g));\n                    d[i] = val;\n                }\n\n                addDegreeCandidate(pool, seen, d);\n\n                for (int i = 0; i < N; ++i) d[i] = (N - 1) - d[i];\n                addDegreeCandidate(pool, seen, d);\n            }\n        }\n    }\n\n    mt19937_64 rng(0x3141592653589793ULL\n                   + (uint64_t)M * 1000003ULL\n                   + (uint64_t)N * 9176ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 19260817ULL);\n\n    int finalTarget = min(target, 26000);\n    int attempts = 0;\n    int maxAttempts = finalTarget * 40;\n\n    while ((int)pool.size() < finalTarget && attempts < maxAttempts) {\n        attempts++;\n\n        int mode = rng() % 6;\n        vector<int> d(N, 0);\n\n        if (mode == 0) {\n            int lo = rng() % N;\n            int hi = rng() % N;\n            if (lo > hi) swap(lo, hi);\n\n            double g = exp(log(0.25) + rnd01(rng) * (log(5.0) - log(0.25)));\n            int noise = rng() % max(2, N / 8 + 1);\n\n            for (int i = 0; i < N; ++i) {\n                double x = (N == 1 ? 0.0 : (double)i / (N - 1));\n                int val = (int)llround(lo + (hi - lo) * pow(x, g));\n                val += (int)(rng() % (2 * noise + 1)) - noise;\n                d[i] = val;\n            }\n        } else if (mode == 1) {\n            int K = 2 + (rng() % 8);\n            vector<int> levels(K);\n\n            for (int i = 0; i < K; ++i) levels[i] = rng() % N;\n            sort(levels.begin(), levels.end());\n\n            vector<int> cuts(K + 1);\n            cuts[0] = 0;\n            cuts[K] = N;\n\n            for (int i = 1; i < K; ++i) cuts[i] = rng() % (N + 1);\n            sort(cuts.begin(), cuts.end());\n\n            for (int k = 0; k < K; ++k) {\n                for (int i = cuts[k]; i < cuts[k + 1]; ++i) d[i] = levels[k];\n            }\n        } else if (mode == 2) {\n            vector<int> bit(N);\n\n            for (int i = 0; i < N; ++i) {\n                bit[i] = ((rng() >> (i & 63)) & 1ULL);\n            }\n\n            int cnt = 0;\n            vector<int> tmp(N);\n\n            for (int i = N - 1; i >= 0; --i) {\n                if (bit[i]) tmp[i] = i + cnt;\n                else tmp[i] = cnt;\n                if (bit[i]) cnt++;\n            }\n\n            d = tmp;\n        } else if (mode == 3) {\n            double p = rnd01(rng);\n            vector<double> w(N);\n\n            double gamma = exp(log(0.3) + rnd01(rng) * (log(3.5) - log(0.3)));\n\n            for (int i = 0; i < N; ++i) {\n                w[i] = pow(rnd01(rng), gamma);\n            }\n\n            for (int i = 0; i < N; ++i) d[i] = 0;\n\n            for (int i = 0; i < N; ++i) {\n                for (int j = i + 1; j < N; ++j) {\n                    double pp = 0.15 * p + 0.85 * (w[i] + w[j]) * 0.5;\n                    pp = min(1.0, max(0.0, pp));\n\n                    if (rnd01(rng) < pp) {\n                        d[i]++;\n                        d[j]++;\n                    }\n                }\n            }\n        } else if (mode == 4) {\n            int a = rng() % N;\n            int b = rng() % N;\n            if (a > b) swap(a, b);\n\n            for (int i = 0; i < N; ++i) {\n                double x = (N == 1 ? 0.0 : (double)i / (N - 1));\n                double y = 0.5 - 0.5 * cos(acos(-1.0) * x);\n                d[i] = (int)llround(a + (b - a) * y);\n            }\n        } else {\n            for (int i = 0; i < N; ++i) d[i] = rng() % N;\n            sort(d.begin(), d.end());\n        }\n\n        addDegreeCandidate(pool, seen, d);\n    }\n\n    return pool;\n}\n\nQueryFeat makeFeatureFromRows(const vector<Row>& rowsIn, const array<int, MAXN>& deg) {\n    QueryFeat q;\n    q.hist.fill(0);\n\n    q.rows.assign(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : q.rows) r = {0ULL, 0ULL};\n\n    vector<int> ord(Ncur);\n    iota(ord.begin(), ord.end(), 0);\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    for (int i = 0; i < Ncur; ++i) {\n        q.degSorted[i] = deg[ord[i]];\n        q.hist[q.degSorted[i]]++;\n    }\n\n    for (int a = 0; a < Ncur; ++a) {\n        for (int b = a + 1; b < Ncur; ++b) {\n            if (getEdge(rowsIn, ord[a], ord[b])) {\n                setEdge(q.rows, a, b);\n            }\n        }\n    }\n\n    q.blockCnt = computeBlockCounts(q.rows);\n    return q;\n}\n\nQueryFeat featureFromString(const string& s) {\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    int pos = 0;\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (s[pos++] == '1') {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    return makeFeatureFromRows(rows, deg);\n}\n\nQueryFeat simulateQuery(int k, mt19937_64& rng) {\n    const Codeword& cw = codes[k];\n\n    vector<Row> rows(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : rows) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg{};\n    deg.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            int h = getEdge(cw.rows, i, j) ? 1 : 0;\n            if (rnd01(rng) < EPS) h ^= 1;\n\n            if (h) {\n                setEdge(rows, i, j);\n                deg[i]++;\n                deg[j]++;\n            }\n        }\n    }\n\n    array<int, MAXN> perm{};\n    for (int i = 0; i < Ncur; ++i) perm[i] = i;\n\n    for (int i = Ncur - 1; i >= 1; --i) {\n        int r = rng() % (i + 1);\n        swap(perm[i], perm[r]);\n    }\n\n    vector<Row> shuf(Ncur, Row{0ULL, 0ULL});\n    for (auto& r : shuf) r = {0ULL, 0ULL};\n\n    array<int, MAXN> deg2{};\n    deg2.fill(0);\n\n    for (int i = 0; i < Ncur; ++i) deg2[i] = deg[perm[i]];\n\n    for (int i = 0; i < Ncur; ++i) {\n        for (int j = i + 1; j < Ncur; ++j) {\n            if (getEdge(rows, perm[i], perm[j])) {\n                setEdge(shuf, i, j);\n            }\n        }\n    }\n\n    return makeFeatureFromRows(shuf, deg2);\n}\n\nint edgeMismatch(const vector<Row>& A, const vector<Row>& B) {\n    int s = 0;\n\n    for (int i = 0; i < Ncur; ++i) {\n        s += __builtin_popcountll(A[i][0] ^ B[i][0]);\n        if (Ncur > 64) s += __builtin_popcountll(A[i][1] ^ B[i][1]);\n    }\n\n    return s / 2;\n}\n\nstruct Components {\n    double sortedCost;\n    double mixCost;\n    double blockCost;\n    int edgeMis;\n};\n\nComponents computeComponents(const QueryFeat& q, const Codeword& c) {\n    Components comp{0.0, 0.0, 0.0, 0};\n\n    for (int i = 0; i < Ncur; ++i) {\n        comp.sortedCost += NEGLOGP[(int)c.deg[i]][q.degSorted[i]];\n    }\n\n    for (int x = 0; x < Ncur; ++x) {\n        if (q.hist[x]) comp.mixCost += q.hist[x] * c.mixNeg[x];\n    }\n\n    for (int f = 0; f < Fcur; ++f) {\n        int pairs = PAIRCNT[f];\n        if (pairs <= 0) continue;\n\n        double mu = EPS * pairs + QV * c.blockCnt[f];\n        double var = pairs * EPS * (1.0 - EPS) + 1.0;\n        double diff = q.blockCnt[f] - mu;\n\n        comp.blockCost += diff * diff / (2.0 * var);\n    }\n\n    comp.edgeMis = edgeMismatch(q.rows, c.rows);\n    return comp;\n}\n\ninline double scoreWithConfig(const Components& comp, const Config& cfg) {\n    double degCost = cfg.alpha * comp.sortedCost + (1.0 - cfg.alpha) * comp.mixCost;\n    return degCost + cfg.wb * comp.blockCost + cfg.we * edgePenalty * comp.edgeMis;\n}\n\nvector<Config> buildConfigs() {\n    vector<Config> cfgs;\n    cfgs.push_back({0.5, 0.0, 0.0});\n\n    vector<double> alphas = {0.0, 0.25, 0.5, 0.75, 1.0};\n    vector<double> wbs = {0.0, 0.2, 0.5, 1.0, 2.0};\n    vector<double> wes = {0.0, 0.02, 0.05, 0.1, 0.2};\n\n    for (double a : alphas) {\n        for (double wb : wbs) {\n            for (double we : wes) {\n                cfgs.push_back({a, wb, we});\n            }\n        }\n    }\n\n    return cfgs;\n}\n\nvector<Config> buildDegreeSimpleConfigs() {\n    vector<Config> cfgs;\n    vector<double> alphas = {0.0, 0.25, 0.5, 0.75, 1.0};\n    for (double a : alphas) cfgs.push_back({a, 0.0, 0.0});\n    return cfgs;\n}\n\nTrainResult trainDecoderWithConfigs(const vector<Config>& cfgs, uint64_t seedSalt = 0) {\n    int C = (int)cfgs.size();\n\n    int R = 3;\n    if (EPS > 0.25) R = 5;\n    else if (EPS > 0.12) R = 4;\n\n    if (M <= 20) R += 4;\n    else if (M <= 50) R += 1;\n\n    int samples = M * R;\n    vector<int> errs(C, 0);\n\n    mt19937_64 rng(1234567ULL\n                   + (uint64_t)M * 1009ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 9176ULL\n                   + (uint64_t)Ncur * 1000003ULL\n                   + (uint64_t)Bcur * 19260817ULL\n                   + seedSalt);\n\n    vector<double> best(C);\n    vector<int> bestId(C);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n\n            fill(best.begin(), best.end(), 1e300);\n            fill(bestId.begin(), bestId.end(), -1);\n\n            for (int k = 0; k < M; ++k) {\n                Components comp = computeComponents(q, codes[k]);\n\n                for (int ci = 0; ci < C; ++ci) {\n                    double sc = scoreWithConfig(comp, cfgs[ci]);\n\n                    if (sc < best[ci]) {\n                        best[ci] = sc;\n                        bestId[ci] = k;\n                    }\n                }\n            }\n\n            for (int ci = 0; ci < C; ++ci) {\n                if (bestId[ci] != trueId) errs[ci]++;\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int ci = 1; ci < C; ++ci) {\n        if (errs[ci] < errs[bestC]) bestC = ci;\n    }\n\n    return {cfgs[bestC], errs[bestC], samples};\n}\n\nTrainResult trainDecoder(uint64_t seedSalt = 0) {\n    return trainDecoderWithConfigs(buildConfigs(), seedSalt);\n}\n\nint predictBaseline(const QueryFeat& q) {\n    double best = 1e300;\n    int ans = 0;\n\n    for (int k = 0; k < M; ++k) {\n        Components comp = computeComponents(q, codes[k]);\n        double sc = scoreWithConfig(comp, bestCfg);\n\n        if (sc < best) {\n            best = sc;\n            ans = k;\n        }\n    }\n\n    return ans;\n}\n\nvoid computeBaseScores(const QueryFeat& q, vector<double>& scores, vector<int>& order) {\n    scores.assign(M, 0.0);\n    order.resize(M);\n\n    for (int k = 0; k < M; ++k) {\n        Components comp = computeComponents(q, codes[k]);\n        scores[k] = scoreWithConfig(comp, bestCfg);\n        order[k] = k;\n    }\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return scores[a] < scores[b];\n    });\n}\n\nstruct LocalResult {\n    double score = 0.0;\n};\n\nLocalResult localRefineOne(const QueryFeat& q, const Codeword& c, const LocalMode& lm) {\n    vector<int> perm(Ncur);\n    iota(perm.begin(), perm.end(), 0);\n\n    double degCost = 0.0;\n    for (int i = 0; i < Ncur; ++i) {\n        degCost += NEGLOGP[(int)c.deg[i]][q.degSorted[i]];\n    }\n\n    int eCost = edgeMismatch(q.rows, c.rows);\n\n    auto trySwap = [&](int a, int b) -> bool {\n        if (a == b) return false;\n        if (a > b) swap(a, b);\n\n        int pa = perm[a], pb = perm[b];\n\n        double oldDeg = NEGLOGP[(int)c.deg[a]][q.degSorted[pa]]\n                      + NEGLOGP[(int)c.deg[b]][q.degSorted[pb]];\n        double newDeg = NEGLOGP[(int)c.deg[a]][q.degSorted[pb]]\n                      + NEGLOGP[(int)c.deg[b]][q.degSorted[pa]];\n        double dDeg = newDeg - oldDeg;\n\n        int dE = 0;\n\n        for (int t = 0; t < Ncur; ++t) {\n            if (t == a || t == b) continue;\n\n            int pt = perm[t];\n\n            int h_at = getEdge(q.rows, pa, pt);\n            int h_bt = getEdge(q.rows, pb, pt);\n\n            int g_at = getEdge(c.rows, a, t);\n            int g_bt = getEdge(c.rows, b, t);\n\n            dE += (h_bt != g_at) + (h_at != g_bt)\n                - (h_at != g_at) - (h_bt != g_bt);\n        }\n\n        double dObj = lm.dg * dDeg + lm.eg * edgePenalty * dE;\n\n        if (dObj < -1e-9) {\n            swap(perm[a], perm[b]);\n            degCost += dDeg;\n            eCost += dE;\n            return true;\n        }\n\n        return false;\n    };\n\n    for (int pass = 0; pass < lm.passes; ++pass) {\n        bool improved = false;\n\n        for (int gap = 1; gap <= lm.window; ++gap) {\n            for (int i = 0; i + gap < Ncur; ++i) {\n                if (trySwap(i, i + gap)) improved = true;\n            }\n        }\n\n        for (int gap = 1; gap <= lm.window; ++gap) {\n            for (int i = Ncur - gap - 1; i >= 0; --i) {\n                if (trySwap(i, i + gap)) improved = true;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return {lm.dg * degCost + lm.eg * edgePenalty * eCost};\n}\n\nint predictLocal(const QueryFeat& q) {\n    vector<double> baseScores;\n    vector<int> order;\n    computeBaseScores(q, baseScores, order);\n\n    int K = min(curLocal.topK, M);\n    double best = 1e300;\n    int ans = order[0];\n\n    for (int ii = 0; ii < K; ++ii) {\n        int k = order[ii];\n\n        LocalResult lr = localRefineOne(q, codes[k], curLocal);\n        double sc = curLocal.baseW * baseScores[k] + lr.score;\n\n        if (sc < best) {\n            best = sc;\n            ans = k;\n        }\n    }\n\n    return ans;\n}\n\nint predict(const QueryFeat& q) {\n    if (predMode == 1 && elapsedSec() < 4.95) {\n        return predictLocal(q);\n    }\n    return predictBaseline(q);\n}\n\nint chooseN() {\n    int minN = minimalNForM();\n\n    double r = sqrt(EPS * (1.0 - EPS)) / QV;\n    int nest = (int)ceil(4.0 + 38.0 * r * sqrt(M / 100.0) + 0.03 * M);\n    nest = max(minN, min(100, nest));\n\n    int start, end;\n\n    if (EPS < 0.05) {\n        start = minN;\n        end = min(100, max(nest + 15, minN + 8));\n    } else {\n        start = max(minN, nest - 20);\n        end = min(100, nest + 25);\n        if (EPS > 0.34) end = 100;\n    }\n\n    vector<int> ns;\n\n    for (int n = start; n <= end;) {\n        ns.push_back(n);\n\n        if (n < 35) n++;\n        else if (n < 75) n += 2;\n        else n += 4;\n    }\n\n    ns.push_back(minN);\n    ns.push_back(nest);\n    ns.push_back(100);\n\n    sort(ns.begin(), ns.end());\n    ns.erase(unique(ns.begin(), ns.end()), ns.end());\n\n    double target = 3.25 + 0.12 * log((double)M);\n\n    if (EPS > 0.25) target += 0.15;\n    if (EPS < 0.03) target -= 0.75;\n    else if (EPS < 0.07) target -= 0.30;\n    if (M <= 20) target -= 0.15;\n\n    target = max(2.4, target);\n\n    for (int n : ns) {\n        if (n < minN || n > 100) continue;\n\n        int Bs = min(n, (n >= 80 ? 12 : 11));\n        vector<Candidate> pool = buildPool(n, Bs);\n\n        if ((int)pool.size() < M) continue;\n\n        Selection sel = selectFarthest(pool, n, M, 0);\n        if (sel.idx.empty()) continue;\n\n        double sigma = sqrt((n - 1) * EPS * (1.0 - EPS));\n        double z = QV * sqrt((double)sel.minD2) / (2.0 * sigma);\n\n        if (z >= target) return n;\n    }\n\n    return 100;\n}\n\nSolution captureSolution(const string& name, const TrainResult& tr) {\n    Solution sol;\n\n    sol.N = Ncur;\n    sol.B = Bcur;\n    sol.Lfeat = Lcur;\n    sol.codes = codes;\n    sol.cfg = bestCfg;\n    sol.trainErr = tr.err;\n    sol.trainSamples = tr.samples;\n    sol.name = name;\n\n    return sol;\n}\n\nvoid activateSolution(const Solution& sol) {\n    Ncur = sol.N;\n    Bcur = sol.B;\n\n    setupBlocks(Ncur, sol.Lfeat);\n    setupPMF(Ncur);\n    edgePenalty = log((1.0 - EPS) / EPS);\n\n    codes = sol.codes;\n    bestCfg = sol.cfg;\n\n    predMode = sol.mode;\n    curLocal = sol.local;\n}\n\nSolution buildThresholdSolution(int initialN) {\n    int chosenN = initialN;\n    int attempts = 0;\n\n    while (true) {\n        Ncur = chosenN;\n        Bcur = min(Ncur, (Ncur >= 70 ? 14 : (Ncur >= 35 ? 13 : 12)));\n\n        vector<Candidate> pool = buildPool(Ncur, Bcur);\n\n        if ((int)pool.size() < M) {\n            chosenN++;\n            continue;\n        }\n\n        Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n        setupBlocks(Ncur, 10);\n        setupPMF(Ncur);\n        edgePenalty = log((1.0 - EPS) / EPS);\n\n        codes.clear();\n        codes.reserve(M);\n\n        for (int id : sel.idx) {\n            codes.push_back(buildThresholdCodeword(pool[id]));\n        }\n\n        TrainResult tr = trainDecoder(0);\n        bestCfg = tr.cfg;\n\n        int allowed;\n        if (EPS < 0.05) allowed = max(4, tr.samples / 50);\n        else allowed = max(3, tr.samples / 100);\n\n        if (tr.err > allowed && chosenN < 100 && attempts < 3) {\n            int inc = (chosenN < 50 ? 10 : 6);\n            if (EPS > 0.3) inc = max(inc, 8);\n\n            chosenN = min(100, chosenN + inc);\n            attempts++;\n            continue;\n        }\n\n        return captureSolution(\"threshold\", tr);\n    }\n}\n\nSolution buildThresholdFixedSolution(int N, int B, const string& name, uint64_t seedSalt) {\n    if (B < 1 || B > 20) return Solution{};\n\n    Ncur = N;\n    Bcur = B;\n\n    vector<Candidate> pool = buildPool(Ncur, Bcur);\n    if ((int)pool.size() < M) return Solution{};\n\n    Selection sel = selectFarthest(pool, Ncur, M, 1);\n\n    setupBlocks(Ncur, 10);\n    setupPMF(Ncur);\n    edgePenalty = log((1.0 - EPS) / EPS);\n\n    codes.clear();\n    codes.reserve(M);\n\n    for (int id : sel.idx) {\n        codes.push_back(buildThresholdCodeword(pool[id]));\n    }\n\n    TrainResult tr = trainDecoder(seedSalt);\n    bestCfg = tr.cfg;\n\n    return captureSolution(name, tr);\n}\n\nvector<Solution> buildDegreeSolutions(int N) {\n    vector<Solution> sols;\n\n    Ncur = N;\n    Bcur = 0;\n\n    setupBlocks(Ncur, 10);\n    setupPMF(Ncur);\n    edgePenalty = log((1.0 - EPS) / EPS);\n\n    int target = 18000;\n    if (EPS >= 0.34) target = 23000;\n    if (M <= 50) target -= 3000;\n    target = max(target, 12000);\n\n    vector<Candidate> pool = buildDegreePool(Ncur, target);\n    if ((int)pool.size() < M) return sols;\n\n    Selection sel = selectFarthest(pool, Ncur, M, 0);\n    if ((int)sel.idx.size() < M) return sols;\n\n    codes.clear();\n    codes.reserve(M);\n\n    for (int id : sel.idx) {\n        codes.push_back(buildDegreeCodeword(pool[id]));\n    }\n\n    vector<Codeword> built = codes;\n\n    codes = built;\n    TrainResult trFull = trainDecoder(424242);\n    bestCfg = trFull.cfg;\n    sols.push_back(captureSolution(\"degree-full\", trFull));\n\n    if (elapsedSec() < 4.00) {\n        codes = built;\n        TrainResult trSimple = trainDecoderWithConfigs(buildDegreeSimpleConfigs(), 989898);\n        bestCfg = trSimple.cfg;\n        sols.push_back(captureSolution(\"degree-simple\", trSimple));\n    }\n\n    return sols;\n}\n\nSolution makeLocalVariant(const Solution& base) {\n    Solution s = base;\n    s.name = base.name + \"-local\";\n    s.mode = 1;\n    s.local = LocalMode{0.35, 0.90, 0.25, min(M, 8), 1, 1};\n    return s;\n}\n\nSolution makeLocalVariant2(const Solution& base) {\n    Solution s = base;\n    s.name = base.name + \"-local2\";\n    s.mode = 1;\n    s.local = LocalMode{0.22, 1.10, 0.18, min(M, 6), 2, 1};\n    return s;\n}\n\nSolution makeDegreeLocalVariant(const Solution& base) {\n    Solution s = base;\n    s.name = base.name + \"-local\";\n    s.mode = 1;\n    s.local = LocalMode{0.30, 0.75, 0.25, min(M, 6), 1, 1};\n    return s;\n}\n\nEvalResult validateSolution(const Solution& sol, int R, uint64_t seedExtra) {\n    activateSolution(sol);\n\n    int err = 0;\n    int samples = M * R;\n    int done = 0;\n\n    mt19937_64 rng(0x9e3779b97f4a7c15ULL\n                   + seedExtra * 1000003ULL\n                   + (uint64_t)M * 9176ULL\n                   + (uint64_t)Ncur * 19260817ULL\n                   + (uint64_t)Bcur * 1234567ULL\n                   + (uint64_t)Lcur * 314159ULL\n                   + (uint64_t)(EPS * 100 + 0.5) * 998244353ULL);\n\n    for (int trueId = 0; trueId < M; ++trueId) {\n        for (int rep = 0; rep < R; ++rep) {\n            QueryFeat q = simulateQuery(trueId, rng);\n            int ans = predict(q);\n\n            if (ans != trueId) err++;\n            done++;\n\n            if (elapsedSec() > 4.82) {\n                return {err, max(1, done)};\n            }\n        }\n    }\n\n    return {err, samples};\n}\n\ndouble validationProxy(const Solution& sol, const EvalResult& e) {\n    double expectedE = 100.0 * e.err / max(1, e.samples);\n    return exp(log(0.9) * expectedE) / sol.N;\n}\n\nbool validationBetter(const Solution& base, const EvalResult& eb,\n                      const Solution& alt, const EvalResult& ea) {\n    if (alt.N < base.N) {\n        double pb = validationProxy(base, eb);\n        double pa = validationProxy(alt, ea);\n\n        double ratio = 1.05;\n        if (alt.name == \"threshold-low\") ratio = 1.08;\n        if (alt.name == \"threshold-low-mid\") ratio = 1.06;\n\n        return pa > pb * ratio;\n    }\n\n    double Eb = 100.0 * eb.err / max(1, eb.samples);\n    double Ea = 100.0 * ea.err / max(1, ea.samples);\n\n    double need = log((double)alt.N / (double)base.N) / (-log(0.9));\n\n    double margin = 5.0;\n\n    if (alt.name == \"threshold-bplus\") margin = 3.5;\n    if (alt.name == \"degree-full\") {\n        margin = 4.7;\n        if (EPS >= 0.34) margin = 4.0;\n    }\n    if (alt.name == \"degree-simple\") {\n        margin = 5.2;\n        if (EPS >= 0.34) margin = 4.5;\n    }\n    if (alt.name == \"degree-full-local\" || alt.name == \"degree-simple-local\") {\n        margin = 5.4;\n        if (EPS >= 0.36) margin = 4.8;\n    } else if (alt.name.find(\"local\") != string::npos) {\n        margin = 4.2;\n        if (EPS >= 0.36) margin = 3.5;\n    }\n    if (M <= 40) margin += 0.7;\n\n    return (Eb - Ea > need + margin);\n}\n\n// Exact solver for epsilon = 0.\nstruct ExactSolver {\n    int n, T;\n    vector<string> reps;\n    vector<int> cmap;\n    vector<array<int, 15>> trans;\n\n    int pairPos[6][6];\n\n    void prepareTrans(int n_) {\n        n = n_;\n        T = n * (n - 1) / 2;\n\n        for (int i = 0; i < 6; ++i) {\n            for (int j = 0; j < 6; ++j) pairPos[i][j] = -1;\n        }\n\n        int p = 0;\n        for (int i = 0; i < n; ++i) {\n            for (int j = i + 1; j < n; ++j) {\n                pairPos[i][j] = pairPos[j][i] = p++;\n            }\n        }\n\n        vector<int> perm(n);\n        iota(perm.begin(), perm.end(), 0);\n\n        trans.clear();\n\n        do {\n            array<int, 15> tr{};\n            int pos = 0;\n\n            for (int i = 0; i < n; ++i) {\n                for (int j = i + 1; j < n; ++j) {\n                    int a = perm[i], b = perm[j];\n                    tr[pos++] = pairPos[a][b];\n                }\n            }\n\n            trans.push_back(tr);\n        } while (next_permutation(perm.begin(), perm.end()));\n    }\n\n    int canonicalMask(int mask) const {\n        int best = INT_MAX;\n\n        for (const auto& tr : trans) {\n            int val = 0;\n\n            for (int i = 0; i < T; ++i) {\n                val = (val << 1) | ((mask >> tr[i]) & 1);\n            }\n\n            if (val < best) best = val;\n        }\n\n        return best;\n    }\n\n    string maskToString(int mask) const {\n        string s;\n        s.resize(T);\n\n        for (int i = 0; i < T; ++i) {\n            s[i] = ((mask >> i) & 1) ? '1' : '0';\n        }\n\n        return s;\n    }\n\n    int stringToMask(const string& s) const {\n        int mask = 0;\n\n        for (int i = 0; i < T; ++i) {\n            if (s[i] == '1') mask |= 1 << i;\n        }\n\n        return mask;\n    }\n\n    void generate(int M) {\n        for (int nn = 4; nn <= 6; ++nn) {\n            prepareTrans(nn);\n\n            reps.clear();\n            cmap.assign(1 << T, -1);\n\n            for (int mask = 0; mask < (1 << T); ++mask) {\n                int c = canonicalMask(mask);\n\n                if (cmap[c] == -1) {\n                    int id = (int)reps.size();\n                    cmap[c] = id;\n                    reps.push_back(maskToString(mask));\n\n                    if ((int)reps.size() == M) return;\n                }\n            }\n        }\n    }\n\n    int decode(const string& s) const {\n        int mask = stringToMask(s);\n        int c = canonicalMask(mask);\n\n        if (0 <= c && c < (int)cmap.size() && cmap[c] != -1) return cmap[c];\n        return 0;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    cin >> M >> EPS;\n    QV = 1.0 - 2.0 * EPS;\n\n    if (EPS < 1e-12) {\n        ExactSolver ex;\n        ex.generate(M);\n\n        cout << ex.n << '\\n';\n        for (int i = 0; i < M; ++i) {\n            cout << ex.reps[i] << '\\n';\n        }\n        cout.flush();\n\n        for (int q = 0; q < 100; ++q) {\n            string H;\n            cin >> H;\n\n            int ans = ex.decode(H);\n\n            cout << ans << '\\n';\n            cout.flush();\n        }\n\n        return 0;\n    }\n\n    int initialN = chooseN();\n\n    Solution baseSol = buildThresholdSolution(initialN);\n    Solution bestSol = baseSol;\n\n    vector<Solution> alternatives;\n    bool hasLowAlternative = false;\n\n    // Conservative lower-N candidates only.\n    if (baseSol.N > initialN && elapsedSec() < 2.80) {\n        vector<pair<int, string>> lowNs;\n        lowNs.push_back({initialN, \"threshold-low\"});\n\n        int diff = baseSol.N - initialN;\n        if (diff >= 8) {\n            int midN = (baseSol.N + initialN) / 2;\n            lowNs.push_back({midN, \"threshold-low-mid\"});\n        }\n\n        sort(lowNs.begin(), lowNs.end());\n        lowNs.erase(unique(lowNs.begin(), lowNs.end()), lowNs.end());\n\n        int seedBase = 12345;\n        for (int idx = 0; idx < (int)lowNs.size(); ++idx) {\n            if (elapsedSec() > 3.05) break;\n\n            int n = lowNs[idx].first;\n            if (n <= 0 || n >= baseSol.N) continue;\n\n            int b = min(n, (n >= 70 ? 14 : (n >= 35 ? 13 : 12)));\n            Solution low = buildThresholdFixedSolution(n, b, lowNs[idx].second,\n                                                        seedBase + idx * 1009);\n            if (low.N > 0) {\n                alternatives.push_back(low);\n                hasLowAlternative = true;\n            }\n        }\n    }\n\n    if (EPS >= 0.10 && EPS <= 0.30 && elapsedSec() < 2.95) {\n        int b2 = baseSol.B + 1;\n        if (b2 <= 14) {\n            Solution s2 = buildThresholdFixedSolution(baseSol.N, b2, \"threshold-bplus\", 777);\n            if (s2.N > 0) alternatives.push_back(s2);\n        }\n    }\n\n    if (EPS >= 0.32 && M >= 40 && elapsedSec() < 3.15) {\n        alternatives.push_back(makeLocalVariant(baseSol));\n    }\n\n    if (EPS >= 0.27 && M >= 40 && elapsedSec() < 3.45) {\n        vector<Solution> degSols = buildDegreeSolutions(baseSol.N);\n        for (auto& s : degSols) {\n            if (s.N > 0) {\n                alternatives.push_back(s);\n\n                if ((s.name == \"degree-full\" || s.name == \"degree-simple\")\n                    && EPS >= 0.34 && elapsedSec() < 4.10) {\n                    alternatives.push_back(makeDegreeLocalVariant(s));\n                }\n            }\n        }\n    }\n\n    if (EPS >= 0.36 && M >= 45 && elapsedSec() < 4.05) {\n        alternatives.push_back(makeLocalVariant2(baseSol));\n    }\n\n    if (!alternatives.empty() && elapsedSec() < 4.55) {\n        int Rv = 4;\n        if (EPS >= 0.30) Rv = 5;\n        if (EPS >= 0.36) Rv = 6;\n        if (M <= 30) Rv++;\n\n        if (hasLowAlternative) Rv = max(Rv, 6);\n\n        EvalResult bestEval = validateSolution(bestSol, Rv, 1);\n\n        for (int i = 0; i < (int)alternatives.size(); ++i) {\n            if (elapsedSec() > 4.72) break;\n\n            EvalResult altEval = validateSolution(alternatives[i], Rv, 10 + i);\n\n            if (validationBetter(bestSol, bestEval, alternatives[i], altEval)) {\n                bestSol = alternatives[i];\n                bestEval = altEval;\n            }\n        }\n    }\n\n    activateSolution(bestSol);\n\n    cout << Ncur << '\\n';\n    for (int i = 0; i < M; ++i) {\n        cout << codes[i].out << '\\n';\n    }\n    cout.flush();\n\n    for (int q = 0; q < 100; ++q) {\n        string H;\n        cin >> H;\n\n        QueryFeat feat = featureFromString(H);\n        int ans = predict(feat);\n\n        cout << ans << '\\n';\n        cout.flush();\n    }\n\n    return 0;\n}","ahc017":"#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() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nstruct Solver {\n    static constexpr int INF = 1100000000;\n    static constexpr int UNREACH = 1000000000;\n    static constexpr long long DISCONN_SCORE = 4000000000000000LL;\n\n    struct Edge {\n        int u, v, w;\n        int cell;\n        uint32_t key;\n    };\n    struct Arc {\n        int to, w, id;\n    };\n    struct ScoreRes {\n        long long total;\n        vector<long long> day;\n    };\n    struct State {\n        vector<int> assign;\n        vector<int> count;\n        vector<vector<int>> dayEdges;\n        vector<int> pos;\n        vector<int> inc;\n        vector<double> dayImp;\n        vector<int> cellCnt;\n        vector<int> cutCnt;\n        vector<long long> dayScore;\n        long long totalScore = 0;\n    };\n    struct Cand {\n        int type = 0; // 1: move, 2: swap\n        int e = -1, f = -1;\n        double cheap = 1e100;\n    };\n\n    int N, M, D, K;\n    vector<Edge> edges;\n    vector<vector<Arc>> adj;\n    vector<int> xs, ys;\n    vector<int> deg;\n\n    vector<int> origDist;\n    vector<long long> load;\n    vector<vector<int>> cutAdj;\n    vector<double> stretch;\n    vector<double> impNorm;\n    vector<int> target;\n    vector<int> optSources;\n\n    static constexpr int G = 16;\n    static constexpr int C = G * G;\n    vector<vector<int>> neighCells;\n    vector<unsigned char> nearCell;\n\n    RNG rng;\n    chrono::steady_clock::time_point startTime;\n    double localEndTime = 5.65;\n\n    vector<pair<int, int>> heapBuf;\n    vector<int> distBuf;\n    vector<int> bfsVis, bfsQ;\n    int bfsStamp = 1;\n\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    static uint64_t mix64(uint64_t z) {\n        z += 0x9e3779b97f4a7c15ull;\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ull;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebull;\n        return z ^ (z >> 31);\n    }\n\n    uint32_t zOrder(int x, int y) const {\n        uint32_t r = 0;\n        for (int b = 0; b < 11; b++) {\n            r |= ((x >> b) & 1u) << (2 * b);\n            r |= ((y >> b) & 1u) << (2 * b + 1);\n        }\n        return r;\n    }\n\n    int edgeCellFromSum(int sx, int sy) const {\n        int cx = min(G - 1, (sx * G) / 2001);\n        int cy = min(G - 1, (sy * G) / 2001);\n        return cx * G + cy;\n    }\n\n    void setupCells() {\n        neighCells.assign(C, {});\n        nearCell.assign(C * C, 0);\n        for (int cx = 0; cx < G; cx++) {\n            for (int cy = 0; cy < G; cy++) {\n                int c = cx * G + cy;\n                for (int dx = -1; dx <= 1; dx++) {\n                    for (int dy = -1; dy <= 1; dy++) {\n                        int nx = cx + dx;\n                        int ny = cy + dy;\n                        if (0 <= nx && nx < G && 0 <= ny && ny < G) {\n                            int nc = nx * G + ny;\n                            neighCells[c].push_back(nc);\n                            nearCell[c * C + nc] = 1;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    double lowDegAddPenalty(int v, int existingRemoved) const {\n        if (existingRemoved <= 0) return 0.0;\n\n        int dg = max(2, deg[v]);\n        int after = existingRemoved + 1;\n        int safeRemoved = max(1, dg - 2);\n\n        if (after <= safeRemoved) return 0.0;\n\n        int x = after - safeRemoved;\n        double base;\n        if (dg <= 3) base = 55.0;\n        else if (dg == 4) base = 28.0;\n        else base = 12.0;\n\n        return base * x * x;\n    }\n\n    void readInput() {\n        cin >> N >> M >> D >> K;\n\n        edges.resize(M);\n        adj.assign(N, {});\n        deg.assign(N, 0);\n\n        uint64_t seed = 123456789;\n\n        for (int i = 0; i < M; i++) {\n            int u, v, w;\n            cin >> u >> v >> w;\n            --u;\n            --v;\n\n            edges[i].u = u;\n            edges[i].v = v;\n            edges[i].w = w;\n            edges[i].cell = 0;\n            edges[i].key = 0;\n\n            adj[u].push_back({v, w, i});\n            adj[v].push_back({u, w, i});\n            deg[u]++;\n            deg[v]++;\n\n            seed ^= mix64((uint64_t)(u + 1) * 1000003ull + (uint64_t)(v + 1) * 1009ull + w);\n        }\n\n        xs.resize(N);\n        ys.resize(N);\n        for (int i = 0; i < N; i++) {\n            cin >> xs[i] >> ys[i];\n            seed ^= mix64((uint64_t)(xs[i] + 1) * 10007ull + ys[i] + i * 97ull);\n        }\n\n        rng.x = seed ? seed : 88172645463325252ull;\n\n        setupCells();\n\n        for (int i = 0; i < M; i++) {\n            int u = edges[i].u;\n            int v = edges[i].v;\n            int sx = xs[u] + xs[v];\n            int sy = ys[u] + ys[v];\n\n            edges[i].cell = edgeCellFromSum(sx, sy);\n\n            int hx = min(2047, (sx * 2047) / 2000);\n            int hy = min(2047, (sy * 2047) / 2000);\n            edges[i].key = zOrder(hx, hy);\n        }\n\n        target.assign(D, M / D);\n        for (int d = 0; d < M % D; d++) target[d]++;\n\n        distBuf.assign(N, INF);\n        bfsVis.assign(N, 0);\n        bfsQ.assign(N, 0);\n        heapBuf.reserve(max(10000, 4 * M + 2 * N));\n    }\n\n    void heapPush(int d, int v) {\n        pair<int, int> val = {d, v};\n        int i = (int)heapBuf.size();\n        heapBuf.push_back(val);\n\n        while (i > 0) {\n            int p = (i - 1) >> 1;\n            if (heapBuf[p].first <= val.first) break;\n            heapBuf[i] = heapBuf[p];\n            i = p;\n        }\n\n        heapBuf[i] = val;\n    }\n\n    pair<int, int> heapPop() {\n        pair<int, int> res = heapBuf[0];\n        pair<int, int> val = heapBuf.back();\n        heapBuf.pop_back();\n\n        if (!heapBuf.empty()) {\n            int i = 0;\n            int n = (int)heapBuf.size();\n\n            while (true) {\n                int l = i * 2 + 1;\n                if (l >= n) break;\n\n                int r = l + 1;\n                int c = l;\n                if (r < n && heapBuf[r].first < heapBuf[l].first) c = r;\n\n                if (heapBuf[c].first >= val.first) break;\n\n                heapBuf[i] = heapBuf[c];\n                i = c;\n            }\n\n            heapBuf[i] = val;\n        }\n\n        return res;\n    }\n\n    void dijkstraOriginalParent(\n        int src,\n        vector<int>& dist,\n        vector<int>& parV,\n        vector<int>& parE,\n        vector<int>& order\n    ) {\n        fill(dist.begin(), dist.end(), INF);\n        fill(parV.begin(), parV.end(), -1);\n        fill(parE.begin(), parE.end(), -1);\n        order.clear();\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n\n            order.push_back(v);\n\n            for (const auto& a : adj[v]) {\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    parV[a.to] = v;\n                    parE[a.to] = a.id;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    void dijkstraDaySource(int src, int day, const vector<int>& assign, vector<int>& dist) {\n        fill(dist.begin(), dist.end(), INF);\n        heapBuf.clear();\n\n        dist[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != dist[v]) continue;\n\n            for (const auto& a : adj[v]) {\n                if (assign[a.id] == day) continue;\n\n                int nd = du + a.w;\n                if (nd < dist[a.to]) {\n                    dist[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n    }\n\n    int dijkstraBetweenSkipEdge(int src, int dst, int banned) {\n        fill(distBuf.begin(), distBuf.end(), INF);\n        heapBuf.clear();\n\n        distBuf[src] = 0;\n        heapPush(0, src);\n\n        while (!heapBuf.empty()) {\n            auto [du, v] = heapPop();\n            if (du != distBuf[v]) continue;\n            if (v == dst) return du;\n\n            for (const auto& a : adj[v]) {\n                if (a.id == banned) continue;\n\n                int nd = du + a.w;\n                if (nd < distBuf[a.to]) {\n                    distBuf[a.to] = nd;\n                    heapPush(nd, a.to);\n                }\n            }\n        }\n\n        return INF;\n    }\n\n    void computeOriginalAndLoad() {\n        origDist.assign(N * N, INF);\n        load.assign(M, 0);\n\n        vector<int> dist(N), parV(N), parE(N), order;\n        vector<int> sub(N);\n\n        for (int s = 0; s < N; s++) {\n            dijkstraOriginalParent(s, dist, parV, parE, order);\n            memcpy(&origDist[s * N], dist.data(), sizeof(int) * N);\n\n            fill(sub.begin(), sub.end(), 1);\n\n            for (int ii = (int)order.size() - 1; ii >= 0; ii--) {\n                int v = order[ii];\n                int e = parE[v];\n\n                if (e != -1) {\n                    load[e] += sub[v];\n                    sub[parV[v]] += sub[v];\n                }\n            }\n        }\n    }\n\n    void detectTwoEdgeCuts() {\n        cutAdj.assign(M, {});\n        vector<int> tin(N), low(N);\n\n        for (int banned = 0; banned < M; banned++) {\n            fill(tin.begin(), tin.end(), 0);\n            fill(low.begin(), low.end(), 0);\n\n            int timer = 0;\n\n            auto dfs = [&](auto&& self, int v, int pe) -> void {\n                tin[v] = low[v] = ++timer;\n\n                for (const auto& a : adj[v]) {\n                    if (a.id == banned || a.id == pe) continue;\n\n                    int to = a.to;\n                    if (!tin[to]) {\n                        self(self, to, a.id);\n                        low[v] = min(low[v], low[to]);\n\n                        if (low[to] > tin[v]) {\n                            int f = a.id;\n                            if (banned < f) {\n                                cutAdj[banned].push_back(f);\n                                cutAdj[f].push_back(banned);\n                            }\n                        }\n                    } else {\n                        low[v] = min(low[v], tin[to]);\n                    }\n                }\n            };\n\n            dfs(dfs, 0, -1);\n        }\n\n        for (auto& v : cutAdj) {\n            sort(v.begin(), v.end());\n            v.erase(unique(v.begin(), v.end()), v.end());\n        }\n    }\n\n    void computeStretch() {\n        stretch.assign(M, 0.0);\n        const double deadline = 1.35;\n\n        for (int e = 0; e < M; e++) {\n            if (elapsed() > deadline) break;\n\n            int u = edges[e].u;\n            int v = edges[e].v;\n            int repl = dijkstraBetweenSkipEdge(u, v, e);\n            int base = origDist[u * N + v];\n\n            if (repl >= INF) {\n                stretch[e] = 5.0;\n            } else {\n                stretch[e] = max(0.0, (double)(repl - base) / max(1, base));\n                stretch[e] = min(stretch[e], 8.0);\n            }\n        }\n    }\n\n    void computeImportance() {\n        double sumLoad = 0.0;\n        for (auto x : load) sumLoad += (double)x;\n\n        double meanLoad = max(1.0, sumLoad / max(1, M));\n\n        double avgW = 0.0;\n        for (const auto& e : edges) avgW += e.w;\n        avgW /= max(1, M);\n\n        vector<double> raw(M);\n        double sumRaw = 0.0;\n\n        for (int e = 0; e < M; e++) {\n            double r = (double)load[e] + 0.05 * meanLoad + 1.0;\n            r *= 1.0 + 0.7 * min(5.0, stretch[e]);\n            r *= 1.0 + 0.03 * min(50, (int)cutAdj[e].size());\n            r *= 0.75 + 0.25 * sqrt(max(0.1, edges[e].w / avgW));\n\n            raw[e] = r;\n            sumRaw += r;\n        }\n\n        double meanRaw = max(1e-9, sumRaw / max(1, M));\n\n        impNorm.assign(M, 1.0);\n        for (int e = 0; e < M; e++) {\n            impNorm[e] = raw[e] / meanRaw;\n            impNorm[e] = min(60.0, max(0.03, impNorm[e]));\n        }\n    }\n\n    vector<int> selectSources(int P) {\n        P = min(P, N);\n\n        vector<pair<uint32_t, int>> ord;\n        ord.reserve(N);\n\n        for (int i = 0; i < N; i++) {\n            int hx = xs[i] * 2047 / 1000;\n            int hy = ys[i] * 2047 / 1000;\n            ord.push_back({zOrder(hx, hy), i});\n        }\n\n        sort(ord.begin(), ord.end());\n\n        vector<int> res;\n        vector<char> used(N, 0);\n\n        for (int t = 0; t < P; t++) {\n            int idx = (int)(((long long)(2 * t + 1) * N) / (2 * P));\n            idx = min(idx, N - 1);\n\n            int v = ord[idx].second;\n            if (used[v]) {\n                for (int k = 0; k < N; k++) {\n                    int nv = ord[(idx + k) % N].second;\n                    if (!used[nv]) {\n                        v = nv;\n                        break;\n                    }\n                }\n            }\n\n            used[v] = 1;\n            res.push_back(v);\n        }\n\n        return res;\n    }\n\n    bool isConnectedSkip(const vector<int>& assign, int day, int extraSkip = -1) {\n        ++bfsStamp;\n        if (bfsStamp == INT_MAX) {\n            fill(bfsVis.begin(), bfsVis.end(), 0);\n            bfsStamp = 1;\n        }\n\n        int head = 0, tail = 0;\n        bfsVis[0] = bfsStamp;\n        bfsQ[tail++] = 0;\n        int seen = 1;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n\n            for (const auto& a : adj[v]) {\n                if (a.id == extraSkip) continue;\n                if (assign[a.id] == day) continue;\n\n                int to = a.to;\n                if (bfsVis[to] == bfsStamp) continue;\n\n                bfsVis[to] = bfsStamp;\n                bfsQ[tail++] = to;\n                seen++;\n            }\n        }\n\n        return seen == N;\n    }\n\n    long long computeDayScore(\n        const vector<int>& assign,\n        int day,\n        const vector<int>& sources,\n        int removedCount,\n        bool checkConn\n    ) {\n        if (removedCount == 0) return 0;\n        if (checkConn && !isConnectedSkip(assign, day, -1)) return DISCONN_SCORE;\n\n        long long sum = 0;\n\n        for (int s : sources) {\n            dijkstraDaySource(s, day, assign, distBuf);\n\n            int base = s * N;\n            for (int v = 0; v < N; v++) {\n                int d = distBuf[v];\n                int dd = (d >= INF ? UNREACH : d);\n                int diff = dd - origDist[base + v];\n                if (diff > 0) sum += diff;\n            }\n        }\n\n        return sum;\n    }\n\n    ScoreRes scoreAll(const vector<int>& assign, const vector<int>& sources) {\n        vector<int> cnt(D, 0);\n\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n            cnt[assign[e]]++;\n        }\n\n        for (int d = 0; d < D; d++) {\n            if (cnt[d] > K) {\n                return {DISCONN_SCORE * D, vector<long long>(D, DISCONN_SCORE)};\n            }\n        }\n\n        ScoreRes r;\n        r.total = 0;\n        r.day.assign(D, 0);\n\n        for (int d = 0; d < D; d++) {\n            r.day[d] = computeDayScore(assign, d, sources, cnt[d], true);\n            r.total += r.day[d];\n        }\n\n        return r;\n    }\n\n    void shuffleVec(vector<int>& v) {\n        for (int i = (int)v.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(v[i], v[j]);\n        }\n    }\n\n    int localCellCount(const vector<int>& cellCnt, int day, int cell) const {\n        int s = 0;\n        int base = day * C;\n        for (int nb : neighCells[cell]) s += cellCnt[base + nb];\n        return s;\n    }\n\n    vector<int> buildHilbertLike(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0 || variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                int ax = xs[edges[a].u] + xs[edges[a].v];\n                int bx = xs[edges[b].u] + xs[edges[b].v];\n                if (ax != bx) return ax < bx;\n\n                int ay = ys[edges[a].u] + ys[edges[a].v];\n                int by = ys[edges[b].u] + ys[edges[b].v];\n                return ay < by;\n            });\n        }\n\n        vector<int> assign(M, 0);\n        vector<int> perm(D);\n\n        for (int b = 0; b < M; b += D) {\n            iota(perm.begin(), perm.end(), 0);\n\n            if (variant == 0) {\n                rotate(perm.begin(), perm.begin() + ((b / D) % D), perm.end());\n            } else {\n                shuffleVec(perm);\n            }\n\n            for (int i = 0; i < D && b + i < M; i++) {\n                assign[order[b + i]] = perm[i];\n            }\n        }\n\n        return assign;\n    }\n\n    vector<int> buildRandomBalanced() {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n        shuffleVec(order);\n\n        vector<int> days;\n        days.reserve(M);\n\n        for (int d = 0; d < D; d++) {\n            for (int i = 0; i < target[d]; i++) days.push_back(d);\n        }\n        shuffleVec(days);\n\n        vector<int> assign(M);\n        for (int i = 0; i < M; i++) assign[order[i]] = days[i];\n\n        return assign;\n    }\n\n    vector<int> buildGreedy(int variant) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        if (variant == 0) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (impNorm[a] != impNorm[b]) return impNorm[a] > impNorm[b];\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (cutAdj[a].size() != cutAdj[b].size()) return cutAdj[a].size() > cutAdj[b].size();\n                return impNorm[a] > impNorm[b];\n            });\n        } else if (variant == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key < edges[b].key;\n            });\n        } else if (variant == 3) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return edges[a].key > edges[b].key;\n            });\n        } else {\n            vector<double> key(M);\n            for (int e = 0; e < M; e++) {\n                key[e] = impNorm[e] * (0.6 + 0.8 * rng.nextDouble());\n            }\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                return key[a] > key[b];\n            });\n        }\n\n        vector<int> assign(M, -1);\n        vector<int> count(D, 0);\n        vector<int> inc(N * D, 0);\n        vector<double> dayImp(D, 0.0);\n        vector<int> cellCnt(D * C, 0);\n        vector<int> cutCnt(M * D, 0);\n\n        for (int e : order) {\n            int u = edges[e].u;\n            int v = edges[e].v;\n            int cell = edges[e].cell;\n\n            vector<pair<double, int>> cand;\n            cand.reserve(D);\n\n            for (int d = 0; d < D; d++) {\n                if (count[d] >= K) continue;\n\n                int cu = inc[u * D + d];\n                int cv = inc[v * D + d];\n                int adjCnt = cu + cv;\n                int loc = localCellCount(cellCnt, d, cell);\n                int cut = cutCnt[e * D + d];\n\n                double over = max(0, count[d] + 1 - target[d]);\n\n                double cost = 100000000.0 * cut;\n                cost += 25.0 * adjCnt;\n                cost += lowDegAddPenalty(u, cu);\n                cost += lowDegAddPenalty(v, cv);\n                cost += 2.0 * loc;\n                cost += 4.0 * impNorm[e] * (dayImp[d] / max(1, target[d]));\n\n                if (count[d] >= target[d]) cost += 600.0 * over * over;\n                else cost += 0.1 * (double)count[d] / max(1, target[d]);\n\n                cost += 0.01 * rng.nextDouble();\n\n                cand.push_back({cost, d});\n            }\n\n            if (cand.empty()) {\n                int best = min_element(count.begin(), count.end()) - count.begin();\n                cand.push_back({0.0, best});\n            }\n\n            sort(cand.begin(), cand.end());\n\n            int chosen = -1;\n            for (auto [cost, d] : cand) {\n                if (isConnectedSkip(assign, d, e)) {\n                    chosen = d;\n                    break;\n                }\n            }\n\n            if (chosen == -1) chosen = cand[0].second;\n\n            assign[e] = chosen;\n            count[chosen]++;\n            inc[u * D + chosen]++;\n            inc[v * D + chosen]++;\n            dayImp[chosen] += impNorm[e];\n            cellCnt[chosen * C + cell]++;\n\n            for (int g : cutAdj[e]) cutCnt[g * D + chosen]++;\n        }\n\n        return assign;\n    }\n\n    State buildState(const vector<int>& assign, const vector<int>& sources) {\n        State st;\n        st.assign = assign;\n        st.count.assign(D, 0);\n        st.dayEdges.assign(D, {});\n        st.pos.assign(M, -1);\n        st.inc.assign(N * D, 0);\n        st.dayImp.assign(D, 0.0);\n        st.cellCnt.assign(D * C, 0);\n        st.cutCnt.assign(M * D, 0);\n        st.dayScore.assign(D, 0);\n        st.totalScore = 0;\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n\n            st.pos[e] = (int)st.dayEdges[d].size();\n            st.dayEdges[d].push_back(e);\n            st.count[d]++;\n\n            st.inc[edges[e].u * D + d]++;\n            st.inc[edges[e].v * D + d]++;\n            st.dayImp[d] += impNorm[e];\n            st.cellCnt[d * C + edges[e].cell]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = st.assign[e];\n            for (int g : cutAdj[e]) {\n                st.cutCnt[g * D + d]++;\n            }\n        }\n\n        for (int d = 0; d < D; d++) {\n            st.dayScore[d] = computeDayScore(st.assign, d, sources, st.count[d], true);\n            st.totalScore += st.dayScore[d];\n        }\n\n        return st;\n    }\n\n    bool isCutPair(int a, int b) const {\n        const auto& v = cutAdj[a];\n        return binary_search(v.begin(), v.end(), b);\n    }\n\n    double placeCost(const State& st, int e, int d, int removeY) {\n        bool inD = (st.assign[e] == d);\n        int u = edges[e].u;\n        int v = edges[e].v;\n\n        int cu = st.inc[u * D + d];\n        int cv = st.inc[v * D + d];\n\n        if (inD) {\n            cu--;\n            cv--;\n        }\n\n        if (removeY >= 0 && st.assign[removeY] == d) {\n            int ru = edges[removeY].u;\n            int rv = edges[removeY].v;\n            if (ru == u || rv == u) cu--;\n            if (ru == v || rv == v) cv--;\n        }\n\n        cu = max(0, cu);\n        cv = max(0, cv);\n\n        int adjCnt = cu + cv;\n\n        int cut = st.cutCnt[e * D + d];\n        if (removeY >= 0 && st.assign[removeY] == d && isCutPair(e, removeY)) cut--;\n        cut = max(0, cut);\n\n        int loc = localCellCount(st.cellCnt, d, edges[e].cell);\n        if (inD) loc--;\n\n        if (removeY >= 0 &&\n            st.assign[removeY] == d &&\n            nearCell[edges[e].cell * C + edges[removeY].cell]) {\n            loc--;\n        }\n\n        loc = max(0, loc);\n\n        double impSum = st.dayImp[d];\n        if (inD) impSum -= impNorm[e];\n        if (removeY >= 0 && st.assign[removeY] == d) impSum -= impNorm[removeY];\n        impSum = max(0.0, impSum);\n\n        double cost = 1000000.0 * cut;\n        cost += 10.0 * adjCnt;\n        cost += lowDegAddPenalty(u, cu);\n        cost += lowDegAddPenalty(v, cv);\n        cost += 1.5 * loc;\n        cost += 2.0 * impNorm[e] * (impSum / max(1, target[d]));\n\n        return cost;\n    }\n\n    double edgeBadness(const State& st, int e, int d) {\n        return placeCost(st, e, d, -1) + 0.5 * impNorm[e];\n    }\n\n    int randomNonemptyDay(const State& st, int exclude = -1) {\n        for (int t = 0; t < 50; t++) {\n            int d = rng.nextInt(D);\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n\n        for (int d = 0; d < D; d++) {\n            if (d != exclude && !st.dayEdges[d].empty()) return d;\n        }\n\n        return -1;\n    }\n\n    int argMaxDay(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n\n        for (int d = 0; d < D; d++) {\n            if (st.dayEdges[d].empty()) continue;\n\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n\n        return best;\n    }\n\n    int argMinDay(const State& st, int exclude = -1, bool requireNonempty = true) {\n        int best = -1;\n        long long val = LLONG_MAX;\n\n        for (int d = 0; d < D; d++) {\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n\n        return best;\n    }\n\n    int tournamentHigh(const State& st) {\n        int best = -1;\n        long long val = LLONG_MIN;\n\n        for (int i = 0; i < 5; i++) {\n            int d = randomNonemptyDay(st);\n            if (d == -1) continue;\n\n            if (st.dayScore[d] > val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n\n        if (best == -1) best = argMaxDay(st);\n        return best;\n    }\n\n    int tournamentLow(const State& st, int exclude, bool requireNonempty) {\n        int best = -1;\n        long long val = LLONG_MAX;\n\n        for (int i = 0; i < 5; i++) {\n            int d = rng.nextInt(D);\n            if (d == exclude) continue;\n            if (requireNonempty && st.dayEdges[d].empty()) continue;\n\n            if (st.dayScore[d] < val) {\n                val = st.dayScore[d];\n                best = d;\n            }\n        }\n\n        if (best == -1) best = argMinDay(st, exclude, requireNonempty);\n        return best;\n    }\n\n    int selectEdge(const State& st, int day, bool bad) {\n        const auto& v = st.dayEdges[day];\n        if (v.empty()) return -1;\n\n        int best = v[rng.nextInt((int)v.size())];\n        double bv = edgeBadness(st, best, day);\n\n        int samples = min(7, (int)v.size());\n\n        for (int i = 1; i < samples; i++) {\n            int e = v[rng.nextInt((int)v.size())];\n            double val = edgeBadness(st, e, day);\n\n            if ((bad && val > bv) || (!bad && val < bv)) {\n                bv = val;\n                best = e;\n            }\n        }\n\n        return best;\n    }\n\n    double cheapDeltaSwap(const State& st, int e, int f) {\n        int a = st.assign[e];\n        int b = st.assign[f];\n        if (a == b) return 1e100;\n\n        double before = placeCost(st, e, a, -1) + placeCost(st, f, b, -1);\n        double after = placeCost(st, e, b, f) + placeCost(st, f, a, e);\n\n        return after - before;\n    }\n\n    double cheapDeltaMove(const State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return 1e100;\n\n        double before = placeCost(st, e, a, -1);\n        double after = placeCost(st, e, b, -1);\n\n        return after - before;\n    }\n\n    Cand proposeSwap(const State& st) {\n        Cand best;\n        best.type = 2;\n\n        for (int t = 0; t < 14; t++) {\n            int a, b;\n            int mode = rng.nextInt(100);\n\n            if (mode < 45) {\n                a = argMaxDay(st);\n                b = argMinDay(st, a, true);\n            } else if (mode < 80) {\n                a = tournamentHigh(st);\n                b = tournamentLow(st, a, true);\n            } else {\n                a = randomNonemptyDay(st);\n                b = randomNonemptyDay(st, a);\n            }\n\n            if (a < 0 || b < 0 || a == b) continue;\n\n            int e = selectEdge(st, a, true);\n            int f = selectEdge(st, b, false);\n            if (e < 0 || f < 0) continue;\n\n            double cd = cheapDeltaSwap(st, e, f);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = f;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    Cand proposeMove(const State& st) {\n        Cand best;\n        best.type = 1;\n\n        int lowBound = max(0, M / D - 2);\n        int highBound = min(K, (M + D - 1) / D + 2);\n\n        for (int t = 0; t < 12; t++) {\n            int a = -1;\n            long long av = LLONG_MIN;\n\n            if (rng.nextInt(100) < 60) {\n                for (int d = 0; d < D; d++) {\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            } else {\n                for (int k = 0; k < 8; k++) {\n                    int d = rng.nextInt(D);\n                    if (st.count[d] <= lowBound || st.dayEdges[d].empty()) continue;\n                    if (st.dayScore[d] > av) {\n                        av = st.dayScore[d];\n                        a = d;\n                    }\n                }\n            }\n\n            if (a < 0) continue;\n\n            int b = -1;\n            long long bv = LLONG_MAX;\n\n            for (int k = 0; k < 8; k++) {\n                int d = rng.nextInt(D);\n                if (d == a) continue;\n                if (st.count[d] >= highBound || st.count[d] >= K) continue;\n\n                if (st.dayScore[d] < bv) {\n                    bv = st.dayScore[d];\n                    b = d;\n                }\n            }\n\n            if (b < 0) {\n                for (int d = 0; d < D; d++) {\n                    if (d == a) continue;\n                    if (st.count[d] >= highBound || st.count[d] >= K) continue;\n\n                    if (st.dayScore[d] < bv) {\n                        bv = st.dayScore[d];\n                        b = d;\n                    }\n                }\n            }\n\n            if (b < 0) continue;\n\n            int e = selectEdge(st, a, true);\n            if (e < 0) continue;\n\n            double cd = cheapDeltaMove(st, e, b);\n            if (cd < best.cheap) {\n                best.cheap = cd;\n                best.e = e;\n                best.f = b;\n            }\n        }\n\n        if (best.e == -1) best.type = 0;\n        return best;\n    }\n\n    bool acceptDelta(const State& st, long long delta, bool isMove) {\n        if (delta <= 0) return true;\n\n        double avg = max(1.0, st.totalScore / (double)max(1, D));\n        double prog = min(1.0, elapsed() / localEndTime);\n        double factor = isMove ? 0.004 : 0.008;\n        double T = avg * (factor * (1.0 - prog) + 0.00002);\n\n        if (T <= 1.0) return false;\n        if ((double)delta > T * 20.0) return false;\n\n        return rng.nextDouble() < exp(-(double)delta / T);\n    }\n\n    void applySwap(State& st, int e, int f, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e];\n        int pf = st.pos[f];\n\n        st.dayEdges[a][pe] = f;\n        st.dayEdges[b][pf] = e;\n        st.pos[f] = pe;\n        st.pos[e] = pf;\n\n        auto decEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]--;\n            st.inc[edges[x].v * D + d]--;\n            st.dayImp[d] -= impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]--;\n        };\n\n        auto incEdge = [&](int x, int d) {\n            st.inc[edges[x].u * D + d]++;\n            st.inc[edges[x].v * D + d]++;\n            st.dayImp[d] += impNorm[x];\n            st.cellCnt[d * C + edges[x].cell]++;\n        };\n\n        decEdge(e, a);\n        incEdge(e, b);\n        decEdge(f, b);\n        incEdge(f, a);\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n\n        for (int g : cutAdj[f]) {\n            st.cutCnt[g * D + b]--;\n            st.cutCnt[g * D + a]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    void applyMove(State& st, int e, int a, int b, long long newA, long long newB) {\n        int pe = st.pos[e];\n        int last = st.dayEdges[a].back();\n\n        st.dayEdges[a][pe] = last;\n        st.pos[last] = pe;\n        st.dayEdges[a].pop_back();\n\n        st.pos[e] = (int)st.dayEdges[b].size();\n        st.dayEdges[b].push_back(e);\n\n        st.count[a]--;\n        st.count[b]++;\n\n        st.inc[edges[e].u * D + a]--;\n        st.inc[edges[e].v * D + a]--;\n        st.inc[edges[e].u * D + b]++;\n        st.inc[edges[e].v * D + b]++;\n\n        st.dayImp[a] -= impNorm[e];\n        st.dayImp[b] += impNorm[e];\n\n        st.cellCnt[a * C + edges[e].cell]--;\n        st.cellCnt[b * C + edges[e].cell]++;\n\n        for (int g : cutAdj[e]) {\n            st.cutCnt[g * D + a]--;\n            st.cutCnt[g * D + b]++;\n        }\n\n        st.totalScore += newA + newB - st.dayScore[a] - st.dayScore[b];\n        st.dayScore[a] = newA;\n        st.dayScore[b] = newB;\n    }\n\n    bool trySwap(State& st, int e, int f) {\n        int a = st.assign[e];\n        int b = st.assign[f];\n        if (a == b) return false;\n\n        st.assign[e] = b;\n        st.assign[f] = a;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE;\n        long long newB = DISCONN_SCORE;\n\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a], false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b], false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, false);\n\n        if (acc) {\n            applySwap(st, e, f, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            st.assign[f] = b;\n            return false;\n        }\n    }\n\n    bool tryMove(State& st, int e, int b) {\n        int a = st.assign[e];\n        if (a == b) return false;\n        if (st.count[b] >= K) return false;\n\n        st.assign[e] = b;\n\n        bool ok = isConnectedSkip(st.assign, a, -1) && isConnectedSkip(st.assign, b, -1);\n\n        long long newA = DISCONN_SCORE;\n        long long newB = DISCONN_SCORE;\n\n        if (ok) {\n            newA = computeDayScore(st.assign, a, optSources, st.count[a] - 1, false);\n            newB = computeDayScore(st.assign, b, optSources, st.count[b] + 1, false);\n        }\n\n        long long delta = newA + newB - st.dayScore[a] - st.dayScore[b];\n        bool acc = ok && acceptDelta(st, delta, true);\n\n        if (acc) {\n            applyMove(st, e, a, b, newA, newB);\n            return true;\n        } else {\n            st.assign[e] = a;\n            return false;\n        }\n    }\n\n    void ensureLegal(vector<int>& assign) {\n        vector<int> cnt(D, 0);\n\n        for (int e = 0; e < M; e++) {\n            if (assign[e] < 0 || assign[e] >= D) assign[e] = 0;\n            cnt[assign[e]]++;\n        }\n\n        for (int e = 0; e < M; e++) {\n            int d = assign[e];\n            if (cnt[d] <= K) continue;\n\n            int b = -1;\n            for (int j = 0; j < D; j++) {\n                if (cnt[j] < K) {\n                    b = j;\n                    break;\n                }\n            }\n\n            if (b == -1) break;\n\n            cnt[d]--;\n            assign[e] = b;\n            cnt[b]++;\n        }\n    }\n\n    void solve() {\n        startTime = chrono::steady_clock::now();\n\n        readInput();\n\n        computeOriginalAndLoad();\n        detectTwoEdgeCuts();\n        computeStretch();\n        computeImportance();\n\n        int P = 24;\n        if (D <= 10) P += 8;\n        else if (D <= 18) P += 4;\n        if (M <= 1200) P += 8;\n        else if (M <= 2000) P += 4;\n        if (N <= 700) P += 4;\n        P = min({P, N, 52});\n\n        optSources = selectSources(P);\n\n        vector<int> bestAssign;\n        long long bestScore = LLONG_MAX;\n\n        auto consider = [&](const vector<int>& assign) {\n            ScoreRes sc = scoreAll(assign, optSources);\n            if (sc.total < bestScore) {\n                bestScore = sc.total;\n                bestAssign = assign;\n            }\n        };\n\n        consider(buildHilbertLike(0));\n        consider(buildGreedy(0));\n\n        const double initDeadline = 2.25;\n\n        if (elapsed() < initDeadline) consider(buildGreedy(1));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(1));\n        if (elapsed() < initDeadline) consider(buildGreedy(2));\n        if (elapsed() < initDeadline) consider(buildHilbertLike(2));\n        if (elapsed() < initDeadline) consider(buildGreedy(4));\n        if (elapsed() < initDeadline) consider(buildRandomBalanced());\n\n        if (bestAssign.empty()) bestAssign = buildRandomBalanced();\n\n        State st = buildState(bestAssign, optSources);\n\n        vector<int> bestLocal = st.assign;\n        long long bestLocalScore = st.totalScore;\n\n        localEndTime = 5.65;\n\n        while (elapsed() < localEndTime) {\n            Cand cand;\n\n            if (rng.nextInt(100) < 18) cand = proposeMove(st);\n            if (cand.type == 0) cand = proposeSwap(st);\n\n            bool accepted = false;\n\n            if (cand.type == 1) {\n                accepted = tryMove(st, cand.e, cand.f);\n            } else if (cand.type == 2) {\n                accepted = trySwap(st, cand.e, cand.f);\n            }\n\n            if (accepted && st.totalScore < bestLocalScore) {\n                bestLocalScore = st.totalScore;\n                bestLocal = st.assign;\n            }\n        }\n\n        ensureLegal(bestLocal);\n\n        for (int i = 0; i < M; i++) {\n            if (i) cout << ' ';\n            cout << bestLocal[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\n    return 0;\n}","ahc019":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    struct I3 { short x, y, z; };\n    struct Rot { int perm[3]; int sign[3]; };\n    struct Transform { bool valid=false; int ori=0, tx=0, ty=0, tz=0; };\n    struct AlignCand { long long key; int ori, tid, cnt, w; };\n    struct AlignMinCmp { bool operator()(const AlignCand& a,const AlignCand& b) const { return a.key>b.key; } };\n    struct CompCand {\n        bool valid=false; double score=-1e100; int size=0,cov=0;\n        int ori=0,tx=0,ty=0,tz=0; vector<int> cells;\n    };\n    struct Box {\n        int x=0,y=0,z=0,lx=0,ly=0,lz=0,cov=-1,vol=0; bool valid=false;\n    };\n    struct BoxCand {\n        bool valid=false; Box b0,b1; int vol=0,cov=0; double score=-1;\n    };\n    struct Bar {\n        int x=0,y=0,z=0,dir=0,len=0,cov=0; bool valid=false;\n        array<int,15> nf{}, nr{};\n    };\n    struct BarCand {\n        bool valid=false; Bar b0,b1; int len=0,cov=0; double score=-1e100;\n    };\n    struct SimpleBox {\n        int x=0,y=0,z=0,lx=0,ly=0,lz=0,vol=0; bool valid=false;\n    };\n    struct PoolBoxCand {\n        bool valid=false; SimpleBox b0,b1; int vol=0;\n    };\n    struct PoolCompCand {\n        bool valid=false; double gain=-1e100; int size=0,core0=0,core1=0;\n        int ori=0,tx=0,ty=0,tz=0; vector<int> cells;\n    };\n\n    int D,D2,N,rangeT,offsetT,Tcnt;\n    array<vector<string>,2> F,Rt;\n    array<vector<char>,2> allowed,rem,covF,covR;\n    array<vector<int>,2> ans;\n    array<vector<unsigned char>,2> aw;\n    vector<int> xs,ys,zs;\n    vector<array<int,6>> neigh;\n    vector<Rot> rots;\n    vector<vector<I3>> rotp;\n    int unF[2][15], unR[2][15];\n    int allowedCount[2]={0,0}, remCnt[2]={0,0};\n    int minAllowed=0,totalUncov=0,label=0;\n    int commonVol=0,uniqueVol[2]={0,0};\n    double commonCost=0.0;\n    vector<int> cnt,wcnt,mark,vis,qmap;\n    int markToken=1,visToken=1;\n    array<vector<int>,2> tmpF,tmpR;\n    int pixToken=1;\n    vector<int> startTid,curTid,entries;\n    array<vector<vector<int>>,2> blk;\n    vector<char> activeLab;\n    chrono::steady_clock::time_point startTime;\n\n    Solver(int D_, const array<vector<string>,2>& F_, const array<vector<string>,2>& Rt_)\n        : D(D_), F(F_), Rt(Rt_) {\n        D2=D*D; N=D*D*D;\n        rangeT=3*D-2; offsetT=D-1; Tcnt=rangeT*rangeT*rangeT;\n        memset(unF,0,sizeof(unF)); memset(unR,0,sizeof(unR));\n\n        for(int s=0;s<2;s++){\n            allowed[s].assign(N,0); rem[s].assign(N,0);\n            covF[s].assign(D2,0); covR[s].assign(D2,0);\n            ans[s].assign(N,0); aw[s].assign(N,0);\n            tmpF[s].assign(D2,0); tmpR[s].assign(D2,0);\n        }\n\n        xs.resize(N); ys.resize(N); zs.resize(N); neigh.resize(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 v=id(x,y,z); xs[v]=x; ys[v]=y; zs[v]=z;\n        }\n        for(int v=0;v<N;v++){\n            int x=xs[v],y=ys[v],z=zs[v];\n            array<int,6> nb; nb.fill(-1);\n            if(x>0) nb[0]=id(x-1,y,z);\n            if(x+1<D) nb[1]=id(x+1,y,z);\n            if(y>0) nb[2]=id(x,y-1,z);\n            if(y+1<D) nb[3]=id(x,y+1,z);\n            if(z>0) nb[4]=id(x,y,z-1);\n            if(z+1<D) nb[5]=id(x,y,z+1);\n            neigh[v]=nb;\n        }\n\n        for(int s=0;s<2;s++){\n            for(int z=0;z<D;z++){\n                for(int x=0;x<D;x++) if(F[s][z][x]=='1'){\n                    unF[s][z]++; totalUncov++;\n                }\n                for(int y=0;y<D;y++) if(Rt[s][z][y]=='1'){\n                    unR[s][z]++; totalUncov++;\n                }\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(F[s][z][x]=='1' && Rt[s][z][y]=='1'){\n                    int v=id(x,y,z);\n                    allowed[s][v]=1; rem[s][v]=1; allowedCount[s]++;\n                }\n            }\n            remCnt[s]=allowedCount[s];\n        }\n        minAllowed=min(allowedCount[0],allowedCount[1]);\n\n        generateRotations();\n        rotp.assign(rots.size(), vector<I3>(N));\n        for(int ri=0;ri<(int)rots.size();ri++){\n            for(int v=0;v<N;v++){\n                int p[3]={xs[v],ys[v],zs[v]}, q[3];\n                for(int a=0;a<3;a++) q[a]=rots[ri].sign[a]*p[rots[ri].perm[a]];\n                rotp[ri][v]=I3{(short)q[0],(short)q[1],(short)q[2]};\n            }\n        }\n\n        cnt.assign(Tcnt,0); wcnt.assign(Tcnt,0);\n        startTid.assign(Tcnt,0); curTid.assign(Tcnt,0);\n        mark.assign(N,0); vis.assign(N,0); qmap.assign(N,-1);\n    }\n\n    inline int id(int x,int y,int z) const { return (x*D+y)*D+z; }\n    double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now()-startTime).count();\n    }\n\n    void generateRotations(){\n        array<int,3> p={0,1,2};\n        sort(p.begin(),p.end());\n        do{\n            int inv=0;\n            for(int i=0;i<3;i++) for(int j=i+1;j<3;j++) if(p[i]>p[j]) inv++;\n            int parity=(inv%2==0?1:-1);\n            for(int sx:{-1,1}) for(int sy:{-1,1}) for(int sz:{-1,1}){\n                if(parity*sx*sy*sz==1){\n                    Rot r;\n                    r.perm[0]=p[0]; r.perm[1]=p[1]; r.perm[2]=p[2];\n                    r.sign[0]=sx; r.sign[1]=sy; r.sign[2]=sz;\n                    rots.push_back(r);\n                }\n            }\n        }while(next_permutation(p.begin(),p.end()));\n    }\n\n    inline int activeWeight(int s,int v) const {\n        int z=zs[v],x=xs[v],y=ys[v],w=0;\n        if(!covF[s][z*D+x]) w++;\n        if(!covR[s][z*D+y]) w++;\n        return w;\n    }\n\n    void coverCell(int s,int v){\n        int z=zs[v],x=xs[v],y=ys[v];\n        int fid=z*D+x, rid=z*D+y;\n        if(F[s][z][x]=='1' && !covF[s][fid]){\n            covF[s][fid]=1; unF[s][z]--; totalUncov--;\n        }\n        if(Rt[s][z][y]=='1' && !covR[s][rid]){\n            covR[s][rid]=1; unR[s][z]--; totalUncov--;\n        }\n    }\n\n    int calcLBNow(int s) const {\n        int res=0;\n        for(int z=0;z<D;z++) res+=max(unF[s][z],unR[s][z]);\n        return res;\n    }\n\n    int currentDeficit() const {\n        return max(0, max(calcLBNow(0),calcLBNow(1))-min(remCnt[0],remCnt[1]));\n    }\n\n    int calcLBAfter(int s,const int* nf,const int* nr) const {\n        int res=0;\n        for(int z=0;z<D;z++){\n            int a=unF[s][z]-nf[z], b=unR[s][z]-nr[z];\n            if(a<0) a=0; if(b<0) b=0;\n            res+=max(a,b);\n        }\n        return res;\n    }\n\n    void decodeTid(int tid,int& tx,int& ty,int& tz) const {\n        tz=tid%rangeT; tid/=rangeT;\n        ty=tid%rangeT; tx=tid/rangeT;\n        tx-=offsetT; ty-=offsetT; tz-=offsetT;\n    }\n\n    void evalAlignment(int ori,int tid,const vector<int>& list0,CompCand& best){\n        int tx,ty,tz; decodeTid(tid,tx,ty,tz);\n        int mt=++markToken, inter=0;\n        for(int p:list0){\n            I3 rp=rotp[ori][p];\n            int qx=rp.x+tx, qy=rp.y+ty, qz=rp.z+tz;\n            if(0<=qx&&qx<D&&0<=qy&&qy<D&&0<=qz&&qz<D){\n                int q=id(qx,qy,qz);\n                if(rem[1][q]){ mark[p]=mt; qmap[p]=q; inter++; }\n            }\n        }\n        if(!inter) return;\n\n        int vt=++visToken;\n        vector<int> que,comp; que.reserve(inter); comp.reserve(inter);\n        int curDef=currentDeficit();\n\n        for(int st:list0){\n            if(mark[st]!=mt || vis[st]==vt) continue;\n            que.clear(); comp.clear();\n            que.push_back(st); vis[st]=vt;\n            for(int head=0;head<(int)que.size();head++){\n                int v=que[head]; comp.push_back(v);\n                for(int nb:neigh[v]) if(nb>=0 && mark[nb]==mt && vis[nb]!=vt){\n                    vis[nb]=vt; que.push_back(nb);\n                }\n            }\n\n            int sz=(int)comp.size();\n            int token=++pixToken;\n            int nf0[15]={},nr0[15]={},nf1[15]={},nr1[15]={};\n            int cov0=0,cov1=0;\n\n            auto addPixel=[&](int s,int v,int* nf,int* nr,int& cov){\n                int z=zs[v],x=xs[v],y=ys[v];\n                int fid=z*D+x, rid=z*D+y;\n                if(F[s][z][x]=='1' && !covF[s][fid] && tmpF[s][fid]!=token){\n                    tmpF[s][fid]=token; nf[z]++; cov++;\n                }\n                if(Rt[s][z][y]=='1' && !covR[s][rid] && tmpR[s][rid]!=token){\n                    tmpR[s][rid]=token; nr[z]++; cov++;\n                }\n            };\n\n            for(int v:comp){\n                addPixel(0,v,nf0,nr0,cov0);\n                addPixel(1,qmap[v],nf1,nr1,cov1);\n            }\n\n            int cov=cov0+cov1;\n            if(!cov) continue;\n\n            int lb0=calcLBAfter(0,nf0,nr0);\n            int lb1=calcLBAfter(1,nf1,nr1);\n            int remCap=min(remCnt[0],remCnt[1])-sz;\n            int def=max(0,max(lb0,lb1)-remCap);\n            int incDef=max(0,def-curDef);\n\n            double score=(double)cov*sz/(1.0+0.18*incDef);\n            if(!best.valid || score>best.score || (abs(score-best.score)<1e-9 && sz>best.size)){\n                best.valid=true; best.score=score; best.size=sz; best.cov=cov;\n                best.ori=ori; best.tx=tx; best.ty=ty; best.tz=tz; best.cells=comp;\n            }\n        }\n    }\n\n    CompCand findBestComponent(int topK,double timeLimit){\n        CompCand best;\n        vector<int> list0,list1; list0.reserve(N); list1.reserve(N);\n        for(int v=0;v<N;v++){\n            if(rem[0][v]) list0.push_back(v);\n            if(rem[1][v]) list1.push_back(v);\n        }\n        if(list0.empty()||list1.empty()) return best;\n\n        for(int v:list0) aw[0][v]=(unsigned char)activeWeight(0,v);\n        for(int v:list1) aw[1][v]=(unsigned char)activeWeight(1,v);\n\n        int n1=(int)list1.size();\n        vector<short> qx(n1),qy(n1),qz(n1);\n        vector<unsigned char> qaw(n1);\n        for(int i=0;i<n1;i++){\n            int v=list1[i];\n            qx[i]=xs[v]; qy[i]=ys[v]; qz[i]=zs[v]; qaw[i]=aw[1][v];\n        }\n\n        priority_queue<AlignCand,vector<AlignCand>,AlignMinCmp> pq1,pq2;\n        auto consider=[&](auto& pq,const AlignCand& a){\n            if((int)pq.size()<topK) pq.push(a);\n            else if(a.key>pq.top().key){ pq.pop(); pq.push(a); }\n        };\n\n        for(int oi=0;oi<(int)rots.size();oi++){\n            fill(cnt.begin(),cnt.end(),0);\n            fill(wcnt.begin(),wcnt.end(),0);\n\n            for(int p:list0){\n                I3 rp=rotp[oi][p];\n                int awp=aw[0][p];\n                for(int j=0;j<n1;j++){\n                    int tx=qx[j]-rp.x+offsetT;\n                    int ty=qy[j]-rp.y+offsetT;\n                    int tz=qz[j]-rp.z+offsetT;\n                    int tid=(tx*rangeT+ty)*rangeT+tz;\n                    cnt[tid]++;\n                    wcnt[tid]+=awp+qaw[j];\n                }\n            }\n\n            for(int tid=0;tid<Tcnt;tid++){\n                if(!wcnt[tid]) continue;\n                int c=cnt[tid], w=wcnt[tid];\n                consider(pq1,AlignCand{1LL*c*(w+1),oi,tid,c,w});\n                consider(pq2,AlignCand{1LL*c*c,oi,tid,c,w});\n            }\n            if(elapsed()>timeLimit) break;\n        }\n\n        vector<AlignCand> aligns;\n        while(!pq1.empty()){ aligns.push_back(pq1.top()); pq1.pop(); }\n        while(!pq2.empty()){ aligns.push_back(pq2.top()); pq2.pop(); }\n        sort(aligns.begin(),aligns.end(),[](const AlignCand& a,const AlignCand& b){ return a.key>b.key; });\n\n        unordered_set<long long> seen;\n        seen.reserve(aligns.size()*2+1);\n        int evalCnt=0;\n        for(const auto& a:aligns){\n            long long code=1LL*a.ori*Tcnt+a.tid;\n            if(!seen.insert(code).second) continue;\n            evalAlignment(a.ori,a.tid,list0,best);\n            evalCnt++;\n            if(evalCnt>=topK) break;\n            if(elapsed()>timeLimit) break;\n        }\n        return best;\n    }\n\n    void evalBucketAlignment(int ori,int tid,int l,int r,int minSize,int oldNeed,CompCand& best){\n        if(r-l<minSize) return;\n        int tx,ty,tz; decodeTid(tid,tx,ty,tz);\n        int mt=++markToken;\n        for(int idx=l;idx<r;idx++){\n            int p=entries[idx];\n            I3 rp=rotp[ori][p];\n            mark[p]=mt;\n            qmap[p]=id(rp.x+tx,rp.y+ty,rp.z+tz);\n        }\n\n        int vt=++visToken;\n        vector<int> que,comp; que.reserve(r-l); comp.reserve(r-l);\n        int curDef=currentDeficit();\n\n        for(int idx=l;idx<r;idx++){\n            int st=entries[idx];\n            if(vis[st]==vt) continue;\n            que.clear(); comp.clear();\n            que.push_back(st); vis[st]=vt;\n            for(int head=0;head<(int)que.size();head++){\n                int v=que[head]; comp.push_back(v);\n                for(int nb:neigh[v]) if(nb>=0 && mark[nb]==mt && vis[nb]!=vt){\n                    vis[nb]=vt; que.push_back(nb);\n                }\n            }\n\n            int sz=(int)comp.size();\n            if(sz<minSize) continue;\n\n            int token=++pixToken;\n            int nf0[15]={},nr0[15]={},nf1[15]={},nr1[15]={};\n            int cov0=0,cov1=0;\n\n            auto addPixel=[&](int s,int v,int* nf,int* nr,int& cov){\n                int z=zs[v],x=xs[v],y=ys[v];\n                int fid=z*D+x, rid=z*D+y;\n                if(F[s][z][x]=='1' && !covF[s][fid] && tmpF[s][fid]!=token){\n                    tmpF[s][fid]=token; nf[z]++; cov++;\n                }\n                if(Rt[s][z][y]=='1' && !covR[s][rid] && tmpR[s][rid]!=token){\n                    tmpR[s][rid]=token; nr[z]++; cov++;\n                }\n            };\n\n            for(int v:comp){\n                addPixel(0,v,nf0,nr0,cov0);\n                addPixel(1,qmap[v],nf1,nr1,cov1);\n            }\n\n            int cov=cov0+cov1;\n            if(!cov) continue;\n\n            int lb0=calcLBAfter(0,nf0,nr0);\n            int lb1=calcLBAfter(1,nf1,nr1);\n            int newNeed=max(lb0,lb1);\n            int gainNeed=max(0,oldNeed-newNeed);\n            int cap=min(remCnt[0],remCnt[1])-sz;\n            int def=max(0,newNeed-cap);\n            int incDef=max(0,def-curDef);\n\n            double score=10.0*gainNeed + cov + 0.7*log((double)sz+1.0)\n                         +0.3*(1.0-1.0/sz) -4.0*incDef +0.0001*sz;\n\n            if(!best.valid || score>best.score || (abs(score-best.score)<1e-9 && sz>best.size)){\n                best.valid=true; best.score=score; best.size=sz; best.cov=cov;\n                best.ori=ori; best.tx=tx; best.ty=ty; best.tz=tz; best.cells=comp;\n            }\n        }\n    }\n\n    CompCand findBestComponentExhaustive(double deadline,int minSize){\n        CompCand best;\n        vector<int> list0,list1; list0.reserve(N); list1.reserve(N);\n        for(int v=0;v<N;v++){\n            if(rem[0][v]) list0.push_back(v);\n            if(rem[1][v]) list1.push_back(v);\n        }\n        if((int)list0.size()<minSize || (int)list1.size()<minSize) return best;\n\n        for(int v:list0) aw[0][v]=(unsigned char)activeWeight(0,v);\n        for(int v:list1) aw[1][v]=(unsigned char)activeWeight(1,v);\n\n        int n1=(int)list1.size();\n        vector<short> qx(n1),qy(n1),qz(n1);\n        vector<unsigned char> qaw(n1);\n        for(int i=0;i<n1;i++){\n            int v=list1[i];\n            qx[i]=xs[v]; qy[i]=ys[v]; qz[i]=zs[v]; qaw[i]=aw[1][v];\n        }\n\n        int oldNeed=max(calcLBNow(0),calcLBNow(1));\n        vector<int> activeTids; activeTids.reserve(Tcnt);\n\n        for(int oi=0;oi<(int)rots.size();oi++){\n            if(elapsed()>deadline) break;\n            fill(cnt.begin(),cnt.end(),0);\n            fill(wcnt.begin(),wcnt.end(),0);\n            activeTids.clear();\n\n            for(int p:list0){\n                I3 rp=rotp[oi][p];\n                int bx=offsetT-rp.x, by=offsetT-rp.y, bz=offsetT-rp.z;\n                int awp=aw[0][p];\n                for(int j=0;j<n1;j++){\n                    int tid=((qx[j]+bx)*rangeT+(qy[j]+by))*rangeT+(qz[j]+bz);\n                    if(cnt[tid]==0) activeTids.push_back(tid);\n                    cnt[tid]++;\n                    wcnt[tid]+=awp+qaw[j];\n                }\n            }\n\n            int total=0;\n            for(int tid:activeTids){\n                startTid[tid]=total;\n                curTid[tid]=total;\n                total+=cnt[tid];\n            }\n            entries.resize(total);\n\n            for(int p:list0){\n                I3 rp=rotp[oi][p];\n                int bx=offsetT-rp.x, by=offsetT-rp.y, bz=offsetT-rp.z;\n                for(int j=0;j<n1;j++){\n                    int tid=((qx[j]+bx)*rangeT+(qy[j]+by))*rangeT+(qz[j]+bz);\n                    entries[curTid[tid]++]=p;\n                }\n            }\n\n            for(int tid:activeTids){\n                if(wcnt[tid]==0 || cnt[tid]<minSize) continue;\n                evalBucketAlignment(oi,tid,startTid[tid],startTid[tid]+cnt[tid],minSize,oldNeed,best);\n                if(elapsed()>deadline) break;\n            }\n        }\n        return best;\n    }\n\n    void placeCommonMapped(const CompCand& c){\n        int lab=++label;\n        int sz=(int)c.cells.size();\n        for(int p:c.cells){\n            I3 rp=rotp[c.ori][p];\n            int q=id(rp.x+c.tx,rp.y+c.ty,rp.z+c.tz);\n\n            ans[0][p]=lab; rem[0][p]=0; coverCell(0,p);\n            ans[1][q]=lab; rem[1][q]=0; coverCell(1,q);\n        }\n        remCnt[0]-=sz; remCnt[1]-=sz;\n        commonVol+=sz; commonCost+=1.0/sz;\n    }\n\n    inline int p3id(int x,int y,int z) const {\n        int P=D+1; return (x*P+y)*P+z;\n    }\n    inline int p2id(int a,int b) const {\n        int P=D+1; return a*P+b;\n    }\n\n    int query3(const vector<int>& ps,int x0,int x1,int y0,int y1,int z0,int z1) const {\n        return ps[p3id(x1,y1,z1)]\n             - ps[p3id(x0,y1,z1)]\n             - ps[p3id(x1,y0,z1)]\n             - ps[p3id(x1,y1,z0)]\n             + ps[p3id(x0,y0,z1)]\n             + ps[p3id(x0,y1,z0)]\n             + ps[p3id(x1,y0,z0)]\n             - ps[p3id(x0,y0,z0)];\n    }\n\n    int query2(const vector<int>& ps,int a0,int a1,int b0,int b1) const {\n        return ps[p2id(a1,b1)] - ps[p2id(a0,b1)] - ps[p2id(a1,b0)] + ps[p2id(a0,b0)];\n    }\n\n    void buildPrefix3(int s,vector<int>& ps){\n        int P=D+1;\n        ps.assign(P*P*P,0);\n        for(int x=1;x<=D;x++) for(int y=1;y<=D;y++) for(int z=1;z<=D;z++){\n            int val=rem[s][id(x-1,y-1,z-1)]?1:0;\n            ps[p3id(x,y,z)] =\n                val + ps[p3id(x-1,y,z)] + ps[p3id(x,y-1,z)] + ps[p3id(x,y,z-1)]\n                - ps[p3id(x-1,y-1,z)] - ps[p3id(x-1,y,z-1)] - ps[p3id(x,y-1,z-1)]\n                + ps[p3id(x-1,y-1,z-1)];\n        }\n    }\n\n    void buildPrefix2F(int s,vector<int>& ps){\n        int P=D+1;\n        ps.assign(P*P,0);\n        for(int z=1;z<=D;z++) for(int x=1;x<=D;x++){\n            int val=(F[s][z-1][x-1]=='1' && !covF[s][(z-1)*D+(x-1)])?1:0;\n            ps[p2id(z,x)]=val+ps[p2id(z-1,x)]+ps[p2id(z,x-1)]-ps[p2id(z-1,x-1)];\n        }\n    }\n\n    void buildPrefix2R(int s,vector<int>& ps){\n        int P=D+1;\n        ps.assign(P*P,0);\n        for(int z=1;z<=D;z++) for(int y=1;y<=D;y++){\n            int val=(Rt[s][z-1][y-1]=='1' && !covR[s][(z-1)*D+(y-1)])?1:0;\n            ps[p2id(z,y)]=val+ps[p2id(z-1,y)]+ps[p2id(z,y-1)]-ps[p2id(z-1,y-1)];\n        }\n    }\n\n    int shapeKey(int a,int b,int c) const {\n        if(a>b) swap(a,b);\n        if(b>c) swap(b,c);\n        if(a>b) swap(a,b);\n        return (a*15+b)*15+c;\n    }\n\n    void enumerateBoxesSide(int s,vector<Box>& best,double timeLimit){\n        vector<int> ps3,psF,psR;\n        buildPrefix3(s,ps3);\n        buildPrefix2F(s,psF);\n        buildPrefix2R(s,psR);\n\n        for(int x0=0;x0<D;x0++){\n            if(elapsed()>timeLimit) return;\n            for(int x1=x0+1;x1<=D;x1++){\n                int lx=x1-x0;\n                for(int y0=0;y0<D;y0++) for(int y1=y0+1;y1<=D;y1++){\n                    int ly=y1-y0;\n                    for(int z0=0;z0<D;z0++) for(int z1=z0+1;z1<=D;z1++){\n                        int lz=z1-z0, vol=lx*ly*lz;\n                        if(vol<2) continue;\n                        if(query3(ps3,x0,x1,y0,y1,z0,z1)!=vol) continue;\n\n                        int cov=query2(psF,z0,z1,x0,x1)+query2(psR,z0,z1,y0,y1);\n                        int key=shapeKey(lx,ly,lz);\n                        if(!best[key].valid || cov>best[key].cov){\n                            Box b;\n                            b.x=x0; b.y=y0; b.z=z0;\n                            b.lx=lx; b.ly=ly; b.lz=lz;\n                            b.cov=cov; b.vol=vol; b.valid=true;\n                            best[key]=b;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    BoxCand findBestCuboid(double timeLimit){\n        const int KEY=15*15*15;\n        vector<Box> best0(KEY),best1(KEY);\n        enumerateBoxesSide(0,best0,timeLimit);\n        if(elapsed()>timeLimit) return BoxCand();\n        enumerateBoxesSide(1,best1,timeLimit);\n\n        BoxCand res;\n        for(int k=0;k<KEY;k++){\n            if(!best0[k].valid || !best1[k].valid) continue;\n            int cov=best0[k].cov+best1[k].cov;\n            if(cov<=0) continue;\n            int vol=best0[k].vol;\n            double score=(double)cov*vol;\n            if(!res.valid || score>res.score || (abs(score-res.score)<1e-9 && vol>res.vol)){\n                res.valid=true; res.b0=best0[k]; res.b1=best1[k];\n                res.vol=vol; res.cov=cov; res.score=score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBox(const Box& b0,const Box& b1){\n        int lab=++label, vol=b0.vol;\n        auto put=[&](int s,const Box& b){\n            for(int x=b.x;x<b.x+b.lx;x++) for(int y=b.y;y<b.y+b.ly;y++) for(int z=b.z;z<b.z+b.lz;z++){\n                int v=id(x,y,z);\n                ans[s][v]=lab; rem[s][v]=0; coverCell(s,v);\n            }\n        };\n        put(0,b0); put(1,b1);\n        remCnt[0]-=vol; remCnt[1]-=vol;\n        commonVol+=vol; commonCost+=1.0/vol;\n    }\n\n    void considerBar(vector<Bar>& best,const Bar& b){\n        if(b.len<2 || b.cov<=0) return;\n        if(!best[b.len].valid || b.cov>best[b.len].cov) best[b.len]=b;\n    }\n\n    void enumerateBarsSide(int s,vector<Bar>& best,double deadline){\n        for(int z=0;z<D;z++) for(int y=0;y<D;y++) for(int x0=0;x0<D;x0++){\n            if(elapsed()>deadline) return;\n            if(!rem[s][id(x0,y,z)]) continue;\n            Bar b; b.x=x0; b.y=y; b.z=z; b.dir=0; b.nf.fill(0); b.nr.fill(0);\n            int cov=0;\n            if(!covR[s][z*D+y]){ b.nr[z]=1; cov++; }\n            for(int x=x0;x<D && rem[s][id(x,y,z)];x++){\n                if(!covF[s][z*D+x]){ b.nf[z]++; cov++; }\n                b.len=x-x0+1; b.cov=cov; b.valid=true;\n                considerBar(best,b);\n            }\n        }\n\n        for(int z=0;z<D;z++) for(int x=0;x<D;x++) for(int y0=0;y0<D;y0++){\n            if(elapsed()>deadline) return;\n            if(!rem[s][id(x,y0,z)]) continue;\n            Bar b; b.x=x; b.y=y0; b.z=z; b.dir=1; b.nf.fill(0); b.nr.fill(0);\n            int cov=0;\n            if(!covF[s][z*D+x]){ b.nf[z]=1; cov++; }\n            for(int y=y0;y<D && rem[s][id(x,y,z)];y++){\n                if(!covR[s][z*D+y]){ b.nr[z]++; cov++; }\n                b.len=y-y0+1; b.cov=cov; b.valid=true;\n                considerBar(best,b);\n            }\n        }\n\n        for(int x=0;x<D;x++) for(int y=0;y<D;y++) for(int z0=0;z0<D;z0++){\n            if(elapsed()>deadline) return;\n            if(!rem[s][id(x,y,z0)]) continue;\n            Bar b; b.x=x; b.y=y; b.z=z0; b.dir=2; b.nf.fill(0); b.nr.fill(0);\n            int cov=0;\n            for(int z=z0;z<D && rem[s][id(x,y,z)];z++){\n                if(!covF[s][z*D+x]){ b.nf[z]++; cov++; }\n                if(!covR[s][z*D+y]){ b.nr[z]++; cov++; }\n                b.len=z-z0+1; b.cov=cov; b.valid=true;\n                considerBar(best,b);\n            }\n        }\n    }\n\n    BarCand findBestBar(double deadline){\n        vector<Bar> best0(D+1),best1(D+1);\n        enumerateBarsSide(0,best0,deadline);\n        if(elapsed()>deadline) return BarCand();\n        enumerateBarsSide(1,best1,deadline);\n\n        BarCand res;\n        int curDef=currentDeficit();\n\n        for(int L=2;L<=D;L++){\n            if(!best0[L].valid || !best1[L].valid) continue;\n            int cov=best0[L].cov+best1[L].cov;\n            if(cov<=0) continue;\n\n            int lb0=calcLBAfter(0,best0[L].nf.data(),best0[L].nr.data());\n            int lb1=calcLBAfter(1,best1[L].nf.data(),best1[L].nr.data());\n            int newDef=max(0,max(lb0,lb1)-(min(remCnt[0],remCnt[1])-L));\n            int incDef=max(0,newDef-curDef);\n            if(incDef>0) continue;\n\n            double score=(double)cov*L+0.05*L;\n            if(!res.valid || score>res.score){\n                res.valid=true; res.b0=best0[L]; res.b1=best1[L];\n                res.len=L; res.cov=cov; res.score=score;\n            }\n        }\n        return res;\n    }\n\n    void placeCommonBar(const Bar& b0,const Bar& b1){\n        int lab=++label, len=b0.len;\n        auto put=[&](int s,const Bar& b){\n            for(int t=0;t<b.len;t++){\n                int x=b.x+(b.dir==0?t:0);\n                int y=b.y+(b.dir==1?t:0);\n                int z=b.z+(b.dir==2?t:0);\n                int v=id(x,y,z);\n                ans[s][v]=lab; rem[s][v]=0; coverCell(s,v);\n            }\n        };\n        put(0,b0); put(1,b1);\n        remCnt[0]-=len; remCnt[1]-=len;\n        commonVol+=len; commonCost+=1.0/len;\n    }\n\n    int findBestCell(int s,bool needActive) const {\n        int best=-1, bestW=needActive?0:100;\n        for(int v=0;v<N;v++){\n            if(!rem[s][v]) continue;\n            int w=activeWeight(s,v);\n            if(needActive){\n                if(w>bestW){ bestW=w; best=v; }\n            }else{\n                if(best==-1 || w<bestW){ bestW=w; best=v; }\n            }\n        }\n        return best;\n    }\n\n    void placeCommonUnit(int a,int b){\n        int lab=++label;\n        ans[0][a]=lab; rem[0][a]=0; coverCell(0,a);\n        ans[1][b]=lab; rem[1][b]=0; coverCell(1,b);\n        remCnt[0]--; remCnt[1]--;\n        commonVol++; commonCost+=1.0;\n    }\n\n    bool placeUniqueCell(int s,int v){\n        if(v<0 || !rem[s][v]) return false;\n        int lab=++label;\n        ans[s][v]=lab; rem[s][v]=0; coverCell(s,v);\n        remCnt[s]--; uniqueVol[s]++;\n        return true;\n    }\n\n    void placeCommonUnits(){\n        while(totalUncov>0){\n            int a0=findBestCell(0,true);\n            int a1=findBestCell(1,true);\n            if(a0==-1 && a1==-1) break;\n\n            if(a0!=-1 && a1!=-1) placeCommonUnit(a0,a1);\n            else if(a0!=-1){\n                int b=findBestCell(1,false);\n                if(b==-1) break;\n                placeCommonUnit(a0,b);\n            }else{\n                int a=findBestCell(0,false);\n                if(a==-1) break;\n                placeCommonUnit(a,a1);\n            }\n        }\n    }\n\n    int sideUncovered(int s) const {\n        int res=0;\n        for(int z=0;z<D;z++) res+=unF[s][z]+unR[s][z];\n        return res;\n    }\n\n    int chooseCell(int s,int z,int x,int y) const {\n        if(x>=0 && y>=0){\n            int v=id(x,y,z);\n            if(rem[s][v]) return v;\n        }\n        if(x>=0){\n            for(int yy=0;yy<D;yy++) if(Rt[s][z][yy]=='1'){\n                int v=id(x,yy,z);\n                if(rem[s][v]) return v;\n            }\n        }\n        if(y>=0){\n            for(int xx=0;xx<D;xx++) if(F[s][z][xx]=='1'){\n                int v=id(xx,y,z);\n                if(rem[s][v]) return v;\n            }\n        }\n        for(int xx=0;xx<D;xx++){\n            if(F[s][z][xx]!='1') continue;\n            for(int yy=0;yy<D;yy++){\n                if(Rt[s][z][yy]!='1') continue;\n                int v=id(xx,yy,z);\n                if(rem[s][v]) return v;\n            }\n        }\n        return -1;\n    }\n\n    void fillUnique(int s){\n        int guard=0;\n        while(sideUncovered(s)>0 && guard++<1000){\n            bool progress=false;\n            for(int z=0;z<D;z++){\n                vector<int> X,Y;\n                for(int x=0;x<D;x++) if(F[s][z][x]=='1' && !covF[s][z*D+x]) X.push_back(x);\n                for(int y=0;y<D;y++) if(Rt[s][z][y]=='1' && !covR[s][z*D+y]) Y.push_back(y);\n\n                if(X.empty() && Y.empty()) continue;\n\n                if(!X.empty() && !Y.empty()){\n                    int m=max((int)X.size(),(int)Y.size());\n                    for(int k=0;k<m;k++){\n                        int x=(k<(int)X.size()?X[k]:X[0]);\n                        int y=(k<(int)Y.size()?Y[k]:Y[0]);\n                        int v=chooseCell(s,z,x,y);\n                        if(placeUniqueCell(s,v)) progress=true;\n                    }\n                }else if(!X.empty()){\n                    for(int x:X){\n                        int v=chooseCell(s,z,x,-1);\n                        if(placeUniqueCell(s,v)) progress=true;\n                    }\n                }else{\n                    for(int y:Y){\n                        int v=chooseCell(s,z,-1,y);\n                        if(placeUniqueCell(s,v)) progress=true;\n                    }\n                }\n            }\n            if(!progress){\n                int v=findBestCell(s,true);\n                if(!placeUniqueCell(s,v)) break;\n            }\n        }\n    }\n\n    void finalRepair(){\n        for(int s=0;s<2;s++){\n            int guard=0;\n            while(sideUncovered(s)>0 && guard++<1000){\n                bool progress=false;\n                for(int z=0;z<D;z++){\n                    for(int x=0;x<D;x++) if(F[s][z][x]=='1' && !covF[s][z*D+x]){\n                        int v=chooseCell(s,z,x,-1);\n                        if(placeUniqueCell(s,v)) progress=true;\n                    }\n                    for(int y=0;y<D;y++) if(Rt[s][z][y]=='1' && !covR[s][z*D+y]){\n                        int v=chooseCell(s,z,-1,y);\n                        if(placeUniqueCell(s,v)) progress=true;\n                    }\n                }\n                if(!progress) break;\n            }\n        }\n    }\n\n    void buildBlockLists(){\n        for(int s=0;s<2;s++){\n            blk[s].assign(label+1,vector<int>());\n            for(int v=0;v<N;v++){\n                int a=ans[s][v];\n                if(a>0 && a<=label) blk[s][a].push_back(v);\n            }\n        }\n        activeLab.assign(label+1,0);\n        for(int l=1;l<=label;l++){\n            if(!blk[0][l].empty() || !blk[1][l].empty()) activeLab[l]=1;\n        }\n    }\n\n    bool isCommonLabel(int l) const {\n        return l>0 && l<(int)activeLab.size() && activeLab[l] && !blk[0][l].empty() && !blk[1][l].empty();\n    }\n\n    vector<int> canonicalShape(const vector<int>& cells) const {\n        vector<int> best,enc;\n        bool first=true;\n        vector<array<int,3>> tmp;\n        tmp.reserve(cells.size()); enc.reserve(cells.size());\n\n        for(const Rot& rr:rots){\n            tmp.clear();\n            int mn[3]={INT_MAX,INT_MAX,INT_MAX};\n            for(int v:cells){\n                int p[3]={xs[v],ys[v],zs[v]}, q[3];\n                for(int a=0;a<3;a++){\n                    q[a]=rr.sign[a]*p[rr.perm[a]];\n                    mn[a]=min(mn[a],q[a]);\n                }\n                tmp.push_back({q[0],q[1],q[2]});\n            }\n            enc.clear();\n            for(auto t:tmp){\n                int a=t[0]-mn[0], b=t[1]-mn[1], c=t[2]-mn[2];\n                enc.push_back((a*64+b)*64+c);\n            }\n            sort(enc.begin(),enc.end());\n            if(first || enc<best){ first=false; best=enc; }\n        }\n        return best;\n    }\n\n    void pairUniqueUnits(){\n        vector<int> u0,u1;\n        for(int l=1;l<=label;l++){\n            if(!activeLab[l]) continue;\n            if(blk[0][l].size()==1 && blk[1][l].empty()) u0.push_back(l);\n            if(blk[1][l].size()==1 && blk[0][l].empty()) u1.push_back(l);\n        }\n\n        int m=min((int)u0.size(),(int)u1.size());\n        for(int i=0;i<m;i++){\n            int a=u0[i], b=u1[i];\n            if(!activeLab[a] || !activeLab[b]) continue;\n            if(blk[0][a].size()!=1 || !blk[1][a].empty()) continue;\n            if(blk[1][b].size()!=1 || !blk[0][b].empty()) continue;\n\n            int v=blk[1][b][0];\n            blk[1][a].push_back(v);\n            ans[1][v]=a;\n            blk[1][b].clear();\n            activeLab[b]=0;\n        }\n    }\n\n    bool canMergeCommon(int a,int b) const {\n        if(!isCommonLabel(a) || !isCommonLabel(b)) return false;\n        if(blk[0][a].size()!=blk[1][a].size()) return false;\n        if(blk[0][b].size()!=blk[1][b].size()) return false;\n\n        vector<int> u0,u1;\n        u0.reserve(blk[0][a].size()+blk[0][b].size());\n        u1.reserve(blk[1][a].size()+blk[1][b].size());\n        u0.insert(u0.end(),blk[0][a].begin(),blk[0][a].end());\n        u0.insert(u0.end(),blk[0][b].begin(),blk[0][b].end());\n        u1.insert(u1.end(),blk[1][a].begin(),blk[1][a].end());\n        u1.insert(u1.end(),blk[1][b].begin(),blk[1][b].end());\n        if(u0.size()!=u1.size()) return false;\n        return canonicalShape(u0)==canonicalShape(u1);\n    }\n\n    void mergeCommonLabels(int a,int b){\n        if((int)blk[0][a].size() < (int)blk[0][b].size()) swap(a,b);\n        for(int s=0;s<2;s++){\n            for(int v:blk[s][b]){\n                ans[s][v]=a;\n                blk[s][a].push_back(v);\n            }\n            blk[s][b].clear();\n        }\n        activeLab[b]=0;\n    }\n\n    void postMergeCommon(double deadline){\n        while(elapsed()<deadline){\n            unordered_map<long long,int> flags;\n            flags.reserve(N*4+10);\n\n            for(int s=0;s<2;s++){\n                for(int v=0;v<N;v++){\n                    int a=ans[s][v];\n                    if(!isCommonLabel(a)) continue;\n                    for(int dir:{1,3,5}){\n                        int nb=neigh[v][dir];\n                        if(nb<0) continue;\n                        int b=ans[s][nb];\n                        if(a==b || !isCommonLabel(b)) continue;\n                        int x=a,y=b;\n                        if(x>y) swap(x,y);\n                        long long key=((long long)x<<32)|(unsigned int)y;\n                        flags[key]|=(1<<s);\n                    }\n                }\n            }\n\n            int bestA=-1,bestB=-1,bestVol=-1;\n            double bestSave=1e-12;\n\n            for(auto& kv:flags){\n                if(elapsed()>deadline) return;\n                if(kv.second!=3) continue;\n\n                int a=(int)(kv.first>>32);\n                int b=(int)(kv.first&0xffffffffLL);\n                if(!isCommonLabel(a) || !isCommonLabel(b)) continue;\n\n                int va=(int)blk[0][a].size();\n                int vb=(int)blk[0][b].size();\n                if(va<=0 || vb<=0) continue;\n\n                double save=1.0/va+1.0/vb-1.0/(va+vb);\n                if(save+1e-12<bestSave) continue;\n\n                if(!canMergeCommon(a,b)) continue;\n\n                int vol=va+vb;\n                if(save>bestSave+1e-12 || vol>bestVol){\n                    bestSave=save; bestVol=vol; bestA=a; bestB=b;\n                }\n            }\n\n            if(bestA==-1) break;\n            mergeCommonLabels(bestA,bestB);\n        }\n    }\n\n    void postProcess(double deadline){\n        buildBlockLists();\n        pairUniqueUnits();\n        if(elapsed()<deadline) postMergeCommon(deadline);\n    }\n\n    double computeScoreForAns(const array<vector<int>,2>& A,int maxLab) const {\n        vector<int> c0(maxLab+1,0), c1(maxLab+1,0);\n        for(int v=0;v<N;v++){\n            if(A[0][v]>0 && A[0][v]<=maxLab) c0[A[0][v]]++;\n            if(A[1][v]>0 && A[1][v]<=maxLab) c1[A[1][v]]++;\n        }\n        double sc=0.0;\n        for(int l=1;l<=maxLab;l++){\n            if(c0[l] && c1[l]) sc+=1.0/max(1,c0[l]);\n            else if(c0[l]) sc+=c0[l];\n            else if(c1[l]) sc+=c1[l];\n        }\n        return sc;\n    }\n\n    void buildPrefix3Mask(const vector<char>& mask,vector<int>& ps){\n        int P=D+1;\n        ps.assign(P*P*P,0);\n        for(int x=1;x<=D;x++) for(int y=1;y<=D;y++) for(int z=1;z<=D;z++){\n            int val=mask[id(x-1,y-1,z-1)]?1:0;\n            ps[p3id(x,y,z)] =\n                val + ps[p3id(x-1,y,z)] + ps[p3id(x,y-1,z)] + ps[p3id(x,y,z-1)]\n                - ps[p3id(x-1,y-1,z)] - ps[p3id(x-1,y,z-1)] - ps[p3id(x,y-1,z-1)]\n                + ps[p3id(x-1,y-1,z-1)];\n        }\n    }\n\n    void enumeratePoolBoxesSide(const vector<char>& pool,vector<SimpleBox>& best,double deadline){\n        vector<int> ps;\n        buildPrefix3Mask(pool,ps);\n\n        for(int x0=0;x0<D;x0++){\n            if(elapsed()>deadline) return;\n            for(int x1=x0+1;x1<=D;x1++){\n                int lx=x1-x0;\n                for(int y0=0;y0<D;y0++) for(int y1=y0+1;y1<=D;y1++){\n                    int ly=y1-y0;\n                    for(int z0=0;z0<D;z0++) for(int z1=z0+1;z1<=D;z1++){\n                        int lz=z1-z0, vol=lx*ly*lz;\n                        if(vol<2) continue;\n                        if(query3(ps,x0,x1,y0,y1,z0,z1)!=vol) continue;\n\n                        int key=shapeKey(lx,ly,lz);\n                        if(!best[key].valid || vol>best[key].vol){\n                            SimpleBox b;\n                            b.x=x0; b.y=y0; b.z=z0;\n                            b.lx=lx; b.ly=ly; b.lz=lz;\n                            b.vol=vol; b.valid=true;\n                            best[key]=b;\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    PoolBoxCand findBestPoolCuboid(array<vector<char>,2>& pool,double deadline){\n        const int KEY=15*15*15;\n        vector<SimpleBox> best0(KEY),best1(KEY);\n        enumeratePoolBoxesSide(pool[0],best0,deadline);\n        if(elapsed()>deadline) return PoolBoxCand();\n        enumeratePoolBoxesSide(pool[1],best1,deadline);\n\n        PoolBoxCand res;\n        for(int k=0;k<KEY;k++){\n            if(!best0[k].valid || !best1[k].valid) continue;\n            int vol=best0[k].vol;\n            if(!res.valid || vol>res.vol){\n                res.valid=true; res.b0=best0[k]; res.b1=best1[k]; res.vol=vol;\n            }\n        }\n        return res;\n    }\n\n    void postRepartitionSmall(int freezeMin,double deadline){\n        if(elapsed()>deadline) return;\n\n        array<vector<int>,2> oldAns=ans;\n        int oldLabel=label;\n        double oldScore=computeScoreForAns(oldAns,oldLabel);\n\n        array<vector<vector<int>>,2> cells;\n        cells[0].assign(label+1,vector<int>());\n        cells[1].assign(label+1,vector<int>());\n        for(int s=0;s<2;s++){\n            for(int v=0;v<N;v++){\n                int a=ans[s][v];\n                if(a>0 && a<=label) cells[s][a].push_back(v);\n            }\n        }\n\n        array<vector<int>,2> newAns;\n        newAns[0].assign(N,0); newAns[1].assign(N,0);\n        array<vector<char>,2> pool;\n        pool[0].assign(N,0); pool[1].assign(N,0);\n\n        int newLabel=0;\n        for(int l=1;l<=label;l++){\n            int c0=cells[0][l].size();\n            int c1=cells[1][l].size();\n            bool freeze=(c0>0 && c1>0 && c0==c1 && c0>=freezeMin);\n\n            if(freeze){\n                int nl=++newLabel;\n                for(int s=0;s<2;s++) for(int v:cells[s][l]) newAns[s][v]=nl;\n            }else{\n                for(int s=0;s<2;s++) for(int v:cells[s][l]) pool[s][v]=1;\n            }\n        }\n\n        while(elapsed()<deadline){\n            PoolBoxCand pc=findBestPoolCuboid(pool,deadline);\n            if(!pc.valid || pc.vol<2) break;\n\n            int nl=++newLabel;\n            auto put=[&](int s,const SimpleBox& b){\n                for(int x=b.x;x<b.x+b.lx;x++) for(int y=b.y;y<b.y+b.ly;y++) for(int z=b.z;z<b.z+b.lz;z++){\n                    int v=id(x,y,z);\n                    newAns[s][v]=nl;\n                    pool[s][v]=0;\n                }\n            };\n            put(0,pc.b0); put(1,pc.b1);\n        }\n\n        vector<int> rest0,rest1;\n        for(int v=0;v<N;v++){\n            if(pool[0][v]) rest0.push_back(v);\n            if(pool[1][v]) rest1.push_back(v);\n        }\n\n        int m=min((int)rest0.size(),(int)rest1.size());\n        for(int i=0;i<m;i++){\n            int nl=++newLabel;\n            newAns[0][rest0[i]]=nl;\n            newAns[1][rest1[i]]=nl;\n        }\n        for(int i=m;i<(int)rest0.size();i++){\n            int nl=++newLabel;\n            newAns[0][rest0[i]]=nl;\n        }\n        for(int i=m;i<(int)rest1.size();i++){\n            int nl=++newLabel;\n            newAns[1][rest1[i]]=nl;\n        }\n\n        double newScore=computeScoreForAns(newAns,newLabel);\n        if(newScore+1e-12<oldScore){\n            ans=std::move(newAns);\n            label=newLabel;\n        }else{\n            ans=std::move(oldAns);\n            label=oldLabel;\n        }\n    }\n\n    void evalAvailBucket(int ori,int tid,int l,int r,int minSize,\n                         const array<vector<char>,2>& core,\n                         int coreCnt0,int coreCnt1,PoolCompCand& best){\n        if(r-l<minSize) return;\n\n        int tx,ty,tz; decodeTid(tid,tx,ty,tz);\n        int mt=++markToken;\n        for(int idx=l;idx<r;idx++){\n            int p=entries[idx];\n            I3 rp=rotp[ori][p];\n            mark[p]=mt;\n            qmap[p]=id(rp.x+tx,rp.y+ty,rp.z+tz);\n        }\n\n        int vt=++visToken;\n        vector<int> que,comp; que.reserve(r-l); comp.reserve(r-l);\n        int beforeUnit=max(coreCnt0,coreCnt1);\n\n        for(int idx=l;idx<r;idx++){\n            int st=entries[idx];\n            if(vis[st]==vt) continue;\n            que.clear(); comp.clear();\n            que.push_back(st); vis[st]=vt;\n\n            for(int head=0;head<(int)que.size();head++){\n                int v=que[head]; comp.push_back(v);\n                for(int nb:neigh[v]) if(nb>=0 && mark[nb]==mt && vis[nb]!=vt){\n                    vis[nb]=vt; que.push_back(nb);\n                }\n            }\n\n            int sz=(int)comp.size();\n            if(sz<minSize) continue;\n\n            int c0=0,c1=0;\n            for(int v:comp){\n                if(core[0][v]) c0++;\n                int q=qmap[v];\n                if(core[1][q]) c1++;\n            }\n            if(c0+c1==0) continue;\n\n            int afterUnit=max(coreCnt0-c0,coreCnt1-c1);\n            double gain=(double)(beforeUnit-afterUnit)-1.0/sz;\n            if(gain<=1e-10) continue;\n\n            if(!best.valid || gain>best.gain+1e-12 || (abs(gain-best.gain)<1e-12 && sz>best.size)){\n                best.valid=true; best.gain=gain; best.size=sz;\n                best.core0=c0; best.core1=c1;\n                best.ori=ori; best.tx=tx; best.ty=ty; best.tz=tz;\n                best.cells=comp;\n            }\n        }\n    }\n\n    PoolCompCand findBestAvailComponent(const array<vector<char>,2>& avail,\n                                        const array<vector<char>,2>& core,\n                                        int coreCnt0,int coreCnt1,\n                                        double deadline,int minSize){\n        PoolCompCand best;\n\n        vector<int> list0,list1; list0.reserve(N); list1.reserve(N);\n        for(int v=0;v<N;v++){\n            if(avail[0][v]) list0.push_back(v);\n            if(avail[1][v]) list1.push_back(v);\n        }\n        if((int)list0.size()<minSize || (int)list1.size()<minSize) return best;\n\n        int n1=(int)list1.size();\n        vector<short> qx(n1),qy(n1),qz(n1);\n        for(int i=0;i<n1;i++){\n            int v=list1[i];\n            qx[i]=xs[v]; qy[i]=ys[v]; qz[i]=zs[v];\n        }\n\n        vector<int> activeTids; activeTids.reserve(Tcnt);\n\n        for(int oi=0;oi<(int)rots.size();oi++){\n            if(elapsed()>deadline) break;\n            fill(cnt.begin(),cnt.end(),0);\n            activeTids.clear();\n\n            for(int p:list0){\n                I3 rp=rotp[oi][p];\n                int bx=offsetT-rp.x, by=offsetT-rp.y, bz=offsetT-rp.z;\n                for(int j=0;j<n1;j++){\n                    int tid=((qx[j]+bx)*rangeT+(qy[j]+by))*rangeT+(qz[j]+bz);\n                    if(cnt[tid]==0) activeTids.push_back(tid);\n                    cnt[tid]++;\n                }\n            }\n\n            int total=0;\n            for(int tid:activeTids){\n                startTid[tid]=total;\n                curTid[tid]=total;\n                total+=cnt[tid];\n            }\n            entries.resize(total);\n\n            for(int p:list0){\n                I3 rp=rotp[oi][p];\n                int bx=offsetT-rp.x, by=offsetT-rp.y, bz=offsetT-rp.z;\n                for(int j=0;j<n1;j++){\n                    int tid=((qx[j]+bx)*rangeT+(qy[j]+by))*rangeT+(qz[j]+bz);\n                    entries[curTid[tid]++]=p;\n                }\n            }\n\n            for(int tid:activeTids){\n                if(cnt[tid]<minSize) continue;\n                evalAvailBucket(oi,tid,startTid[tid],startTid[tid]+cnt[tid],minSize,\n                                core,coreCnt0,coreCnt1,best);\n                if(elapsed()>deadline) break;\n            }\n        }\n        return best;\n    }\n\n    void postRepartitionExpanded(int freezeMin,double deadline){\n        if(elapsed()>deadline) return;\n\n        array<vector<int>,2> oldAns=ans;\n        int oldLabel=label;\n        double oldScore=computeScoreForAns(oldAns,oldLabel);\n\n        array<vector<vector<int>>,2> cells;\n        cells[0].assign(label+1,vector<int>());\n        cells[1].assign(label+1,vector<int>());\n        for(int s=0;s<2;s++){\n            for(int v=0;v<N;v++){\n                int a=ans[s][v];\n                if(a>0 && a<=label) cells[s][a].push_back(v);\n            }\n        }\n\n        array<vector<int>,2> newAns;\n        newAns[0].assign(N,0); newAns[1].assign(N,0);\n\n        array<vector<char>,2> core,avail;\n        for(int s=0;s<2;s++){ core[s].assign(N,0); avail[s].assign(N,0); }\n\n        int newLabel=0, coreCnt[2]={0,0};\n\n        for(int l=1;l<=label;l++){\n            int c0=(int)cells[0][l].size();\n            int c1=(int)cells[1][l].size();\n            bool freeze=(c0>0 && c1>0 && c0==c1 && c0>=freezeMin);\n\n            if(freeze){\n                int nl=++newLabel;\n                for(int s=0;s<2;s++) for(int v:cells[s][l]) newAns[s][v]=nl;\n            }else{\n                for(int s=0;s<2;s++){\n                    for(int v:cells[s][l]){\n                        if(!core[s][v]){\n                            core[s][v]=1;\n                            coreCnt[s]++;\n                        }\n                    }\n                }\n            }\n        }\n\n        for(int s=0;s<2;s++){\n            for(int v=0;v<N;v++){\n                if(core[s][v]) avail[s][v]=1;\n                else if(newAns[s][v]==0 && allowed[s][v]) avail[s][v]=1;\n            }\n        }\n\n        int iter=0;\n        while(elapsed()<deadline && (coreCnt[0]+coreCnt[1]>0) && iter++<300){\n            PoolCompCand pc=findBestAvailComponent(avail,core,coreCnt[0],coreCnt[1],deadline,2);\n            if(!pc.valid || pc.gain<=1e-10 || pc.size<2) break;\n\n            int nl=++newLabel;\n            for(int p:pc.cells){\n                I3 rp=rotp[pc.ori][p];\n                int q=id(rp.x+pc.tx,rp.y+pc.ty,rp.z+pc.tz);\n\n                newAns[0][p]=nl;\n                avail[0][p]=0;\n                if(core[0][p]){ core[0][p]=0; coreCnt[0]--; }\n\n                newAns[1][q]=nl;\n                avail[1][q]=0;\n                if(core[1][q]){ core[1][q]=0; coreCnt[1]--; }\n            }\n        }\n\n        vector<int> rest0,rest1;\n        for(int v=0;v<N;v++){\n            if(core[0][v]) rest0.push_back(v);\n            if(core[1][v]) rest1.push_back(v);\n        }\n\n        int m=min((int)rest0.size(),(int)rest1.size());\n        for(int i=0;i<m;i++){\n            int nl=++newLabel;\n            newAns[0][rest0[i]]=nl;\n            newAns[1][rest1[i]]=nl;\n        }\n        for(int i=m;i<(int)rest0.size();i++){\n            int nl=++newLabel;\n            newAns[0][rest0[i]]=nl;\n        }\n        for(int i=m;i<(int)rest1.size();i++){\n            int nl=++newLabel;\n            newAns[1][rest1[i]]=nl;\n        }\n\n        double newScore=computeScoreForAns(newAns,newLabel);\n        if(newScore+1e-12<oldScore){\n            ans=std::move(newAns);\n            label=newLabel;\n        }else{\n            ans=std::move(oldAns);\n            label=oldLabel;\n        }\n    }\n\n    Transform findLabelTransform(int l){\n        Transform none;\n        if(!isCommonLabel(l)) return none;\n        if(blk[0][l].size()!=blk[1][l].size()) return none;\n        if(blk[0][l].empty()) return none;\n\n        for(int ri=0;ri<(int)rots.size();ri++){\n            int mnR[3]={INT_MAX,INT_MAX,INT_MAX};\n            int mnQ[3]={INT_MAX,INT_MAX,INT_MAX};\n\n            for(int p:blk[0][l]){\n                I3 rp=rotp[ri][p];\n                mnR[0]=min<int>(mnR[0],rp.x);\n                mnR[1]=min<int>(mnR[1],rp.y);\n                mnR[2]=min<int>(mnR[2],rp.z);\n            }\n            for(int q:blk[1][l]){\n                mnQ[0]=min(mnQ[0],xs[q]);\n                mnQ[1]=min(mnQ[1],ys[q]);\n                mnQ[2]=min(mnQ[2],zs[q]);\n            }\n\n            int tx=mnQ[0]-mnR[0];\n            int ty=mnQ[1]-mnR[1];\n            int tz=mnQ[2]-mnR[2];\n\n            bool ok=true;\n            for(int p:blk[0][l]){\n                I3 rp=rotp[ri][p];\n                int qx=rp.x+tx, qy=rp.y+ty, qz=rp.z+tz;\n                if(!(0<=qx&&qx<D&&0<=qy&&qy<D&&0<=qz&&qz<D)){ ok=false; break; }\n                int q=id(qx,qy,qz);\n                if(ans[1][q]!=l){ ok=false; break; }\n            }\n\n            if(ok){\n                Transform tr;\n                tr.valid=true; tr.ori=ri; tr.tx=tx; tr.ty=ty; tr.tz=tz;\n                return tr;\n            }\n        }\n        return none;\n    }\n\n    vector<Transform> findAllLabelTransforms(int l){\n        vector<Transform> res;\n        if(!isCommonLabel(l)) return res;\n        if(blk[0][l].size()!=blk[1][l].size()) return res;\n        if(blk[0][l].empty()) return res;\n\n        unordered_set<long long> seen;\n\n        for(int ri=0;ri<(int)rots.size();ri++){\n            int mnR[3]={INT_MAX,INT_MAX,INT_MAX};\n            int mnQ[3]={INT_MAX,INT_MAX,INT_MAX};\n\n            for(int p:blk[0][l]){\n                I3 rp=rotp[ri][p];\n                mnR[0]=min<int>(mnR[0],rp.x);\n                mnR[1]=min<int>(mnR[1],rp.y);\n                mnR[2]=min<int>(mnR[2],rp.z);\n            }\n            for(int q:blk[1][l]){\n                mnQ[0]=min(mnQ[0],xs[q]);\n                mnQ[1]=min(mnQ[1],ys[q]);\n                mnQ[2]=min(mnQ[2],zs[q]);\n            }\n\n            int tx=mnQ[0]-mnR[0];\n            int ty=mnQ[1]-mnR[1];\n            int tz=mnQ[2]-mnR[2];\n\n            bool ok=true;\n            for(int p:blk[0][l]){\n                I3 rp=rotp[ri][p];\n                int qx=rp.x+tx, qy=rp.y+ty, qz=rp.z+tz;\n                if(!(0<=qx&&qx<D&&0<=qy&&qy<D&&0<=qz&&qz<D)){ ok=false; break; }\n                int q=id(qx,qy,qz);\n                if(ans[1][q]!=l){ ok=false; break; }\n            }\n            if(!ok) continue;\n\n            long long key=(((long long)ri*100+(tx+50))*100+(ty+50))*100+(tz+50);\n            if(seen.insert(key).second){\n                Transform tr;\n                tr.valid=true; tr.ori=ri; tr.tx=tx; tr.ty=ty; tr.tz=tz;\n                res.push_back(tr);\n            }\n        }\n        return res;\n    }\n\n    bool mapCellByTransform(int p,const Transform& tr,int& q) const {\n        I3 rp=rotp[tr.ori][p];\n        int qx=rp.x+tr.tx, qy=rp.y+tr.ty, qz=rp.z+tr.tz;\n        if(!(0<=qx&&qx<D&&0<=qy&&qy<D&&0<=qz&&qz<D)) return false;\n        q=id(qx,qy,qz);\n        return true;\n    }\n\n    bool adjacentToLabel(int s,int v,int l) const {\n        for(int nb:neigh[v]) if(nb>=0 && ans[s][nb]==l) return true;\n        return false;\n    }\n\n    void expandCommonBlocks(double deadline){\n        if(elapsed()>deadline) return;\n\n        array<vector<int>,2> oldAns=ans;\n        int oldLabel=label;\n        double oldScore=computeScoreForAns(ans,label);\n\n        buildBlockLists();\n\n        vector<int> labs;\n        for(int l=1;l<=label;l++){\n            if(isCommonLabel(l) && blk[0][l].size()==blk[1][l].size()) labs.push_back(l);\n        }\n        sort(labs.begin(),labs.end(),[&](int a,int b){ return blk[0][a].size()<blk[0][b].size(); });\n\n        for(int l:labs){\n            if(elapsed()>deadline) break;\n            if(!isCommonLabel(l)) continue;\n            Transform tr=findLabelTransform(l);\n            if(!tr.valid) continue;\n\n            bool progress=true;\n            int loop=0;\n            while(progress && elapsed()<deadline && loop++<N){\n                progress=false;\n                for(int p=0;p<N;p++){\n                    if(ans[0][p]!=0 || !allowed[0][p]) continue;\n                    if(!adjacentToLabel(0,p,l)) continue;\n\n                    int q;\n                    if(!mapCellByTransform(p,tr,q)) continue;\n                    if(ans[1][q]!=0 || !allowed[1][q]) continue;\n                    if(!adjacentToLabel(1,q,l)) continue;\n\n                    ans[0][p]=l;\n                    ans[1][q]=l;\n                    blk[0][l].push_back(p);\n                    blk[1][l].push_back(q);\n                    progress=true;\n                }\n            }\n        }\n\n        double newScore=computeScoreForAns(ans,label);\n        if(newScore>oldScore+1e-12){\n            ans=std::move(oldAns);\n            label=oldLabel;\n        }\n    }\n\n    void expandCommonBlocksBest(double deadline){\n        if(elapsed()>deadline) return;\n\n        array<vector<int>,2> oldAns=ans;\n        int oldLabel=label;\n        double oldScore=computeScoreForAns(ans,label);\n\n        buildBlockLists();\n\n        vector<int> labs;\n        for(int l=1;l<=label;l++){\n            if(isCommonLabel(l) && blk[0][l].size()==blk[1][l].size()) labs.push_back(l);\n        }\n        sort(labs.begin(),labs.end(),[&](int a,int b){ return blk[0][a].size()<blk[0][b].size(); });\n\n        vector<int> que,comp;\n\n        for(int l:labs){\n            if(elapsed()>deadline) break;\n            if(!isCommonLabel(l)) continue;\n\n            vector<Transform> trs=findAllLabelTransforms(l);\n            if(trs.empty()) continue;\n\n            vector<int> bestCells;\n            Transform bestTr;\n\n            for(const Transform& tr:trs){\n                if(elapsed()>deadline) break;\n\n                int mt=++markToken;\n                int vt=++visToken;\n                que.clear(); comp.clear();\n\n                for(int p=0;p<N;p++){\n                    if(ans[0][p]!=0 || !allowed[0][p]) continue;\n                    int q;\n                    if(!mapCellByTransform(p,tr,q)) continue;\n                    if(ans[1][q]!=0 || !allowed[1][q]) continue;\n\n                    mark[p]=mt;\n                    bool frontier=false;\n                    for(int nb:neigh[p]){\n                        if(nb>=0 && ans[0][nb]==l){ frontier=true; break; }\n                    }\n                    if(frontier){\n                        vis[p]=vt;\n                        que.push_back(p);\n                    }\n                }\n\n                for(int head=0;head<(int)que.size();head++){\n                    int v=que[head];\n                    comp.push_back(v);\n                    for(int nb:neigh[v]){\n                        if(nb>=0 && mark[nb]==mt && vis[nb]!=vt){\n                            vis[nb]=vt;\n                            que.push_back(nb);\n                        }\n                    }\n                }\n\n                if(comp.size()>bestCells.size()){\n                    bestCells=comp;\n                    bestTr=tr;\n                }\n            }\n\n            if(bestCells.empty()) continue;\n\n            for(int p:bestCells){\n                int q;\n                if(!mapCellByTransform(p,bestTr,q)) continue;\n                if(ans[0][p]==0 && ans[1][q]==0 && allowed[0][p] && allowed[1][q]){\n                    ans[0][p]=l;\n                    ans[1][q]=l;\n                    blk[0][l].push_back(p);\n                    blk[1][l].push_back(q);\n                }\n            }\n        }\n\n        double newScore=computeScoreForAns(ans,label);\n        if(newScore>oldScore+1e-12){\n            ans=std::move(oldAns);\n            label=oldLabel;\n        }\n    }\n\n    double contribCount(int a,int b) const {\n        if(a>0 && b>0) return 1.0 / max(1,a);\n        if(a>0) return (double)a;\n        if(b>0) return (double)b;\n        return 0.0;\n    }\n\n    bool connectedAfterRemoveSide(int s,int lab,int remv,const vector<int>& sideCnt){\n        if(lab<=0) return true;\n        int cur=sideCnt[lab];\n        int target=cur-1;\n        if(target<=1) return true;\n        if(lab >= (int)blk[s].size()) return false;\n\n        int st=-1;\n        for(int v:blk[s][lab]){\n            if(v!=remv && ans[s][v]==lab){\n                st=v;\n                break;\n            }\n        }\n        if(st<0) return false;\n\n        int vt=++visToken;\n        vector<int> que;\n        que.push_back(st);\n        vis[st]=vt;\n        int got=0;\n\n        for(int head=0; head<(int)que.size(); head++){\n            int v=que[head];\n            got++;\n            for(int nb:neigh[v]){\n                if(nb>=0 && nb!=remv && ans[s][nb]==lab && vis[nb]!=vt){\n                    vis[nb]=vt;\n                    que.push_back(nb);\n                }\n            }\n        }\n        return got==target;\n    }\n\n    void rebalanceCellsIntoCommon(double deadline){\n        if(elapsed()>deadline) return;\n\n        array<vector<int>,2> oldAns=ans;\n        int oldLabel=label;\n        double oldScore=computeScoreForAns(ans,label);\n\n        buildBlockLists();\n\n        int L=label;\n        vector<int> c0(L+1,0), c1(L+1,0);\n        for(int l=1;l<=L;l++){\n            c0[l]=(int)blk[0][l].size();\n            c1[l]=(int)blk[1][l].size();\n        }\n\n        vector<Transform> tr(L+1);\n        vector<int> targets;\n\n        for(int l=1;l<=L;l++){\n            if(isCommonLabel(l) && c0[l]==c1[l] && c0[l]>=2){\n                tr[l]=findLabelTransform(l);\n                if(tr[l].valid) targets.push_back(l);\n            }\n        }\n\n        sort(targets.begin(), targets.end(), [&](int a,int b){\n            return c0[a] < c0[b];\n        });\n\n        auto localGain = [&](int l,int a,int b)->double{\n            int labsArr[3]={l,a,b};\n            vector<int> labs;\n            for(int x:labsArr){\n                if(x>0 && find(labs.begin(),labs.end(),x)==labs.end()) labs.push_back(x);\n            }\n\n            double oldPart=0.0, newPart=0.0;\n            for(int x:labs) oldPart += contribCount(c0[x],c1[x]);\n\n            for(int x:labs){\n                int na=c0[x], nb=c1[x];\n                if(x==l){ na++; nb++; }\n                if(x==a) na--;\n                if(x==b) nb--;\n                if(na<0 || nb<0) return -1e100;\n                newPart += contribCount(na,nb);\n            }\n            return oldPart-newPart;\n        };\n\n        auto sourceOK = [&](int l,int p,int q)->bool{\n            int a=ans[0][p];\n            int b=ans[1][q];\n\n            if(a==l || b==l) return false;\n            if(localGain(l,a,b)<=1e-10) return false;\n\n            if(a==b && a>0){\n                if(a<1 || a>L) return false;\n                if(c0[a]<=0 || c1[a]<=0 || c0[a]!=c1[a]) return false;\n                if(!tr[a].valid) return false;\n\n                int qq;\n                if(!mapCellByTransform(p,tr[a],qq) || qq!=q) return false;\n                if(!connectedAfterRemoveSide(0,a,p,c0)) return false;\n                return true;\n            }\n\n            if(a>0){\n                if(a>L) return false;\n                if(c1[a]!=0) return false;\n                if(!connectedAfterRemoveSide(0,a,p,c0)) return false;\n            }\n            if(b>0){\n                if(b>L) return false;\n                if(c0[b]!=0) return false;\n                if(!connectedAfterRemoveSide(1,b,q,c1)) return false;\n            }\n            return true;\n        };\n\n        bool progress=true;\n        int pass=0;\n\n        while(progress && elapsed()<deadline && pass++<15){\n            progress=false;\n\n            for(int l:targets){\n                if(elapsed()>deadline) break;\n                if(c0[l]<=0 || c0[l]!=c1[l] || !tr[l].valid) continue;\n\n                for(int p=0;p<N;p++){\n                    if(elapsed()>deadline) break;\n                    if(!allowed[0][p] || ans[0][p]==l) continue;\n                    if(!adjacentToLabel(0,p,l)) continue;\n\n                    int q;\n                    if(!mapCellByTransform(p,tr[l],q)) continue;\n                    if(!allowed[1][q] || ans[1][q]==l) continue;\n                    if(!adjacentToLabel(1,q,l)) continue;\n                    if(!sourceOK(l,p,q)) continue;\n\n                    int a=ans[0][p];\n                    int b=ans[1][q];\n\n                    if(a>0) c0[a]--;\n                    if(b>0) c1[b]--;\n\n                    ans[0][p]=l;\n                    ans[1][q]=l;\n                    c0[l]++;\n                    c1[l]++;\n\n                    blk[0][l].push_back(p);\n                    blk[1][l].push_back(q);\n\n                    progress=true;\n                }\n            }\n        }\n\n        double newScore=computeScoreForAns(ans,label);\n        if(newScore>oldScore+1e-12){\n            ans=std::move(oldAns);\n            label=oldLabel;\n        }\n    }\n\n    void pruneRedundantBlocks(double deadline){\n        if(elapsed()>deadline) return;\n\n        buildBlockLists();\n\n        array<vector<int>,2> cf,cr;\n        for(int s=0;s<2;s++){\n            cf[s].assign(D2,0);\n            cr[s].assign(D2,0);\n            for(int v=0;v<N;v++){\n                if(ans[s][v]==0) continue;\n                int z=zs[v],x=xs[v],y=ys[v];\n                cf[s][z*D+x]++;\n                cr[s][z*D+y]++;\n            }\n        }\n\n        auto saving=[&](int l)->double{\n            int c0=(int)blk[0][l].size();\n            int c1=(int)blk[1][l].size();\n            if(c0 && c1) return 1.0/max(1,c0);\n            return (double)(c0+c1);\n        };\n\n        auto canRemove=[&](int l)->bool{\n            if(l<=0 || l>label || !activeLab[l]) return false;\n\n            array<vector<int>,2> tf,trc,touchF,touchR;\n            for(int s=0;s<2;s++){\n                tf[s].assign(D2,0);\n                trc[s].assign(D2,0);\n            }\n\n            for(int s=0;s<2;s++){\n                for(int v:blk[s][l]){\n                    int z=zs[v],x=xs[v],y=ys[v];\n                    int fid=z*D+x, rid=z*D+y;\n                    if(tf[s][fid]++==0) touchF[s].push_back(fid);\n                    if(trc[s][rid]++==0) touchR[s].push_back(rid);\n                }\n            }\n\n            for(int s=0;s<2;s++){\n                for(int fid:touchF[s]) if(cf[s][fid]<=tf[s][fid]) return false;\n                for(int rid:touchR[s]) if(cr[s][rid]<=trc[s][rid]) return false;\n            }\n            return true;\n        };\n\n        while(elapsed()<deadline){\n            int best=-1;\n            double bestSave=1e-12;\n\n            for(int l=1;l<=label;l++){\n                if(!activeLab[l]) continue;\n                double sv=saving(l);\n                if(sv<=bestSave) continue;\n                if(!canRemove(l)) continue;\n                bestSave=sv;\n                best=l;\n                if(elapsed()>deadline) break;\n            }\n\n            if(best==-1) break;\n\n            for(int s=0;s<2;s++){\n                for(int v:blk[s][best]){\n                    int z=zs[v],x=xs[v],y=ys[v];\n                    cf[s][z*D+x]--;\n                    cr[s][z*D+y]--;\n                    ans[s][v]=0;\n                }\n                blk[s][best].clear();\n            }\n            activeLab[best]=0;\n        }\n    }\n\n    void run(){\n        startTime=chrono::steady_clock::now();\n\n        double compDeadline=2.35;\n        for(int it=0;it<12 && totalUncov>0 && elapsed()<compDeadline;it++){\n            CompCand c=findBestComponent(90,compDeadline);\n            if(!c.valid || c.size<3) break;\n            placeCommonMapped(c);\n        }\n\n        double cuboidDeadline=4.72;\n        for(int it=0;it<180 && totalUncov>0 && elapsed()<cuboidDeadline;it++){\n            BoxCand b=findBestCuboid(cuboidDeadline);\n            if(!b.valid || b.vol<2 || b.cov<=0) break;\n            placeCommonBox(b.b0,b.b1);\n        }\n\n        double exhaustiveDeadline=5.16;\n        for(int it=0;it<50 && totalUncov>0 && elapsed()<exhaustiveDeadline;it++){\n            CompCand c=findBestComponentExhaustive(exhaustiveDeadline,2);\n            if(!c.valid || c.size<2 || c.score<=0.0) break;\n            placeCommonMapped(c);\n        }\n\n        double barDeadline=5.36;\n        for(int it=0;it<300 && totalUncov>0 && elapsed()<barDeadline;it++){\n            BarCand b=findBestBar(barDeadline);\n            if(!b.valid || b.len<2 || b.cov<=0) break;\n            placeCommonBar(b.b0,b.b1);\n        }\n\n        placeCommonUnits();\n        fillUnique(0);\n        fillUnique(1);\n        finalRepair();\n\n        postProcess(5.43);\n        pruneRedundantBlocks(5.50);\n\n        postRepartitionSmall(3,5.58);\n        postRepartitionSmall(6,5.66);\n        postRepartitionSmall(12,5.71);\n\n        postRepartitionExpanded(4,5.80);\n\n        expandCommonBlocks(5.83);\n        expandCommonBlocksBest(5.86);\n\n        // New local score-improving relabeling.\n        rebalanceCellsIntoCommon(5.90);\n\n        postProcess(5.91);\n        pruneRedundantBlocks(5.94);\n    }\n\n    void print() const {\n        vector<int> mp(label+1,0);\n        for(int s=0;s<2;s++){\n            for(int v=0;v<N;v++){\n                int a=ans[s][v];\n                if(a>0 && a<=label) mp[a]=1;\n            }\n        }\n\n        int n=0;\n        for(int l=1;l<=label;l++){\n            if(mp[l]) mp[l]=++n;\n        }\n\n        cout<<n<<'\\n';\n        for(int s=0;s<2;s++){\n            for(int i=0;i<N;i++){\n                if(i) cout<<' ';\n                int a=ans[s][i];\n                cout<<(a==0?0:mp[a]);\n            }\n            cout<<'\\n';\n        }\n    }\n};\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int D;\n    cin>>D;\n\n    array<vector<string>,2> F,R;\n    for(int i=0;i<2;i++){\n        F[i].resize(D);\n        R[i].resize(D);\n        for(int z=0;z<D;z++) cin>>F[i][z];\n        for(int z=0;z<D;z++) cin>>R[i][z];\n    }\n\n    Solver solver(D,F,R);\n    solver.run();\n    solver.print();\n\n    return 0;\n}","ahc020":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 105;\nstatic const int MAXM = 305;\nstatic const long long INFLL = (1LL << 62);\nstatic const long long STABLE_SWITCH_TH = 350000;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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} gtimer;\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) {\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);\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 Edge {\n    int u, v;\n    long long w;\n};\n\nstruct RK {\n    unsigned short p;\n    int k;\n};\n\nstruct TreeResult {\n    long long cost = INFLL;\n    bitset<MAXM> mask;\n};\n\nstruct Solution {\n    vector<int> P;\n    TreeResult tree;\n    long long radCost = INFLL;\n    long long total = INFLL;\n};\n\nint N, M, K;\nvector<int> X, Y, RA, RB;\nvector<Edge> edges;\nvector<vector<pair<int,int>>> adj;\n\nvector<vector<int>> distSq;\nvector<vector<unsigned short>> ceilD;\nvector<RK> coverList[MAXN];\n\nvector<int> coverCnt5000;\nvector<long long> coverSumP5000;\n\nlong long spDist[MAXN][MAXN];\nbitset<MAXM> pathE[MAXN][MAXN];\nbitset<MAXN> pathV[MAXN][MAXN];\n\nvector<int> edgeOrder;\nbitset<MAXM> globalMSTMask;\nbitset<MAXM> allEdgesMask;\n\nint ceil_sqrt_ll(long long v) {\n    int r = (int) sqrt((long double) v);\n    while (1LL * r * r < v) ++r;\n    while (r > 0 && 1LL * (r - 1) * (r - 1) >= v) --r;\n    return r;\n}\n\nlong long calcRadCost(const vector<int>& P) {\n    long long s = 0;\n    for (int p : P) s += 1LL * p * p;\n    return s;\n}\n\nint computeCovered(const vector<int>& P, vector<char>& covered) {\n    covered.assign(K, 0);\n    int rem = K;\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                if (rem == 0) return K;\n            }\n        }\n    }\n    return K - rem;\n}\n\nbool isFull(const vector<int>& P) {\n    vector<char> covered;\n    return computeCovered(P, covered) == K;\n}\n\nvector<char> makeTerminal(const vector<int>& P) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terminal[i] = 1;\n    }\n    return terminal;\n}\n\nSolution stableChoose(const Solution& cur, const Solution& first, const Solution& best) {\n    if (best.total >= cur.total) return cur;\n    if (first.total < INFLL / 2 && first.total < cur.total) {\n        if (first.total - best.total <= STABLE_SWITCH_TH) return first;\n    }\n    return best;\n}\n\nvector<int> makeOrder(const vector<int>& P, int mode, const vector<long long>* branch = nullptr) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            double p2 = 1.0 * P[i] * P[i];\n            double rd = (double) spDist[0][i];\n            if (mode == 0) sc = p2;\n            else if (mode == 1) sc = p2 + 0.7 * rd;\n            else if (mode == 2) sc = 0.2 * p2 + rd;\n            else {\n                long long b = (branch ? (*branch)[i] : 0LL);\n                sc = p2 + (double)b;\n            }\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvector<int> makeOrderWeighted(\n    const vector<int>& P,\n    const vector<long long>& branch,\n    double wp,\n    double wb,\n    double wr\n) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n    for (int i = 0; i < N; ++i) {\n        double sc;\n        if (P[i] == 0) {\n            sc = -1e100;\n        } else {\n            sc = wp * (double)(1LL * P[i] * P[i])\n               + wb * (double)branch[i]\n               + wr * (double)spDist[0][i];\n        }\n        v.push_back({sc, i});\n    }\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvector<int> makeCoverageOrder(const vector<int>& P, int variant) {\n    vector<pair<double,int>> v;\n    v.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        double sc = -1e100;\n        if (P[i] > 0) {\n            double cnt = (double)coverCnt5000[i];\n            double avg = (cnt > 0.0 ? (double)coverSumP5000[i] / cnt : 6000.0);\n            double rd = (double)spDist[0][i];\n\n            if (variant == 0) {\n                sc = -cnt;\n            } else if (variant == 1) {\n                sc = rd / 10000.0 - cnt;\n            } else if (variant == 2) {\n                sc = avg - 0.20 * cnt;\n            } else if (variant == 3) {\n                sc = rd / 15000.0 + 0.20 * avg - 0.50 * cnt;\n            } else {\n                double dens = cnt / (avg + 1.0);\n                sc = -dens;\n            }\n        }\n        v.push_back({sc, i});\n    }\n\n    sort(v.begin(), v.end(), [](const auto& a, const auto& b) {\n        if (a.first != b.first) return a.first > b.first;\n        return a.second < b.second;\n    });\n\n    vector<int> ord;\n    ord.reserve(N);\n    for (auto [_, id] : v) ord.push_back(id);\n    return ord;\n}\n\nvector<int> orderWithLast(const vector<int>& P, int mode, int last, const vector<long long>* branch = nullptr) {\n    vector<int> ord = makeOrder(P, mode, branch);\n    auto it = find(ord.begin(), ord.end(), last);\n    if (it != ord.end()) {\n        ord.erase(it);\n        ord.push_back(last);\n    }\n    return ord;\n}\n\nvoid trimP(vector<int>& P, const vector<int>& order) {\n    vector<int> cnt(K, 0);\n    for (int i = 0; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        int p = P[i];\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > p) break;\n            cnt[rk.k]++;\n        }\n    }\n\n    for (int i : order) {\n        if (P[i] <= 0) continue;\n        int old = P[i];\n        int need = 0;\n        for (const auto& rk : coverList[i]) {\n            if ((int)rk.p > old) break;\n            if (cnt[rk.k] == 1) need = max(need, (int)rk.p);\n        }\n        if (need < old) {\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > old) break;\n                if ((int)rk.p > need) cnt[rk.k]--;\n            }\n            P[i] = need;\n        }\n    }\n}\n\nvoid applyFixedTrimType(vector<int>& q, int typ) {\n    if (typ == 0) {\n        trimP(q, makeOrder(q, 0));\n    } else if (typ == 1) {\n        trimP(q, makeOrder(q, 1));\n    } else if (typ == 2) {\n        trimP(q, makeOrder(q, 2));\n    } else if (typ == 3) {\n        trimP(q, makeOrder(q, 1));\n        trimP(q, makeOrder(q, 0));\n    } else if (typ == 4) {\n        trimP(q, makeOrder(q, 2));\n        trimP(q, makeOrder(q, 0));\n    } else if (typ == 5) {\n        trimP(q, makeOrder(q, 0));\n        trimP(q, makeOrder(q, 1));\n    } else if (typ == 6) {\n        trimP(q, makeOrder(q, 0));\n        trimP(q, makeOrder(q, 2));\n    } else if (typ == 7) {\n        trimP(q, makeCoverageOrder(q, 0));\n        trimP(q, makeOrder(q, 0));\n    } else if (typ == 8) {\n        trimP(q, makeCoverageOrder(q, 1));\n        trimP(q, makeOrder(q, 0));\n    } else if (typ == 9) {\n        trimP(q, makeCoverageOrder(q, 2));\n        trimP(q, makeOrder(q, 1));\n    } else if (typ == 10) {\n        trimP(q, makeCoverageOrder(q, 3));\n        trimP(q, makeOrder(q, 0));\n    } else if (typ == 11) {\n        trimP(q, makeCoverageOrder(q, 4));\n        trimP(q, makeOrder(q, 1));\n    } else {\n        trimP(q, makeCoverageOrder(q, 4));\n        trimP(q, makeOrder(q, 0));\n    }\n}\n\nTreeResult reduceMask(const bitset<MAXM>& mask, const vector<char>& terminal) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    int par[MAXN], sz[MAXN], deg[MAXN];\n    for (int i = 0; i < N; ++i) {\n        par[i] = i;\n        sz[i] = 1;\n        deg[i] = 0;\n    }\n\n    auto findp = [&](int x) {\n        while (par[x] != x) {\n            par[x] = par[par[x]];\n            x = par[x];\n        }\n        return x;\n    };\n\n    auto unite = [&](int a, int b) {\n        a = findp(a);\n        b = findp(b);\n        if (a == b) return false;\n        if (sz[a] < sz[b]) swap(a, b);\n        par[b] = a;\n        sz[a] += sz[b];\n        return true;\n    };\n\n    bitset<MAXM> tree;\n    for (int eid : edgeOrder) {\n        if (!mask.test(eid)) continue;\n        int u = edges[eid].u, v = edges[eid].v;\n        if (unite(u, v)) {\n            tree.set(eid);\n            deg[u]++;\n            deg[v]++;\n        }\n    }\n\n    queue<int> q;\n    for (int i = 0; i < N; ++i) {\n        if (!terminal[i] && deg[i] <= 1) q.push(i);\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n        if (terminal[v] || deg[v] != 1) continue;\n\n        int remEdge = -1;\n        for (auto [to, eid] : adj[v]) {\n            if (tree.test(eid)) {\n                remEdge = eid;\n                break;\n            }\n        }\n        if (remEdge == -1) {\n            deg[v] = 0;\n            continue;\n        }\n\n        int to = edges[remEdge].u ^ edges[remEdge].v ^ v;\n        tree.reset(remEdge);\n        deg[v]--;\n        deg[to]--;\n        if (!terminal[to] && deg[to] == 1) q.push(to);\n    }\n\n    char vis[MAXN];\n    for (int i = 0; i < N; ++i) vis[i] = 0;\n\n    queue<int> qq;\n    vis[0] = 1;\n    qq.push(0);\n    while (!qq.empty()) {\n        int v = qq.front();\n        qq.pop();\n        for (auto [to, eid] : adj[v]) {\n            if (!tree.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            qq.push(to);\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (terminal[i] && !vis[i]) return res;\n    }\n\n    long long cost = 0;\n    for (int e = 0; e < M; ++e) {\n        if (tree.test(e)) cost += edges[e].w;\n    }\n    res.cost = cost;\n    res.mask = tree;\n    return res;\n}\n\nbitset<MAXM> buildMetricMSTMask(const vector<char>& terminal) {\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) terms.push_back(i);\n    }\n\n    int T = (int)terms.size();\n    bitset<MAXM> mask;\n    if (T <= 1) return mask;\n\n    vector<char> used(T, 0);\n    vector<long long> key(T, INFLL);\n    vector<int> parent(T, -1);\n    key[0] = 0;\n\n    for (int it = 0; it < T; ++it) {\n        int v = -1;\n        long long best = INFLL;\n        for (int i = 0; i < T; ++i) {\n            if (!used[i] && key[i] < best) {\n                best = key[i];\n                v = i;\n            }\n        }\n        if (v == -1) break;\n        used[v] = 1;\n        if (parent[v] != -1) {\n            mask |= pathE[terms[v]][terms[parent[v]]];\n        }\n\n        for (int u = 0; u < T; ++u) {\n            if (!used[u] && spDist[terms[v]][terms[u]] < key[u]) {\n                key[u] = spDist[terms[v]][terms[u]];\n                parent[u] = v;\n            }\n        }\n    }\n    return mask;\n}\n\nbitset<MAXM> buildSPTMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    for (int i = 1; i < N; ++i) {\n        if (terminal[i]) mask |= pathE[0][i];\n    }\n    return mask;\n}\n\nbitset<MAXM> buildGreedyMask(const vector<char>& terminal) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(0);\n\n    while (true) {\n        bool any = false;\n        for (int t = 1; t < N; ++t) {\n            if (terminal[t] && !treeV.test(t)) {\n                any = true;\n                break;\n            }\n        }\n        if (!any) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n        for (int t = 1; t < N; ++t) {\n            if (!terminal[t] || treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult buildBestTree(const vector<int>& P, const bitset<MAXM>* extraMask = nullptr) {\n    vector<char> terminal(N, 0);\n    terminal[0] = 1;\n    int termCnt = 1;\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) {\n            terminal[i] = 1;\n            termCnt++;\n        }\n    }\n\n    TreeResult best;\n    best.cost = INFLL;\n    best.mask.reset();\n\n    if (termCnt <= 1) {\n        best.cost = 0;\n        return best;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    upd(buildMetricMSTMask(terminal));\n    upd(buildSPTMask(terminal));\n    upd(buildGreedyMask(terminal));\n    upd(globalMSTMask);\n\n    if (extraMask) upd(*extraMask);\n\n    return best;\n}\n\nvector<char> getReachable(const bitset<MAXM>& mask) {\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] : adj[v]) {\n            if (!mask.test(eid) || vis[to]) continue;\n            vis[to] = 1;\n            q.push(to);\n        }\n    }\n    return vis;\n}\n\nvector<long long> computeBranch(const vector<int>& P, const TreeResult& tr) {\n    vector<char> terminal = makeTerminal(P);\n\n    vector<long long> branch(N, 0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] <= 0) continue;\n        vector<char> t2 = terminal;\n        t2[i] = 0;\n        t2[0] = 1;\n        TreeResult r = reduceMask(tr.mask, t2);\n        if (r.cost < INFLL / 2) {\n            branch[i] = max(0LL, tr.cost - r.cost);\n        }\n    }\n    return branch;\n}\n\nSolution evaluateSolution(const vector<int>& P, const bitset<MAXM>* extraMask = nullptr) {\n    Solution s;\n    s.P = P;\n    if (!isFull(P)) {\n        s.total = INFLL;\n        return s;\n    }\n    s.radCost = calcRadCost(P);\n    s.tree = buildBestTree(P, extraMask);\n    if (s.tree.cost >= INFLL / 2) {\n        s.total = INFLL;\n    } else {\n        s.total = s.radCost + s.tree.cost;\n    }\n    return s;\n}\n\nbool greedyRepair(\n    vector<int>& P,\n    const vector<char>& allowed,\n    double connWeight,\n    double exponent,\n    const vector<char>* freeVertices = nullptr,\n    double stopTime = 1e100\n) {\n    for (int i = 0; i < N; ++i) {\n        if (!allowed[i]) P[i] = 0;\n        P[i] = min(5000, max(0, P[i]));\n    }\n\n    vector<char> covered;\n    int cov = computeCovered(P, covered);\n    int rem = K - cov;\n    if (rem == 0) return true;\n\n    vector<long long> minConn(N);\n    for (int i = 0; i < N; ++i) minConn[i] = spDist[0][i];\n\n    if (freeVertices) {\n        for (int v = 0; v < N; ++v) {\n            if (!(*freeVertices)[v]) continue;\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][v]);\n            }\n        }\n    }\n\n    for (int t = 0; t < N; ++t) {\n        if (P[t] > 0) {\n            for (int i = 0; i < N; ++i) {\n                minConn[i] = min(minConn[i], spDist[i][t]);\n            }\n        }\n    }\n\n    vector<double> denom(K + 1, 1.0);\n    if (fabs(exponent - 1.0) < 1e-9) {\n        for (int i = 1; i <= K; ++i) denom[i] = (double)i;\n    } else {\n        for (int i = 1; i <= K; ++i) denom[i] = pow((double)i, exponent);\n    }\n\n    int iter = 0;\n    while (rem > 0) {\n        if ((iter & 7) == 0 && gtimer.elapsed() > stopTime) return false;\n        if (iter > 1000) {\n            for (int k = 0; k < K && rem > 0; ++k) {\n                if (covered[k]) continue;\n                int bestI = -1, bestP = 0;\n                double bestCost = 1e100;\n\n                for (int i = 0; i < N; ++i) {\n                    if (!allowed[i]) continue;\n                    int p = (int)ceilD[i][k];\n                    if (p > 5000) continue;\n                    int old = P[i];\n                    int np = max(old, p);\n                    double act = 0.0;\n                    if (old == 0 && connWeight != 0.0) {\n                        if (freeVertices && (*freeVertices)[i]) act = 0.0;\n                        else act = connWeight * (double)minConn[i];\n                    }\n                    double cost = (double)(1LL * np * np - 1LL * old * old) + act;\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestI = i;\n                        bestP = np;\n                    }\n                }\n\n                if (bestI == -1) return false;\n\n                int old = P[bestI];\n                P[bestI] = bestP;\n                if (old == 0) {\n                    for (int j = 0; j < N; ++j) {\n                        minConn[j] = min(minConn[j], spDist[j][bestI]);\n                    }\n                }\n\n                for (const auto& rk : coverList[bestI]) {\n                    if ((int)rk.p > bestP) break;\n                    if (!covered[rk.k]) {\n                        covered[rk.k] = 1;\n                        --rem;\n                    }\n                }\n\n                if (gtimer.elapsed() > stopTime) return false;\n            }\n            return rem == 0;\n        }\n\n        ++iter;\n\n        double bestScore = 1e100;\n        double bestAbsCost = 1e100;\n        int bestI = -1, bestP = -1, bestCnt = -1;\n\n        for (int i = 0; i < N; ++i) {\n            if (!allowed[i] || P[i] >= 5000 || coverList[i].empty()) continue;\n\n            int old = P[i];\n            double activation = 0.0;\n            if (old == 0 && connWeight != 0.0) {\n                if (freeVertices && (*freeVertices)[i]) activation = 0.0;\n                else activation = connWeight * (double)minConn[i];\n            }\n\n            int cnt = 0;\n            const auto& lst = coverList[i];\n            int idx = 0, sz = (int)lst.size();\n\n            while (idx < sz && (int)lst[idx].p <= old) idx++;\n\n            while (idx < sz) {\n                int p = (int)lst[idx].p;\n                int add = 0;\n                while (idx < sz && (int)lst[idx].p == p) {\n                    if (!covered[lst[idx].k]) add++;\n                    idx++;\n                }\n                if (add == 0) continue;\n\n                cnt += add;\n                double cost = (double)(1LL * p * p - 1LL * old * old) + activation;\n                double score = cost / denom[cnt];\n\n                if (score < bestScore - 1e-12 ||\n                    (fabs(score - bestScore) <= 1e-12 &&\n                     (cost < bestAbsCost || cnt > bestCnt))) {\n                    bestScore = score;\n                    bestAbsCost = cost;\n                    bestI = i;\n                    bestP = p;\n                    bestCnt = cnt;\n                }\n            }\n        }\n\n        if (bestI == -1) return false;\n\n        int old = P[bestI];\n        P[bestI] = bestP;\n\n        int gained = 0;\n        for (const auto& rk : coverList[bestI]) {\n            if ((int)rk.p > bestP) break;\n            if (!covered[rk.k]) {\n                covered[rk.k] = 1;\n                --rem;\n                gained++;\n            }\n        }\n\n        if (old == 0) {\n            for (int j = 0; j < N; ++j) {\n                minConn[j] = min(minConn[j], spDist[j][bestI]);\n            }\n        }\n\n        if (gained == 0) return false;\n    }\n\n    return true;\n}\n\nvoid computeShortestPaths() {\n    for (int s = 0; s < N; ++s) {\n        vector<long long> dist(N, INFLL);\n        vector<int> parNode(N, -1), parEdge(N, -1);\n        priority_queue<pair<long long,int>, vector<pair<long long,int>>, greater<pair<long long,int>>> pq;\n\n        dist[s] = 0;\n        pq.push({0, s});\n\n        while (!pq.empty()) {\n            auto [d, v] = pq.top();\n            pq.pop();\n            if (d != dist[v]) continue;\n\n            for (auto [to, eid] : adj[v]) {\n                long long nd = d + edges[eid].w;\n                if (nd < dist[to]) {\n                    dist[to] = nd;\n                    parNode[to] = v;\n                    parEdge[to] = eid;\n                    pq.push({nd, to});\n                }\n            }\n        }\n\n        for (int t = 0; t < N; ++t) {\n            spDist[s][t] = dist[t];\n            pathE[s][t].reset();\n            pathV[s][t].reset();\n\n            if (dist[t] >= INFLL / 2) continue;\n\n            int cur = t;\n            pathV[s][t].set(cur);\n            while (cur != s) {\n                int e = parEdge[cur];\n                if (e < 0) break;\n                pathE[s][t].set(e);\n                cur = parNode[cur];\n                pathV[s][t].set(cur);\n            }\n        }\n    }\n}\n\nbitset<MAXM> buildGlobalMST() {\n    DSU d(N);\n    bitset<MAXM> m;\n    for (int eid : edgeOrder) {\n        if (d.unite(edges[eid].u, edges[eid].v)) {\n            m.set(eid);\n        }\n    }\n    return m;\n}\n\nvector<int> nearestSolution(double lambda) {\n    vector<int> P(N, 0);\n    for (int k = 0; k < K; ++k) {\n        double best = 1e100;\n        int bi = -1;\n        for (int i = 0; i < N; ++i) {\n            int p = (int)ceilD[i][k];\n            if (p > 5000) continue;\n            double val = (double)distSq[i][k] + lambda * (double)spDist[0][i];\n            if (val < best) {\n                best = val;\n                bi = i;\n            }\n        }\n\n        if (bi == -1) {\n            int bp = INT_MAX;\n            for (int i = 0; i < N; ++i) {\n                if ((int)ceilD[i][k] < bp) {\n                    bp = (int)ceilD[i][k];\n                    bi = i;\n                }\n            }\n        }\n\n        P[bi] = max(P[bi], (int)ceilD[bi][k]);\n    }\n    return P;\n}\n\nvoid considerCandidate(vector<int> P, vector<Solution>& sols, double stopTime) {\n    for (int& p : P) p = min(5000, max(0, p));\n\n    vector<char> allAllowed(N, 1);\n    if (!isFull(P)) {\n        greedyRepair(P, allAllowed, 0.6, 1.0, nullptr, stopTime);\n    }\n    if (!isFull(P)) return;\n\n    auto add = [&](const vector<int>& Q) {\n        Solution s = evaluateSolution(Q);\n        if (s.total < INFLL / 2) sols.push_back(s);\n    };\n\n    add(P);\n\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<int> q = P;\n        trimP(q, makeOrder(q, mode));\n        add(q);\n    }\n\n    vector<int> q = P;\n    trimP(q, makeOrder(q, 1));\n    trimP(q, makeOrder(q, 0));\n    add(q);\n}\n\nSolution localSearch(Solution cur, double deadline) {\n    vector<char> allAllowed(N, 1);\n\n    for (int pass = 0; pass < 6 && gtimer.elapsed() < deadline; ++pass) {\n        cur = evaluateSolution(cur.P);\n        bool improved = false;\n\n        if (gtimer.elapsed() < deadline) {\n            vector<long long> br = computeBranch(cur.P, cur.tree);\n            vector<int> p2 = cur.P;\n            trimP(p2, makeOrder(p2, 3, &br));\n            Solution ns = evaluateSolution(p2);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n            }\n        }\n        if (improved) continue;\n\n        if (gtimer.elapsed() < deadline) {\n            vector<char> avail = getReachable(cur.tree.mask);\n            double exps[2] = {1.0, 1.15};\n            for (double ex : exps) {\n                vector<int> p0(N, 0);\n                if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n                trimP(p0, makeOrder(p0, 0));\n                Solution ns = evaluateSolution(p0);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        vector<int> order = makeOrder(cur.P, 3, &br);\n\n        int stationTried = 0;\n        int maxStations = (pass == 0 ? 50 : 30);\n\n        for (int id : order) {\n            if (cur.P[id] <= 0) continue;\n            if (gtimer.elapsed() > deadline) break;\n            if (stationTried++ >= maxStations) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            vector<int> uniqTargets;\n            for (int t : targets) {\n                if (t < 0 || t >= p) continue;\n                bool seen = false;\n                for (int u : uniqTargets) if (u == t) seen = true;\n                if (!seen) uniqTargets.push_back(t);\n            }\n\n            for (int np : uniqTargets) {\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                p2[id] = np;\n\n                double beta = (np == 0 ? 0.8 : 0.4);\n                if (!greedyRepair(p2, allAllowed, beta, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n            if (improved) break;\n        }\n        if (improved) continue;\n\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            struct CutCand {\n                long long score;\n                int e;\n                vector<int> terms;\n            };\n            vector<CutCand> cuts;\n\n            for (int e = 0; e < M; ++e) {\n                if (!cur.tree.mask.test(e)) continue;\n\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] : adj[v]) {\n                        if (eid == e || !cur.tree.mask.test(eid) || vis[to]) continue;\n                        vis[to] = 1;\n                        q.push(to);\n                    }\n                }\n\n                vector<int> terms;\n                long long p2sum = 0;\n                for (int v = 0; v < N; ++v) {\n                    if (!vis[v] && cur.P[v] > 0) {\n                        terms.push_back(v);\n                        p2sum += 1LL * cur.P[v] * cur.P[v];\n                    }\n                }\n                if (terms.empty()) continue;\n\n                long long branchCost = edges[e].w;\n                for (int ee = 0; ee < M; ++ee) {\n                    if (ee == e || !cur.tree.mask.test(ee)) continue;\n                    int u = edges[ee].u, v = edges[ee].v;\n                    if (!vis[u] && !vis[v]) branchCost += edges[ee].w;\n                }\n\n                cuts.push_back({branchCost + p2sum, e, terms});\n            }\n\n            sort(cuts.begin(), cuts.end(), [](const CutCand& a, const CutCand& b) {\n                return a.score > b.score;\n            });\n\n            int tried = 0;\n            for (const auto& cc : cuts) {\n                if (tried++ >= 8) break;\n                if (gtimer.elapsed() > deadline) break;\n\n                vector<int> p2 = cur.P;\n                for (int v : cc.terms) p2[v] = 0;\n\n                if (!greedyRepair(p2, allAllowed, 0.9, 1.05, nullptr, deadline)) continue;\n\n                trimP(p2, makeOrder(p2, 1));\n                trimP(p2, makeOrder(p2, 0));\n\n                Solution ns = evaluateSolution(p2);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n        if (improved) continue;\n\n        if (pass <= 3 && gtimer.elapsed() < deadline) {\n            vector<int> top;\n            for (int id : order) {\n                if (cur.P[id] > 0) {\n                    top.push_back(id);\n                    if ((int)top.size() >= 8) break;\n                }\n            }\n\n            for (int a = 0; a < (int)top.size() && !improved; ++a) {\n                for (int b = a + 1; b < (int)top.size(); ++b) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> p2 = cur.P;\n                    p2[top[a]] = 0;\n                    p2[top[b]] = 0;\n\n                    if (!greedyRepair(p2, allAllowed, 0.85, 1.05, nullptr, deadline)) continue;\n\n                    trimP(p2, makeOrder(p2, 1));\n                    trimP(p2, makeOrder(p2, 0));\n\n                    Solution ns = evaluateSolution(p2);\n                    if (ns.total < cur.total) {\n                        cur = ns;\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution fixedTreeReverseDeleteFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        Solution first;\n        first.total = INFLL;\n        Solution bestRound = cur;\n\n        for (int typ = 0; typ < 12 && gtimer.elapsed() < deadline; ++typ) {\n            vector<int> q(N, 0);\n            for (int i = 0; i < N; ++i) {\n                if (avail[i]) q[i] = 5000;\n            }\n\n            applyFixedTrimType(q, typ);\n\n            Solution ns = evaluateSolution(q, &baseMask);\n            if (ns.total < cur.total && first.total >= INFLL / 2) first = ns;\n            if (ns.total < bestRound.total) bestRound = ns;\n        }\n\n        Solution chosen = stableChoose(cur, first, bestRound);\n        if (chosen.total < cur.total) cur = chosen;\n        else break;\n    }\n\n    return cur;\n}\n\nSolution fixedTreeExcludeFinal(Solution cur, double deadline) {\n    static const int typeMap[6] = {3, 5, 7, 8, 9, 12};\n\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        vector<int> order = makeOrder(cur.P, 3, &br);\n\n        Solution first;\n        first.total = INFLL;\n        Solution bestRound = cur;\n        int excludedTried = 0;\n\n        for (int ban : order) {\n            if (gtimer.elapsed() > deadline) break;\n            if (cur.P[ban] <= 0) continue;\n            if (excludedTried++ >= 6) break;\n\n            for (int ti = 0; ti < 6 && gtimer.elapsed() < deadline; ++ti) {\n                vector<int> q(N, 0);\n                for (int i = 0; i < N; ++i) {\n                    if (avail[i] && i != ban) q[i] = 5000;\n                }\n\n                applyFixedTrimType(q, typeMap[ti]);\n\n                Solution ns = evaluateSolution(q, &baseMask);\n                if (ns.total < cur.total && first.total >= INFLL / 2) first = ns;\n                if (ns.total < bestRound.total) bestRound = ns;\n            }\n        }\n\n        Solution chosen = stableChoose(cur, first, bestRound);\n        if (chosen.total < cur.total) cur = chosen;\n        else break;\n    }\n\n    return cur;\n}\n\nSolution optimizeOnReachableFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        bool improved = false;\n        vector<double> exps = {1.0, 1.15, 0.9, 1.3, 0.75};\n\n        for (double ex : exps) {\n            if (gtimer.elapsed() > deadline) break;\n\n            vector<int> p0(N, 0);\n            if (!greedyRepair(p0, avail, 0.0, ex, nullptr, deadline)) continue;\n\n            vector<vector<int>> candP;\n\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 0));\n                candP.push_back(q);\n            }\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 1));\n                candP.push_back(q);\n            }\n            {\n                vector<int> q = p0;\n                trimP(q, makeOrder(q, 1));\n                trimP(q, makeOrder(q, 0));\n                candP.push_back(q);\n            }\n\n            for (auto& q : candP) {\n                if (gtimer.elapsed() > deadline) break;\n                Solution ns = evaluateSolution(q, &baseMask);\n                if (ns.total < cur.total) {\n                    cur = ns;\n                    improved = true;\n                }\n            }\n\n            if (improved) break;\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution reachableLocalFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n        bool improved = false;\n\n        vector<int> cnt(K, 0), owner(K, -1);\n        for (int i = 0; i < N; ++i) {\n            if (cur.P[i] <= 0) continue;\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > cur.P[i]) break;\n                if (cnt[rk.k] == 0) owner[rk.k] = i;\n                cnt[rk.k]++;\n            }\n        }\n\n        vector<int> critCnt(N, 0);\n        for (int k = 0; k < K; ++k) {\n            if (cnt[k] == 1 && owner[k] >= 0) critCnt[owner[k]]++;\n        }\n\n        struct AddCand {\n            double score;\n            int v, p;\n        };\n        vector<AddCand> adds;\n\n        for (int v = 0; v < N; ++v) {\n            if (!avail[v] || cur.P[v] > 0 || coverList[v].empty()) continue;\n\n            double gain = 0.0;\n            int critical = 0;\n            double bestScore = -1e100;\n            int bestP = 0;\n            double bestRatio = -1e100;\n            int bestPR = 0;\n\n            int idx = 0, sz = (int)coverList[v].size();\n            while (idx < sz) {\n                int p = (int)coverList[v][idx].p;\n                while (idx < sz && (int)coverList[v][idx].p == p) {\n                    int k = coverList[v][idx].k;\n                    if (cnt[k] == 1) {\n                        int o = owner[k];\n                        if (o >= 0 && critCnt[o] > 0) {\n                            gain += (double)(1LL * cur.P[o] * cur.P[o]) / (double)critCnt[o];\n                            critical++;\n                        }\n                    }\n                    idx++;\n                }\n\n                if (critical >= 3) {\n                    double cost = (double)(1LL * p * p);\n                    double score = gain - cost;\n                    double ratio = gain / (cost + 1.0);\n                    if (score > bestScore) {\n                        bestScore = score;\n                        bestP = p;\n                    }\n                    if (ratio > bestRatio) {\n                        bestRatio = ratio;\n                        bestPR = p;\n                    }\n                }\n            }\n\n            if (bestP > 0 && bestScore > 0.0) adds.push_back({bestScore, v, bestP});\n            if (bestPR > 0 && bestRatio > 1.15 && bestPR != bestP) {\n                adds.push_back({bestRatio * 1000000.0, v, bestPR});\n            }\n        }\n\n        sort(adds.begin(), adds.end(), [](const AddCand& a, const AddCand& b) {\n            return a.score > b.score;\n        });\n\n        Solution firstAdd;\n        firstAdd.total = INFLL;\n        Solution bestAdd = cur;\n        int addTried = 0;\n\n        for (const auto& c : adds) {\n            if (gtimer.elapsed() > deadline) break;\n            if (addTried++ >= 7) break;\n\n            vector<int> q = cur.P;\n            q[c.v] = max(q[c.v], c.p);\n\n            trimP(q, orderWithLast(q, 0, c.v));\n            trimP(q, orderWithLast(q, 1, c.v));\n\n            Solution ns = evaluateSolution(q, &baseMask);\n            if (ns.total < cur.total && firstAdd.total >= INFLL / 2) firstAdd = ns;\n            if (ns.total < bestAdd.total) bestAdd = ns;\n        }\n\n        Solution chosenAdd = stableChoose(cur, firstAdd, bestAdd);\n        if (chosenAdd.total < cur.total) {\n            cur = chosenAdd;\n            improved = true;\n        }\n\n        if (improved) continue;\n\n        vector<int> order = makeOrder(cur.P, 1);\n        int delTried = 0;\n\n        for (int id : order) {\n            if (gtimer.elapsed() > deadline) break;\n            if (cur.P[id] <= 0) continue;\n            if (delTried++ >= 7) break;\n\n            int p = cur.P[id];\n            vector<int> targets;\n            targets.push_back(0);\n            if (p > 1000) {\n                targets.push_back(p / 2);\n                targets.push_back((p * 2) / 3);\n                targets.push_back((p * 4) / 5);\n            }\n\n            sort(targets.begin(), targets.end());\n            targets.erase(unique(targets.begin(), targets.end()), targets.end());\n\n            Solution firstDel;\n            firstDel.total = INFLL;\n            Solution bestDel = cur;\n\n            for (int t : targets) {\n                if (gtimer.elapsed() > deadline) break;\n                if (t < 0 || t >= p) continue;\n\n                double exps[2] = {1.0, 1.15};\n                for (double ex : exps) {\n                    if (gtimer.elapsed() > deadline) break;\n\n                    vector<int> q = cur.P;\n                    q[id] = t;\n\n                    vector<char> allow2 = avail;\n                    if (t == 0) allow2[id] = 0;\n\n                    if (!greedyRepair(q, allow2, 0.0, ex, nullptr, deadline)) continue;\n\n                    trimP(q, makeOrder(q, 1));\n                    trimP(q, makeOrder(q, 0));\n\n                    Solution ns = evaluateSolution(q, &baseMask);\n                    if (ns.total < cur.total && firstDel.total >= INFLL / 2) firstDel = ns;\n                    if (ns.total < bestDel.total) bestDel = ns;\n                }\n            }\n\n            Solution chosenDel = stableChoose(cur, firstDel, bestDel);\n            if (chosenDel.total < cur.total) {\n                cur = chosenDel;\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nSolution pairReplaceFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        bitset<MAXM> baseMask = cur.tree.mask;\n        vector<char> avail = getReachable(baseMask);\n\n        vector<int> cnt(K, 0), owner(K, -1);\n        for (int i = 0; i < N; ++i) {\n            if (cur.P[i] <= 0) continue;\n            for (const auto& rk : coverList[i]) {\n                if ((int)rk.p > cur.P[i]) break;\n                if (cnt[rk.k] == 0) owner[rk.k] = i;\n                cnt[rk.k]++;\n            }\n        }\n\n        vector<vector<int>> uniqueBy(N);\n        for (int k = 0; k < K; ++k) {\n            if (cnt[k] == 1 && owner[k] >= 0) {\n                uniqueBy[owner[k]].push_back(k);\n            }\n        }\n\n        vector<long long> branch = computeBranch(cur.P, cur.tree);\n\n        vector<long long> minConn(N, INFLL);\n        vector<int> nearV(N, 0);\n        for (int v = 0; v < N; ++v) {\n            for (int u = 0; u < N; ++u) {\n                if (!avail[u]) continue;\n                if (spDist[v][u] < minConn[v]) {\n                    minConn[v] = spDist[v][u];\n                    nearV[v] = u;\n                }\n            }\n        }\n\n        struct Cand {\n            double score;\n            int i, j, req;\n        };\n        vector<Cand> cands;\n\n        for (int i = 0; i < N; ++i) {\n            if (cur.P[i] <= 0 || uniqueBy[i].empty()) continue;\n\n            for (int j = 0; j < N; ++j) {\n                if (i == j || coverList[j].empty()) continue;\n\n                int req = cur.P[j];\n                bool ok = true;\n                for (int k : uniqueBy[i]) {\n                    int d = (int)ceilD[j][k];\n                    if (d > 5000) {\n                        ok = false;\n                        break;\n                    }\n                    req = max(req, d);\n                }\n                if (!ok || req > 5000) continue;\n\n                double conn = 0.0;\n                if (cur.P[j] == 0 && !avail[j]) conn = 0.85 * (double)minConn[j];\n\n                double delta =\n                    (double)(1LL * req * req - 1LL * cur.P[j] * cur.P[j])\n                    - (double)(1LL * cur.P[i] * cur.P[i])\n                    - (double)branch[i]\n                    + conn;\n\n                if (delta < 2.0e6) {\n                    cands.push_back({delta, i, j, req});\n                }\n            }\n        }\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        Solution first;\n        first.total = INFLL;\n        Solution bestRound = cur;\n        int tried = 0;\n\n        for (const auto& c : cands) {\n            if (gtimer.elapsed() > deadline) break;\n            if (tried++ >= 14) break;\n\n            vector<int> q = cur.P;\n            q[c.i] = 0;\n            q[c.j] = max(q[c.j], c.req);\n\n            trimP(q, orderWithLast(q, 0, c.j));\n            trimP(q, orderWithLast(q, 1, c.j));\n\n            bitset<MAXM> extra = baseMask;\n            if (q[c.j] > 0 && !avail[c.j]) {\n                extra |= pathE[c.j][nearV[c.j]];\n            }\n\n            Solution ns = evaluateSolution(q, &extra);\n            if (ns.total < cur.total && first.total >= INFLL / 2) first = ns;\n            if (ns.total < bestRound.total) bestRound = ns;\n        }\n\n        Solution chosen = stableChoose(cur, first, bestRound);\n        if (chosen.total < cur.total) cur = chosen;\n        else break;\n    }\n\n    return cur;\n}\n\nSolution multiTrimFinal(Solution cur, double deadline) {\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        vector<long long> br = computeBranch(cur.P, cur.tree);\n        bitset<MAXM> baseMask = cur.tree.mask;\n        bool improved = false;\n\n        for (int typ = 0; typ < 10 && gtimer.elapsed() < deadline; ++typ) {\n            vector<int> q = cur.P;\n\n            if (typ == 0) {\n                trimP(q, makeOrder(q, 3, &br));\n            } else if (typ == 1) {\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 2) {\n                trimP(q, makeOrder(q, 1));\n            } else if (typ == 3) {\n                trimP(q, makeOrder(q, 2));\n            } else if (typ == 4) {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 2.0, 0.0));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 5) {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 0.5, 0.5));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 6) {\n                trimP(q, makeOrderWeighted(q, br, 0.5, 1.5, 0.2));\n                trimP(q, makeOrder(q, 1));\n            } else if (typ == 7) {\n                trimP(q, makeOrderWeighted(q, br, 0.2, 2.0, 1.0));\n                trimP(q, makeOrder(q, 0));\n            } else if (typ == 8) {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 1.0, 1.0));\n                trimP(q, makeOrder(q, 0));\n            } else {\n                trimP(q, makeOrderWeighted(q, br, 1.0, 3.0, 0.0));\n                trimP(q, makeOrder(q, 0));\n            }\n\n            Solution ns = evaluateSolution(q, &baseMask);\n            if (ns.total < cur.total) {\n                cur = ns;\n                improved = true;\n                break;\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return cur;\n}\n\nbitset<MAXM> buildGreedyFromVertex(int start, const vector<int>& terms) {\n    bitset<MAXM> mask;\n    bitset<MAXN> treeV;\n    treeV.set(start);\n\n    while (true) {\n        bool done = true;\n        for (int t : terms) {\n            if (!treeV.test(t)) {\n                done = false;\n                break;\n            }\n        }\n        if (done) break;\n\n        long long best = INFLL;\n        int bestFrom = -1, bestT = -1;\n\n        for (int t : terms) {\n            if (treeV.test(t)) continue;\n            for (int v = 0; v < N; ++v) {\n                if (!treeV.test(v)) continue;\n                if (spDist[v][t] < best) {\n                    best = spDist[v][t];\n                    bestFrom = v;\n                    bestT = t;\n                }\n            }\n        }\n\n        if (bestT == -1) break;\n        mask |= pathE[bestFrom][bestT];\n        treeV |= pathV[bestFrom][bestT];\n    }\n\n    return mask;\n}\n\nTreeResult exactSteinerSmall(const vector<int>& terms, const vector<char>& terminal, double deadline) {\n    TreeResult res;\n    res.cost = INFLL;\n    res.mask.reset();\n\n    int T = (int)terms.size();\n    if (T <= 1) {\n        res.cost = 0;\n        return res;\n    }\n    if (T > 10) return res;\n    if (T == 10 && gtimer.elapsed() > deadline - 0.025) return res;\n\n    int S = 1 << T;\n    int total = S * N;\n\n    vector<long long> dp(total, INFLL);\n    vector<bitset<MAXM>> bm(total);\n\n    auto id = [&](int mask, int v) {\n        return mask * N + v;\n    };\n\n    for (int i = 0; i < T; ++i) {\n        int mask = 1 << i;\n        for (int v = 0; v < N; ++v) {\n            dp[id(mask, v)] = spDist[terms[i]][v];\n            bm[id(mask, v)] = pathE[terms[i]][v];\n        }\n    }\n\n    for (int mask = 1; mask < S; ++mask) {\n        if ((mask & (mask - 1)) == 0) continue;\n        if ((mask & 3) == 0 && gtimer.elapsed() > deadline) return res;\n\n        int rowM = mask * N;\n\n        for (int sub = (mask - 1) & mask; sub; sub = (sub - 1) & mask) {\n            int other = mask ^ sub;\n            if (sub > other) continue;\n\n            int rowS = sub * N;\n            int rowO = other * N;\n\n            for (int v = 0; v < N; ++v) {\n                long long a = dp[rowS + v];\n                long long b = dp[rowO + v];\n                if (a >= INFLL / 4 || b >= INFLL / 4) continue;\n                long long nd = a + b;\n                if (nd < dp[rowM + v]) {\n                    dp[rowM + v] = nd;\n                    bm[rowM + v] = bm[rowS + v] | bm[rowO + v];\n                }\n            }\n        }\n\n        long long baseC[MAXN];\n        bitset<MAXM> baseB[MAXN];\n        for (int v = 0; v < N; ++v) {\n            baseC[v] = dp[rowM + v];\n            baseB[v] = bm[rowM + v];\n        }\n\n        for (int s = 0; s < N; ++s) {\n            if (baseC[s] >= INFLL / 4) continue;\n            for (int v = 0; v < N; ++v) {\n                long long nd = baseC[s] + spDist[s][v];\n                if (nd < dp[rowM + v]) {\n                    dp[rowM + v] = nd;\n                    bm[rowM + v] = baseB[s] | pathE[s][v];\n                }\n            }\n        }\n    }\n\n    int full = S - 1;\n    int bestV = -1;\n    long long bestCost = INFLL;\n    for (int v = 0; v < N; ++v) {\n        if (dp[id(full, v)] < bestCost) {\n            bestCost = dp[id(full, v)];\n            bestV = v;\n        }\n    }\n\n    if (bestV != -1) {\n        res = reduceMask(bm[id(full, bestV)], terminal);\n    }\n    return res;\n}\n\nTreeResult finalImproveTree(const vector<int>& P, TreeResult best, double deadline) {\n    vector<char> terminal = makeTerminal(P);\n\n    vector<int> terms;\n    terms.push_back(0);\n    for (int i = 1; i < N; ++i) {\n        if (P[i] > 0) terms.push_back(i);\n    }\n\n    if ((int)terms.size() <= 1) {\n        TreeResult r;\n        r.cost = 0;\n        r.mask.reset();\n        return r;\n    }\n\n    auto upd = [&](const bitset<MAXM>& m) {\n        if (gtimer.elapsed() > deadline) return;\n        TreeResult r = reduceMask(m, terminal);\n        if (r.cost < best.cost) best = r;\n    };\n\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        TreeResult rb = best;\n        for (int e = 0; e < M; ++e) {\n            if ((e & 15) == 0 && gtimer.elapsed() > deadline) break;\n            if (best.mask.test(e)) continue;\n            bitset<MAXM> nm = best.mask;\n            nm.set(e);\n            TreeResult r = reduceMask(nm, terminal);\n            if (r.cost < rb.cost) rb = r;\n        }\n        if (rb.cost < best.cost) best = rb;\n        else break;\n    }\n\n    if (gtimer.elapsed() < deadline) {\n        bitset<MAXM> m;\n        for (int i = 0; i < (int)terms.size(); ++i) {\n            for (int j = i + 1; j < (int)terms.size(); ++j) {\n                m |= pathE[terms[i]][terms[j]];\n            }\n        }\n        upd(m);\n    }\n\n    for (int c = 0; c < N && gtimer.elapsed() < deadline; ++c) {\n        bitset<MAXM> m;\n        for (int t : terms) {\n            if (t != c) m |= pathE[c][t];\n        }\n        upd(m);\n    }\n\n    for (int depth = 0; depth < 2 && gtimer.elapsed() < deadline; ++depth) {\n        vector<char> vset(N, 0);\n        for (int t : terms) vset[t] = 1;\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                vset[edges[e].u] = 1;\n                vset[edges[e].v] = 1;\n            }\n        }\n\n        if (depth == 1) {\n            vector<char> ex = vset;\n            for (int e = 0; e < M; ++e) {\n                if (vset[edges[e].u] || vset[edges[e].v]) {\n                    ex[edges[e].u] = 1;\n                    ex[edges[e].v] = 1;\n                }\n            }\n            vset.swap(ex);\n        }\n\n        bitset<MAXM> m;\n        for (int e = 0; e < M; ++e) {\n            if (vset[edges[e].u] && vset[edges[e].v]) m.set(e);\n        }\n        upd(m);\n    }\n\n    {\n        double greedyDeadline = deadline - 0.004;\n        vector<int> starts;\n        vector<char> used(N, 0);\n        auto addStart = [&](int v) {\n            if (!used[v]) {\n                used[v] = 1;\n                starts.push_back(v);\n            }\n        };\n\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                addStart(edges[e].u);\n                addStart(edges[e].v);\n            }\n        }\n        for (int t : terms) addStart(t);\n        for (int v = 0; v < N; ++v) addStart(v);\n\n        for (int s : starts) {\n            if (gtimer.elapsed() > greedyDeadline) break;\n            bitset<MAXM> m = buildGreedyFromVertex(s, terms);\n            TreeResult r = reduceMask(m, terminal);\n            if (r.cost < best.cost) best = r;\n        }\n    }\n\n    for (int round = 0; round < 2 && gtimer.elapsed() < deadline; ++round) {\n        vector<char> vset(N, 0);\n        for (int t : terms) vset[t] = 1;\n        for (int e = 0; e < M; ++e) {\n            if (best.mask.test(e)) {\n                vset[edges[e].u] = 1;\n                vset[edges[e].v] = 1;\n            }\n        }\n\n        vector<int> vs;\n        for (int i = 0; i < N; ++i) if (vset[i]) vs.push_back(i);\n\n        TreeResult rb = best;\n        for (int a = 0; a < (int)vs.size() && gtimer.elapsed() < deadline; ++a) {\n            for (int b = a + 1; b < (int)vs.size(); ++b) {\n                if ((b & 15) == 0 && gtimer.elapsed() > deadline) break;\n                bitset<MAXM> nm = best.mask | pathE[vs[a]][vs[b]];\n                TreeResult r = reduceMask(nm, terminal);\n                if (r.cost < rb.cost) rb = r;\n            }\n        }\n\n        if (rb.cost < best.cost) best = rb;\n        else break;\n    }\n\n    double need = ((int)terms.size() <= 9 ? 0.006 : 0.025);\n    if ((int)terms.size() <= 10 && gtimer.elapsed() < deadline - need) {\n        TreeResult r = exactSteinerSmall(terms, terminal, deadline);\n        if (r.cost < best.cost) best = r;\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    gtimer.reset();\n\n    cin >> N >> M >> K;\n\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    adj.assign(N, {});\n    for (int j = 0; j < M; ++j) {\n        int u, v;\n        long long w;\n        cin >> u >> v >> w;\n        --u; --v;\n        edges[j] = {u, v, w};\n        adj[u].push_back({v, j});\n        adj[v].push_back({u, j});\n    }\n\n    RA.resize(K);\n    RB.resize(K);\n    for (int k = 0; k < K; ++k) cin >> RA[k] >> RB[k];\n\n    edgeOrder.resize(M);\n    iota(edgeOrder.begin(), edgeOrder.end(), 0);\n    sort(edgeOrder.begin(), edgeOrder.end(), [&](int a, int b) {\n        if (edges[a].w != edges[b].w) return edges[a].w < edges[b].w;\n        return a < b;\n    });\n\n    allEdgesMask.reset();\n    for (int e = 0; e < M; ++e) allEdgesMask.set(e);\n\n    computeShortestPaths();\n    globalMSTMask = buildGlobalMST();\n\n    distSq.assign(N, vector<int>(K));\n    ceilD.assign(N, vector<unsigned short>(K));\n    coverCnt5000.assign(N, 0);\n    coverSumP5000.assign(N, 0);\n\n    for (int i = 0; i < N; ++i) {\n        coverList[i].clear();\n        for (int k = 0; k < K; ++k) {\n            long long dx = (long long)X[i] - RA[k];\n            long long dy = (long long)Y[i] - RB[k];\n            long long d2 = dx * dx + dy * dy;\n            int p = ceil_sqrt_ll(d2);\n            distSq[i][k] = (int)d2;\n            ceilD[i][k] = (unsigned short)p;\n            if (p <= 5000) {\n                coverList[i].push_back({(unsigned short)p, k});\n                coverCnt5000[i]++;\n                coverSumP5000[i] += p;\n            }\n        }\n        sort(coverList[i].begin(), coverList[i].end(), [](const RK& a, const RK& b) {\n            if (a.p != b.p) return a.p < b.p;\n            return a.k < b.k;\n        });\n    }\n\n    vector<Solution> sols;\n    const double GEN_DEADLINE = 0.85;\n    const double LOCAL_DEADLINE = 1.90;\n\n    vector<double> lambdas = {0.0, 0.05, 0.2, 0.7, 1.5};\n    for (double l : lambdas) {\n        vector<int> P = nearestSolution(l);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    {\n        vector<int> P(N, 5000);\n        considerCandidate(P, sols, GEN_DEADLINE);\n    }\n\n    vector<pair<double,double>> params = {\n        {0.0, 1.0}, {0.2, 1.0}, {0.5, 1.0}, {0.8, 1.0},\n        {1.2, 1.0}, {2.0, 1.0}, {0.3, 1.15}, {0.8, 1.15},\n        {1.5, 1.15}, {0.5, 0.9}\n    };\n\n    vector<char> allAllowed(N, 1);\n    for (auto [beta, ex] : params) {\n        if (gtimer.elapsed() > GEN_DEADLINE) break;\n        vector<int> P(N, 0);\n        if (greedyRepair(P, allAllowed, beta, ex, nullptr, GEN_DEADLINE)) {\n            considerCandidate(P, sols, GEN_DEADLINE);\n        }\n    }\n\n    if (sols.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        if (!isFull(P)) greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        sols.push_back(evaluateSolution(P));\n    }\n\n    sort(sols.begin(), sols.end(), [](const Solution& a, const Solution& b) {\n        return a.total < b.total;\n    });\n\n    vector<Solution> uniq;\n    for (const auto& s : sols) {\n        if (s.total >= INFLL / 2) continue;\n        bool dup = false;\n        for (const auto& u : uniq) {\n            if (u.P == s.P) {\n                dup = true;\n                break;\n            }\n        }\n        if (!dup) uniq.push_back(s);\n        if ((int)uniq.size() >= 20) break;\n    }\n\n    if (uniq.empty()) {\n        vector<int> P = nearestSolution(0.0);\n        greedyRepair(P, allAllowed, 0.0, 1.0);\n        trimP(P, makeOrder(P, 0));\n        uniq.push_back(evaluateSolution(P));\n    }\n\n    Solution best = uniq[0];\n\n    int optN = min(5, (int)uniq.size());\n    for (int i = 0; i < optN && gtimer.elapsed() < LOCAL_DEADLINE; ++i) {\n        Solution opt = localSearch(uniq[i], LOCAL_DEADLINE);\n        if (opt.total < best.total) best = opt;\n    }\n\n    best = evaluateSolution(best.P);\n\n    if (gtimer.elapsed() < 1.945) {\n        Solution ns = multiTrimFinal(best, 1.955);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (!isFull(best.P)) {\n        greedyRepair(best.P, allAllowed, 0.0, 1.0);\n        best = evaluateSolution(best.P);\n    } else {\n        best = evaluateSolution(best.P);\n    }\n\n    Solution safeBest = best;\n\n    if (gtimer.elapsed() < 1.958) {\n        Solution ns = fixedTreeReverseDeleteFinal(best, 1.964);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.964) {\n        Solution ns = fixedTreeExcludeFinal(best, 1.967);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.965) {\n        Solution ns = optimizeOnReachableFinal(best, 1.970);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.970) {\n        Solution ns = reachableLocalFinal(best, 1.974);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.973) {\n        Solution ns = pairReplaceFinal(best, 1.977);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.976) {\n        Solution ns = multiTrimFinal(best, 1.979);\n        if (ns.total < best.total) best = ns;\n    }\n\n    if (gtimer.elapsed() < 1.982) {\n        TreeResult tr = finalImproveTree(best.P, best.tree, 1.992);\n        if (tr.cost < best.tree.cost) {\n            best.tree = tr;\n            best.total = best.radCost + best.tree.cost;\n        }\n    }\n\n    if (!isFull(best.P) || best.total >= INFLL / 2) {\n        best = safeBest;\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 e = 0; e < M; ++e) {\n        if (e) cout << ' ';\n        cout << (best.tree.mask.test(e) ? 1 : 0);\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 int M = N * (N + 1) / 2;\nstatic constexpr int INTERNAL = M - N;\n\nint ID[N][N], Xc[M], Yc[M];\nvector<int> G[M], PAR[M], CH[M];\nvector<pair<int,int>> EDGES, ADJ;\nvector<int> INCIDENT[M];\nbool ADJMAT[M][M];\n\nbool validXY(int x, int y){ return 0 <= x && x < N && 0 <= y && y <= x; }\n\nint distHex(int a, int b){\n    int dx = Xc[a] - Xc[b];\n    int dy = Yc[a] - Yc[b];\n    int dz = (Xc[a] - Yc[a]) - (Xc[b] - Yc[b]);\n    return max({abs(dx), abs(dy), abs(dz)});\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 FastRand{\n    uint64_t x;\n    FastRand(uint64_t seed=1): x(seed){}\n    uint64_t next(){\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n){ return (int)(next() % (uint64_t)n); }\n};\n\nvoid precompute(){\n    memset(ADJMAT, 0, sizeof(ADJMAT));\n    for(int i=0;i<N;i++) for(int j=0;j<N;j++) ID[i][j] = -1;\n\n    int idx = 0;\n    for(int x=0;x<N;x++){\n        for(int y=0;y<=x;y++){\n            ID[x][y] = idx;\n            Xc[idx] = x;\n            Yc[idx] = y;\n            idx++;\n        }\n    }\n\n    int dx[6] = {0,0,-1,-1,1,1};\n    int dy[6] = {-1,1,-1,0,0,1};\n\n    for(int p=0;p<M;p++){\n        int x = Xc[p], y = Yc[p];\n\n        for(int k=0;k<6;k++){\n            int nx = x + dx[k], ny = y + dy[k];\n            if(validXY(nx,ny)){\n                int q = ID[nx][ny];\n                G[p].push_back(q);\n                ADJMAT[p][q] = true;\n            }\n        }\n\n        if(x+1<N){\n            CH[p].push_back(ID[x+1][y]);\n            CH[p].push_back(ID[x+1][y+1]);\n        }\n        if(x>0){\n            if(y>0) PAR[p].push_back(ID[x-1][y-1]);\n            if(y<x) PAR[p].push_back(ID[x-1][y]);\n        }\n    }\n\n    for(int p=0;p<M;p++){\n        for(int c: CH[p]){\n            int ei = (int)EDGES.size();\n            EDGES.emplace_back(p,c);\n            INCIDENT[p].push_back(ei);\n            INCIDENT[c].push_back(ei);\n        }\n    }\n\n    for(int p=0;p<M;p++){\n        for(int q: G[p]) if(p<q) ADJ.emplace_back(p,q);\n    }\n}\n\nstruct Work{\n    array<int,M> a;\n    array<int,M> pos;\n    vector<pair<int,int>> ops;\n\n    Work(){}\n    Work(const array<int,M>& init){\n        a = init;\n        for(int i=0;i<M;i++) pos[a[i]] = i;\n        ops.clear();\n    }\n};\n\ninline void doSwap(Work& w, int u, int v){\n    int lu = w.a[u], lv = w.a[v];\n    swap(w.a[u], w.a[v]);\n    w.pos[lu] = v;\n    w.pos[lv] = u;\n    w.ops.emplace_back(u,v);\n}\n\nint countViol(const array<int,M>& a){\n    int e = 0;\n    for(auto [p,c]: EDGES) if(a[p] > a[c]) e++;\n    return e;\n}\n\narray<int,M> simulateOps(const array<int,M>& init, const vector<pair<int,int>>& ops){\n    array<int,M> a = init;\n    for(auto [u,v]: ops) swap(a[u], a[v]);\n    return a;\n}\n\nint centerVal(int p){ return abs(2 * Yc[p] - Xc[p]); }\n\nint chooseCand(const vector<int>& cand, int choice, const Work& w){\n    int best = cand[0];\n    for(int q: cand){\n        bool take = false;\n        if(choice == 0){\n            if(w.a[q] > w.a[best]) take = true;\n        }else if(choice == 1){\n            if(w.a[q] < w.a[best]) take = true;\n        }else if(choice == 2){\n            if(Yc[q] < Yc[best]) take = true;\n        }else if(choice == 3){\n            if(Yc[q] > Yc[best]) take = true;\n        }else{\n            int cq = centerVal(q), cb = centerVal(best);\n            if(cq < cb || (cq == cb && w.a[q] > w.a[best])) take = true;\n        }\n        if(take) best = q;\n    }\n    return best;\n}\n\nint chooseCandRand(const vector<int>& cand, int mode, const Work& w, FastRand& rng, int dir){\n    if((int)cand.size() == 1) return cand[0];\n\n    if(mode == 0) return cand[rng.nextInt((int)cand.size())];\n\n    if(1 <= mode && mode <= 5){\n        int base = chooseCand(cand, mode - 1, w);\n        if(rng.nextInt(100) < 75) return base;\n\n        vector<int> other;\n        for(int q: cand) if(q != base) other.push_back(q);\n        if(other.empty()) return base;\n        return other[rng.nextInt((int)other.size())];\n    }\n\n    int best = cand[0];\n    long long bestSc = LLONG_MIN;\n\n    for(int q: cand){\n        long long sc;\n        if(mode == 6) sc = 100LL * w.a[q] - 15LL * centerVal(q);\n        else sc = -100LL * w.a[q] - 15LL * centerVal(q);\n\n        if(dir == 0) sc -= 3LL * Xc[q];\n        else sc += 3LL * Xc[q];\n\n        sc += (long long)(rng.nextInt(301) - 150);\n\n        if(sc > bestSc){\n            bestSc = sc;\n            best = q;\n        }\n    }\n    return best;\n}\n\nbool appendCone(Work& w, int yOrder, int pathMode, int limit){\n    if(countViol(w.a) == 0) return true;\n\n    for(int x=0;x<=N-2;x++){\n        for(int yi=0; yi<=x; yi++){\n            int y = (yOrder == 0 ? yi : x - yi);\n\n            int best = ID[x][y];\n            int bv = w.a[best];\n\n            for(int r=x;r<N;r++){\n                int c0 = y;\n                int c1 = y + (r - x);\n                for(int c=c0;c<=c1;c++){\n                    int p = ID[r][c];\n                    if(w.a[p] < bv){\n                        bv = w.a[p];\n                        best = p;\n                    }\n                }\n            }\n\n            int cur = best;\n            while(Xc[cur] > x){\n                int cx = Xc[cur], cy = Yc[cur];\n                bool goLeft = false;\n\n                if(pathMode == 0){\n                    goLeft = (cy > y);\n                }else if(pathMode == 1){\n                    goLeft = !(cx - cy > x - y);\n                }else{\n                    int rem = cx - x;\n                    int needLeft = cy - y;\n                    if(needLeft <= 0) goLeft = false;\n                    else if(needLeft >= rem) goLeft = true;\n                    else goLeft = (needLeft * 2 >= rem);\n                }\n\n                int np = goLeft ? ID[cx-1][cy-1] : ID[cx-1][cy];\n                if((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, cur, np);\n                cur = np;\n            }\n\n            if(countViol(w.a) == 0) return true;\n        }\n    }\n    return countViol(w.a) == 0;\n}\n\nbool appendSift(Work& w, int dir, int choice, int limit){\n    if(countViol(w.a) == 0) return true;\n    if((int)w.ops.size() > limit) return false;\n\n    vector<char> fixed(M, 0);\n\n    if(dir == 0){\n        int internalFixed = 0;\n\n        for(int v=0; v<M && internalFixed<INTERNAL; v++){\n            while(true){\n                int p = w.pos[v];\n                vector<int> cand;\n                for(int q: PAR[p]) if(w.a[q] > v) cand.push_back(q);\n                if(cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if(fixed[p]) return false;\n            fixed[p] = 1;\n            if(Xc[p] < N-1) internalFixed++;\n\n            if(countViol(w.a) == 0) return true;\n        }\n    }else{\n        int nonTopFixed = 0;\n\n        for(int v=M-1; v>=1 && nonTopFixed<M-1; v--){\n            while(true){\n                int p = w.pos[v];\n                vector<int> cand;\n                for(int q: CH[p]) if(w.a[q] < v) cand.push_back(q);\n                if(cand.empty()) break;\n\n                int q = chooseCand(cand, choice, w);\n                if((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if(fixed[p]) return false;\n            fixed[p] = 1;\n            if(Xc[p] > 0) nonTopFixed++;\n\n            if(countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool appendSiftRandom(Work& w, int dir, int mode, uint64_t seed, int limit){\n    if(countViol(w.a) == 0) return true;\n    if((int)w.ops.size() > limit) return false;\n\n    FastRand rng(seed);\n    vector<char> fixed(M, 0);\n\n    if(dir == 0){\n        int internalFixed = 0;\n\n        for(int v=0; v<M && internalFixed<INTERNAL; v++){\n            while(true){\n                int p = w.pos[v];\n                vector<int> cand;\n                for(int q: PAR[p]) if(w.a[q] > v) cand.push_back(q);\n                if(cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if(fixed[p]) return false;\n            fixed[p] = 1;\n            if(Xc[p] < N-1) internalFixed++;\n\n            if(countViol(w.a) == 0) return true;\n        }\n    }else{\n        int nonTopFixed = 0;\n\n        for(int v=M-1; v>=1 && nonTopFixed<M-1; v--){\n            while(true){\n                int p = w.pos[v];\n                vector<int> cand;\n                for(int q: CH[p]) if(w.a[q] < v) cand.push_back(q);\n                if(cand.empty()) break;\n\n                int q = chooseCandRand(cand, mode, w, rng, dir);\n                if((int)w.ops.size() + 1 > limit) return false;\n                doSwap(w, p, q);\n            }\n\n            int p = w.pos[v];\n            if(fixed[p]) return false;\n            fixed[p] = 1;\n            if(Xc[p] > 0) nonTopFixed++;\n\n            if(countViol(w.a) == 0) return true;\n        }\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool solveSift(const array<int,M>& init, int dir, int choice, int limit, Work& out){\n    Work w(init);\n    if(appendSift(w, dir, choice, limit)){\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint pathLenLoose(const Work& w, int label, int dir, int choice){\n    int cur = w.pos[label];\n    int len = 0;\n\n    while(len <= 80){\n        vector<int> cand;\n        if(dir == 0){\n            for(int q: PAR[cur]) if(w.a[q] > label) cand.push_back(q);\n        }else{\n            for(int q: CH[cur]) if(w.a[q] < label) cand.push_back(q);\n        }\n\n        if(cand.empty()) break;\n        cur = chooseCand(cand, choice, w);\n        len++;\n    }\n\n    if(len > 80) return 1000000;\n    return len;\n}\n\nbool performLoose(Work& w, int label, int dir, int choice, int limit){\n    int guard = 0;\n\n    while(guard++ <= 80){\n        int p = w.pos[label];\n        vector<int> cand;\n\n        if(dir == 0){\n            for(int q: PAR[p]) if(w.a[q] > label) cand.push_back(q);\n        }else{\n            for(int q: CH[p]) if(w.a[q] < label) cand.push_back(q);\n        }\n\n        if(cand.empty()) break;\n\n        int q = chooseCand(cand, choice, w);\n        if((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, p, q);\n    }\n\n    return guard <= 82;\n}\n\nbool solveBiLoose(const array<int,M>& init, int mode, int choiceSmall, int choiceLarge,\n                  int finishDir, int finishChoice, uint64_t seed, int limit, Work& out){\n    Work w(init);\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n\n    FastRand rng(seed);\n    int lo = 0, hi = M-1;\n    int step = 0;\n\n    while(lo <= hi && countViol(w.a) != 0){\n        int ls = pathLenLoose(w, lo, 0, choiceSmall);\n        int lb = pathLenLoose(w, hi, 1, choiceLarge);\n\n        bool chooseSmall = true;\n\n        if(mode == 0) chooseSmall = (step % 2 == 0);\n        else if(mode == 1) chooseSmall = (step % 2 == 1);\n        else if(mode == 2) chooseSmall = (ls <= lb);\n        else if(mode == 3) chooseSmall = (2 * ls <= 3 * lb);\n        else if(mode == 4) chooseSmall = (3 * ls <= 2 * lb);\n        else if(mode == 5) chooseSmall = ((step % 3) != 2);\n        else if(mode == 6) chooseSmall = ((step % 3) == 0);\n        else{\n            int total = max(1, ls + lb + 2);\n            chooseSmall = (rng.nextInt(total) >= ls + 1);\n        }\n\n        if(chooseSmall){\n            if(!performLoose(w, lo, 0, choiceSmall, limit)) return false;\n            lo++;\n        }else{\n            if(!performLoose(w, hi, 1, choiceLarge, limit)) return false;\n            hi--;\n        }\n\n        if((int)w.ops.size() > limit) return false;\n        step++;\n    }\n\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n\n    if(finishDir >= 0){\n        if(appendSift(w, finishDir, finishChoice, limit)){\n            out = move(w);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool parentsFixed(int p, const vector<char>& fixed){\n    for(int q: PAR[p]) if(!fixed[q]) return false;\n    return true;\n}\n\nbool childrenFixed(int p, const vector<char>& fixed){\n    for(int q: CH[p]) if(!fixed[q]) return false;\n    return true;\n}\n\nint openInc(int p, const vector<char>& fixed){\n    int res = 0;\n    for(int ch: CH[p]){\n        if(fixed[ch]) continue;\n        bool ok = true;\n        for(int q: PAR[ch]){\n            if(q != p && !fixed[q]){\n                ok = false;\n                break;\n            }\n        }\n        if(ok) res++;\n    }\n    return res;\n}\n\nint openDec(int p, const vector<char>& fixed){\n    int res = 0;\n    for(int pr: PAR[p]){\n        if(fixed[pr]) continue;\n        bool ok = true;\n        for(int q: CH[pr]){\n            if(q != p && !fixed[q]){\n                ok = false;\n                break;\n            }\n        }\n        if(ok) res++;\n    }\n    return res;\n}\n\nstruct Strat{\n    int w;\n    int row;\n    int center;\n    int open;\n    int randAmp;\n    uint64_t seed;\n};\n\nbool solveBFS(const array<int,M>& init, int dir, const Strat& st, int limit, Work& out){\n    Work w(init);\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n\n    vector<char> fixed(M, 0), avail(M, 0);\n\n    if(dir == 0){\n        avail[ID[0][0]] = 1;\n        int internalFixed = 0;\n\n        for(int v=0; v<M && internalFixed<INTERNAL; v++){\n            int start = w.pos[v];\n            if(fixed[start]) return false;\n\n            array<int,M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while(head < tail){\n                int u = que[head++];\n                for(int nb: G[u]){\n                    if(fixed[nb]) continue;\n                    if(dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n\n            for(int p=0;p<M;p++){\n                if(!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openInc(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if(st.randAmp > 0){\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(v+1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if(best == -1 || sc < bestSc || (sc == bestSc && p < best)){\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if(best == -1) return false;\n            if((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for(int cur=best; cur!=-1; cur=prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for(int i=0;i+1<(int)path.size();i++) doSwap(w, path[i], path[i+1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if(Xc[best] < N-1) internalFixed++;\n\n            for(int ch: CH[best]){\n                if(!fixed[ch] && parentsFixed(ch, fixed)) avail[ch] = 1;\n            }\n\n            if(countViol(w.a) == 0){\n                out = move(w);\n                return true;\n            }\n        }\n    }else{\n        for(int y=0;y<N;y++) avail[ID[N-1][y]] = 1;\n\n        int nonTopFixed = 0;\n\n        for(int v=M-1; v>=1 && nonTopFixed<M-1; v--){\n            int start = w.pos[v];\n            if(fixed[start]) return false;\n\n            array<int,M> dist, prv;\n            dist.fill(-1);\n            prv.fill(-1);\n\n            int que[M], head = 0, tail = 0;\n            dist[start] = 0;\n            que[tail++] = start;\n\n            while(head < tail){\n                int u = que[head++];\n                for(int nb: G[u]){\n                    if(fixed[nb]) continue;\n                    if(dist[nb] != -1) continue;\n                    dist[nb] = dist[u] + 1;\n                    prv[nb] = u;\n                    que[tail++] = nb;\n                }\n            }\n\n            int best = -1;\n            long long bestSc = LLONG_MAX;\n            int step = M - 1 - v;\n\n            for(int p=0;p<M;p++){\n                if(!avail[p] || fixed[p] || dist[p] < 0) continue;\n\n                int opn = openDec(p, fixed);\n                long long sc = 1LL * dist[p] * st.w\n                             + 1LL * st.row * Xc[p]\n                             + 1LL * st.center * centerVal(p)\n                             + 1LL * st.open * opn;\n\n                if(st.randAmp > 0){\n                    uint64_t h = splitmix64(st.seed ^ (uint64_t)(step+1) * 1000003ULL ^ (uint64_t)p);\n                    sc += (long long)(h % (uint64_t)st.randAmp);\n                }\n\n                if(best == -1 || sc < bestSc || (sc == bestSc && p < best)){\n                    best = p;\n                    bestSc = sc;\n                }\n            }\n\n            if(best == -1) return false;\n            if((int)w.ops.size() + dist[best] > limit) return false;\n\n            vector<int> path;\n            for(int cur=best; cur!=-1; cur=prv[cur]) path.push_back(cur);\n            reverse(path.begin(), path.end());\n\n            for(int i=0;i+1<(int)path.size();i++) doSwap(w, path[i], path[i+1]);\n\n            fixed[best] = 1;\n            avail[best] = 0;\n            if(Xc[best] > 0) nonTopFixed++;\n\n            for(int pr: PAR[best]){\n                if(!fixed[pr] && childrenFixed(pr, fixed)) avail[pr] = 1;\n            }\n\n            if(countViol(w.a) == 0){\n                out = move(w);\n                return true;\n            }\n        }\n    }\n\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool parentsTop(int p, const vector<unsigned char>& type){\n    for(int q: PAR[p]) if(type[q] != 1) return false;\n    return true;\n}\n\nbool childrenBottom(int p, const vector<unsigned char>& type){\n    for(int q: CH[p]) if(type[q] != 2) return false;\n    return true;\n}\n\nint openTopCnt(int p, const vector<unsigned char>& type){\n    int res = 0;\n    for(int ch: CH[p]){\n        if(type[ch]) continue;\n        bool ok = true;\n        for(int q: PAR[ch]){\n            if(q != p && type[q] != 1){\n                ok = false;\n                break;\n            }\n        }\n        if(ok) res++;\n    }\n    return res;\n}\n\nint openBottomCnt(int p, const vector<unsigned char>& type){\n    int res = 0;\n    for(int pr: PAR[p]){\n        if(type[pr]) continue;\n        bool ok = true;\n        for(int q: CH[pr]){\n            if(q != p && type[q] != 2){\n                ok = false;\n                break;\n            }\n        }\n        if(ok) res++;\n    }\n    return res;\n}\n\nstruct BiOpt{\n    bool ok = false;\n    int target = -1;\n    int dist = 0;\n    long long score = 0;\n};\n\nBiOpt getBiOption(\n    const Work& w,\n    const vector<unsigned char>& type,\n    const vector<char>& avail,\n    int label,\n    bool topSide,\n    const Strat& st,\n    int step,\n    array<int,M>& dist,\n    array<int,M>& prv\n){\n    BiOpt opt;\n    int start = w.pos[label];\n    if(type[start]) return opt;\n\n    dist.fill(-1);\n    prv.fill(-1);\n\n    int que[M], head = 0, tail = 0;\n    dist[start] = 0;\n    que[tail++] = start;\n\n    while(head < tail){\n        int u = que[head++];\n        for(int nb: G[u]){\n            if(type[nb]) continue;\n            if(dist[nb] != -1) continue;\n            dist[nb] = dist[u] + 1;\n            prv[nb] = u;\n            que[tail++] = nb;\n        }\n    }\n\n    long long bestSc = LLONG_MAX;\n    int best = -1;\n\n    for(int p=0;p<M;p++){\n        if(!avail[p] || type[p] || dist[p] < 0) continue;\n\n        int opn = topSide ? openTopCnt(p, type) : openBottomCnt(p, type);\n        long long sc = 1LL * dist[p] * st.w\n                     + 1LL * st.row * Xc[p]\n                     + 1LL * st.center * centerVal(p)\n                     + 1LL * st.open * opn;\n\n        if(st.randAmp > 0){\n            uint64_t h = splitmix64(st.seed ^ (uint64_t)(step+1) * 1000003ULL ^ (uint64_t)p);\n            sc += (long long)(h % (uint64_t)st.randAmp);\n        }\n\n        if(best == -1 || sc < bestSc || (sc == bestSc && p < best)){\n            best = p;\n            bestSc = sc;\n        }\n    }\n\n    if(best == -1) return opt;\n\n    opt.ok = true;\n    opt.target = best;\n    opt.dist = dist[best];\n    opt.score = bestSc;\n    return opt;\n}\n\nbool solveBiBFS(const array<int,M>& init, const Strat& topSt, const Strat& botSt,\n                int sideBias, int limit, Work& out){\n    Work w(init);\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n\n    vector<unsigned char> type(M, 0);\n    vector<char> topAvail(M, 0), botAvail(M, 0);\n\n    topAvail[ID[0][0]] = 1;\n    for(int y=0;y<N;y++) botAvail[ID[N-1][y]] = 1;\n\n    int lo = 0, hi = M-1;\n    int step = 0;\n\n    while(lo <= hi){\n        array<int,M> distTop, prvTop, distBot, prvBot;\n\n        BiOpt ot = getBiOption(w, type, topAvail, lo, true, topSt, step, distTop, prvTop);\n        BiOpt ob = getBiOption(w, type, botAvail, hi, false, botSt, step, distBot, prvBot);\n\n        if(!ot.ok && !ob.ok) return false;\n\n        bool chooseTop;\n        if(!ob.ok) chooseTop = true;\n        else if(!ot.ok) chooseTop = false;\n        else chooseTop = (ot.score + sideBias <= ob.score);\n\n        int target;\n        array<int,M>* prv;\n\n        if(chooseTop){\n            target = ot.target;\n            prv = &prvTop;\n            if((int)w.ops.size() + ot.dist > limit) return false;\n        }else{\n            target = ob.target;\n            prv = &prvBot;\n            if((int)w.ops.size() + ob.dist > limit) return false;\n        }\n\n        vector<int> path;\n        for(int cur=target; cur!=-1; cur=(*prv)[cur]) path.push_back(cur);\n        reverse(path.begin(), path.end());\n\n        for(int i=0;i+1<(int)path.size();i++) doSwap(w, path[i], path[i+1]);\n\n        if(chooseTop){\n            type[target] = 1;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            lo++;\n\n            for(int ch: CH[target]){\n                if(!type[ch] && parentsTop(ch, type)) topAvail[ch] = 1;\n            }\n        }else{\n            type[target] = 2;\n            topAvail[target] = 0;\n            botAvail[target] = 0;\n            hi--;\n\n            for(int pr: PAR[target]){\n                if(!type[pr] && childrenBottom(pr, type)) botAvail[pr] = 1;\n            }\n        }\n\n        step++;\n\n        if(countViol(w.a) == 0){\n            out = move(w);\n            return true;\n        }\n    }\n\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nint localDelta(const Work& w, int p, int c){\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e){\n        for(int i=0;i<cnt;i++) if(idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for(int e: INCIDENT[p]) add(e);\n    for(int e: INCIDENT[c]) add(e);\n\n    int before = 0, after = 0;\n\n    for(int i=0;i<cnt;i++){\n        auto [u,v] = EDGES[idxs[i]];\n        if(w.a[u] > w.a[v]) before++;\n\n        int au = (u == p ? w.a[c] : (u == c ? w.a[p] : w.a[u]));\n        int av = (v == p ? w.a[c] : (v == c ? w.a[p] : w.a[v]));\n        if(au > av) after++;\n    }\n\n    return before - after;\n}\n\nint chooseViolationEdge(const Work& w, int variant){\n    long long bestKey = LLONG_MIN;\n    int best = -1;\n\n    for(int ei=0; ei<(int)EDGES.size(); ei++){\n        auto [p,c] = EDGES[ei];\n        if(w.a[p] <= w.a[c]) continue;\n\n        int diff = w.a[p] - w.a[c];\n        int delta = 0;\n        if(variant >= 6) delta = localDelta(w, p, c);\n\n        long long key = 0;\n        if(variant == 0) key = diff;\n        else if(variant == 1) key = 1LL * (M - w.a[c]) * 1000 + diff;\n        else if(variant == 2) key = 1LL * w.a[p] * 1000 + diff;\n        else if(variant == 3) key = 1LL * (N - Xc[p]) * 100000 + diff;\n        else if(variant == 4) key = 1LL * Xc[p] * 100000 + diff;\n        else if(variant == 5) key = 1LL * diff * 1000 + (N - Xc[p]) * 20 + (M - w.a[c]);\n        else if(variant == 6) key = 1LL * delta * 1000000 + 1LL * diff * 1000 + (M - w.a[c]);\n        else if(variant == 7) key = 1LL * delta * 1000000 + 1LL * (N - Xc[p]) * 1000 + diff;\n        else key = 1LL * delta * 1000000 + 1LL * Xc[p] * 1000 + diff;\n\n        if(key > bestKey){\n            bestKey = key;\n            best = ei;\n        }\n    }\n\n    return best;\n}\n\n// New cheap stochastic violation-edge choice.\nint chooseViolationEdgeRandom(const Work& w, int variant, FastRand& rng){\n    vector<pair<long long,int>> cand;\n    cand.reserve(EDGES.size());\n\n    for(int ei=0; ei<(int)EDGES.size(); ei++){\n        auto [p,c] = EDGES[ei];\n        if(w.a[p] <= w.a[c]) continue;\n\n        int diff = w.a[p] - w.a[c];\n        int ld = localDelta(w, p, c);\n\n        long long score = 0;\n        if(variant == 0){\n            score = 1000000LL * ld + 3000LL * diff;\n        }else if(variant == 1){\n            score = 1000000LL * ld + 3000LL * (M - w.a[c]) + diff;\n        }else if(variant == 2){\n            score = 1000000LL * ld + 3000LL * w.a[p] + diff;\n        }else if(variant == 3){\n            score = 500000LL * ld + 5000LL * diff + 20000LL * (N - Xc[p]);\n        }else if(variant == 4){\n            score = 500000LL * ld + 5000LL * diff + 20000LL * Xc[p];\n        }else{\n            score = 700000LL * ld + 6000LL * diff\n                  + 1000LL * (rng.nextInt(101) - 50);\n        }\n\n        score += (long long)rng.nextInt(250000);\n        cand.emplace_back(score, ei);\n    }\n\n    if(cand.empty()) return -1;\n\n    sort(cand.rbegin(), cand.rend());\n\n    int top = min((int)cand.size(), 3 + (variant % 4));\n    int r = rng.nextInt(100);\n    int pick;\n    if(r < 65) pick = 0;\n    else if(r < 85) pick = min(1, top - 1);\n    else pick = rng.nextInt(top);\n\n    return cand[pick].second;\n}\n\nbool runLocalSteps(Work& w, int variant, int steps, int limit){\n    for(int s=0;s<steps;s++){\n        int ei = chooseViolationEdge(w, variant);\n        if(ei < 0) return true;\n\n        if((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n    return true;\n}\n\nbool runLocalRandomSteps(Work& w, int variant, int steps, int limit, FastRand& rng){\n    for(int s=0; s<steps; s++){\n        if(countViol(w.a) == 0) return true;\n\n        int ei = chooseViolationEdgeRandom(w, variant, rng);\n        if(ei < 0) return true;\n\n        if((int)w.ops.size() + 1 > limit) return false;\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n    return true;\n}\n\nbool solveLocal(const array<int,M>& init, int variant, int limit, Work& out){\n    Work w(init);\n\n    while((int)w.ops.size() < limit){\n        int ei = chooseViolationEdge(w, variant);\n        if(ei < 0){\n            out = move(w);\n            return true;\n        }\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool solveLocalRandom(const array<int,M>& init, int variant, uint64_t seed, int limit, Work& out){\n    Work w(init);\n    FastRand rng(seed);\n\n    while((int)w.ops.size() < limit){\n        if(countViol(w.a) == 0){\n            out = move(w);\n            return true;\n        }\n\n        int ei = chooseViolationEdgeRandom(w, variant, rng);\n        if(ei < 0) break;\n\n        doSwap(w, EDGES[ei].first, EDGES[ei].second);\n    }\n\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nbool solveSweep(const array<int,M>& init, int xdir, int ydir, int choice, int limit, Work& out){\n    Work w(init);\n\n    while((int)w.ops.size() < limit){\n        bool changed = false;\n\n        for(int xi=0; xi<N-1; xi++){\n            int x = (xdir == 0 ? N-2-xi : xi);\n\n            for(int yi=0; yi<=x; yi++){\n                int y = (ydir == 0 ? yi : x - yi);\n                int cur = ID[x][y];\n\n                while(Xc[cur] < N-1){\n                    vector<int> cand;\n                    for(int q: CH[cur]){\n                        if(w.a[cur] > w.a[q]) cand.push_back(q);\n                    }\n                    if(cand.empty()) break;\n\n                    int q = chooseCand(cand, choice, w);\n                    if((int)w.ops.size() + 1 > limit) return false;\n\n                    doSwap(w, cur, q);\n                    cur = q;\n                    changed = true;\n                }\n            }\n        }\n\n        if(countViol(w.a) == 0){\n            out = move(w);\n            return true;\n        }\n        if(!changed) break;\n    }\n\n    if(countViol(w.a) == 0){\n        out = move(w);\n        return true;\n    }\n    return false;\n}\n\nlong long edgeCostVal(int ap, int ac, int W, bool quad){\n    if(ap <= ac) return 0;\n    long long d = ap - ac;\n    if(quad) return (long long)W + d * d;\n    return (long long)W + d;\n}\n\nlong long swapGainCost(const array<int,M>& a, int p, int q, int W, bool quad){\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e){\n        for(int i=0;i<cnt;i++) if(idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for(int e: INCIDENT[p]) add(e);\n    for(int e: INCIDENT[q]) add(e);\n\n    long long before = 0, after = 0;\n\n    for(int i=0;i<cnt;i++){\n        auto [u,v] = EDGES[idxs[i]];\n        before += edgeCostVal(a[u], a[v], W, quad);\n\n        int au = (u == p ? a[q] : (u == q ? a[p] : a[u]));\n        int av = (v == p ? a[q] : (v == q ? a[p] : a[v]));\n        after += edgeCostVal(au, av, W, quad);\n    }\n\n    return before - after;\n}\n\nbool runGreedyCost(Work& w, int W, bool quad, int maxSteps, int limit){\n    for(int s=0;s<maxSteps;s++){\n        if((int)w.ops.size() >= limit) return countViol(w.a) == 0;\n\n        long long bestGain = 0;\n        long long bestTie = LLONG_MIN;\n        int bu = -1, bv = -1;\n\n        for(auto [u,v]: ADJ){\n            long long gain = swapGainCost(w.a, u, v, W, quad);\n            if(gain <= 0) continue;\n\n            long long deltaP = 1LL * (w.a[u] - w.a[v]) * (Xc[v] - Xc[u]);\n            long long rowGain = -deltaP;\n\n            if(gain > bestGain || (gain == bestGain && rowGain > bestTie)){\n                bestGain = gain;\n                bestTie = rowGain;\n                bu = u;\n                bv = v;\n            }\n        }\n\n        if(bu == -1) break;\n\n        doSwap(w, bu, bv);\n        if(countViol(w.a) == 0) return true;\n    }\n\n    return countViol(w.a) == 0;\n}\n\nbool canSwapKeepValid(const array<int,M>& a, int p, int q){\n    int idxs[20];\n    int cnt = 0;\n\n    auto add = [&](int e){\n        for(int i=0;i<cnt;i++) if(idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for(int e: INCIDENT[p]) add(e);\n    for(int e: INCIDENT[q]) add(e);\n\n    for(int i=0;i<cnt;i++){\n        auto [u,v] = EDGES[idxs[i]];\n\n        int au = a[u], av = a[v];\n        if(u == p) au = a[q];\n        else if(u == q) au = a[p];\n\n        if(v == p) av = a[q];\n        else if(v == q) av = a[p];\n\n        if(au > av) return false;\n    }\n\n    return true;\n}\n\nvector<pair<int,int>> pruneOpsFast(const array<int,M>& init, const vector<pair<int,int>>& ops, int passes=3){\n    vector<pair<int,int>> cur = ops;\n\n    for(int pass=0; pass<passes; pass++){\n        if(cur.empty()) break;\n\n        array<int,M> a = simulateOps(init, cur);\n        if(countViol(a) != 0) return cur;\n\n        array<int,M> suff;\n        for(int i=0;i<M;i++) suff[i] = i;\n\n        vector<unsigned char> keep(cur.size(), 1);\n        int deleted = 0;\n\n        for(int ii=(int)cur.size(); ii-- > 0; ){\n            int u = cur[ii].first;\n            int v = cur[ii].second;\n\n            int p = suff[u];\n            int q = suff[v];\n\n            if(canSwapKeepValid(a, p, q)){\n                swap(a[p], a[q]);\n                keep[ii] = 0;\n                deleted++;\n            }else{\n                swap(suff[u], suff[v]);\n            }\n        }\n\n        if(deleted == 0) break;\n\n        vector<pair<int,int>> nxt;\n        nxt.reserve(cur.size() - deleted);\n        for(int i=0;i<(int)cur.size();i++){\n            if(keep[i]) nxt.push_back(cur[i]);\n        }\n        cur.swap(nxt);\n    }\n\n    return cur;\n}\n\nbool validSkipping(const array<int,M>& init, const vector<pair<int,int>>& ops, int s1, int s2=-1){\n    array<int,M> a = init;\n    for(int i=0;i<(int)ops.size();i++){\n        if(i == s1 || i == s2) continue;\n        swap(a[ops[i].first], a[ops[i].second]);\n    }\n    return countViol(a) == 0;\n}\n\nbool validSkippingTwo(const array<int,M>& init, const vector<pair<int,int>>& ops, int s1, int s2){\n    if(s1 == s2) return false;\n    if(s1 > s2) swap(s1, s2);\n\n    array<int,M> a = init;\n    for(int i=0;i<(int)ops.size();i++){\n        if(i == s1 || i == s2) continue;\n        swap(a[ops[i].first], a[ops[i].second]);\n    }\n    return countViol(a) == 0;\n}\n\nuint64_t encodePermVec(const vector<int>& p){\n    uint64_t code = 0;\n    for(int i=0;i<(int)p.size();i++) code |= (uint64_t)p[i] << (4 * i);\n    return code;\n}\n\nuint64_t encodeIdentity(int m){\n    uint64_t code = 0;\n    for(int i=0;i<m;i++) code |= (uint64_t)i << (4 * i);\n    return code;\n}\n\nvoid decodePerm(uint64_t code, int m, int arr[8]){\n    for(int i=0;i<m;i++) arr[i] = (int)((code >> (4 * i)) & 15);\n}\n\nbool shortestLocalPath(int m, const vector<pair<int,int>>& edges, uint64_t target,\n                       int maxDepth, vector<int>& edgePath){\n    edgePath.clear();\n\n    uint64_t start = encodeIdentity(m);\n    if(start == target) return true;\n    if(edges.empty() || maxDepth <= 0) return false;\n\n    unordered_map<uint64_t,int> id;\n    id.reserve(10000);\n\n    vector<uint64_t> state;\n    vector<int> par, pedge, dep;\n\n    id[start] = 0;\n    state.push_back(start);\n    par.push_back(-1);\n    pedge.push_back(-1);\n    dep.push_back(0);\n\n    int arr[8];\n\n    for(int head=0; head<(int)state.size(); head++){\n        if((int)state.size() > 30000) break;\n        if(dep[head] >= maxDepth) continue;\n\n        decodePerm(state[head], m, arr);\n\n        for(int ei=0; ei<(int)edges.size(); ei++){\n            auto [a,b] = edges[ei];\n            swap(arr[a], arr[b]);\n\n            uint64_t nc = 0;\n            for(int i=0;i<m;i++) nc |= (uint64_t)arr[i] << (4 * i);\n\n            if(!id.count(nc)){\n                int nid = (int)state.size();\n                id[nc] = nid;\n                state.push_back(nc);\n                par.push_back(head);\n                pedge.push_back(ei);\n                dep.push_back(dep[head] + 1);\n\n                if(nc == target){\n                    int cur = nid;\n                    while(cur != 0){\n                        edgePath.push_back(pedge[cur]);\n                        cur = par[cur];\n                    }\n                    reverse(edgePath.begin(), edgePath.end());\n                    return true;\n                }\n            }\n\n            swap(arr[a], arr[b]);\n        }\n    }\n\n    return false;\n}\n\ntemplate<class TimeOK>\nvoid optimizeWindows(vector<pair<int,int>>& ops, TimeOK timeOK){\n    const int MAXLEN = 6;\n\n    for(int pass=0; pass<2 && timeOK(); pass++){\n        bool changedPass = false;\n\n        for(int i=0; i<(int)ops.size() && timeOK(); ){\n            bool replaced = false;\n\n            for(int len=MAXLEN; len>=2 && !replaced; len--){\n                if(i + len > (int)ops.size()) continue;\n\n                array<int,M> loc;\n                loc.fill(-1);\n\n                vector<int> verts;\n                verts.reserve(len + 1);\n\n                auto addv = [&](int v){\n                    if(loc[v] == -1){\n                        loc[v] = (int)verts.size();\n                        verts.push_back(v);\n                    }\n                };\n\n                for(int j=i; j<i+len; j++){\n                    addv(ops[j].first);\n                    addv(ops[j].second);\n                }\n\n                int m = (int)verts.size();\n                if(m > 8) continue;\n\n                vector<int> perm(m);\n                iota(perm.begin(), perm.end(), 0);\n\n                for(int j=i; j<i+len; j++){\n                    int a = loc[ops[j].first];\n                    int b = loc[ops[j].second];\n                    swap(perm[a], perm[b]);\n                }\n\n                uint64_t target = encodePermVec(perm);\n\n                vector<pair<int,int>> localEdges;\n                for(int a=0;a<m;a++){\n                    for(int b=a+1;b<m;b++){\n                        if(ADJMAT[verts[a]][verts[b]]) localEdges.emplace_back(a,b);\n                    }\n                }\n\n                vector<int> edgePath;\n                if(!shortestLocalPath(m, localEdges, target, len - 1, edgePath)) continue;\n                if((int)edgePath.size() >= len) continue;\n\n                vector<pair<int,int>> repl;\n                repl.reserve(edgePath.size());\n                for(int ei: edgePath){\n                    auto [a,b] = localEdges[ei];\n                    repl.emplace_back(verts[a], verts[b]);\n                }\n\n                ops.erase(ops.begin() + i, ops.begin() + i + len);\n                ops.insert(ops.begin() + i, repl.begin(), repl.end());\n\n                i = max(0, i - len);\n                changedPass = true;\n                replaced = true;\n            }\n\n            if(!replaced) i++;\n        }\n\n        if(!changedPass) break;\n    }\n}\n\nvector<array<int,M>> buildSuffixMaps(const vector<pair<int,int>>& ops){\n    int K = (int)ops.size();\n    vector<array<int,M>> suff(K + 1);\n\n    for(int i=0;i<M;i++) suff[K][i] = i;\n\n    for(int i=K-1;i>=0;i--){\n        suff[i] = suff[i+1];\n        auto [u,v] = ops[i];\n        swap(suff[i][u], suff[i][v]);\n    }\n    return suff;\n}\n\nbool validWithSourceMap(const array<int,M>& a, int src[M], const vector<int>& changed){\n    int idxs[128];\n    int cnt = 0;\n\n    auto add = [&](int e){\n        for(int i=0;i<cnt;i++) if(idxs[i] == e) return;\n        idxs[cnt++] = e;\n    };\n\n    for(int p: changed){\n        for(int e: INCIDENT[p]) add(e);\n    }\n\n    auto val = [&](int p){\n        return src[p] >= 0 ? a[src[p]] : a[p];\n    };\n\n    for(int i=0;i<cnt;i++){\n        auto [u,v] = EDGES[idxs[i]];\n        if(val(u) > val(v)) return false;\n    }\n    return true;\n}\n\nbool canDeleteBlockFast(const array<int,M>& finalA,\n                        const array<int,M>& suff,\n                        const vector<pair<int,int>>& ops,\n                        int l, int r){\n    array<int,M> b;\n    array<unsigned char,M> seen;\n    seen.fill(0);\n\n    vector<int> touched;\n    touched.reserve(r - l + 1);\n\n    auto touch = [&](int p){\n        if(!seen[p]){\n            seen[p] = 1;\n            b[p] = p;\n            touched.push_back(p);\n        }\n    };\n\n    for(int i=l;i<r;i++){\n        int u = ops[i].first, v = ops[i].second;\n        touch(u);\n        touch(v);\n        swap(b[u], b[v]); // post -> pre\n    }\n\n    int inv[M];\n    for(int i=0;i<M;i++) inv[i] = -1;\n    for(int t: touched) inv[b[t]] = t; // pre -> post\n\n    int src[M];\n    for(int i=0;i<M;i++) src[i] = -1;\n\n    vector<int> changed;\n    changed.reserve(touched.size());\n\n    for(int pre: touched){\n        int oldPost = inv[pre];\n        if(oldPost < 0 || oldPost == pre) continue;\n\n        int fp = suff[pre];\n        int fs = suff[oldPost];\n\n        src[fp] = fs;\n        changed.push_back(fp);\n    }\n\n    if(changed.empty()) return true;\n    return validWithSourceMap(finalA, src, changed);\n}\n\ntemplate<class TimeOK>\nvoid pruneBlocksFast(const array<int,M>& init,\n                     vector<pair<int,int>>& ops,\n                     int maxLen,\n                     TimeOK timeOK){\n    int deletedBlocks = 0;\n\n    while(timeOK() && deletedBlocks < 80){\n        array<int,M> finalA = simulateOps(init, ops);\n        if(countViol(finalA) != 0) return;\n\n        auto suff = buildSuffixMaps(ops);\n\n        bool found = false;\n        int K = (int)ops.size();\n\n        for(int i=0; i<K && timeOK(); i++){\n            int ml = min(maxLen, K - i);\n\n            for(int len=ml; len>=2; len--){\n                if(canDeleteBlockFast(finalA, suff[i+len], ops, i, i+len)){\n                    ops.erase(ops.begin() + i, ops.begin() + i + len);\n                    found = true;\n                    deletedBlocks++;\n                    break;\n                }\n            }\n            if(found) break;\n        }\n\n        if(!found) break;\n    }\n}\n\nbool canReplacePermValid(const array<int,M>& finalA,\n                         const array<int,M>& suff,\n                         const vector<int>& verts,\n                         const int permB[8],\n                         const int permR[8],\n                         int m,\n                         int src[M]){\n    int invB[8];\n    for(int e=0;e<m;e++) invB[permB[e]] = e;\n\n    vector<int> changed;\n    changed.reserve(m);\n\n    for(int e=0;e<m;e++){\n        int token = permR[e];\n        int oldEnd = invB[token];\n\n        int fp = suff[verts[e]];\n        int fs = suff[verts[oldEnd]];\n\n        if(fp != fs){\n            src[fp] = fs;\n            changed.push_back(fp);\n        }\n    }\n\n    bool ok = true;\n    if(!changed.empty()) ok = validWithSourceMap(finalA, src, changed);\n\n    for(int p: changed) src[p] = -1;\n    return ok;\n}\n\ntemplate<class TimeOK>\nbool findValidReplacement(int m,\n                          const vector<pair<int,int>>& edges,\n                          const array<int,M>& finalA,\n                          const array<int,M>& suff,\n                          const vector<int>& verts,\n                          const int permB[8],\n                          int maxDepth,\n                          vector<int>& edgePath,\n                          TimeOK timeOK){\n    edgePath.clear();\n    if(m > 8) return false;\n\n    int src[M];\n    for(int i=0;i<M;i++) src[i] = -1;\n\n    int arr[8];\n\n    auto testCode = [&](uint64_t code){\n        decodePerm(code, m, arr);\n        return canReplacePermValid(finalA, suff, verts, permB, arr, m, src);\n    };\n\n    uint64_t start = encodeIdentity(m);\n    if(testCode(start)) return true;\n    if(edges.empty() || maxDepth <= 0) return false;\n\n    unordered_map<uint64_t,int> id;\n    id.reserve(10000);\n\n    vector<uint64_t> state;\n    vector<int> par, pedge, dep;\n\n    id[start] = 0;\n    state.push_back(start);\n    par.push_back(-1);\n    pedge.push_back(-1);\n    dep.push_back(0);\n\n    for(int head=0; head<(int)state.size() && timeOK(); head++){\n        if((int)state.size() > 26000) break;\n        if(dep[head] >= maxDepth) continue;\n\n        decodePerm(state[head], m, arr);\n\n        for(int ei=0; ei<(int)edges.size(); ei++){\n            auto [a,b] = edges[ei];\n            swap(arr[a], arr[b]);\n\n            uint64_t nc = 0;\n            for(int i=0;i<m;i++) nc |= (uint64_t)arr[i] << (4 * i);\n\n            if(!id.count(nc)){\n                int nid = (int)state.size();\n                id[nc] = nid;\n                state.push_back(nc);\n                par.push_back(head);\n                pedge.push_back(ei);\n                dep.push_back(dep[head] + 1);\n\n                if(testCode(nc)){\n                    int cur = nid;\n                    while(cur != 0){\n                        edgePath.push_back(pedge[cur]);\n                        cur = par[cur];\n                    }\n                    reverse(edgePath.begin(), edgePath.end());\n                    return true;\n                }\n            }\n\n            swap(arr[a], arr[b]);\n        }\n    }\n\n    return false;\n}\n\ntemplate<class TimeOK>\nvoid optimizeWindowsValid(const array<int,M>& init,\n                          vector<pair<int,int>>& ops,\n                          int maxLen,\n                          TimeOK timeOK){\n    int improvements = 0;\n\n    while(timeOK() && improvements < 40){\n        array<int,M> finalA = simulateOps(init, ops);\n        if(countViol(finalA) != 0) return;\n\n        auto suff = buildSuffixMaps(ops);\n\n        bool found = false;\n        int K = (int)ops.size();\n\n        for(int i=0; i<K && timeOK(); i++){\n            int ml = min(maxLen, K - i);\n\n            for(int len=ml; len>=2 && timeOK(); len--){\n                array<int,M> loc;\n                loc.fill(-1);\n\n                vector<int> verts;\n                verts.reserve(len + 1);\n\n                auto addv = [&](int v){\n                    if(loc[v] == -1){\n                        loc[v] = (int)verts.size();\n                        verts.push_back(v);\n                    }\n                };\n\n                for(int j=i;j<i+len;j++){\n                    addv(ops[j].first);\n                    addv(ops[j].second);\n                }\n\n                int m = (int)verts.size();\n                if(m > 8) continue;\n\n                int permB[8];\n                for(int t=0;t<m;t++) permB[t] = t;\n\n                for(int j=i;j<i+len;j++){\n                    int a = loc[ops[j].first];\n                    int b = loc[ops[j].second];\n                    swap(permB[a], permB[b]);\n                }\n\n                vector<pair<int,int>> localEdges;\n                for(int a=0;a<m;a++){\n                    for(int b=a+1;b<m;b++){\n                        if(ADJMAT[verts[a]][verts[b]]) localEdges.emplace_back(a,b);\n                    }\n                }\n\n                vector<int> edgePath;\n                if(!findValidReplacement(m, localEdges, finalA, suff[i+len],\n                                          verts, permB, len - 1, edgePath, timeOK)){\n                    continue;\n                }\n\n                if((int)edgePath.size() >= len) continue;\n\n                vector<pair<int,int>> repl;\n                repl.reserve(edgePath.size());\n\n                for(int ei: edgePath){\n                    auto [a,b] = localEdges[ei];\n                    repl.emplace_back(verts[a], verts[b]);\n                }\n\n                ops.erase(ops.begin() + i, ops.begin() + i + len);\n                ops.insert(ops.begin() + i, repl.begin(), repl.end());\n\n                found = true;\n                improvements++;\n                break;\n            }\n\n            if(found) break;\n        }\n\n        if(!found) break;\n    }\n}\n\ntemplate<class TimeOK>\nbool tryAppendPruneImprove(const array<int,M>& init,\n                           const array<int,M>& initPos,\n                           vector<pair<int,int>>& bestOps,\n                           uint64_t seed,\n                           TimeOK timeOK){\n    array<int,M> base = simulateOps(init, bestOps);\n    if(countViol(base) != 0) return false;\n\n    int origK = (int)bestOps.size();\n\n    unordered_map<int,int> freq;\n    freq.reserve(bestOps.size() * 2 + 1);\n\n    for(auto [u,v]: bestOps){\n        if(u > v) swap(u,v);\n        freq[u * M + v]++;\n    }\n\n    for(int trial=0; trial<24 && timeOK(); trial++){\n        array<int,M> a = base;\n        vector<pair<int,int>> seq = bestOps;\n        FastRand rng(seed ^ (uint64_t)(trial + 1) * 0x9e3779b97f4a7c15ULL);\n\n        int mode = (trial < 16 ? trial % 4 : 4 + (trial - 16) % 3);\n\n        int maxSteps;\n        if(mode == 0) maxSteps = 18;\n        else if(mode == 1) maxSteps = 26;\n        else if(mode == 2) maxSteps = 36;\n        else if(mode == 3) maxSteps = 48;\n        else if(mode == 4) maxSteps = 14;\n        else if(mode == 5) maxSteps = 22;\n        else maxSteps = 30;\n\n        int lastU = -1, lastV = -1;\n\n        for(int step=0; step<maxSteps && timeOK(); step++){\n            long long bestScore = LLONG_MIN;\n            int bu = -1, bv = -1;\n\n            for(auto [u,v]: ADJ){\n                if(!canSwapKeepValid(a, u, v)) continue;\n\n                int A = a[u], B = a[v];\n\n                int du0 = distHex(u, initPos[A]);\n                int dv0 = distHex(v, initPos[B]);\n                int du1 = distHex(v, initPos[A]);\n                int dv1 = distHex(u, initPos[B]);\n\n                long long before, after;\n                if(mode == 1){\n                    before = 1LL * du0 * du0 + 1LL * dv0 * dv0;\n                    after  = 1LL * du1 * du1 + 1LL * dv1 * dv1;\n                }else{\n                    before = du0 + dv0;\n                    after  = du1 + dv1;\n                }\n\n                long long delta = after - before;\n\n                if(mode == 0 && delta >= 0) continue;\n                if(mode == 1 && delta >= 0) continue;\n                if(mode == 2 && delta > 0) continue;\n                if(mode == 3 && delta > 1) continue;\n                if(mode == 4 && delta > 3) continue;\n\n                int x = u, y = v;\n                if(x > y) swap(x,y);\n\n                int f = 0;\n                auto it = freq.find(x * M + y);\n                if(it != freq.end()) f = it->second;\n\n                long long score;\n                if(mode <= 3){\n                    score = -delta * 100000LL + 500LL * f + (long long)rng.nextInt(5000);\n                }else{\n                    score = 20000LL * f - 5000LL * delta + (long long)rng.nextInt(20000);\n                }\n\n                if((u == lastV && v == lastU) || (u == lastU && v == lastV)) score -= 10000000LL;\n\n                if(score > bestScore){\n                    bestScore = score;\n                    bu = u;\n                    bv = v;\n                }\n            }\n\n            if(bu == -1) break;\n\n            swap(a[bu], a[bv]);\n            seq.emplace_back(bu, bv);\n            lastU = bu;\n            lastV = bv;\n        }\n\n        if((int)seq.size() <= origK) continue;\n        if(countViol(a) != 0) continue;\n\n        vector<pair<int,int>> pruned = pruneOpsFast(init, seq, 3);\n        if((int)pruned.size() < origK){\n            array<int,M> aa = simulateOps(init, pruned);\n            if(countViol(aa) == 0){\n                bestOps = move(pruned);\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\ntemplate<class TimeOK>\nvoid pairDeletionSearch(const array<int,M>& init,\n                        vector<pair<int,int>>& ops,\n                        uint64_t seed,\n                        TimeOK timeOK){\n    FastRand rng(seed ^ 0xabcdef1234567890ULL);\n\n    int rounds = 0;\n\n    while(timeOK() && rounds < 20){\n        int K = (int)ops.size();\n        if(K < 2) break;\n\n        bool found = false;\n        vector<pair<int,int>> cand;\n        cand.reserve(1200);\n\n        unordered_map<int, vector<int>> mp;\n        mp.reserve(K * 2 + 1);\n\n        for(int i=0;i<K;i++){\n            int u = ops[i].first, v = ops[i].second;\n            if(u > v) swap(u,v);\n            mp[u * M + v].push_back(i);\n        }\n\n        for(auto& kv: mp){\n            auto& vec = kv.second;\n            if((int)vec.size() < 2) continue;\n\n            for(int a=0; a+1<(int)vec.size() && (int)cand.size()<500; a++){\n                cand.emplace_back(vec[a], vec[a+1]);\n            }\n            for(int a=0; a+2<(int)vec.size() && (int)cand.size()<650; a++){\n                cand.emplace_back(vec[a], vec[a+2]);\n            }\n        }\n\n        auto shareVertex = [&](int i, int j){\n            int a = ops[i].first, b = ops[i].second;\n            int c = ops[j].first, d = ops[j].second;\n            return a == c || a == d || b == c || b == d;\n        };\n\n        for(int i=0; i<K && (int)cand.size()<1000; i++){\n            int to = min(K, i + 45);\n            for(int j=i+2; j<to && (int)cand.size()<1000; j++){\n                if(shareVertex(i,j)) cand.emplace_back(i,j);\n            }\n        }\n\n        for(auto [i,j]: cand){\n            if(!timeOK()) break;\n            if(i == j) continue;\n\n            if(validSkippingTwo(init, ops, i, j)){\n                if(i > j) swap(i,j);\n                ops.erase(ops.begin() + j);\n                ops.erase(ops.begin() + i);\n                found = true;\n                break;\n            }\n        }\n\n        if(found){\n            rounds++;\n            continue;\n        }\n\n        vector<vector<int>> byV(M);\n        for(int i=0;i<K;i++){\n            byV[ops[i].first].push_back(i);\n            byV[ops[i].second].push_back(i);\n        }\n\n        for(int t=0; t<400 && timeOK() && !found; t++){\n            int v = rng.nextInt(M);\n            if((int)byV[v].size() < 2) continue;\n\n            int a = byV[v][rng.nextInt((int)byV[v].size())];\n            int b = byV[v][rng.nextInt((int)byV[v].size())];\n            if(a == b) continue;\n\n            if(validSkippingTwo(init, ops, a, b)){\n                if(a > b) swap(a,b);\n                ops.erase(ops.begin() + b);\n                ops.erase(ops.begin() + a);\n                found = true;\n                break;\n            }\n        }\n\n        for(int t=0; t<180 && timeOK() && !found; t++){\n            int a = rng.nextInt(K);\n            int b = rng.nextInt(K);\n            if(a == b) continue;\n\n            if(validSkippingTwo(init, ops, a, b)){\n                if(a > b) swap(a,b);\n                ops.erase(ops.begin() + b);\n                ops.erase(ops.begin() + a);\n                found = true;\n                break;\n            }\n        }\n\n        if(!found) break;\n        rounds++;\n    }\n}\n\nint main(){\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    precompute();\n\n    array<int,M> init;\n    for(int x=0;x<N;x++){\n        for(int y=0;y<=x;y++){\n            cin >> init[ID[x][y]];\n        }\n    }\n\n    array<int,M> initPos;\n    for(int i=0;i<M;i++) initPos[init[i]] = i;\n\n    uint64_t inputHash = 0;\n    for(int i=0;i<M;i++){\n        inputHash = splitmix64(inputHash ^ (uint64_t)(init[i] + 1) * 1000003ULL ^ (uint64_t)i);\n    }\n\n    auto startTime = chrono::steady_clock::now();\n\n    auto elapsed = [&](){\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n    auto searchOK = [&](){ return elapsed() < 1.78; };\n    auto finalOK = [&](){ return elapsed() < 1.955; };\n\n    vector<pair<int,int>> bestOps;\n    int bestK = 10001;\n    const int PRUNE_MARGIN = 1600;\n\n    auto consider = [&](Work&& w){\n        int raw = (int)w.ops.size();\n        if(raw > 10000) return;\n        if(countViol(w.a) != 0) return;\n\n        if(bestK <= 10000 && raw >= bestK + PRUNE_MARGIN) return;\n\n        vector<pair<int,int>> pruned = pruneOpsFast(init, w.ops, 3);\n        if((int)pruned.size() > 10000) return;\n\n        array<int,M> aa = simulateOps(init, pruned);\n        if(countViol(aa) != 0) return;\n\n        int k = (int)pruned.size();\n        if(k < bestK){\n            bestK = k;\n            bestOps = move(pruned);\n        }\n    };\n\n    auto limitGen = [&](){\n        if(bestK > 10000) return 10000;\n        return min(10000, bestK + PRUNE_MARGIN);\n    };\n\n    for(int yo=0; yo<2; yo++){\n        for(int pm=0; pm<3; pm++){\n            Work w(init);\n            if(appendCone(w, yo, pm, 10000)) consider(move(w));\n        }\n    }\n\n    for(int dir=0; dir<2 && searchOK() && bestK>0; dir++){\n        for(int ch=0; ch<5 && searchOK() && bestK>0; ch++){\n            Work w;\n            if(solveSift(init, dir, ch, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    vector<pair<int,int>> looseChoices = {\n        {0,0}, {1,1}, {4,4}, {0,1}, {1,0}\n    };\n\n    for(int mode=0; mode<8 && searchOK() && bestK>0; mode++){\n        for(auto [cs,cl]: looseChoices){\n            if(!searchOK() || bestK == 0) break;\n\n            Work w;\n            if(solveBiLoose(init, mode, cs, cl, -1, 0,\n                            inputHash ^ (uint64_t)(mode * 100 + cs * 10 + cl),\n                            limitGen(), w)){\n                consider(move(w));\n            }\n        }\n    }\n\n    for(int mode: {2,3,4,5,6}){\n        for(auto [cs,cl]: vector<pair<int,int>>{{0,0},{1,1},{4,4}}){\n            for(int fd=0; fd<2; fd++){\n                if(!searchOK() || bestK == 0) break;\n\n                Work w;\n                if(solveBiLoose(init, mode, cs, cl, fd, (fd == 0 ? cs : cl),\n                                inputHash ^ (uint64_t)(999 + mode * 100 + fd * 10 + cs),\n                                limitGen(), w)){\n                    consider(move(w));\n                }\n            }\n        }\n    }\n\n    // New cheap randomized local prefixes.\n    vector<int> rndSteps = {60, 120, 220, 360, 520};\n    for(int t=0; t<14 && searchOK() && bestK>0; t++){\n        Work pref(init);\n        FastRand rng(inputHash ^ (uint64_t)(0x515151 + t * 1000003ULL));\n\n        int variant = t % 6;\n        int steps = rndSteps[t % (int)rndSteps.size()];\n\n        if(!runLocalRandomSteps(pref, variant, steps, limitGen(), rng)) continue;\n\n        if(countViol(pref.a) == 0){\n            consider(Work(pref));\n            continue;\n        }\n\n        int ch1 = (t % 3 == 0 ? 0 : (t % 3 == 1 ? 1 : 4));\n\n        for(int z=0; z<2 && searchOK() && bestK>0; z++){\n            Work w = pref;\n            int dir = (t + z) & 1;\n            if(appendSift(w, dir, ch1, limitGen())) consider(move(w));\n        }\n\n        if((t % 3) == 0 && searchOK() && bestK>0){\n            Work w = pref;\n            if(appendCone(w, t & 1, t % 3, limitGen())) consider(move(w));\n        }\n    }\n\n    for(int t=0; t<90 && searchOK() && bestK>0; t++){\n        int dir = t & 1;\n        int mode = (t / 2) % 8;\n        uint64_t seed = inputHash ^ (uint64_t)(t + 1) * 0x9e3779b97f4a7c15ULL;\n\n        Work w(init);\n        if(appendSiftRandom(w, dir, mode, seed, limitGen())) consider(move(w));\n    }\n\n    vector<tuple<Strat,Strat,int>> biStrats;\n\n    auto addBi = [&](Strat a, Strat b, int bias){\n        biStrats.emplace_back(a,b,bias);\n    };\n\n    addBi({1000, 5, 0, -20, 0, 0}, {1000, -5, 0, -20, 0, 0}, 0);\n    addBi({1000, 10, 0, -20, 0, 0}, {1000, -10, 0, -20, 0, 0}, 0);\n    addBi({1000, 0, 0, -20, 0, 0}, {1000, 0, 0, -20, 0, 0}, 0);\n    addBi({1000, 5, -3, -20, 0, 0}, {1000, -5, -3, -20, 0, 0}, 0);\n    addBi({1000, 5, 3, -20, 0, 0}, {1000, -5, 3, -20, 0, 0}, 0);\n    addBi({300, 20, 0, -30, 0, 0}, {300, -20, 0, -30, 0, 0}, 0);\n    addBi({500, 10, -5, -30, 80, inputHash ^ 111}, {500, -10, -5, -30, 80, inputHash ^ 222}, 0);\n    addBi({500, 10, 5, -30, 80, inputHash ^ 333}, {500, -10, 5, -30, 80, inputHash ^ 444}, 0);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 555}, {1000, -5, 0, -20, 100, inputHash ^ 666}, -200);\n    addBi({1000, 5, 0, -20, 100, inputHash ^ 777}, {1000, -5, 0, -20, 100, inputHash ^ 888}, 200);\n\n    for(auto [ts,bs,bias]: biStrats){\n        if(!searchOK() || bestK == 0) break;\n\n        Work w;\n        if(solveBiBFS(init, ts, bs, bias, limitGen(), w)) consider(move(w));\n    }\n\n    vector<tuple<int,bool,int>> gparams = {\n        {10000, false, 120},\n        {10000, false, 300},\n        {3000, false, 300},\n        {1000, false, 500},\n        {300, false, 500},\n        {20000, true, 250}\n    };\n\n    for(auto [W,quad,steps]: gparams){\n        if(!searchOK() || bestK == 0) break;\n\n        Work pref(init);\n        runGreedyCost(pref, W, quad, steps, limitGen());\n\n        if(countViol(pref.a) == 0) consider(Work(pref));\n\n        for(int dir=0; dir<2 && searchOK() && bestK>0; dir++){\n            for(int ch: {0,1,4}){\n                if(!searchOK() || bestK == 0) break;\n\n                Work w = pref;\n                if(appendSift(w, dir, ch, limitGen())) consider(move(w));\n            }\n        }\n    }\n\n    vector<int> prefVars = {0,1,6,7};\n    vector<int> prefSteps = {80,180,350,700};\n\n    for(int var: prefVars){\n        for(int stp: prefSteps){\n            if(!searchOK() || bestK == 0) break;\n\n            Work pref(init);\n            if(!runLocalSteps(pref, var, stp, limitGen())) continue;\n\n            if(countViol(pref.a) == 0){\n                consider(Work(pref));\n                continue;\n            }\n\n            for(int dir=0; dir<2 && searchOK() && bestK>0; dir++){\n                for(int ch: {0,1,4}){\n                    if(!searchOK() || bestK == 0) break;\n\n                    Work w = pref;\n                    if(appendSift(w, dir, ch, limitGen())) consider(move(w));\n                }\n            }\n\n            for(int yo=0; yo<2 && searchOK() && bestK>0; yo++){\n                for(int pm=0; pm<3; pm++){\n                    if(!searchOK() || bestK == 0) break;\n\n                    Work w = pref;\n                    if(appendCone(w, yo, pm, limitGen())) consider(move(w));\n                }\n            }\n        }\n    }\n\n    vector<Strat> strats;\n\n    auto addStrat = [&](int w, int r, int c, int o, int ra=0, uint64_t seed=0){\n        strats.push_back({w,r,c,o,ra,seed});\n    };\n\n    addStrat(1000, 0, 0, 0);\n    addStrat(1000, 1, 0, 0);\n    addStrat(1000, -1, 0, 0);\n    addStrat(1000, 0, 1, 0);\n    addStrat(1000, 0, -1, 0);\n    addStrat(1000, 0, 0, -10);\n    addStrat(200, 10, 0, 0);\n    addStrat(200, -10, 0, 0);\n    addStrat(200, 30, 0, 0);\n    addStrat(200, -30, 0, 0);\n    addStrat(200, 0, 10, 0);\n    addStrat(200, 0, -10, 0);\n    addStrat(200, 10, -5, -20);\n    addStrat(200, -10, 5, -20);\n    addStrat(100, 10, 0, -30);\n    addStrat(100, -10, 0, -30);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 1234567);\n    addStrat(1000, 0, 0, 0, 100, inputHash ^ 9876543);\n    addStrat(700, 5, -3, -15, 150, inputHash ^ 5555555);\n    addStrat(700, -5, 3, -15, 150, inputHash ^ 3141592);\n\n    for(int dir=0; dir<2 && searchOK() && bestK>0; dir++){\n        for(const auto& st: strats){\n            if(!searchOK() || bestK == 0) break;\n\n            Work w;\n            if(solveBFS(init, dir, st, limitGen(), w)) consider(move(w));\n        }\n    }\n\n    for(int xd=0; xd<2 && searchOK() && bestK>0; xd++){\n        for(int yd=0; yd<2 && searchOK() && bestK>0; yd++){\n            for(int ch=0; ch<4 && searchOK() && bestK>0; ch++){\n                Work w;\n                if(solveSweep(init, xd, yd, ch, limitGen(), w)) consider(move(w));\n            }\n        }\n    }\n\n    for(int var=0; var<9 && searchOK() && bestK>0; var++){\n        Work w;\n        if(solveLocal(init, var, limitGen(), w)) consider(move(w));\n    }\n\n    for(int t=0; t<8 && searchOK() && bestK>0; t++){\n        Work w;\n        if(solveLocalRandom(init, t % 6,\n                            inputHash ^ (uint64_t)(0x7777777 + t * 998244353ULL),\n                            limitGen(), w)){\n            consider(move(w));\n        }\n    }\n\n    if(bestK > 10000){\n        Work w(init);\n        appendCone(w, 0, 0, 10000);\n        bestOps = move(w.ops);\n        bestK = (int)bestOps.size();\n    }\n\n    bestOps = pruneOpsFast(init, bestOps, 5);\n\n    auto slowSingle = [&](bool rev){\n        if(rev){\n            for(int i=(int)bestOps.size()-1; i>=0 && finalOK(); i--){\n                if(validSkipping(init, bestOps, i)){\n                    bestOps.erase(bestOps.begin() + i);\n                }\n            }\n        }else{\n            for(int i=0; i<(int)bestOps.size() && finalOK(); ){\n                if(validSkipping(init, bestOps, i)){\n                    bestOps.erase(bestOps.begin() + i);\n                }else{\n                    i++;\n                }\n            }\n        }\n    };\n\n    auto slowPairs = [&](){\n        for(int i=0; i+1<(int)bestOps.size() && finalOK(); ){\n            if(validSkipping(init, bestOps, i, i+1)){\n                bestOps.erase(bestOps.begin() + i, bestOps.begin() + i + 2);\n            }else{\n                i++;\n            }\n        }\n    };\n\n    if(finalOK()) slowSingle(false);\n    if(finalOK()) slowSingle(true);\n    if(finalOK()) slowPairs();\n    if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n\n    if(finalOK()){\n        optimizeWindows(bestOps, finalOK);\n        if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 2);\n    }\n\n    for(int rep=0; rep<4 && finalOK(); rep++){\n        int before = (int)bestOps.size();\n\n        bool improved = tryAppendPruneImprove(init, initPos, bestOps,\n                                              inputHash ^ (uint64_t)(rep + 12345),\n                                              finalOK);\n        if(!improved) break;\n\n        if(finalOK()) optimizeWindows(bestOps, finalOK);\n        if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n\n        if((int)bestOps.size() >= before) break;\n    }\n\n    if(finalOK()) pruneBlocksFast(init, bestOps, 10, finalOK);\n    if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 2);\n    if(finalOK()) optimizeWindowsValid(init, bestOps, 6, finalOK);\n    if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n    if(finalOK()) optimizeWindows(bestOps, finalOK);\n\n    if(finalOK()) pruneBlocksFast(init, bestOps, 14, finalOK);\n    if(finalOK()) optimizeWindowsValid(init, bestOps, 7, finalOK);\n    if(finalOK()) pairDeletionSearch(init, bestOps, inputHash, finalOK);\n    if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n    if(finalOK()) optimizeWindows(bestOps, finalOK);\n\n    for(int rep=0; rep<3 && finalOK(); rep++){\n        int before = (int)bestOps.size();\n\n        bool improved = tryAppendPruneImprove(init, initPos, bestOps,\n                                              inputHash ^ (uint64_t)(98765 + rep * 1009),\n                                              finalOK);\n\n        if(!improved) continue;\n\n        if(finalOK()) optimizeWindows(bestOps, finalOK);\n        if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n        if(finalOK()) optimizeWindowsValid(init, bestOps, 6, finalOK);\n        if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 2);\n        if(finalOK()) pruneBlocksFast(init, bestOps, 8, finalOK);\n\n        if((int)bestOps.size() >= before) {\n            continue;\n        }\n    }\n\n    if(finalOK()) bestOps = pruneOpsFast(init, bestOps, 3);\n    if(finalOK()) optimizeWindows(bestOps, finalOK);\n\n    {\n        array<int,M> aa = simulateOps(init, bestOps);\n        if(countViol(aa) != 0 || (int)bestOps.size() > 10000){\n            Work w(init);\n            appendCone(w, 0, 0, 10000);\n            bestOps = move(w.ops);\n        }\n    }\n\n    cout << bestOps.size() << '\\n';\n    for(auto [u,v]: bestOps){\n        cout << Xc[u] << ' ' << Yc[u] << ' ' << Xc[v] << ' ' << Yc[v] << '\\n';\n    }\n\n    return 0;\n}","toyota2023summer-final":"#include <bits/stdc++.h>\nusing namespace std;\n\nconst int INF = 1e9;\n\nint D, N, M;\nint rootR, rootC;\nbool obs[9][9];\nint gid[9][9];\n\nvector<pair<int,int>> posi;\nvector<vector<int>> adjList;\nvector<int> rootAdjCells;\nvector<char> isRootAdj;\n\nvector<uint64_t> adjLo, adjHi;\nvector<int> orderP, pIndex;\nvector<int> defaultOrderP;\n\nvector<int> assignedLabel;\nvector<char> unseenLabel;\nint emptyCnt;\n\nchrono::steady_clock::time_point globalStart;\n\nbool timeOver(double lim) {\n    return chrono::duration<double>(chrono::steady_clock::now() - globalStart).count() > lim;\n}\n\nstatic inline bool inside(int r, int c) {\n    return 0 <= r && r < D && 0 <= c && c < D;\n}\n\nstatic inline bool hasBit(uint64_t lo, uint64_t hi, int i) {\n    if (i < 64) return (lo >> i) & 1ULL;\n    return (hi >> (i - 64)) & 1ULL;\n}\n\nstatic inline void setBit(uint64_t &lo, uint64_t &hi, int i) {\n    if (i < 64) lo |= 1ULL << i;\n    else hi |= 1ULL << (i - 64);\n}\n\nstatic inline void clearBit(uint64_t &lo, uint64_t &hi, int i) {\n    if (i < 64) lo &= ~(1ULL << i);\n    else hi &= ~(1ULL << (i - 64));\n}\n\nstatic inline bool intersects(uint64_t aLo, uint64_t aHi, uint64_t bLo, uint64_t bHi) {\n    return ((aLo & bLo) | (aHi & bHi)) != 0;\n}\n\nstatic inline bool accessibleFrom(int cell, uint64_t lo, uint64_t hi) {\n    return isRootAdj[cell] || intersects(adjLo[cell], adjHi[cell], lo, hi);\n}\n\nstatic inline int countLessMask(uint64_t lo, uint64_t hi, int x) {\n    if (x <= 0) return 0;\n    if (x < 64) return __builtin_popcountll(lo & ((1ULL << x) - 1));\n    if (x == 64) return __builtin_popcountll(lo);\n    int h = x - 64;\n    uint64_t mask = (1ULL << h) - 1;\n    return __builtin_popcountll(lo) + __builtin_popcountll(hi & mask);\n}\n\nbool connectedAvoid(int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (assignedLabel[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (assignedLabel[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validPlacementCandidates() {\n    vector<int> cand;\n\n    for (int c = 0; c < M; c++) {\n        if (assignedLabel[c] != -1) continue;\n        if (connectedAvoid(c, -1, emptyCnt - 1)) cand.push_back(c);\n    }\n\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (assignedLabel[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nint countNextValidAfter(int c) {\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return 0;\n    if (rem == 1) return 1;\n\n    int cnt = 0;\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (connectedAvoid(c, e, rem - 1)) cnt++;\n    }\n\n    return cnt;\n}\n\nvector<int> collectNextValidAfter(int c) {\n    vector<int> res;\n    int rem = emptyCnt - 1;\n    if (rem <= 0) return res;\n\n    for (int e = 0; e < M; e++) {\n        if (assignedLabel[e] != -1 || e == c) continue;\n        if (rem == 1 || connectedAvoid(c, e, rem - 1)) {\n            res.push_back(e);\n        }\n    }\n\n    return res;\n}\n\nint invOfValues(const int *seq) {\n    uint64_t lo = 0, hi = 0;\n    int seen = 0;\n    int inv = 0;\n\n    for (int i = 0; i < M; i++) {\n        int v = seq[i];\n        int less = countLessMask(lo, hi, v);\n        inv += seen - less;\n        setBit(lo, hi, v);\n        seen++;\n    }\n\n    return inv;\n}\n\nint sequenceCost(const vector<int> &seq, const vector<int> &lab) {\n    if ((int)seq.size() != M) return INF;\n\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int x = lab[seq[step]];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nbool isLegalSequence(const vector<int> &seq) {\n    if ((int)seq.size() != M) return false;\n\n    vector<char> seen(M, 0);\n    uint64_t lo = 0, hi = 0;\n\n    for (int cell : seq) {\n        if (cell < 0 || cell >= M || seen[cell]) return false;\n        if (!accessibleFrom(cell, lo, hi)) return false;\n\n        seen[cell] = 1;\n        setBit(lo, hi, cell);\n    }\n\n    return true;\n}\n\nint greedyCostLabels(const vector<int> &lab) {\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n    int cost = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            if (accessibleFrom(i, rlo, rhi) && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) return INF;\n\n        int x = lab[best];\n        int less = countLessMask(llo, lhi, x);\n        cost += step - less;\n\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return cost;\n}\n\nbool connectedAvoidSim(const vector<int> &ass, int a, int b, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (ass[s] == -1 && s != a && s != b && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n        for (int to : adjList[v]) {\n            if (ass[to] != -1 || to == a || to == b || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nvector<int> validCandSim(const vector<int> &ass, int ecnt) {\n    vector<int> cand;\n\n    for (int c = 0; c < M; c++) {\n        if (ass[c] != -1) continue;\n        if (connectedAvoidSim(ass, c, -1, ecnt - 1)) cand.push_back(c);\n    }\n\n    if (cand.empty()) {\n        for (int c = 0; c < M; c++) {\n            if (ass[c] == -1) cand.push_back(c);\n        }\n    }\n\n    return cand;\n}\n\nlong long simulateTemplateScore(\n    const vector<int> &ord,\n    const vector<int> &pidx,\n    const vector<vector<int>> &perms\n) {\n    long long total = 0;\n\n    for (const auto &perm : perms) {\n        vector<int> ass(M, -1);\n        vector<char> unseen(M, 1);\n        int ecnt = M;\n\n        for (int step = 0; step < M; step++) {\n            int t = perm[step];\n\n            vector<int> cand = validCandSim(ass, ecnt);\n\n            int rankLabel = 0;\n            for (int x = 0; x < M; x++) {\n                if (unseen[x] && x < t) rankLabel++;\n            }\n\n            int bestCell = cand[0];\n            int bestAbs = INF;\n            int bestPDiff = INF;\n            int bestPos = INF;\n\n            for (int c : cand) {\n                int rankCell = 0;\n                for (int e = 0; e < M; e++) {\n                    if (ass[e] == -1 && pidx[e] < pidx[c]) rankCell++;\n                }\n\n                int ad = abs(rankCell - rankLabel);\n                int pd = abs(pidx[c] - t);\n                int ps = pidx[c];\n\n                if (ad < bestAbs ||\n                    (ad == bestAbs && pd < bestPDiff) ||\n                    (ad == bestAbs && pd == bestPDiff && ps < bestPos)) {\n                    bestAbs = ad;\n                    bestPDiff = pd;\n                    bestPos = ps;\n                    bestCell = c;\n                }\n            }\n\n            ass[bestCell] = t;\n            unseen[t] = 0;\n            ecnt--;\n        }\n\n        int c1 = sequenceCost(ord, ass);\n        int c2 = greedyCostLabels(ass);\n        total += min(c1, c2);\n    }\n\n    return total;\n}\n\nvector<int> chooseStorageOrderBySimulation(const vector<vector<int>> &orders) {\n    if (orders.empty() || N == 0) return orders.empty() ? vector<int>() : orders[0];\n\n    uint64_t seed = 123456789;\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (obs[r][c]) seed = seed * 1000003ULL + (uint64_t)(r * 17 + c + 1);\n        }\n    }\n\n    mt19937 rng((unsigned)seed);\n\n    int S = 8;\n    vector<vector<int>> perms(S, vector<int>(M));\n\n    for (int s = 0; s < S; s++) {\n        iota(perms[s].begin(), perms[s].end(), 0);\n        shuffle(perms[s].begin(), perms[s].end(), rng);\n    }\n\n    long long baseScore = LLONG_MAX;\n    long long bestScore = LLONG_MAX;\n    int bestId = 0;\n\n    for (int ti = 0; ti < (int)orders.size(); ti++) {\n        vector<int> pidx(M);\n        for (int i = 0; i < M; i++) pidx[orders[ti][i]] = i;\n\n        long long sc = simulateTemplateScore(orders[ti], pidx, perms);\n\n        if (ti == 0) baseScore = sc;\n\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestId = ti;\n        }\n    }\n\n    if (bestId != 0 && bestScore + 3LL * S < baseScore) {\n        return orders[bestId];\n    }\n\n    return orders[0];\n}\n\nint evaluateHypWithExtra(\n    int c1,\n    int t1,\n    int c2,\n    int t2,\n    const vector<int> &futureLabels,\n    vector<int> &lab,\n    int *seqVals\n) {\n    int ptr = 0;\n    int si = 0;\n\n    for (int cell : orderP) {\n        int v;\n\n        if (assignedLabel[cell] != -1) {\n            v = assignedLabel[cell];\n        } else if (cell == c1) {\n            v = t1;\n        } else if (cell == c2) {\n            v = t2;\n        } else {\n            v = futureLabels[ptr++];\n        }\n\n        lab[cell] = v;\n        seqVals[si++] = v;\n    }\n\n    int fixedInv = invOfValues(seqVals);\n    int greedyInv = greedyCostLabels(lab);\n\n    return min(fixedInv, greedyInv);\n}\n\n// Exact expected fixed-template optimization for very late storage.\nvector<int> exactLab;\n\nbool connectedMaskAfter(uint64_t lo, uint64_t hi, int rem, int expected) {\n    if (expected == 0) return true;\n\n    bool vis[85] = {};\n    int q[85];\n    int head = 0, tail = 0;\n    int cnt = 0;\n\n    for (int s : rootAdjCells) {\n        if (s != rem && hasBit(lo, hi, s) && !vis[s]) {\n            vis[s] = true;\n            q[tail++] = s;\n            cnt++;\n        }\n    }\n\n    while (head < tail) {\n        int v = q[head++];\n\n        for (int to : adjList[v]) {\n            if (to == rem || !hasBit(lo, hi, to) || vis[to]) continue;\n            vis[to] = true;\n            q[tail++] = to;\n            cnt++;\n        }\n    }\n\n    return cnt == expected;\n}\n\nint exactPartialCost() {\n    uint64_t lo = 0, hi = 0;\n    int seen = 0;\n    int cost = 0;\n\n    for (int cell : orderP) {\n        int x = exactLab[cell];\n        if (x < 0) continue;\n\n        int less = countLessMask(lo, hi, x);\n        cost += seen - less;\n        setBit(lo, hi, x);\n        seen++;\n    }\n\n    return cost;\n}\n\nint exactIncrementCost(int cell, int label) {\n    int pc = pIndex[cell];\n    int inc = 0;\n\n    for (int a = 0; a < M; a++) {\n        int y = exactLab[a];\n        if (y < 0) continue;\n\n        if (pIndex[a] < pc) {\n            if (y > label) inc++;\n        } else {\n            if (label > y) inc++;\n        }\n    }\n\n    return inc;\n}\n\ndouble exactDfsLate(uint64_t elo, uint64_t ehi, vector<int> &labs) {\n    int n = (int)labs.size();\n    if (n == 0) return 0.0;\n    if (timeOver(1.18)) return 1e90;\n\n    double sum = 0.0;\n\n    for (int idx = 0; idx < n; idx++) {\n        int u = labs[idx];\n        int last = labs.back();\n        labs[idx] = last;\n        labs.pop_back();\n\n        double best = 1e90;\n\n        for (int e = 0; e < M; e++) {\n            if (!hasBit(elo, ehi, e)) continue;\n            if (!connectedMaskAfter(elo, ehi, e, n - 1)) continue;\n\n            int inc = exactIncrementCost(e, u);\n\n            uint64_t nlo = elo, nhi = ehi;\n            clearBit(nlo, nhi, e);\n\n            exactLab[e] = u;\n            double val = inc + exactDfsLate(nlo, nhi, labs);\n            exactLab[e] = -1;\n\n            if (val < best) best = val;\n        }\n\n        labs.push_back(last);\n        labs[idx] = u;\n\n        sum += best;\n    }\n\n    return sum / n;\n}\n\ndouble exactExpectedAfterPlacement(int c, int t, const vector<int> &futureLabels) {\n    exactLab = assignedLabel;\n    exactLab[c] = t;\n\n    uint64_t elo = 0, ehi = 0;\n\n    for (int i = 0; i < M; i++) {\n        if (assignedLabel[i] == -1 && i != c) {\n            setBit(elo, ehi, i);\n        }\n    }\n\n    int base = exactPartialCost();\n\n    vector<int> labs = futureLabels;\n    double add = exactDfsLate(elo, ehi, labs);\n\n    return base + add;\n}\n\nvector<int> greedySequenceMinLabel(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestLab = INT_MAX;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(rlo, rhi, i)) continue;\n\n            if (accessibleFrom(i, rlo, rhi) && lab[i] < bestLab) {\n                bestLab = lab[i];\n                best = i;\n            }\n        }\n\n        if (best == -1) break;\n\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n    }\n\n    return seq;\n}\n\nvector<int> greedySequenceLookahead2(const vector<int> &lab) {\n    vector<int> seq;\n    seq.reserve(M);\n\n    uint64_t rlo = 0, rhi = 0;\n    uint64_t llo = 0, lhi = 0;\n\n    for (int step = 0; step < M; step++) {\n        int best = -1;\n        int bestScore = INT_MAX;\n        int bestCostInc = INT_MAX;\n        int bestLab = INT_MAX;\n\n        for (int c = 0; c < M; c++) {\n            if (hasBit(rlo, rhi, c)) continue;\n            if (!accessibleFrom(c, rlo, rhi)) continue;\n\n            int x = lab[c];\n            int less = countLessMask(llo, lhi, x);\n            int inc1 = x - less;\n            int costInc = step - less;\n\n            uint64_t nrlo = rlo, nrhi = rhi;\n            uint64_t nllo = llo, nlhi = lhi;\n            setBit(nrlo, nrhi, c);\n            setBit(nllo, nlhi, x);\n\n            int inc2 = 0;\n\n            if (step + 1 < M) {\n                inc2 = INT_MAX / 4;\n\n                for (int d = 0; d < M; d++) {\n                    if (hasBit(nrlo, nrhi, d)) continue;\n                    if (!accessibleFrom(d, nrlo, nrhi)) continue;\n\n                    int y = lab[d];\n                    int less2 = countLessMask(nllo, nlhi, y);\n                    inc2 = min(inc2, y - less2);\n                }\n            }\n\n            int score = inc1 + inc2;\n\n            if (score < bestScore ||\n                (score == bestScore && costInc < bestCostInc) ||\n                (score == bestScore && costInc == bestCostInc && x < bestLab)) {\n                bestScore = score;\n                bestCostInc = costInc;\n                bestLab = x;\n                best = c;\n            }\n        }\n\n        if (best == -1) break;\n\n        int x = lab[best];\n        seq.push_back(best);\n        setBit(rlo, rhi, best);\n        setBit(llo, lhi, x);\n    }\n\n    return seq;\n}\n\nvector<int> improveSequenceByInsertion(vector<int> seq, const vector<int> &lab, int maxIter = 1000) {\n    if (!isLegalSequence(seq)) return seq;\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (timeOver(1.86)) break;\n\n        vector<uint64_t> prefLo(M + 1, 0), prefHi(M + 1, 0);\n        vector<int> arr(M);\n\n        for (int i = 0; i < M; i++) {\n            arr[i] = lab[seq[i]];\n            prefLo[i + 1] = prefLo[i];\n            prefHi[i + 1] = prefHi[i];\n            setBit(prefLo[i + 1], prefHi[i + 1], seq[i]);\n        }\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1;\n\n        for (int j = 1; j < M; j++) {\n            int x = arr[j];\n            int delta = 0;\n\n            for (int i = j - 1; i >= 0; i--) {\n                int y = arr[i];\n\n                if (x > y) delta++;\n                else delta--;\n\n                if (delta < bestDelta && accessibleFrom(seq[j], prefLo[i], prefHi[i])) {\n                    bestDelta = delta;\n                    bestI = i;\n                    bestJ = j;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        int cell = seq[bestJ];\n        seq.erase(seq.begin() + bestJ);\n        seq.insert(seq.begin() + bestI, cell);\n    }\n\n    return seq;\n}\n\nvector<int> improveSequenceByBlockInsertion(vector<int> seq, const vector<int> &lab, int maxIter = 60) {\n    if (!isLegalSequence(seq)) return seq;\n\n    for (int iter = 0; iter < maxIter; iter++) {\n        if (timeOver(1.84)) break;\n\n        vector<uint64_t> prefCellLo(M + 1, 0), prefCellHi(M + 1, 0);\n        vector<uint64_t> prefLabLo(M + 1, 0), prefLabHi(M + 1, 0);\n\n        for (int i = 0; i < M; i++) {\n            prefCellLo[i + 1] = prefCellLo[i];\n            prefCellHi[i + 1] = prefCellHi[i];\n            prefLabLo[i + 1] = prefLabLo[i];\n            prefLabHi[i + 1] = prefLabHi[i];\n\n            setBit(prefCellLo[i + 1], prefCellHi[i + 1], seq[i]);\n            setBit(prefLabLo[i + 1], prefLabHi[i + 1], lab[seq[i]]);\n        }\n\n        int bestDelta = 0;\n        int bestI = -1, bestJ = -1, bestK = -1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = i + 1; j < M; j++) {\n                int lenA = j - i;\n                uint64_t segLo = prefLabLo[j] & ~prefLabLo[i];\n                uint64_t segHi = prefLabHi[j] & ~prefLabHi[i];\n\n                uint64_t curLo = prefCellLo[i];\n                uint64_t curHi = prefCellHi[i];\n\n                int delta = 0;\n\n                for (int k = j; k < M; k++) {\n                    int cell = seq[k];\n\n                    if (!accessibleFrom(cell, curLo, curHi)) break;\n\n                    int y = lab[cell];\n                    int less = countLessMask(segLo, segHi, y);\n                    delta += 2 * less - lenA;\n\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestI = i;\n                        bestJ = j;\n                        bestK = k;\n                    }\n\n                    setBit(curLo, curHi, cell);\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        vector<int> ns;\n        ns.reserve(M);\n\n        for (int p = 0; p < bestI; p++) ns.push_back(seq[p]);\n        for (int p = bestJ; p <= bestK; p++) ns.push_back(seq[p]);\n        for (int p = bestI; p < bestJ; p++) ns.push_back(seq[p]);\n        for (int p = bestK + 1; p < M; p++) ns.push_back(seq[p]);\n\n        seq.swap(ns);\n    }\n\n    return seq;\n}\n\nvector<int> winDpBuf;\nvector<unsigned char> winParBuf;\nvector<uint64_t> winSubLoBuf, winSubHiBuf, winSubLabLoBuf, winSubLabHiBuf;\n\nvoid ensureWinBuf(int S) {\n    if ((int)winDpBuf.size() < S) {\n        winDpBuf.resize(S);\n        winParBuf.resize(S);\n        winSubLoBuf.resize(S);\n        winSubHiBuf.resize(S);\n        winSubLabLoBuf.resize(S);\n        winSubLabHiBuf.resize(S);\n    }\n}\n\nbool improveWindowAt(vector<int> &seq, const vector<int> &lab, int l, int K, double lim) {\n    if (K <= 1) return false;\n    if (K > 20) K = 20;\n    if (l + K > M) K = M - l;\n    if (K <= 1) return false;\n\n    int cells[20];\n\n    for (int i = 0; i < K; i++) {\n        cells[i] = seq[l + i];\n    }\n\n    int originalInv = 0;\n    for (int i = 0; i < K; i++) {\n        for (int j = i + 1; j < K; j++) {\n            if (lab[cells[i]] > lab[cells[j]]) originalInv++;\n        }\n    }\n\n    if (originalInv == 0) return false;\n\n    uint64_t prefLo = 0, prefHi = 0;\n    for (int i = 0; i < l; i++) {\n        setBit(prefLo, prefHi, seq[i]);\n    }\n\n    uint64_t cellLo[20] = {}, cellHi[20] = {};\n    uint64_t labelLo[20] = {}, labelHi[20] = {};\n\n    for (int i = 0; i < K; i++) {\n        setBit(cellLo[i], cellHi[i], cells[i]);\n        setBit(labelLo[i], labelHi[i], lab[cells[i]]);\n    }\n\n    int S = 1 << K;\n    int full = S - 1;\n\n    ensureWinBuf(S);\n\n    winSubLoBuf[0] = winSubHiBuf[0] = 0;\n    winSubLabLoBuf[0] = winSubLabHiBuf[0] = 0;\n\n    for (int mask = 1; mask < S; mask++) {\n        if ((mask & 8191) == 0 && timeOver(lim)) return false;\n\n        int b = __builtin_ctz((unsigned)mask);\n        int pm = mask ^ (1 << b);\n\n        winSubLoBuf[mask] = winSubLoBuf[pm] | cellLo[b];\n        winSubHiBuf[mask] = winSubHiBuf[pm] | cellHi[b];\n        winSubLabLoBuf[mask] = winSubLabLoBuf[pm] | labelLo[b];\n        winSubLabHiBuf[mask] = winSubLabHiBuf[pm] | labelHi[b];\n    }\n\n    fill(winDpBuf.begin(), winDpBuf.begin() + S, INF);\n    fill(winParBuf.begin(), winParBuf.begin() + S, 255);\n\n    winDpBuf[0] = 0;\n\n    for (int mask = 0; mask < S; mask++) {\n        if ((mask & 4095) == 0 && timeOver(lim)) return false;\n\n        int cur = winDpBuf[mask];\n        if (cur >= originalInv) continue;\n\n        uint64_t rmLo = prefLo | winSubLoBuf[mask];\n        uint64_t rmHi = prefHi | winSubHiBuf[mask];\n\n        int selectedCnt = __builtin_popcount((unsigned)mask);\n\n        for (int j = 0; j < K; j++) {\n            if (mask & (1 << j)) continue;\n\n            int cell = cells[j];\n            if (!accessibleFrom(cell, rmLo, rmHi)) continue;\n\n            int x = lab[cell];\n            int less = countLessMask(winSubLabLoBuf[mask], winSubLabHiBuf[mask], x);\n            int add = selectedCnt - less;\n\n            int nm = mask | (1 << j);\n            int nc = cur + add;\n\n            if (nc < winDpBuf[nm]) {\n                winDpBuf[nm] = nc;\n                winParBuf[nm] = (unsigned char)j;\n            }\n        }\n    }\n\n    if (winDpBuf[full] >= originalInv) return false;\n\n    vector<int> rev;\n    rev.reserve(K);\n\n    int mask = full;\n    while (mask) {\n        int j = winParBuf[mask];\n        if (j < 0 || j >= K) return false;\n\n        rev.push_back(cells[j]);\n        mask ^= (1 << j);\n    }\n\n    reverse(rev.begin(), rev.end());\n\n    for (int i = 0; i < K; i++) {\n        seq[l + i] = rev[i];\n    }\n\n    return true;\n}\n\nvector<int> improveSequenceByWindowDP(vector<int> seq, const vector<int> &lab, int maxK, int passes, double lim) {\n    if (!isLegalSequence(seq)) return seq;\n    maxK = min(maxK, 20);\n\n    for (int pass = 0; pass < passes; pass++) {\n        if (timeOver(lim)) break;\n\n        bool any = false;\n\n        if (pass % 2 == 0) {\n            for (int l = 0; l < M - 1; l++) {\n                if (timeOver(lim)) return seq;\n\n                int K = min(maxK, M - l);\n                if (K >= 2 && improveWindowAt(seq, lab, l, K, lim)) {\n                    any = true;\n                }\n            }\n        } else {\n            for (int l = M - 2; l >= 0; l--) {\n                if (timeOver(lim)) return seq;\n\n                int K = min(maxK, M - l);\n                if (K >= 2 && improveWindowAt(seq, lab, l, K, lim)) {\n                    any = true;\n                }\n            }\n        }\n\n        if (!any) break;\n    }\n\n    return seq;\n}\n\nvoid addTemplateOrder(vector<vector<int>> &temps, const vector<int> &ord) {\n    if ((int)ord.size() != M) return;\n    if (!isLegalSequence(ord)) return;\n\n    for (const auto &v : temps) {\n        if (v == ord) return;\n    }\n\n    temps.push_back(ord);\n}\n\nvector<vector<int>> buildFinalTemplates() {\n    vector<vector<int>> temps;\n    addTemplateOrder(temps, orderP);\n\n    const int BIG = 1e9;\n\n    vector<vector<int>> dist(D, vector<int>(D, BIG));\n    queue<pair<int,int>> q;\n\n    dist[rootR][rootC] = 0;\n    q.push({rootR, rootC});\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != BIG) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            q.push({nr, nc});\n        }\n    }\n\n    auto makeDiscOrder = [&](const vector<pair<int,int>> &dirs) {\n        vector<vector<int>> disc(D, vector<int>(D, BIG));\n        queue<pair<int,int>> qq;\n\n        disc[rootR][rootC] = 0;\n        int cnt = 1;\n        qq.push({rootR, rootC});\n\n        while (!qq.empty()) {\n            auto [r, c] = qq.front();\n            qq.pop();\n\n            for (auto [dr, dc] : dirs) {\n                int nr = r + dr;\n                int nc = c + dc;\n\n                if (!inside(nr, nc) || obs[nr][nc]) continue;\n                if (disc[nr][nc] != BIG) continue;\n\n                disc[nr][nc] = cnt++;\n                qq.push({nr, nc});\n            }\n        }\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n\n            return a < b;\n        });\n\n        return ord;\n    };\n\n    addTemplateOrder(temps, makeDiscOrder({{1,0},{0,-1},{0,1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{1,0},{0,1},{0,-1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{0,-1},{1,0},{0,1},{-1,0}}));\n    addTemplateOrder(temps, makeDiscOrder({{0,1},{1,0},{0,-1},{-1,0}}));\n\n    auto keyOf = [&](int type, int id) -> long long {\n        auto [r, c] = posi[id];\n\n        switch (type) {\n            case 0: return c * 100LL + r;\n            case 1: return -c * 100LL + r;\n            case 2: return llabs(c - rootC) * 100LL + c;\n            case 3: return -llabs(c - rootC) * 100LL + c;\n            case 4: return r * 100LL + c;\n            case 5: return -r * 100LL + c;\n            case 6: return (r + c) * 100LL + c;\n            case 7: return (r - c) * 100LL + c;\n            default: return id;\n        }\n    };\n\n    for (int type = 0; type < 8; type++) {\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n\n            long long ka = keyOf(type, a);\n            long long kb = keyOf(type, b);\n\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        addTemplateOrder(temps, ord);\n    }\n\n    auto expansionOrder = [&](int type) {\n        vector<int> ord;\n        vector<char> used(M, 0);\n        uint64_t lo = 0, hi = 0;\n\n        auto score = [&](int id) -> long long {\n            auto [r, c] = posi[id];\n\n            switch (type) {\n                case 0: return c * 100LL + r;\n                case 1: return -c * 100LL + r;\n                case 2: return -r * 100LL + c;\n                case 3: return -r * 100LL - c;\n                case 4: return llabs(c - rootC) * 100LL - r;\n                case 5: return -llabs(c - rootC) * 100LL - r;\n                case 6: return (r + c) * 100LL - r;\n                default: return id;\n            }\n        };\n\n        for (int step = 0; step < M; step++) {\n            int best = -1;\n            long long bestScore = LLONG_MAX;\n\n            for (int id = 0; id < M; id++) {\n                if (used[id]) continue;\n                if (!accessibleFrom(id, lo, hi)) continue;\n\n                long long sc = score(id);\n                if (sc < bestScore || (sc == bestScore && (best == -1 || id < best))) {\n                    bestScore = sc;\n                    best = id;\n                }\n            }\n\n            if (best == -1) return vector<int>();\n\n            used[best] = 1;\n            ord.push_back(best);\n            setBit(lo, hi, best);\n        }\n\n        return ord;\n    };\n\n    for (int type = 0; type < 7; type++) {\n        addTemplateOrder(temps, expansionOrder(type));\n    }\n\n    return temps;\n}\n\nstruct Key {\n    uint64_t lo, hi;\n\n    bool operator==(const Key &o) const {\n        return lo == o.lo && hi == o.hi;\n    }\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\nstruct KeyHash {\n    size_t operator()(const Key &k) const {\n        return splitmix64(k.lo) ^ (splitmix64(k.hi + 0x123456789abcdefULL) >> 1);\n    }\n};\n\nstruct Node {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nstruct Temp {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int cost;\n    int forced;\n    int parent;\n    int cell;\n};\n\nvector<int> beamSearchRemoval(const vector<int> &lab, int upperBound) {\n    const int BEAM = 12000;\n\n    vector<Node> nodes;\n    nodes.reserve((M + 1) * BEAM + 1);\n    nodes.push_back(Node{0, 0, 0, 0, 0, 0, -1, -1});\n\n    vector<int> cur;\n    cur.push_back(0);\n\n    auto betterTemp = [](const Temp &a, const Temp &b) {\n        if (a.forced != b.forced) return a.forced < b.forced;\n        if (a.cost != b.cost) return a.cost < b.cost;\n        if (a.lo != b.lo) return a.lo < b.lo;\n        return a.hi < b.hi;\n    };\n\n    for (int depth = 0; depth < M; depth++) {\n        if (timeOver(1.82)) break;\n\n        vector<Temp> temps;\n        size_t reserveSize = min<size_t>((size_t)cur.size() * 40 + 100, 700000);\n        temps.reserve(reserveSize);\n\n        unordered_map<Key, int, KeyHash> mp;\n        mp.reserve(reserveSize * 2);\n\n        for (int idx : cur) {\n            const Node &s = nodes[idx];\n\n            for (int i = 0; i < M; i++) {\n                if (hasBit(s.lo, s.hi, i)) continue;\n                if (!accessibleFrom(i, s.lo, s.hi)) continue;\n\n                int x = lab[i];\n                int less = countLessMask(s.llo, s.lhi, x);\n\n                int cost2 = s.cost + (depth - less);\n                int forced2 = s.forced + (x - less);\n\n                if (forced2 > upperBound) continue;\n\n                uint64_t nlo = s.lo, nhi = s.hi;\n                uint64_t nllo = s.llo, nlhi = s.lhi;\n                setBit(nlo, nhi, i);\n                setBit(nllo, nlhi, x);\n\n                Temp t{nlo, nhi, nllo, nlhi, cost2, forced2, idx, i};\n                Key key{nlo, nhi};\n\n                auto it = mp.find(key);\n\n                if (it == mp.end()) {\n                    int id = (int)temps.size();\n                    temps.push_back(t);\n                    mp.emplace(key, id);\n                } else {\n                    int id = it->second;\n\n                    if (t.cost < temps[id].cost ||\n                        (t.cost == temps[id].cost && t.forced < temps[id].forced)) {\n                        temps[id] = t;\n                    }\n                }\n            }\n        }\n\n        if (temps.empty()) return {};\n\n        if ((int)temps.size() > BEAM) {\n            nth_element(temps.begin(), temps.begin() + BEAM, temps.end(), betterTemp);\n            temps.resize(BEAM);\n        }\n\n        vector<int> nxt;\n        nxt.reserve(temps.size());\n\n        for (const Temp &t : temps) {\n            int id = (int)nodes.size();\n            nodes.push_back(Node{t.lo, t.hi, t.llo, t.lhi, t.cost, t.forced, t.parent, t.cell});\n            nxt.push_back(id);\n        }\n\n        cur.swap(nxt);\n    }\n\n    int bestNode = -1;\n    int bestCost = INF;\n\n    for (int idx : cur) {\n        if (nodes[idx].cost < bestCost &&\n            __builtin_popcountll(nodes[idx].lo) + __builtin_popcountll(nodes[idx].hi) == M) {\n            bestCost = nodes[idx].cost;\n            bestNode = idx;\n        }\n    }\n\n    if (bestNode == -1) return {};\n\n    vector<int> seq;\n\n    while (bestNode != 0 && bestNode != -1) {\n        seq.push_back(nodes[bestNode].cell);\n        bestNode = nodes[bestNode].parent;\n    }\n\n    reverse(seq.begin(), seq.end());\n\n    if ((int)seq.size() != M) return {};\n    return seq;\n}\n\nstruct PQNode {\n    uint64_t lo, hi;\n    uint64_t llo, lhi;\n    int forced;\n    int parent;\n    int cell;\n    int depth;\n};\n\nvector<int> bestFirstSearchRemoval(const vector<int> &lab, int upperBound, int nodeLimit = 120000) {\n    if (timeOver(1.72)) return {};\n\n    struct Item {\n        long long eval;\n        int forced;\n        int depth;\n        int id;\n    };\n\n    struct Cmp {\n        bool operator()(const Item &a, const Item &b) const {\n            if (a.eval != b.eval) return a.eval > b.eval;\n            if (a.forced != b.forced) return a.forced > b.forced;\n            return a.depth < b.depth;\n        }\n    };\n\n    vector<PQNode> nodes;\n    nodes.reserve(nodeLimit + 1);\n\n    priority_queue<Item, vector<Item>, Cmp> pq;\n    unordered_map<Key, int, KeyHash> best;\n    best.reserve(nodeLimit * 2);\n\n    nodes.push_back(PQNode{0, 0, 0, 0, 0, -1, -1, 0});\n    best[{0, 0}] = 0;\n    pq.push(Item{0, 0, 0, 0});\n\n    while (!pq.empty() && (int)nodes.size() < nodeLimit) {\n        if (timeOver(1.86)) break;\n\n        Item it = pq.top();\n        pq.pop();\n\n        const PQNode &s = nodes[it.id];\n        Key curKey{s.lo, s.hi};\n\n        auto mit = best.find(curKey);\n        if (mit == best.end() || mit->second != s.forced) continue;\n\n        if (s.depth == M) {\n            if (s.forced >= upperBound) return {};\n\n            vector<int> seq;\n            int v = it.id;\n\n            while (v != -1 && nodes[v].cell != -1) {\n                seq.push_back(nodes[v].cell);\n                v = nodes[v].parent;\n            }\n\n            reverse(seq.begin(), seq.end());\n\n            if ((int)seq.size() == M) return seq;\n            return {};\n        }\n\n        vector<int> cand;\n\n        for (int i = 0; i < M; i++) {\n            if (hasBit(s.lo, s.hi, i)) continue;\n            if (accessibleFrom(i, s.lo, s.hi)) cand.push_back(i);\n        }\n\n        sort(cand.begin(), cand.end(), [&](int a, int b) {\n            return lab[a] < lab[b];\n        });\n\n        for (int cell : cand) {\n            int x = lab[cell];\n            int less = countLessMask(s.llo, s.lhi, x);\n            int nf = s.forced + (x - less);\n\n            if (nf >= upperBound) continue;\n\n            uint64_t nlo = s.lo, nhi = s.hi;\n            uint64_t nllo = s.llo, nlhi = s.lhi;\n            setBit(nlo, nhi, cell);\n            setBit(nllo, nlhi, x);\n\n            Key nk{nlo, nhi};\n            auto bit = best.find(nk);\n\n            if (bit != best.end() && bit->second <= nf) continue;\n\n            best[nk] = nf;\n\n            if ((int)nodes.size() >= nodeLimit) break;\n\n            int nid = (int)nodes.size();\n            nodes.push_back(PQNode{nlo, nhi, nllo, nlhi, nf, it.id, cell, s.depth + 1});\n\n            long long eval = 1000LL * nf - (s.depth + 1);\n            pq.push(Item{eval, nf, s.depth + 1, nid});\n        }\n    }\n\n    return {};\n}\n\nint main() {\n    globalStart = chrono::steady_clock::now();\n\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> D >> N;\n\n    rootR = 0;\n    rootC = (D - 1) / 2;\n\n    memset(obs, 0, sizeof(obs));\n    memset(gid, -1, sizeof(gid));\n\n    for (int k = 0; k < N; k++) {\n        int r, c;\n        cin >> r >> c;\n        obs[r][c] = true;\n    }\n\n    for (int r = 0; r < D; r++) {\n        for (int c = 0; c < D; c++) {\n            if (r == rootR && c == rootC) continue;\n            if (obs[r][c]) continue;\n\n            gid[r][c] = (int)posi.size();\n            posi.push_back({r, c});\n        }\n    }\n\n    M = (int)posi.size();\n\n    adjList.assign(M, {});\n    isRootAdj.assign(M, 0);\n    adjLo.assign(M, 0);\n    adjHi.assign(M, 0);\n\n    int dirs4[4][2] = {{1,0},{-1,0},{0,1},{0,-1}};\n\n    for (int id = 0; id < M; id++) {\n        auto [r, c] = posi[id];\n\n        for (auto &d : dirs4) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc)) continue;\n\n            if (nr == rootR && nc == rootC) {\n                isRootAdj[id] = 1;\n            } else if (!obs[nr][nc]) {\n                int to = gid[nr][nc];\n                if (to >= 0) adjList[id].push_back(to);\n            }\n        }\n\n        if (isRootAdj[id]) rootAdjCells.push_back(id);\n    }\n\n    for (int i = 0; i < M; i++) {\n        for (int to : adjList[i]) {\n            if (to < 64) adjLo[i] |= 1ULL << to;\n            else adjHi[i] |= 1ULL << (to - 64);\n        }\n    }\n\n    int dist[9][9];\n    int disc[9][9];\n\n    for (int r = 0; r < 9; r++) {\n        for (int c = 0; c < 9; c++) {\n            dist[r][c] = INF;\n            disc[r][c] = INF;\n        }\n    }\n\n    int bfsDirs[4][2] = {{1,0},{0,-1},{0,1},{-1,0}};\n    queue<pair<int,int>> q;\n\n    dist[rootR][rootC] = 0;\n    disc[rootR][rootC] = 0;\n\n    int dcnt = 1;\n    q.push({rootR, rootC});\n\n    while (!q.empty()) {\n        auto [r, c] = q.front();\n        q.pop();\n\n        for (auto &d : bfsDirs) {\n            int nr = r + d[0];\n            int nc = c + d[1];\n\n            if (!inside(nr, nc) || obs[nr][nc]) continue;\n            if (dist[nr][nc] != INF) continue;\n\n            dist[nr][nc] = dist[r][c] + 1;\n            disc[nr][nc] = dcnt++;\n            q.push({nr, nc});\n        }\n    }\n\n    auto makeStorageOrder = [&](const vector<pair<int,int>> &dirs) {\n        vector<vector<int>> localDisc(D, vector<int>(D, INF));\n        queue<pair<int,int>> qq;\n\n        localDisc[rootR][rootC] = 0;\n        int cnt = 1;\n        qq.push({rootR, rootC});\n\n        while (!qq.empty()) {\n            auto [r, c] = qq.front();\n            qq.pop();\n\n            for (auto [dr, dc] : dirs) {\n                int nr = r + dr;\n                int nc = c + dc;\n\n                if (!inside(nr, nc) || obs[nr][nc]) continue;\n                if (localDisc[nr][nc] != INF) continue;\n\n                localDisc[nr][nc] = cnt++;\n                qq.push({nr, nc});\n            }\n        }\n\n        vector<int> ord(M);\n        iota(ord.begin(), ord.end(), 0);\n\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (localDisc[ra][ca] != localDisc[rb][cb]) return localDisc[ra][ca] < localDisc[rb][cb];\n\n            return a < b;\n        });\n\n        return ord;\n    };\n\n    vector<vector<int>> storageOrders;\n\n    auto addStorageOrder = [&](const vector<int> &ord) {\n        if ((int)ord.size() != M) return;\n        if (!isLegalSequence(ord)) return;\n\n        for (auto &v : storageOrders) {\n            if (v == ord) return;\n        }\n\n        storageOrders.push_back(ord);\n    };\n\n    addStorageOrder(makeStorageOrder({{1,0},{0,-1},{0,1},{-1,0}}));\n    addStorageOrder(makeStorageOrder({{1,0},{0,1},{0,-1},{-1,0}}));\n    addStorageOrder(makeStorageOrder({{0,-1},{1,0},{0,1},{-1,0}}));\n    addStorageOrder(makeStorageOrder({{0,1},{1,0},{0,-1},{-1,0}}));\n\n    if (!storageOrders.empty()) defaultOrderP = storageOrders[0];\n\n    orderP = chooseStorageOrderBySimulation(storageOrders);\n\n    if (orderP.empty()) {\n        orderP.resize(M);\n        iota(orderP.begin(), orderP.end(), 0);\n        sort(orderP.begin(), orderP.end(), [&](int a, int b) {\n            auto [ra, ca] = posi[a];\n            auto [rb, cb] = posi[b];\n\n            if (dist[ra][ca] != dist[rb][cb]) return dist[ra][ca] < dist[rb][cb];\n            if (disc[ra][ca] != disc[rb][cb]) return disc[ra][ca] < disc[rb][cb];\n\n            return a < b;\n        });\n    }\n\n    pIndex.assign(M, 0);\n    for (int i = 0; i < M; i++) pIndex[orderP[i]] = i;\n\n    bool useDefaultTie = (!defaultOrderP.empty() && defaultOrderP != orderP);\n\n    assignedLabel.assign(M, -1);\n    unseenLabel.assign(M, 1);\n    emptyCnt = M;\n\n    for (int step = 0; step < M; step++) {\n        int t;\n        cin >> t;\n\n        vector<int> cand = validPlacementCandidates();\n\n        vector<int> futureLabels;\n        futureLabels.reserve(emptyCnt - 1);\n\n        int rankLabel = 0;\n\n        for (int x = 0; x < M; x++) {\n            if (!unseenLabel[x]) continue;\n            if (x < t) rankLabel++;\n            if (x != t) futureLabels.push_back(x);\n        }\n\n        bool useExactLate = false;\n        if (emptyCnt <= 6 && emptyCnt >= 2 && !timeOver(1.08)) {\n            int n = (int)futureLabels.size();\n            long long fact = 1;\n            for (int i = 2; i <= n; i++) fact *= i;\n            long long est = fact * fact * (long long)cand.size();\n            if (est <= 600000) useExactLate = true;\n        }\n\n        bool useLateLookahead = (!useExactLate && emptyCnt <= 12 && emptyCnt >= 2 && !timeOver(1.20));\n\n        int bestCell = -1;\n        int bestHyp = INT_MAX;\n        int bestInv = INT_MAX;\n        int bestDefaultTie = INT_MAX;\n        int bestAbs = INT_MAX;\n        int bestNext = -1;\n        int bestPDiff = INT_MAX;\n        long long bestLateScore = LLONG_MAX / 4;\n        long long bestLatePrimary = LLONG_MAX / 4;\n        double bestExact = 1e100;\n\n        vector<int> lab(M);\n        int seqVals[85];\n        int seqValsDefault[85];\n\n        for (int c : cand) {\n            int ptr = 0;\n            int si = 0;\n\n            for (int cell : orderP) {\n                int v;\n\n                if (assignedLabel[cell] != -1) {\n                    v = assignedLabel[cell];\n                } else if (cell == c) {\n                    v = t;\n                } else {\n                    v = futureLabels[ptr++];\n                }\n\n                lab[cell] = v;\n                seqVals[si++] = v;\n            }\n\n            int fixedInv = invOfValues(seqVals);\n            int greedyInv = greedyCostLabels(lab);\n            int hyp = min(fixedInv, greedyInv);\n\n            int defaultTie = fixedInv;\n            if (useDefaultTie) {\n                int ptrD = 0;\n                int siD = 0;\n\n                for (int cell : defaultOrderP) {\n                    int v;\n\n                    if (assignedLabel[cell] != -1) {\n                        v = assignedLabel[cell];\n                    } else if (cell == c) {\n                        v = t;\n                    } else {\n                        v = futureLabels[ptrD++];\n                    }\n\n                    seqValsDefault[siD++] = v;\n                }\n\n                defaultTie = invOfValues(seqValsDefault);\n            }\n\n            int rankCell = 0;\n\n            for (int e = 0; e < M; e++) {\n                if (assignedLabel[e] == -1 && pIndex[e] < pIndex[c]) rankCell++;\n            }\n\n            int absDiff = abs(rankCell - rankLabel);\n\n            vector<int> nextCells;\n            int nextValid;\n\n            if (useLateLookahead) {\n                nextCells = collectNextValidAfter(c);\n                nextValid = (int)nextCells.size();\n            } else {\n                nextValid = countNextValidAfter(c);\n            }\n\n            int pDiff = abs(pIndex[c] - t);\n\n            long long lateScore = LLONG_MAX / 4;\n\n            if (useLateLookahead) {\n                long long sum = 0;\n\n                for (int u : futureLabels) {\n                    vector<int> future2;\n                    future2.reserve(futureLabels.size() - 1);\n\n                    for (int x : futureLabels) {\n                        if (x != u) future2.push_back(x);\n                    }\n\n                    int bestU = INF;\n\n                    for (int e : nextCells) {\n                        int val = evaluateHypWithExtra(c, t, e, u, future2, lab, seqVals);\n                        if (val < bestU) bestU = val;\n                    }\n\n                    sum += bestU;\n                }\n\n                lateScore = sum;\n            }\n\n            long long latePrimary = lateScore;\n            if (useLateLookahead && emptyCnt > 10) {\n                latePrimary += 10LL * hyp;\n            }\n\n            double exactScore = 1e100;\n            if (useExactLate) {\n                exactScore = exactExpectedAfterPlacement(c, t, futureLabels);\n            }\n\n            bool better = false;\n\n            if (useExactLate && fabs(exactScore - bestExact) > 1e-9) {\n                better = exactScore < bestExact;\n            } else if (useLateLookahead) {\n                if (latePrimary != bestLatePrimary) better = latePrimary < bestLatePrimary;\n                else if (lateScore != bestLateScore) better = lateScore < bestLateScore;\n                else if (hyp != bestHyp) better = hyp < bestHyp;\n                else if (fixedInv != bestInv) better = fixedInv < bestInv;\n                else if (defaultTie != bestDefaultTie) better = defaultTie < bestDefaultTie;\n                else if (absDiff != bestAbs) better = absDiff < bestAbs;\n                else if (nextValid != bestNext) better = nextValid > bestNext;\n                else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n            } else {\n                if (hyp != bestHyp) better = hyp < bestHyp;\n                else if (fixedInv != bestInv) better = fixedInv < bestInv;\n                else if (defaultTie != bestDefaultTie) better = defaultTie < bestDefaultTie;\n                else if (absDiff != bestAbs) better = absDiff < bestAbs;\n                else if (nextValid != bestNext) better = nextValid > bestNext;\n                else if (pDiff != bestPDiff) better = pDiff < bestPDiff;\n            }\n\n            if (better) {\n                bestExact = exactScore;\n                bestLatePrimary = latePrimary;\n                bestLateScore = lateScore;\n                bestHyp = hyp;\n                bestInv = fixedInv;\n                bestDefaultTie = defaultTie;\n                bestAbs = absDiff;\n                bestNext = nextValid;\n                bestPDiff = pDiff;\n                bestCell = c;\n            }\n        }\n\n        if (bestCell == -1) bestCell = cand[0];\n\n        assignedLabel[bestCell] = t;\n        unseenLabel[t] = 0;\n        emptyCnt--;\n\n        cout << posi[bestCell].first << ' ' << posi[bestCell].second << endl;\n    }\n\n    vector<int> bestSeq = orderP;\n    int bestCost = sequenceCost(bestSeq, assignedLabel);\n\n    auto considerSeq = [&](vector<int> seq, int improveIter) {\n        if ((int)seq.size() != M) return;\n        if (!isLegalSequence(seq)) return;\n\n        int c0 = sequenceCost(seq, assignedLabel);\n\n        if (c0 < bestCost) {\n            bestCost = c0;\n            bestSeq = seq;\n        }\n\n        if (improveIter > 0) {\n            vector<int> imp = improveSequenceByInsertion(seq, assignedLabel, improveIter);\n\n            if (isLegalSequence(imp)) {\n                int c1 = sequenceCost(imp, assignedLabel);\n\n                if (c1 < bestCost) {\n                    bestCost = c1;\n                    bestSeq = imp;\n                }\n            }\n        }\n    };\n\n    vector<vector<int>> finalTemplates = buildFinalTemplates();\n\n    for (const auto &seq : finalTemplates) {\n        considerSeq(seq, 300);\n    }\n\n    vector<int> gseq = greedySequenceMinLabel(assignedLabel);\n    considerSeq(gseq, 1000);\n\n    vector<int> lseq = greedySequenceLookahead2(assignedLabel);\n    considerSeq(lseq, 1000);\n\n    vector<int> impBest = improveSequenceByInsertion(bestSeq, assignedLabel, 1000);\n    considerSeq(impBest, 0);\n\n    if (!timeOver(1.30)) {\n        vector<int> wseq = improveSequenceByWindowDP(bestSeq, assignedLabel, 16, 1, 1.42);\n        considerSeq(wseq, 200);\n    }\n\n    vector<int> bseq = beamSearchRemoval(assignedLabel, bestCost);\n    considerSeq(bseq, 1000);\n\n    if (!timeOver(1.70)) {\n        vector<int> wseq = improveSequenceByWindowDP(bestSeq, assignedLabel, 14, 1, 1.76);\n        considerSeq(wseq, 100);\n    }\n\n    if (!timeOver(1.76)) {\n        vector<int> blk = improveSequenceByBlockInsertion(bestSeq, assignedLabel, 60);\n        considerSeq(blk, 400);\n    }\n\n    if (!timeOver(1.78)) {\n        vector<int> aseq = bestFirstSearchRemoval(assignedLabel, bestCost, 120000);\n        considerSeq(aseq, 800);\n    }\n\n    if (!timeOver(1.84)) {\n        vector<int> blk = improveSequenceByBlockInsertion(bestSeq, assignedLabel, 40);\n        considerSeq(blk, 200);\n    }\n\n    if (!timeOver(1.86)) {\n        vector<int> wseq = improveSequenceByWindowDP(bestSeq, assignedLabel, 12, 1, 1.89);\n        considerSeq(wseq, 0);\n    }\n\n    if (!isLegalSequence(bestSeq)) {\n        bestSeq = orderP;\n    }\n\n    for (int cell : bestSeq) {\n        cout << posi[cell].first << ' ' << posi[cell].second << '\\n';\n    }\n\n    cout.flush();\n\n    return 0;\n}","ahc024":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 50;\nstatic const int MAXV = MAXN * MAXN;\nstatic const int MAXC = 105;\n\nint N, M, V;\nbool REQ[MAXC][MAXC];\nint GDEP[MAXC], DEGREQ[MAXC], NEED[MAXC];\n\nint DR[4] = {-1, 1, 0, 0};\nint DC[4] = {0, 0, -1, 1};\n\nint visArr[MAXV];\nint bfsQ[MAXV];\nint visStamp = 1;\n\ninline int newStamp() {\n    ++visStamp;\n    if (visStamp == INT_MAX) {\n        memset(visArr, 0, sizeof(visArr));\n        visStamp = 1;\n    }\n    return visStamp;\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 RNG {\n    uint64_t s;\n    RNG(uint64_t seed = 1) : s(seed) {}\n\n    uint64_t next() {\n        uint64_t z = (s += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n\n    template<class T>\n    void shuffleVec(vector<T>& v) {\n        for (int i = (int)v.size() - 1; i > 0; --i) {\n            swap(v[i], v[nextInt(i + 1)]);\n        }\n    }\n};\n\nstruct State {\n    array<unsigned char, MAXV> g;\n    int cnt[MAXC];\n    int edge[MAXC][MAXC];\n    int zeros;\n\n    void clear() {\n        g.fill(0);\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n        zeros = 0;\n    }\n\n    inline void addEdgeCnt(int a, int b, int d) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        edge[a][b] += d;\n        edge[b][a] += d;\n    }\n\n    void rebuild() {\n        memset(cnt, 0, sizeof(cnt));\n        memset(edge, 0, sizeof(edge));\n\n        for (int p = 0; p < V; ++p) {\n            int a = g[p];\n            cnt[a]++;\n        }\n        zeros = cnt[0];\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                int p = r * N + c;\n                int a = g[p];\n\n                if (r + 1 < N) addEdgeCnt(a, g[(r + 1) * N + c], 1);\n                if (c + 1 < N) addEdgeCnt(a, g[r * N + (c + 1)], 1);\n\n                if (r == 0) addEdgeCnt(0, a, 1);\n                if (r == N - 1) addEdgeCnt(0, a, 1);\n                if (c == 0) addEdgeCnt(0, a, 1);\n                if (c == N - 1) addEdgeCnt(0, a, 1);\n            }\n        }\n    }\n\n    inline bool hasZeroAdj(int p) const {\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) return true;\n            int q = nr * N + nc;\n            if (g[q] == 0) return true;\n        }\n        return false;\n    }\n\n    bool connectedAfterRemoveColor(int p, int col) const {\n        if (cnt[col] <= 1) return false;\n\n        int r = p / N, c = p % N;\n        int nb[4], k = 0;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (g[q] == col) nb[k++] = q;\n        }\n\n        if (k == 0) return false;\n        if (k == 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        bool reached[4] = {};\n        reached[0] = true;\n        int found = 1;\n\n        visArr[nb[0]] = stamp;\n        bfsQ[tail++] = nb[0];\n\n        while (head < tail && found < k) {\n            int v = bfsQ[head++];\n            int vr = v / N, vc = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = vr + DR[d], nc = vc + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n\n                visArr[q] = stamp;\n\n                for (int i = 1; i < k; ++i) {\n                    if (!reached[i] && q == nb[i]) {\n                        reached[i] = true;\n                        ++found;\n                        break;\n                    }\n                }\n\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return found == k;\n    }\n\n    bool zeroConnectedAfterRemove(int p) const {\n        if (cnt[0] <= 1) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int q = r * N + c;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (q == p) continue;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0] - 1;\n    }\n\n    bool connectedColorFull(int col) const {\n        if (col <= 0) return false;\n        if (cnt[col] <= 0) return false;\n\n        int start = -1;\n        for (int p = 0; p < V; ++p) {\n            if (g[p] == col) {\n                start = p;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        visArr[start] = stamp;\n        bfsQ[tail++] = start;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[col];\n    }\n\n    bool zeroConnectedFull() const {\n        if (cnt[0] == 0) return true;\n\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        return seen == cnt[0];\n    }\n\n    bool tryChange(int p, int to) {\n        int from = g[p];\n        if (from == to) return false;\n        if (to < 0 || to > M) return false;\n\n        if (from > 0 && cnt[from] <= 1) return false;\n\n        if (to == 0) {\n            if (from == 0) return false;\n            if (!hasZeroAdj(p)) return false;\n        } else {\n            bool adjTarget = false;\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (g[q] == to) {\n                    adjTarget = true;\n                    break;\n                }\n            }\n            if (!adjTarget) return false;\n        }\n\n        int du[16], dv[16], dd[16], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        int r = p / N, c = p % N;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            int nbcol = 0;\n            if (0 <= nr && nr < N && 0 <= nc && nc < N) {\n                nbcol = g[nr * N + nc];\n            }\n\n            addDelta(from, nbcol, -1);\n            addDelta(to, nbcol, +1);\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        if (from == 0) {\n            if (!zeroConnectedAfterRemove(p)) return false;\n        } else {\n            if (!connectedAfterRemoveColor(p, from)) return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        cnt[from]--;\n        cnt[to]++;\n\n        if (from == 0) zeros--;\n        if (to == 0) zeros++;\n\n        g[p] = (unsigned char)to;\n        return true;\n    }\n\n    bool tryChange2(int p, int np, int q, int nq) {\n        if (p == q) return false;\n\n        int op = g[p], oq = g[q];\n        if (op == np && oq == nq) return false;\n        if (np < 0 || np > M || nq < 0 || nq > M) return false;\n\n        int cc[8], cd[8], cn = 0;\n\n        auto addCntDelta = [&](int c, int d) {\n            if (d == 0) return;\n            for (int i = 0; i < cn; ++i) {\n                if (cc[i] == c) {\n                    cd[i] += d;\n                    return;\n                }\n            }\n            cc[cn] = c;\n            cd[cn] = d;\n            ++cn;\n        };\n\n        addCntDelta(op, -1);\n        addCntDelta(oq, -1);\n        addCntDelta(np, +1);\n        addCntDelta(nq, +1);\n\n        for (int i = 0; i < cn; ++i) {\n            if (cc[i] > 0 && cnt[cc[i]] + cd[i] <= 0) return false;\n        }\n\n        int du[40], dv[40], dd[40], dn = 0;\n\n        auto addDelta = [&](int a, int b, int x) {\n            if (a == b || x == 0) return;\n            if (a > b) swap(a, b);\n            for (int i = 0; i < dn; ++i) {\n                if (du[i] == a && dv[i] == b) {\n                    dd[i] += x;\n                    return;\n                }\n            }\n            du[dn] = a;\n            dv[dn] = b;\n            dd[dn] = x;\n            ++dn;\n        };\n\n        auto oldCol = [&](int x) -> int {\n            if (x == p) return op;\n            if (x == q) return oq;\n            return g[x];\n        };\n\n        auto newCol = [&](int x) -> int {\n            if (x == p) return np;\n            if (x == q) return nq;\n            return g[x];\n        };\n\n        int cells[2] = {p, q};\n\n        for (int ii = 0; ii < 2; ++ii) {\n            int x = cells[ii];\n            int xr = x / N, xc = x % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = xr + DR[d], nc = xc + DC[d];\n\n                int a0 = oldCol(x);\n                int a1 = newCol(x);\n                int b0, b1;\n\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) {\n                    b0 = b1 = 0;\n                } else {\n                    int y = nr * N + nc;\n                    if ((y == p || y == q) && x > y) continue;\n                    b0 = oldCol(y);\n                    b1 = newCol(y);\n                }\n\n                addDelta(a0, b0, -1);\n                addDelta(a1, b1, +1);\n            }\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            int after = edge[u][v] + dd[i];\n            if (after < 0) return false;\n\n            if (REQ[u][v]) {\n                if (after <= 0) return false;\n            } else {\n                if (after != 0) return false;\n            }\n        }\n\n        g[p] = (unsigned char)np;\n        g[q] = (unsigned char)nq;\n\n        for (int i = 0; i < cn; ++i) cnt[cc[i]] += cd[i];\n        zeros = cnt[0];\n\n        int aff[4], an = 0;\n        auto addAff = [&](int c) {\n            for (int i = 0; i < an; ++i) {\n                if (aff[i] == c) return;\n            }\n            aff[an++] = c;\n        };\n\n        addAff(op);\n        addAff(oq);\n        addAff(np);\n        addAff(nq);\n\n        bool ok = true;\n        for (int i = 0; i < an && ok; ++i) {\n            int c = aff[i];\n            if (c == 0) ok = zeroConnectedFull();\n            else ok = connectedColorFull(c);\n        }\n\n        if (!ok) {\n            for (int i = 0; i < cn; ++i) cnt[cc[i]] -= cd[i];\n            zeros = cnt[0];\n            g[p] = (unsigned char)op;\n            g[q] = (unsigned char)oq;\n            return false;\n        }\n\n        for (int i = 0; i < dn; ++i) {\n            if (dd[i] == 0) continue;\n            int u = du[i], v = dv[i];\n            edge[u][v] += dd[i];\n            edge[v][u] += dd[i];\n        }\n\n        return true;\n    }\n};\n\nbool validFast(const State& st) {\n    for (int c = 1; c <= M; ++c) {\n        if (st.cnt[c] <= 0) return false;\n    }\n\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if ((st.edge[i][j] > 0) != REQ[i][j]) return false;\n        }\n    }\n\n    if (st.cnt[0] > 0) {\n        int stamp = newStamp();\n        int head = 0, tail = 0;\n        int seen = 0;\n\n        for (int r = 0; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n                int p = r * N + c;\n                if (st.g[p] == 0 && visArr[p] != stamp) {\n                    visArr[p] = stamp;\n                    bfsQ[tail++] = p;\n                }\n            }\n        }\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            ++seen;\n            int r = v / N, c = v % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n\n        if (seen != st.cnt[0]) return false;\n    }\n\n    static int comp[MAXC];\n    memset(comp, 0, sizeof(comp));\n\n    int stamp = newStamp();\n\n    for (int p = 0; p < V; ++p) {\n        int col = st.g[p];\n        if (col == 0) continue;\n        if (visArr[p] == stamp) continue;\n\n        ++comp[col];\n        if (comp[col] >= 2) return false;\n\n        int head = 0, tail = 0;\n        visArr[p] = stamp;\n        bfsQ[tail++] = p;\n\n        while (head < tail) {\n            int v = bfsQ[head++];\n            int r = v / N, c = v % N;\n\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != col) continue;\n                if (visArr[q] == stamp) continue;\n                visArr[q] = stamp;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n\n    for (int c = 1; c <= M; ++c) {\n        if (comp[c] != 1) return false;\n    }\n\n    return true;\n}\n\nvoid computeGraphInfo() {\n    for (int i = 0; i <= M; ++i) {\n        DEGREQ[i] = 0;\n        for (int j = 0; j <= M; ++j) {\n            if (i != j && REQ[i][j]) DEGREQ[i]++;\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        NEED[i] = max(1, (DEGREQ[i] - 1) / 2);\n    }\n    NEED[0] = 0;\n\n    fill(GDEP, GDEP + MAXC, 1000000);\n    queue<int> q;\n    GDEP[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u = 0; u <= M; ++u) {\n            if (!REQ[v][u]) continue;\n            if (GDEP[u] > GDEP[v] + 1) {\n                GDEP[u] = GDEP[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    for (int i = 1; i <= M; ++i) {\n        if (GDEP[i] > 100000) GDEP[i] = 50;\n    }\n}\n\nvoid computeDist(const State& st, vector<int>& dist) {\n    const int INF = 1e9;\n    dist.assign(V, INF);\n\n    int head = 0, tail = 0;\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] == 0) {\n            dist[p] = 0;\n            bfsQ[tail++] = p;\n        }\n    }\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (!(r == 0 || r == N - 1 || c == 0 || c == N - 1)) continue;\n            int p = r * N + c;\n            if (dist[p] > 1) {\n                dist[p] = 1;\n                bfsQ[tail++] = p;\n            }\n        }\n    }\n\n    while (head < tail) {\n        int v = bfsQ[head++];\n        int r = v / N, c = v % N;\n        int nd = dist[v] + 1;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int q = nr * N + nc;\n            if (dist[q] > nd) {\n                dist[q] = nd;\n                bfsQ[tail++] = q;\n            }\n        }\n    }\n}\n\nint greedyDelete(State& st, RNG& rng, int mode = 0) {\n    vector<int> cand;\n    cand.reserve(V * 5);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0 && st.hasZeroAdj(p)) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    if (mode == 1) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            int sa = st.cnt[ca] - NEED[ca];\n            int sb = st.cnt[cb] - NEED[cb];\n            if (sa != sb) return sa > sb;\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 2) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (st.cnt[ca] != st.cnt[cb]) return st.cnt[ca] > st.cnt[cb];\n            return DEGREQ[ca] < DEGREQ[cb];\n        });\n    } else if (mode == 3) {\n        stable_sort(cand.begin(), cand.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return st.cnt[ca] > st.cnt[cb];\n        });\n    }\n\n    int deleted = 0;\n\n    for (size_t idx = 0; idx < cand.size(); ++idx) {\n        int p = cand[idx];\n        if (st.g[p] == 0) continue;\n        if (!st.hasZeroAdj(p)) continue;\n\n        if (st.tryChange(p, 0)) {\n            ++deleted;\n\n            int r = p / N, c = p % N;\n            for (int d = 0; d < 4; ++d) {\n                int nr = r + DR[d], nc = c + DC[d];\n                if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n                int q = nr * N + nc;\n                if (st.g[q] != 0) cand.push_back(q);\n            }\n        }\n    }\n\n    return deleted;\n}\n\nint greedyDeleteMulti(State& st, RNG& rng, int repeats, int modeBase) {\n    int old = st.zeros;\n    if (repeats <= 1) {\n        greedyDelete(st, rng, modeBase & 3);\n        return st.zeros - old;\n    }\n\n    State base = st;\n    State best = st;\n\n    for (int r = 0; r < repeats; ++r) {\n        State tmp = base;\n        greedyDelete(tmp, rng, (modeBase + r) & 3);\n        if (tmp.zeros > best.zeros) best = tmp;\n    }\n\n    st = best;\n    return st.zeros - old;\n}\n\nstruct Params {\n    int strategy;\n    int orderMode;\n    int eqProb;\n    bool useLayer;\n    bool targetRandom;\n    bool preDelete;\n    int delRepeats;\n    int delMode;\n};\n\nParams getParams(int run) {\n    switch (run % 20) {\n        case 0:  return {0, 0,  0, false, false, true,  1, 0};\n        case 1:  return {0, 0, 10, true,  false, true,  1, 1};\n        case 2:  return {1, 0, 15, false, false, true,  1, 0};\n        case 3:  return {1, 3, 20, true,  false, true,  1, 1};\n        case 4:  return {3, 0, 15, false, false, true,  1, 2};\n        case 5:  return {4, 0, 10, false, false, true,  1, 1};\n        case 6:  return {2, 1,  0, false, true,  true,  1, 0};\n        case 7:  return {0, 1, 30, false, true,  true,  1, 2};\n        case 8:  return {1, 4, 25, false, false, false, 1, 3};\n        case 9:  return {3, 3, 20, true,  false, false, 1, 1};\n        case 10: return {0, 2,  0, false, true,  true,  1, 0};\n        case 11:return {4, 1, 20, false, true,  true,  1, 2};\n        case 12:return {1, 0,  0, true,  false, true,  2, 0};\n        case 13:return {3, 0, 30, false, false, true,  2, 1};\n        case 14:return {2, 1,  0, false, true,  false, 1, 0};\n        case 15:return {0, 0, 50, false, true,  false, 1, 1};\n        case 16:return {1, 3, 40, false, true,  false, 1, 2};\n        case 17:return {4, 3, 30, true,  false, true,  1, 3};\n        case 18:return {3, 1, 10, false, true,  true,  2, 0};\n        default:return {0, 0, 20, true,  false, true,  1, 0};\n    }\n}\n\nint recolorPass(State& st, const vector<int>& dist, RNG& rng, const Params& par) {\n    const int INF = 1e9;\n\n    int layer[MAXC];\n    for (int i = 0; i < MAXC; ++i) layer[i] = INF;\n    layer[0] = 0;\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a > 0) layer[a] = min(layer[a], dist[p]);\n    }\n\n    vector<int> order;\n    order.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) order.push_back(p);\n    }\n\n    rng.shuffleVec(order);\n\n    if (par.orderMode == 0) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 2) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            return dist[a] > dist[b];\n        });\n    } else if (par.orderMode == 3) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] > GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    } else if (par.orderMode == 4) {\n        stable_sort(order.begin(), order.end(), [&](int a, int b) {\n            int ca = st.g[a], cb = st.g[b];\n            if (GDEP[ca] != GDEP[cb]) return GDEP[ca] < GDEP[cb];\n            return dist[a] < dist[b];\n        });\n    }\n\n    struct Target {\n        int col;\n        int score;\n        int td;\n        int gd;\n        int rnd;\n    };\n\n    int changed = 0;\n\n    for (int p : order) {\n        int a = st.g[p];\n        if (a == 0) continue;\n        if (st.cnt[a] <= 1) continue;\n\n        int dp = dist[p];\n        int r = p / N, c = p % N;\n\n        Target ts[4];\n        int tn = 0;\n\n        auto addTarget = [&](int b, int dq, int score) {\n            int pos = -1;\n            for (int i = 0; i < tn; ++i) {\n                if (ts[i].col == b) {\n                    pos = i;\n                    break;\n                }\n            }\n\n            if (pos == -1) {\n                ts[tn++] = {b, score, dq, GDEP[b], (int)(rng.next() & 0x7fffffff)};\n            } else {\n                if (score > ts[pos].score) {\n                    ts[pos].score = score;\n                    ts[pos].td = min(ts[pos].td, dq);\n                }\n            }\n        };\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int q = nr * N + nc;\n            int b = st.g[q];\n            if (b == 0 || b == a) continue;\n\n            int dq = dist[q];\n            bool ok = false;\n            int score = 0;\n\n            if (par.strategy == 0) {\n                ok = (dq < dp) || (dq == dp && par.eqProb > 0 && rng.nextInt(100) < par.eqProb);\n                if (par.useLayer && layer[b] > layer[a]) ok = false;\n                score = (dp - dq) * 20 + (layer[a] - layer[b]) * 3 + (GDEP[a] - GDEP[b]);\n            } else if (par.strategy == 1) {\n                int da = GDEP[a], db = GDEP[b];\n                ok = (db < da) ||\n                     (db == da && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (dq < dp && db <= da + 1);\n\n                if (par.useLayer && layer[b] > layer[a] + 1) ok = false;\n                score = (da - db) * 30 + (dp - dq) * 5 + (layer[a] - layer[b]);\n            } else if (par.strategy == 2) {\n                ok = true;\n                score = (int)(rng.next() & 0xffff);\n            } else if (par.strategy == 3) {\n                int val =\n                    (GDEP[a] - GDEP[b]) * 18 +\n                    (dp - dq) * 7 +\n                    (layer[a] - layer[b]) * 4 +\n                    ((st.cnt[a] - NEED[a]) - (st.cnt[b] - NEED[b]));\n\n                ok = (val > 0) ||\n                     (val == 0 && par.eqProb > 0 && rng.nextInt(100) < par.eqProb) ||\n                     (rng.nextInt(100) < 4);\n\n                score = val;\n            } else {\n                int surplusA = st.cnt[a] - NEED[a];\n                int surplusB = st.cnt[b] - NEED[b];\n                int val =\n                    (surplusA - surplusB) * 5 +\n                    (GDEP[a] - GDEP[b]) * 8 +\n                    (dp - dq) * 3;\n\n                ok = (val > 0) ||\n                     (par.eqProb > 0 && rng.nextInt(100) < par.eqProb / 2);\n\n                score = val;\n            }\n\n            if (!ok) continue;\n            addTarget(b, dq, score);\n        }\n\n        if (tn == 0) continue;\n\n        if (par.targetRandom || par.strategy == 2) {\n            for (int i = tn - 1; i > 0; --i) {\n                swap(ts[i], ts[rng.nextInt(i + 1)]);\n            }\n        } else {\n            for (int i = 0; i < tn; ++i) {\n                for (int j = i + 1; j < tn; ++j) {\n                    bool better = false;\n                    if (ts[j].score != ts[i].score) {\n                        better = ts[j].score > ts[i].score;\n                    } else if (ts[j].td != ts[i].td) {\n                        better = ts[j].td < ts[i].td;\n                    } else if (ts[j].gd != ts[i].gd) {\n                        better = ts[j].gd < ts[i].gd;\n                    } else {\n                        better = ts[j].rnd < ts[i].rnd;\n                    }\n                    if (better) swap(ts[i], ts[j]);\n                }\n            }\n        }\n\n        for (int i = 0; i < tn; ++i) {\n            if (st.tryChange(p, ts[i].col)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid improve(State& st, State& best, RNG& rng, const Params& par, const Timer& timer, double limit) {\n    vector<int> dist;\n    int lastZeros = st.zeros;\n    int stagnant = 0;\n\n    for (int cycle = 0; cycle < 80; ++cycle) {\n        if (timer.elapsed() > limit) break;\n\n        int del = 0;\n\n        if (par.preDelete) {\n            del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode);\n            if (st.zeros > best.zeros) best = st;\n        }\n\n        computeDist(st, dist);\n        int rec = recolorPass(st, dist, rng, par);\n\n        del += greedyDeleteMulti(st, rng, par.delRepeats, par.delMode + cycle);\n        if (st.zeros > best.zeros) best = st;\n\n        if (st.zeros > lastZeros) {\n            lastZeros = st.zeros;\n            stagnant = 0;\n        } else {\n            ++stagnant;\n        }\n\n        if (rec + del == 0) break;\n\n        int maxStag = 4;\n        if (par.strategy == 2) maxStag = 3;\n        if (par.eqProb >= 30) maxStag++;\n        if (par.delRepeats >= 2) maxStag++;\n\n        if (stagnant >= maxStag) break;\n    }\n}\n\nint randomInterfaceRecolorPass(State& st, RNG& rng, int limitChanges) {\n    vector<int> cells;\n    cells.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b > 0 && b != a) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cells.push_back(p);\n    }\n\n    rng.shuffleVec(cells);\n\n    int changed = 0;\n\n    for (int p : cells) {\n        if (changed >= limitChanges) break;\n        int a = st.g[p];\n        if (a == 0 || st.cnt[a] <= 1) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b == 0 || b == a) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint randomExpandPass(State& st, RNG& rng, int quota) {\n    vector<int> cand;\n    cand.reserve(V);\n\n    for (int p = 0; p < V; ++p) {\n        if (st.g[p] != 0) continue;\n\n        int r = p / N, c = p % N;\n        bool ok = false;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            if (st.g[nr * N + nc] > 0) {\n                ok = true;\n                break;\n            }\n        }\n\n        if (ok) cand.push_back(p);\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n\n    for (int p : cand) {\n        if (changed >= quota) break;\n        if (st.g[p] != 0) continue;\n\n        int cols[4], k = 0;\n        int r = p / N, c = p % N;\n\n        for (int d = 0; d < 4; ++d) {\n            int nr = r + DR[d], nc = c + DC[d];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n            int b = st.g[nr * N + nc];\n            if (b <= 0) continue;\n\n            bool seen = false;\n            for (int i = 0; i < k; ++i) {\n                if (cols[i] == b) seen = true;\n            }\n            if (!seen) cols[k++] = b;\n        }\n\n        for (int i = k - 1; i > 0; --i) {\n            swap(cols[i], cols[rng.nextInt(i + 1)]);\n        }\n\n        for (int i = 0; i < k; ++i) {\n            if (st.tryChange(p, cols[i])) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nint swapPass(State& st, RNG& rng, int maxTries, int mode) {\n    vector<pair<int, int>> cand;\n    cand.reserve(2 * V);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n\n            if (r + 1 < N) {\n                int q = (r + 1) * N + c;\n                int a = st.g[p], b = st.g[q];\n                if (a != b) {\n                    bool z = (a == 0 || b == 0);\n                    if (mode == 2 || (mode == 0 && z) || (mode == 1 && !z)) {\n                        cand.push_back({p, q});\n                    }\n                }\n            }\n\n            if (c + 1 < N) {\n                int q = r * N + (c + 1);\n                int a = st.g[p], b = st.g[q];\n                if (a != b) {\n                    bool z = (a == 0 || b == 0);\n                    if (mode == 2 || (mode == 0 && z) || (mode == 1 && !z)) {\n                        cand.push_back({p, q});\n                    }\n                }\n            }\n        }\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n    int tried = 0;\n\n    for (auto [p, q] : cand) {\n        if (tried >= maxTries) break;\n\n        int a = st.g[p], b = st.g[q];\n        if (a == b) continue;\n\n        bool z = (a == 0 || b == 0);\n        if (!(mode == 2 || (mode == 0 && z) || (mode == 1 && !z))) continue;\n\n        ++tried;\n        if (st.tryChange2(p, b, q, a)) {\n            ++changed;\n        }\n    }\n\n    return changed;\n}\n\nint pairDeletePass(State& st, RNG& rng, int maxTries, int mode) {\n    vector<pair<int, int>> cand;\n    cand.reserve(2 * V);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int p = r * N + c;\n            int a = st.g[p];\n\n            if (r + 1 < N) {\n                int q = (r + 1) * N + c;\n                int b = st.g[q];\n                if (a > 0 && b > 0 && a != b && (st.hasZeroAdj(p) || st.hasZeroAdj(q))) {\n                    cand.push_back({p, q});\n                }\n            }\n\n            if (c + 1 < N) {\n                int q = r * N + (c + 1);\n                int b = st.g[q];\n                if (a > 0 && b > 0 && a != b && (st.hasZeroAdj(p) || st.hasZeroAdj(q))) {\n                    cand.push_back({p, q});\n                }\n            }\n        }\n    }\n\n    rng.shuffleVec(cand);\n\n    int changed = 0;\n    int tried = 0;\n\n    struct Var {\n        int np, nq;\n        int score;\n    };\n\n    for (auto [p, q] : cand) {\n        if (tried >= maxTries) break;\n\n        int a = st.g[p], b = st.g[q];\n        if (a <= 0 || b <= 0 || a == b) continue;\n\n        bool hp = st.hasZeroAdj(p);\n        bool hq = st.hasZeroAdj(q);\n        if (!hp && !hq) continue;\n\n        ++tried;\n\n        Var vars[2];\n        int vn = 0;\n\n        if (hp) {\n            int lost = b;\n            int invader = a;\n            int score =\n                (st.cnt[lost] - NEED[lost]) * 12 +\n                (GDEP[lost] - GDEP[invader]) * 5 -\n                DEGREQ[lost];\n            vars[vn++] = {0, a, score};\n        }\n\n        if (hq) {\n            int lost = a;\n            int invader = b;\n            int score =\n                (st.cnt[lost] - NEED[lost]) * 12 +\n                (GDEP[lost] - GDEP[invader]) * 5 -\n                DEGREQ[lost];\n            vars[vn++] = {b, 0, score};\n        }\n\n        if (vn == 2) {\n            bool firstSecond = false;\n            if (mode == 0) {\n                firstSecond = rng.nextInt(2);\n            } else if (mode == 3) {\n                firstSecond = vars[1].score < vars[0].score;\n            } else {\n                firstSecond = vars[1].score > vars[0].score;\n            }\n            if (firstSecond) swap(vars[0], vars[1]);\n        }\n\n        for (int i = 0; i < vn; ++i) {\n            if (st.tryChange2(p, vars[i].np, q, vars[i].nq)) {\n                ++changed;\n                break;\n            }\n        }\n    }\n\n    return changed;\n}\n\nvoid shakeSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    while (timer.elapsed() < limit) {\n        State st = best;\n\n        int rounds = 3 + rng.nextInt(4);\n\n        for (int rd = 0; rd < rounds; ++rd) {\n            if (timer.elapsed() >= limit) break;\n\n            if (st.zeros > best.zeros - 25) {\n                randomExpandPass(st, rng, 2 + rng.nextInt(7));\n            }\n\n            randomInterfaceRecolorPass(st, rng, 80 + rng.nextInt(160));\n            pairDeletePass(st, rng, 120 + rng.nextInt(220), rng.nextInt(4));\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n\n            if (st.zeros > best.zeros) {\n                best = st;\n            }\n\n            if (st.zeros + 30 < best.zeros) break;\n        }\n    }\n}\n\nvoid neutralSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    State cur = best;\n    int stagnant = 0;\n\n    while (timer.elapsed() < limit) {\n        if (stagnant > 9) {\n            cur = best;\n            stagnant = 0;\n        }\n\n        int before = cur.zeros;\n        int total = 0;\n\n        total += pairDeletePass(cur, rng, 300 + rng.nextInt(450), rng.nextInt(4));\n\n        if (total == 0) {\n            total += swapPass(cur, rng, 180 + rng.nextInt(320), rng.nextInt(3));\n            total += randomInterfaceRecolorPass(cur, rng, 50 + rng.nextInt(130));\n            total += pairDeletePass(cur, rng, 180 + rng.nextInt(260), rng.nextInt(4));\n        }\n\n        total += greedyDeleteMulti(cur, rng, 1, rng.nextInt(4));\n\n        if (cur.zeros > best.zeros) {\n            best = cur;\n            stagnant = 0;\n        } else {\n            if (cur.zeros < best.zeros) cur = best;\n            if (cur.zeros == before && total == 0) stagnant += 2;\n            else stagnant++;\n        }\n    }\n}\n\nstruct BandOp {\n    int type;\n    int idx;\n    int len;\n};\n\nvoid applyBandDelete(State& out, const State& st, int type, int idx, int len) {\n    out = st;\n\n    if (type == 0) {\n        for (int r = idx; r + len < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = st.g[(r + len) * N + c];\n            }\n        }\n        for (int r = N - len; r < N; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else if (type == 1) {\n        for (int r = idx + len - 1; r >= len; --r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = st.g[(r - len) * N + c];\n            }\n        }\n        for (int r = 0; r < len; ++r) {\n            for (int c = 0; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else if (type == 2) {\n        for (int r = 0; r < N; ++r) {\n            for (int c = idx; c + len < N; ++c) {\n                out.g[r * N + c] = st.g[r * N + (c + len)];\n            }\n            for (int c = N - len; c < N; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    } else {\n        for (int r = 0; r < N; ++r) {\n            for (int c = idx + len - 1; c >= len; --c) {\n                out.g[r * N + c] = st.g[r * N + (c - len)];\n            }\n            for (int c = 0; c < len; ++c) {\n                out.g[r * N + c] = 0;\n            }\n        }\n    }\n\n    out.rebuild();\n}\n\nbool compactBandsOnce(State& st, RNG& rng, const Timer& timer, double limit, int mode, int maxLen) {\n    vector<BandOp> ops;\n    ops.reserve(4 * N * maxLen);\n\n    for (int len = 1; len <= maxLen; ++len) {\n        for (int idx = 0; idx + len <= N; ++idx) {\n            for (int type = 0; type < 4; ++type) {\n                ops.push_back({type, idx, len});\n            }\n        }\n    }\n\n    rng.shuffleVec(ops);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyBandDelete(tmp, st, op.type, op.idx, op.len);\n\n        if (tmp.zeros <= st.zeros) continue;\n        if (!validFast(tmp)) continue;\n\n        if (mode == 1) {\n            st = tmp;\n            return true;\n        }\n\n        if (!found || tmp.zeros > best.zeros) {\n            best = tmp;\n            found = true;\n        }\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nvoid compactBandSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    int fail = 0;\n\n    while (timer.elapsed() < limit && fail < 4) {\n        State st = best;\n\n        int steps = 0;\n        int mode = (fail == 0 ? 0 : 1);\n        int maxLen = (fail >= 2 ? 3 : 2);\n\n        while (timer.elapsed() < limit && steps < 5) {\n            bool ok = compactBandsOnce(st, rng, timer, limit, mode, maxLen);\n            if (!ok) break;\n\n            ++steps;\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n        }\n\n        if (st.zeros > best.zeros) {\n            best = st;\n            fail = 0;\n        } else {\n            ++fail;\n        }\n    }\n}\n\nvoid applyDeleteLines(State& out, const State& st, int type, uint64_t mask) {\n    out = st;\n\n    if (type == 0) {\n        int nr = 0;\n        for (int r = 0; r < N; ++r) {\n            if ((mask >> r) & 1ULL) continue;\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = st.g[r * N + c];\n            ++nr;\n        }\n        for (; nr < N; ++nr) {\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = 0;\n        }\n    } else if (type == 1) {\n        int nr = N - 1;\n        for (int r = N - 1; r >= 0; --r) {\n            if ((mask >> r) & 1ULL) continue;\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = st.g[r * N + c];\n            --nr;\n        }\n        for (; nr >= 0; --nr) {\n            for (int c = 0; c < N; ++c) out.g[nr * N + c] = 0;\n        }\n    } else if (type == 2) {\n        for (int r = 0; r < N; ++r) {\n            int nc = 0;\n            for (int c = 0; c < N; ++c) {\n                if ((mask >> c) & 1ULL) continue;\n                out.g[r * N + nc] = st.g[r * N + c];\n                ++nc;\n            }\n            for (; nc < N; ++nc) out.g[r * N + nc] = 0;\n        }\n    } else {\n        for (int r = 0; r < N; ++r) {\n            int nc = N - 1;\n            for (int c = N - 1; c >= 0; --c) {\n                if ((mask >> c) & 1ULL) continue;\n                out.g[r * N + nc] = st.g[r * N + c];\n                --nc;\n            }\n            for (; nc >= 0; --nc) out.g[r * N + nc] = 0;\n        }\n    }\n\n    out.rebuild();\n}\n\nstruct LineOp {\n    int type;\n    uint64_t mask;\n    int gain;\n    int score;\n};\n\nbool simpleLineOnce(State& st, RNG& rng, const Timer& timer, double limit) {\n    if (timer.elapsed() > limit - 0.002) return false;\n\n    int rowCnt[MAXN] = {};\n    int colCnt[MAXN] = {};\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (st.g[r * N + c] != 0) {\n                rowCnt[r]++;\n                colCnt[c]++;\n            }\n        }\n    }\n\n    vector<LineOp> ops;\n    ops.reserve(6000);\n\n    auto addOp = [&](int type, uint64_t mask, int gain, int k) {\n        if (gain <= 0) return;\n        int score = gain * 10000 + rng.nextInt(1000) - k * 50;\n        ops.push_back({type, mask, gain, score});\n    };\n\n    for (int i = 0; i < N; ++i) {\n        uint64_t m = 1ULL << i;\n        addOp(0, m, rowCnt[i], 1);\n        addOp(1, m, rowCnt[i], 1);\n        addOp(2, m, colCnt[i], 1);\n        addOp(3, m, colCnt[i], 1);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = i + 1; j < N; ++j) {\n            uint64_t m = (1ULL << i) | (1ULL << j);\n            addOp(0, m, rowCnt[i] + rowCnt[j], 2);\n            addOp(1, m, rowCnt[i] + rowCnt[j], 2);\n            addOp(2, m, colCnt[i] + colCnt[j], 2);\n            addOp(3, m, colCnt[i] + colCnt[j], 2);\n        }\n    }\n\n    if (ops.empty()) return false;\n\n    auto cmp = [](const LineOp& a, const LineOp& b) {\n        return a.score > b.score;\n    };\n\n    const int MAXCAND = 1400;\n    if ((int)ops.size() > MAXCAND) {\n        nth_element(ops.begin(), ops.begin() + MAXCAND, ops.end(), cmp);\n        ops.resize(MAXCAND);\n    }\n    sort(ops.begin(), ops.end(), cmp);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyDeleteLines(tmp, st, op.type, op.mask);\n\n        if (tmp.zeros <= best.zeros) continue;\n        if (!validFast(tmp)) continue;\n\n        best = tmp;\n        found = true;\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nstruct CrossOp {\n    int rt, r, ct, c;\n    int gain;\n    int score;\n};\n\nvoid applyDeleteCross(State& out, const State& st, int rt, int r, int ct, int c) {\n    State tmp;\n    applyDeleteLines(tmp, st, rt, 1ULL << r);\n    applyDeleteLines(out, tmp, ct, 1ULL << c);\n}\n\nbool simpleCrossOnce(State& st, RNG& rng, const Timer& timer, double limit) {\n    if (timer.elapsed() > limit - 0.002) return false;\n\n    int rowCnt[MAXN] = {};\n    int colCnt[MAXN] = {};\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            if (st.g[r * N + c] != 0) {\n                rowCnt[r]++;\n                colCnt[c]++;\n            }\n        }\n    }\n\n    vector<CrossOp> ops;\n    ops.reserve(10000);\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int gain = rowCnt[r] + colCnt[c] - (st.g[r * N + c] != 0);\n            if (gain <= 0) continue;\n\n            for (int rt = 0; rt < 2; ++rt) {\n                for (int ct = 2; ct < 4; ++ct) {\n                    int score = gain * 10000 + rng.nextInt(1000);\n                    ops.push_back({rt, r, ct, c, gain, score});\n                }\n            }\n        }\n    }\n\n    if (ops.empty()) return false;\n\n    auto cmp = [](const CrossOp& a, const CrossOp& b) {\n        return a.score > b.score;\n    };\n\n    const int MAXCAND = 1200;\n    if ((int)ops.size() > MAXCAND) {\n        nth_element(ops.begin(), ops.begin() + MAXCAND, ops.end(), cmp);\n        ops.resize(MAXCAND);\n    }\n    sort(ops.begin(), ops.end(), cmp);\n\n    bool found = false;\n    State best = st;\n\n    for (const auto& op : ops) {\n        if (timer.elapsed() >= limit) break;\n\n        State tmp;\n        applyDeleteCross(tmp, st, op.rt, op.r, op.ct, op.c);\n\n        if (tmp.zeros <= best.zeros) continue;\n        if (!validFast(tmp)) continue;\n\n        best = tmp;\n        found = true;\n    }\n\n    if (found) {\n        st = best;\n        return true;\n    }\n\n    return false;\n}\n\nvoid simpleLineSearch(State& best, RNG& rng, const Timer& timer, double limit) {\n    int fail = 0;\n\n    while (timer.elapsed() < limit && fail < 4) {\n        State st = best;\n\n        bool ok;\n        if (fail % 2 == 0) ok = simpleLineOnce(st, rng, timer, limit);\n        else ok = simpleCrossOnce(st, rng, timer, limit);\n\n        if (ok) {\n            greedyDeleteMulti(st, rng, 1 + rng.nextInt(2), rng.nextInt(4));\n\n            if (st.zeros > best.zeros) {\n                best = st;\n                fail = 0;\n            } else {\n                ++fail;\n            }\n        } else {\n            ++fail;\n        }\n    }\n}\n\nbool validateState(const State& st) {\n    State tmp = st;\n    tmp.rebuild();\n    return validFast(tmp);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M;\n    V = N * N;\n\n    State init;\n    init.clear();\n\n    uint64_t seed = 0x123456789abcdef0ULL;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int x;\n            cin >> x;\n            init.g[i * N + j] = (unsigned char)x;\n\n            seed ^= (uint64_t)x + 0x9e3779b97f4a7c15ULL + (seed << 6) + (seed >> 2);\n        }\n    }\n\n    init.rebuild();\n\n    memset(REQ, 0, sizeof(REQ));\n    for (int i = 0; i <= M; ++i) {\n        for (int j = i + 1; j <= M; ++j) {\n            if (init.edge[i][j] > 0) {\n                REQ[i][j] = REQ[j][i] = true;\n            }\n        }\n    }\n\n    computeGraphInfo();\n\n    Timer timer;\n\n    const double MAIN_LIMIT = 1.55;\n    const double SHAKE_LIMIT = 1.73;\n    const double NEUTRAL_LIMIT = 1.83;\n    const double COMPACT_LIMIT = 1.89;\n    const double LINE_LIMIT = 1.897;\n    const double POLISH_LIMIT = 1.93;\n\n    State best = init;\n\n    int run = 0;\n    while (timer.elapsed() < MAIN_LIMIT) {\n        State st;\n\n        if (run >= 4 && run % 3 == 2) {\n            st = best;\n        } else {\n            st = init;\n        }\n\n        uint64_t rseed =\n            seed\n            + 0x9e3779b97f4a7c15ULL * (uint64_t)(run + 1)\n            + 0xbf58476d1ce4e5b9ULL * (uint64_t)(best.zeros + 1);\n\n        RNG rng(rseed);\n        Params par = getParams(run);\n\n        improve(st, best, rng, par, timer, MAIN_LIMIT);\n        ++run;\n    }\n\n    RNG shakeRng(seed ^ 0xd1b54a32d192ed03ULL ^ (uint64_t)best.zeros);\n    shakeSearch(best, shakeRng, timer, SHAKE_LIMIT);\n\n    RNG neutralRng(seed ^ 0x6a09e667f3bcc909ULL ^ ((uint64_t)best.zeros << 17));\n    neutralSearch(best, neutralRng, timer, NEUTRAL_LIMIT);\n\n    RNG compactRng(seed ^ 0xbb67ae8584caa73bULL ^ ((uint64_t)best.zeros << 9));\n    compactBandSearch(best, compactRng, timer, COMPACT_LIMIT);\n\n    RNG lineRng(seed ^ 0x3c6ef372fe94f82bULL ^ ((uint64_t)best.zeros << 23));\n    simpleLineSearch(best, lineRng, timer, LINE_LIMIT);\n\n    RNG finalRng(seed ^ 0x94d049bb133111ebULL);\n    while (timer.elapsed() < POLISH_LIMIT) {\n        int before = best.zeros;\n\n        greedyDeleteMulti(best, finalRng, 2, finalRng.nextInt(4));\n\n        for (int mode = 0; mode < 4; ++mode) {\n            if (timer.elapsed() >= POLISH_LIMIT) break;\n            greedyDelete(best, finalRng, mode);\n            pairDeletePass(best, finalRng, 250, mode);\n            greedyDelete(best, finalRng, mode);\n        }\n\n        if (best.zeros == before) {\n            State tmp = best;\n            swapPass(tmp, finalRng, 300, finalRng.nextInt(3));\n            randomInterfaceRecolorPass(tmp, finalRng, 90);\n            pairDeletePass(tmp, finalRng, 350, finalRng.nextInt(4));\n            greedyDelete(tmp, finalRng, finalRng.nextInt(4));\n\n            if (tmp.zeros > best.zeros) {\n                best = tmp;\n            } else {\n                break;\n            }\n        }\n    }\n\n    if (!validateState(best)) {\n        best = init;\n    }\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            if (j) cout << ' ';\n            cout << (int)best.g[i * N + j];\n        }\n        cout << '\\n';\n    }\n\n    return 0;\n}","ahc025":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N, D, Q;\nint qUsed = 0;\nmt19937_64 rng;\nvector<vector<char>> itemCmp;\n\nconstexpr int DP_SCALE_BASE = 500;\nconstexpr int DP_SUM_LIMIT = 80000;\n\nstruct Solution {\n    vector<int> assign;\n    vector<vector<int>> bins;\n    vector<double> load;\n    double obj = 1e100;\n};\n\nchar invCmp(char c) {\n    if (c == '>') return '<';\n    if (c == '<') return '>';\n    return c;\n}\n\nchar ask(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    if (!(cin >> s)) exit(0);\n    qUsed++;\n    return s[0];\n}\n\nchar compareItems(int a, int b) {\n    if (a == b) return '=';\n    if (itemCmp[a][b] != '?') return itemCmp[a][b];\n    if (qUsed >= Q) return '?';\n\n    vector<int> L{a}, R{b};\n    char c = ask(L, R);\n    itemCmp[a][b] = c;\n    itemCmp[b][a] = invCmp(c);\n    return c;\n}\n\ndouble norm_pdf(double x) {\n    static const double INV_SQRT_2PI = 1.0 / sqrt(2.0 * acos(-1.0));\n    if (abs(x) > 40) return 0.0;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble norm_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble truncatedNormalMean(double mu, double sd, double lo, double hi) {\n    if (sd < 1e-12) return clamp(mu, lo, hi);\n\n    double a = (lo - mu) / sd;\n    double b = (hi - mu) / sd;\n    double A = norm_cdf(a);\n    double B = norm_cdf(b);\n    double Z = B - A;\n\n    if (Z < 1e-14) {\n        if (mu < lo) return lo;\n        if (mu > hi) return hi;\n        return clamp(mu, lo, hi);\n    }\n\n    double mean = mu + sd * (norm_pdf(a) - norm_pdf(b)) / Z;\n    return clamp(mean, lo, hi);\n}\n\nvector<double> estimateWeights(const vector<double>& score, int qRand) {\n    vector<double> est(N, 1.0);\n    if (qRand <= 0) return est;\n\n    const double PI = acos(-1.0);\n    const double c = sqrt(2.0 / PI);\n\n    int K = N / 2;\n    double pNonZero = 2.0 * K / N;\n    double lambda = 2.0 * K / (N - 1.0);\n    double ce = c * sqrt(lambda);\n\n    double sigmaZ = sqrt(pNonZero * N) / (ce * sqrt((double)qRand));\n\n    double cap = (double)N / D;\n    double e = exp(-cap);\n    double Z = 1.0 - e;\n    double meanX = (1.0 - (cap + 1.0) * e) / Z;\n    double secondX = (2.0 - (cap * cap + 2.0 * cap + 2.0) * e) / Z;\n    double varX = max(1e-12, secondX - meanX * meanX);\n    double cv = sqrt(varX) / meanX;\n    double rMax = cap / meanX;\n\n    double tau = max(1e-6, cv * sigmaZ);\n    double rate = meanX;\n\n    for (int i = 0; i < N; i++) {\n        double zObs = score[i] * sqrt((double)N) / (ce * qRand);\n        double obsR = 1.0 + cv * zObs;\n\n        double mu = obsR - rate * tau * tau;\n        est[i] = truncatedNormalMean(mu, tau, 0.0, rMax);\n        est[i] = max(est[i], 1e-6);\n    }\n\n    return est;\n}\n\ndouble totalWeight(const vector<double>& w) {\n    return accumulate(w.begin(), w.end(), 0.0);\n}\n\ndouble sqr(double x) {\n    return x * x;\n}\n\ndouble calcObjLoad(const vector<double>& load, double target) {\n    double res = 0.0;\n    for (double x : load) {\n        double d = x - target;\n        res += d * d;\n    }\n    return res;\n}\n\nSolution buildSolution(const vector<int>& assign, const vector<double>& w) {\n    Solution sol;\n    sol.assign = assign;\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    for (int i = 0; i < N; i++) {\n        int b = sol.assign[i];\n        sol.bins[b].push_back(i);\n        sol.load[b] += w[i];\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nvoid eraseItem(vector<int>& v, int x) {\n    for (int i = 0; i < (int)v.size(); i++) {\n        if (v[i] == x) {\n            v[i] = v.back();\n            v.pop_back();\n            return;\n        }\n    }\n}\n\nvoid moveItemSol(Solution& sol, int item, int from, int to, const vector<double>& w) {\n    eraseItem(sol.bins[from], item);\n    sol.bins[to].push_back(item);\n    sol.assign[item] = to;\n    sol.load[from] -= w[item];\n    sol.load[to] += w[item];\n}\n\nvoid swapItemsSol(Solution& sol, int x, int y, int bx, int by, const vector<double>& w) {\n    for (int& v : sol.bins[bx]) {\n        if (v == x) {\n            v = y;\n            break;\n        }\n    }\n    for (int& v : sol.bins[by]) {\n        if (v == y) {\n            v = x;\n            break;\n        }\n    }\n\n    sol.assign[x] = by;\n    sol.assign[y] = bx;\n\n    sol.load[bx] += w[y] - w[x];\n    sol.load[by] += w[x] - w[y];\n}\n\nvoid moveSubsetSol(Solution& sol, const vector<int>& sub, int from, int to, const vector<double>& w) {\n    for (int x : sub) {\n        moveItemSol(sol, x, from, to, w);\n    }\n}\n\nvoid localImprove(Solution& sol, const vector<double>& w, double target) {\n    for (int iter = 0; iter < 2000; iter++) {\n        double bestDelta = -1e-12;\n        int bestType = 0;\n        int bestI = -1, bestJ = -1;\n        int bestA = -1, bestB = -1;\n\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            if ((int)sol.bins[a].size() <= 1) continue;\n\n            for (int b = 0; b < D; b++) {\n                if (a == b) continue;\n\n                double oldVal = sqr(sol.load[a] - target) + sqr(sol.load[b] - target);\n                double newVal = sqr(sol.load[a] - w[i] - target) + sqr(sol.load[b] + w[i] - target);\n                double delta = newVal - oldVal;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        for (int i = 0; i < N; i++) {\n            int a = sol.assign[i];\n            for (int j = i + 1; j < N; j++) {\n                int b = sol.assign[j];\n                if (a == b) continue;\n\n                double oldVal = sqr(sol.load[a] - target) + sqr(sol.load[b] - target);\n                double newVal =\n                    sqr(sol.load[a] - w[i] + w[j] - target) +\n                    sqr(sol.load[b] - w[j] + w[i] - target);\n\n                double delta = newVal - oldVal;\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestI = i;\n                    bestJ = j;\n                    bestA = a;\n                    bestB = b;\n                }\n            }\n        }\n\n        if (bestType == 0) break;\n\n        if (bestType == 1) {\n            moveItemSol(sol, bestI, bestA, bestB, w);\n        } else {\n            swapItemsSol(sol, bestI, bestJ, bestA, bestB, w);\n        }\n\n        sol.obj += bestDelta;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nbool pairBalanceDP(Solution& sol, int a, int b, const vector<double>& w, double target) {\n    vector<int> items = sol.bins[a];\n    for (int x : sol.bins[b]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 1) return false;\n\n    double pairSum = sol.load[a] + sol.load[b];\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(w[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1);\n    vector<int> parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    int bestS = -1;\n    int bestDiff = INT_MAX;\n    for (int s = 0; s <= total; s++) {\n        if (!dp[s]) continue;\n        int diff = abs(total - 2 * s);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestS = s;\n        }\n    }\n\n    if (bestS < 0) return false;\n\n    vector<char> inA(M, 0);\n    int cur = bestS;\n    while (cur > 0) {\n        int idx = parItem[cur];\n        if (idx < 0) return false;\n        inA[idx] = 1;\n        cur = parPrev[cur];\n    }\n\n    int cntA = 0;\n    double loadA = 0.0;\n    for (int i = 0; i < M; i++) {\n        if (inA[i]) {\n            cntA++;\n            loadA += w[items[i]];\n        }\n    }\n\n    if (cntA == 0 || cntA == M) return false;\n\n    double loadB = pairSum - loadA;\n\n    double keepCost = abs(loadA - sol.load[a]) + abs(loadB - sol.load[b]);\n    double flipCost = abs(loadB - sol.load[a]) + abs(loadA - sol.load[b]);\n    if (flipCost < keepCost) {\n        for (char& x : inA) x ^= 1;\n        swap(loadA, loadB);\n    }\n\n    double oldPair = sqr(sol.load[a] - target) + sqr(sol.load[b] - target);\n    double newPair = sqr(loadA - target) + sqr(loadB - target);\n\n    if (newPair >= oldPair - 1e-12) return false;\n\n    sol.bins[a].clear();\n    sol.bins[b].clear();\n    sol.load[a] = 0.0;\n    sol.load[b] = 0.0;\n\n    for (int i = 0; i < M; i++) {\n        int item = items[i];\n        if (inA[i]) {\n            sol.assign[item] = a;\n            sol.bins[a].push_back(item);\n            sol.load[a] += w[item];\n        } else {\n            sol.assign[item] = b;\n            sol.bins[b].push_back(item);\n            sol.load[b] += w[item];\n        }\n    }\n\n    sol.obj += newPair - oldPair;\n    return true;\n}\n\nvoid improveSolution(Solution& sol, const vector<double>& w, int sweeps) {\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n\n    localImprove(sol, w, target);\n\n    for (int sw = 0; sw < sweeps; sw++) {\n        double before = sol.obj;\n        vector<tuple<double, int, int>> pairs;\n\n        for (int a = 0; a < D; a++) {\n            for (int b = a + 1; b < D; b++) {\n                pairs.emplace_back(abs(sol.load[a] - sol.load[b]), a, b);\n            }\n        }\n\n        sort(pairs.rbegin(), pairs.rend());\n\n        bool changed = false;\n        for (auto [_, a, b] : pairs) {\n            changed |= pairBalanceDP(sol, a, b, w, target);\n        }\n\n        localImprove(sol, w, target);\n\n        if (!changed || sol.obj >= before - 1e-12) break;\n    }\n\n    sol.obj = calcObjLoad(sol.load, target);\n}\n\nSolution makeGreedyOrder(const vector<int>& order, const vector<double>& w) {\n    Solution sol;\n    sol.assign.assign(N, -1);\n    sol.bins.assign(D, {});\n    sol.load.assign(D, 0.0);\n\n    vector<int> cnt(D, 0);\n\n    for (int item : order) {\n        int best = 0;\n        for (int b = 1; b < D; b++) {\n            if (sol.load[b] < sol.load[best] - 1e-12 ||\n                (abs(sol.load[b] - sol.load[best]) <= 1e-12 && cnt[b] < cnt[best])) {\n                best = b;\n            }\n        }\n\n        sol.assign[item] = best;\n        sol.bins[best].push_back(item);\n        sol.load[best] += w[item];\n        cnt[best]++;\n    }\n\n    double target = totalWeight(w) / D;\n    sol.obj = calcObjLoad(sol.load, target);\n    return sol;\n}\n\nSolution makeSnake(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        int block = i / D;\n        int pos = i % D;\n        int b = (block % 2 == 0) ? pos : (D - 1 - pos);\n        assign[order[i]] = b;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution makeRoundRobin(const vector<int>& order, const vector<double>& w) {\n    vector<int> assign(N);\n    for (int i = 0; i < N; i++) {\n        assign[order[i]] = i % D;\n    }\n    return buildSolution(assign, w);\n}\n\nSolution partitionEstimated(const vector<double>& w) {\n    vector<int> order(N);\n    iota(order.begin(), order.end(), 0);\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return w[a] > w[b];\n    });\n\n    Solution best;\n\n    auto consider = [&](Solution sol) {\n        improveSolution(sol, w, 2);\n        if (sol.obj < best.obj) best = sol;\n    };\n\n    consider(makeGreedyOrder(order, w));\n    consider(makeSnake(order, w));\n    consider(makeRoundRobin(order, w));\n\n    normal_distribution<double> nd(0.0, 0.35);\n\n    for (int rep = 0; rep < 3; rep++) {\n        vector<pair<double, int>> keys;\n        keys.reserve(N);\n\n        for (int i = 0; i < N; i++) {\n            double key = log(max(1e-9, w[i])) + nd(rng);\n            keys.emplace_back(-key, i);\n        }\n\n        sort(keys.begin(), keys.end());\n\n        vector<int> ord;\n        ord.reserve(N);\n        for (auto [_, id] : keys) ord.push_back(id);\n\n        consider(makeGreedyOrder(ord, w));\n    }\n\n    improveSolution(best, w, 2);\n    return best;\n}\n\nvector<int> withoutItem(const vector<int>& v, int x) {\n    vector<int> res;\n    res.reserve(v.size());\n    for (int y : v) {\n        if (y != x) res.push_back(y);\n    }\n    return res;\n}\n\nvector<int> withoutSubset(const vector<int>& v, const vector<int>& sub) {\n    vector<char> used(N, 0);\n    for (int x : sub) used[x] = 1;\n\n    vector<int> res;\n    res.reserve(v.size());\n\n    for (int x : v) {\n        if (!used[x]) res.push_back(x);\n    }\n\n    return res;\n}\n\nbool sameSetVec(const vector<int>& A, const vector<int>& B) {\n    if (A.size() != B.size()) return false;\n\n    vector<char> mark(N, 0);\n    for (int x : A) mark[x] = 1;\n    for (int x : B) {\n        if (!mark[x]) return false;\n    }\n    return true;\n}\n\nvector<int> intersectionVec(const vector<int>& A, const vector<int>& B) {\n    vector<char> mark(N, 0);\n    for (int x : B) mark[x] = 1;\n\n    vector<int> res;\n    for (int x : A) {\n        if (mark[x]) res.push_back(x);\n    }\n    return res;\n}\n\nbool strictLessSet(const vector<int>& A, const vector<int>& B) {\n    if (A.empty() && B.empty()) return false;\n    if (A.empty()) return true;\n    if (B.empty()) return false;\n    if (qUsed >= Q) return false;\n\n    char c = ask(A, B);\n    return c == '<';\n}\n\nvoid applyPairSplit(Solution& sol, int H, int L, const vector<int>& A, const vector<int>& B, const vector<double>& est) {\n    sol.bins[H].clear();\n    sol.bins[L].clear();\n    sol.load[H] = 0.0;\n    sol.load[L] = 0.0;\n\n    for (int x : A) {\n        sol.assign[x] = H;\n        sol.bins[H].push_back(x);\n        sol.load[H] += est[x];\n    }\n\n    for (int x : B) {\n        sol.assign[x] = L;\n        sol.bins[L].push_back(x);\n        sol.load[L] += est[x];\n    }\n}\n\nbool proveAndApplySplit(Solution& sol, int H, int L, const vector<int>& A, const vector<int>& B, const vector<double>& est) {\n    if (A.empty() || B.empty()) return false;\n    if (sameSetVec(A, sol.bins[H]) || sameSetVec(A, sol.bins[L])) return false;\n    if (qUsed >= Q) return false;\n\n    char cAB = ask(A, B);\n\n    if (cAB == '=') {\n        applyPairSplit(sol, H, L, A, B, est);\n        return true;\n    }\n\n    bool ok = false;\n\n    if (cAB == '>') {\n        vector<int> leftMoved = intersectionVec(sol.bins[L], A);\n        vector<int> rightMoved = intersectionVec(sol.bins[H], B);\n        ok = strictLessSet(leftMoved, rightMoved);\n    } else {\n        vector<int> leftMoved = intersectionVec(sol.bins[L], B);\n        vector<int> rightMoved = intersectionVec(sol.bins[H], A);\n        ok = strictLessSet(leftMoved, rightMoved);\n    }\n\n    if (!ok) return false;\n\n    applyPairSplit(sol, H, L, A, B, est);\n    return true;\n}\n\nbool tryRepartitionProof(Solution& sol, int H, int L, const vector<double>& est) {\n    if (qUsed >= Q) return false;\n    if (H == L) return false;\n    if (sol.bins[H].empty() || sol.bins[L].empty()) return false;\n\n    vector<int> items = sol.bins[H];\n    for (int x : sol.bins[L]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 2) return false;\n\n    double pairSum = 0.0;\n    for (int x : items) pairSum += est[x];\n\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(est[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1), parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    int bestS = -1;\n    int bestDiff = INT_MAX;\n    for (int s = 1; s < total; s++) {\n        if (!dp[s]) continue;\n        int diff = abs(total - 2 * s);\n        if (diff < bestDiff) {\n            bestDiff = diff;\n            bestS = s;\n        }\n    }\n\n    if (bestS <= 0) return false;\n\n    vector<char> inA(M, 0);\n    int cur = bestS;\n    while (cur > 0) {\n        int idx = parItem[cur];\n        if (idx < 0) return false;\n        inA[idx] = 1;\n        cur = parPrev[cur];\n    }\n\n    vector<int> A, B;\n    double loadA = 0.0, loadB = 0.0;\n\n    for (int i = 0; i < M; i++) {\n        int item = items[i];\n        if (inA[i]) {\n            A.push_back(item);\n            loadA += est[item];\n        } else {\n            B.push_back(item);\n            loadB += est[item];\n        }\n    }\n\n    if (A.empty() || B.empty()) return false;\n\n    double keepCost = abs(loadA - sol.load[H]) + abs(loadB - sol.load[L]);\n    double flipCost = abs(loadB - sol.load[H]) + abs(loadA - sol.load[L]);\n\n    if (flipCost < keepCost) {\n        swap(A, B);\n        swap(loadA, loadB);\n    }\n\n    if (sameSetVec(A, sol.bins[H]) || sameSetVec(A, sol.bins[L])) return false;\n\n    double oldEstDiff = abs(sol.load[H] - sol.load[L]);\n    double newEstDiff = abs(loadA - loadB);\n\n    if (newEstDiff >= oldEstDiff - 1e-12) return false;\n\n    return proveAndApplySplit(sol, H, L, A, B, est);\n}\n\nbool tryDominatingSubsetMove(\n    Solution& sol,\n    int H,\n    int L,\n    const vector<double>& est,\n    const vector<int>& validItems,\n    int bestMove\n) {\n    if (validItems.size() < 2) return false;\n    if (qUsed >= Q || Q - qUsed < 12) return false;\n\n    double dEst = sol.load[H] - sol.load[L];\n    if (dEst <= 1e-12) return false;\n\n    double target = 0.5 * dEst;\n    if (target <= 1e-12) return false;\n\n    double bestW = est[bestMove];\n    double singleKey = abs(bestW - target);\n\n    int m = (int)validItems.size();\n    if (m >= 20) return false;\n\n    int bestIdx = -1;\n    for (int i = 0; i < m; i++) {\n        if (validItems[i] == bestMove) bestIdx = i;\n    }\n    if (bestIdx < 0) return false;\n\n    struct Cand {\n        double key;\n        int mask;\n        vector<int> sub;\n        bool includesBest;\n    };\n\n    auto makeCand = [&](int mask) -> Cand {\n        vector<int> sub;\n        double sum = 0.0;\n\n        for (int i = 0; i < m; i++) {\n            if (mask >> i & 1) {\n                sub.push_back(validItems[i]);\n                sum += est[validItems[i]];\n            }\n        }\n\n        bool includesBest = (mask >> bestIdx) & 1;\n        double key = abs(sum - target);\n        return {key, mask, sub, includesBest};\n    };\n\n    auto tryCand = [&](const Cand& cand) -> bool {\n        if (qUsed >= Q) return false;\n        if ((int)cand.sub.size() >= (int)sol.bins[H].size()) return false;\n\n        vector<int> left = withoutSubset(sol.bins[H], cand.sub);\n        if (left.empty()) return false;\n\n        vector<int> right = sol.bins[L];\n        for (int x : cand.sub) right.push_back(x);\n\n        char c = ask(left, right);\n        if (c != '>' && c != '=') return false;\n\n        if (!cand.includesBest) {\n            if (qUsed >= Q) return false;\n            vector<int> bm{bestMove};\n            char cmp = ask(cand.sub, bm);\n\n            // Need subset weight > single-item weight to dominate the old single move.\n            if (cmp != '>') return false;\n        }\n\n        moveSubsetSol(sol, cand.sub, H, L, est);\n        return true;\n    };\n\n    set<int> triedMasks;\n\n    // First reproduce the previous successful conservative behavior.\n    if (D >= 5 && bestW < 0.65 * target && singleKey > 1e-12) {\n        vector<Cand> conservative;\n\n        for (int mask = 1; mask < (1 << m); mask++) {\n            if (!(mask & (1 << bestIdx))) continue;\n            if (__builtin_popcount((unsigned)mask) < 2) continue;\n\n            Cand cand = makeCand(mask);\n            double sum = 0.0;\n            for (int x : cand.sub) sum += est[x];\n\n            if ((int)cand.sub.size() >= (int)sol.bins[H].size()) continue;\n            if (sum <= bestW + 0.05 * target) continue;\n            if (sum > 0.98 * target) continue;\n            if (cand.key >= 0.75 * singleKey) continue;\n\n            conservative.push_back(cand);\n        }\n\n        sort(conservative.begin(), conservative.end(), [&](const Cand& a, const Cand& b) {\n            return a.key < b.key;\n        });\n\n        if (!conservative.empty()) {\n            triedMasks.insert(conservative[0].mask);\n            if (tryCand(conservative[0])) return true;\n        }\n    }\n\n    // Additional candidates, only with comfortable remaining budget.\n    if (Q - qUsed < 25 || singleKey <= 1e-12) return false;\n\n    vector<Cand> extra;\n\n    for (int mask = 1; mask < (1 << m); mask++) {\n        if (triedMasks.count(mask)) continue;\n        if (__builtin_popcount((unsigned)mask) < 2) continue;\n\n        Cand cand = makeCand(mask);\n\n        double sum = 0.0;\n        for (int x : cand.sub) sum += est[x];\n\n        if ((int)cand.sub.size() >= (int)sol.bins[H].size()) continue;\n        if (sum <= bestW + 0.03 * target) continue;\n        if (sum > 1.08 * target) continue;\n        if (cand.key >= 0.90 * singleKey) continue;\n\n        extra.push_back(cand);\n    }\n\n    if (extra.empty()) return false;\n\n    sort(extra.begin(), extra.end(), [&](const Cand& a, const Cand& b) {\n        if (a.key != b.key) return a.key < b.key;\n        return a.sub.size() < b.sub.size();\n    });\n\n    int maxTry = (Q - qUsed >= 40 ? 3 : 2);\n    maxTry = min(maxTry, (int)extra.size());\n\n    for (int i = 0; i < maxTry && qUsed < Q; i++) {\n        if (tryCand(extra[i])) return true;\n    }\n\n    return false;\n}\n\nstruct SplitCandidate {\n    vector<int> A, B;\n    double estDiff;\n};\n\nvector<SplitCandidate> generateSplitCandidates(\n    const Solution& sol,\n    int H,\n    int L,\n    const vector<double>& est,\n    int need\n) {\n    vector<SplitCandidate> res;\n    if (need <= 0) return res;\n\n    vector<int> items = sol.bins[H];\n    for (int x : sol.bins[L]) items.push_back(x);\n\n    int M = items.size();\n    if (M <= 2) return res;\n\n    double pairSum = 0.0;\n    for (int x : items) pairSum += est[x];\n\n    int scale = DP_SCALE_BASE;\n    if (pairSum * scale > DP_SUM_LIMIT) {\n        scale = max(50, (int)(DP_SUM_LIMIT / max(1e-9, pairSum)));\n    }\n\n    vector<int> val(M);\n    int total = 0;\n    for (int i = 0; i < M; i++) {\n        val[i] = max(1, (int)llround(est[items[i]] * scale));\n        total += val[i];\n    }\n\n    vector<char> dp(total + 1, 0);\n    vector<int> parItem(total + 1, -1), parPrev(total + 1, -1);\n    dp[0] = 1;\n\n    for (int i = 0; i < M; i++) {\n        int v = val[i];\n        for (int s = total - v; s >= 0; s--) {\n            if (dp[s] && !dp[s + v]) {\n                dp[s + v] = 1;\n                parItem[s + v] = i;\n                parPrev[s + v] = s;\n            }\n        }\n    }\n\n    vector<int> sums;\n    for (int s = 1; s < total; s++) {\n        if (dp[s]) sums.push_back(s);\n    }\n\n    sort(sums.begin(), sums.end(), [&](int a, int b) {\n        int da = abs(total - 2 * a);\n        int db = abs(total - 2 * b);\n        if (da != db) return da < db;\n        return a < b;\n    });\n\n    set<string> seen;\n    double oldEstDiff = abs(sol.load[H] - sol.load[L]);\n\n    for (int bestS : sums) {\n        vector<char> inA(M, 0);\n        int cur = bestS;\n        bool ok = true;\n\n        while (cur > 0) {\n            int idx = parItem[cur];\n            if (idx < 0) {\n                ok = false;\n                break;\n            }\n            inA[idx] = 1;\n            cur = parPrev[cur];\n        }\n\n        if (!ok) continue;\n\n        vector<int> A, B;\n        double loadA = 0.0, loadB = 0.0;\n\n        for (int i = 0; i < M; i++) {\n            int item = items[i];\n            if (inA[i]) {\n                A.push_back(item);\n                loadA += est[item];\n            } else {\n                B.push_back(item);\n                loadB += est[item];\n            }\n        }\n\n        if (A.empty() || B.empty()) continue;\n\n        double keepCost = abs(loadA - sol.load[H]) + abs(loadB - sol.load[L]);\n        double flipCost = abs(loadB - sol.load[H]) + abs(loadA - sol.load[L]);\n\n        if (flipCost < keepCost) {\n            swap(A, B);\n            swap(loadA, loadB);\n        }\n\n        if (sameSetVec(A, sol.bins[H]) || sameSetVec(A, sol.bins[L])) continue;\n\n        double newEstDiff = abs(loadA - loadB);\n        if (newEstDiff >= oldEstDiff - 1e-12) continue;\n\n        string mask(N, '0');\n        for (int x : A) mask[x] = '1';\n        if (!seen.insert(mask).second) continue;\n\n        res.push_back({A, B, newEstDiff});\n        if ((int)res.size() >= need) break;\n    }\n\n    return res;\n}\n\nbool tryRepartitionProofMulti(\n    Solution& sol,\n    int H,\n    int L,\n    const vector<double>& est,\n    int maxCand,\n    bool skipFirst,\n    int queryBudget\n) {\n    if (qUsed >= Q) return false;\n    if (H == L) return false;\n    if (sol.bins[H].empty() || sol.bins[L].empty()) return false;\n\n    int need = maxCand + (skipFirst ? 1 : 0);\n    auto cands = generateSplitCandidates(sol, H, L, est, need);\n    if (cands.empty()) return false;\n\n    int startIdx = skipFirst ? 1 : 0;\n    int startQ = qUsed;\n    int tried = 0;\n\n    for (int i = startIdx; i < (int)cands.size() && tried < maxCand; i++) {\n        if (qUsed >= Q) break;\n        if (queryBudget >= 0 && qUsed - startQ >= queryBudget) break;\n\n        tried++;\n        if (proveAndApplySplit(sol, H, L, cands[i].A, cands[i].B, est)) return true;\n    }\n\n    return false;\n}\n\nint minMaxCost() {\n    int pairs = D / 2;\n    int sz = pairs + (D % 2);\n    return pairs + max(0, sz - 1) + max(0, sz - 1);\n}\n\nbool findActualMinMax(const vector<vector<int>>& bins, int& mn, int& mx) {\n    vector<int> winners, losers;\n\n    for (int i = 0; i + 1 < D; i += 2) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[i], bins[i + 1]);\n        if (c == '>') {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        } else if (c == '<') {\n            winners.push_back(i + 1);\n            losers.push_back(i);\n        } else {\n            winners.push_back(i);\n            losers.push_back(i + 1);\n        }\n    }\n\n    if (D % 2 == 1) {\n        winners.push_back(D - 1);\n        losers.push_back(D - 1);\n    }\n\n    mx = winners[0];\n    for (int i = 1; i < (int)winners.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[winners[i]], bins[mx]);\n        if (c == '>') mx = winners[i];\n    }\n\n    mn = losers[0];\n    for (int i = 1; i < (int)losers.size(); i++) {\n        if (qUsed >= Q) return false;\n\n        char c = ask(bins[losers[i]], bins[mn]);\n        if (c == '<') mn = losers[i];\n    }\n\n    return true;\n}\n\nbool tryImproveOrientedPair(Solution& sol, int H, int L, const vector<double>& est, int moveCap, int swapCap) {\n    if (H == L) return false;\n    if (sol.bins[H].empty() || sol.bins[L].empty()) return false;\n\n    if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n        vector<int> items = sol.bins[H];\n        sort(items.begin(), items.end(), [&](int a, int b) {\n            return est[a] < est[b];\n        });\n\n        int rem = Q - qUsed;\n        int moveLimit = min((int)items.size(), min(moveCap, max(1, rem / 3)));\n        if (rem <= 3) moveLimit = min((int)items.size(), rem);\n\n        int bestMove = -1;\n        vector<int> validItems;\n        int tried = 0;\n\n        for (int x : items) {\n            if (tried >= moveLimit || qUsed >= Q) break;\n\n            vector<int> left = withoutItem(sol.bins[H], x);\n            if (left.empty()) break;\n\n            char c = ask(left, sol.bins[L]);\n            tried++;\n\n            if (c == '>') {\n                bestMove = x;\n                validItems.push_back(x);\n            } else if (bestMove != -1) {\n                break;\n            }\n        }\n\n        if (bestMove != -1) {\n            if (tryDominatingSubsetMove(sol, H, L, est, validItems, bestMove)) {\n                return true;\n            }\n\n            moveItemSol(sol, bestMove, H, L, est);\n            return true;\n        }\n    }\n\n    if ((int)sol.bins[H].size() > 1 && qUsed < Q) {\n        vector<tuple<double, int, int>> cand;\n\n        for (int x : sol.bins[H]) {\n            for (int y : sol.bins[L]) {\n                double diff = est[x] - est[y];\n                double key = (diff >= 0.0) ? diff : (2.0 + (-diff));\n                cand.emplace_back(key, x, y);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        int tried = 0;\n        for (auto [_, x, y] : cand) {\n            if (tried >= swapCap || qUsed >= Q) break;\n            tried++;\n\n            char xy = compareItems(x, y);\n            if (xy == '?') break;\n            if (xy != '>') continue;\n\n            if ((int)sol.bins[L].size() == 1) {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n\n            vector<int> left = withoutItem(sol.bins[H], x);\n            vector<int> right = withoutItem(sol.bins[L], y);\n\n            if (left.empty()) continue;\n            if (right.empty()) {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n\n            if (qUsed >= Q) break;\n\n            char c = ask(left, right);\n            if (c == '>') {\n                swapItemsSol(sol, x, y, H, L, est);\n                return true;\n            }\n        }\n    }\n\n    return false;\n}\n\nbool tryImproveUnknownPair(Solution& sol, int a, int b, const vector<double>& est) {\n    if (a == b) return false;\n    if (qUsed >= Q) return false;\n    if (sol.bins[a].empty() || sol.bins[b].empty()) return false;\n\n    char c = ask(sol.bins[a], sol.bins[b]);\n    if (c == '=') return false;\n\n    int H = a, L = b;\n    if (c == '<') swap(H, L);\n\n    return tryImproveOrientedPair(sol, H, L, est, 4, 10);\n}\n\nbool tryEstimatedPairFallback(Solution& sol, const vector<double>& est, int skipA = -1, int skipB = -1) {\n    if (qUsed >= Q) return false;\n\n    vector<tuple<double, int, int>> pairs;\n\n    for (int a = 0; a < D; a++) {\n        for (int b = a + 1; b < D; b++) {\n            if ((a == skipA && b == skipB) || (a == skipB && b == skipA)) continue;\n\n            if (sol.load[a] >= sol.load[b]) {\n                pairs.emplace_back(sol.load[a] - sol.load[b], a, b);\n            } else {\n                pairs.emplace_back(sol.load[b] - sol.load[a], b, a);\n            }\n        }\n    }\n\n    sort(pairs.rbegin(), pairs.rend());\n\n    int maxPairs = min((int)pairs.size(), max(5, min(80, Q - qUsed)));\n\n    for (int i = 0; i < maxPairs && qUsed < Q; i++) {\n        auto [_, Hest, Lest] = pairs[i];\n        if (tryImproveUnknownPair(sol, Hest, Lest, est)) return true;\n    }\n\n    return false;\n}\n\nint actualRefine(Solution& sol, const vector<double>& est) {\n    int successes = 0;\n\n    while (qUsed < Q) {\n        bool success = false;\n        int failedH = -1, failedL = -1;\n\n        int cost = minMaxCost();\n        if (Q - qUsed >= cost + 1) {\n            int mn = -1, mx = -1;\n            if (!findActualMinMax(sol.bins, mn, mx)) break;\n\n            failedH = mx;\n            failedL = mn;\n\n            if (mx != mn) {\n                success = tryImproveOrientedPair(sol, mx, mn, est, 6, 20);\n\n                if (!success && qUsed < Q) {\n                    success = tryRepartitionProof(sol, mx, mn, est);\n                }\n\n                if (!success && Q - qUsed >= 50) {\n                    success = tryRepartitionProofMulti(sol, mx, mn, est, 2, true, 4);\n                }\n            }\n\n            if (success) {\n                successes++;\n                continue;\n            }\n        }\n\n        if (qUsed < Q) {\n            success = tryEstimatedPairFallback(sol, est, failedH, failedL);\n        }\n\n        if (success) {\n            successes++;\n            continue;\n        }\n\n        break;\n    }\n\n    return successes;\n}\n\nvoid postRepartitionRefine(Solution& sol, const vector<double>& est) {\n    int guard = 0;\n\n    while (qUsed < Q && guard++ < 20) {\n        bool success = false;\n\n        if (Q - qUsed >= minMaxCost() + 3) {\n            int mn = -1, mx = -1;\n            if (!findActualMinMax(sol.bins, mn, mx)) break;\n\n            if (mx != mn && qUsed < Q) {\n                success = tryRepartitionProofMulti(sol, mx, mn, est, 5, false, 10);\n            }\n        }\n\n        if (success) {\n            actualRefine(sol, est);\n            continue;\n        }\n\n        if (qUsed >= Q) break;\n\n        vector<tuple<double, int, int>> pairs;\n        for (int a = 0; a < D; a++) {\n            for (int b = a + 1; b < D; b++) {\n                if (sol.load[a] >= sol.load[b]) {\n                    pairs.emplace_back(sol.load[a] - sol.load[b], a, b);\n                } else {\n                    pairs.emplace_back(sol.load[b] - sol.load[a], b, a);\n                }\n            }\n        }\n\n        sort(pairs.rbegin(), pairs.rend());\n\n        int maxPairs = min((int)pairs.size(), min(10, max(1, Q - qUsed)));\n\n        for (int i = 0; i < maxPairs && qUsed < Q; i++) {\n            auto [_, a, b] = pairs[i];\n\n            char c = ask(sol.bins[a], sol.bins[b]);\n            if (c == '=') continue;\n\n            int H = a, L = b;\n            if (c == '<') swap(H, L);\n\n            if (tryRepartitionProofMulti(sol, H, L, est, 3, false, 6)) {\n                success = true;\n                break;\n            }\n        }\n\n        if (success) {\n            actualRefine(sol, est);\n            continue;\n        }\n\n        break;\n    }\n}\n\nvoid randomBalancedQueries(int cnt, vector<double>& score) {\n    vector<int> perm(N);\n    iota(perm.begin(), perm.end(), 0);\n\n    int K = N / 2;\n\n    for (int q = 0; q < cnt && qUsed < Q; q++) {\n        shuffle(perm.begin(), perm.end(), rng);\n\n        vector<int> L, R;\n        L.reserve(K);\n        R.reserve(K);\n\n        for (int i = 0; i < K; i++) L.push_back(perm[i]);\n        for (int i = 0; i < K; i++) R.push_back(perm[K + i]);\n\n        char c = ask(L, R);\n        int y = 0;\n        if (c == '>') y = 1;\n        else if (c == '<') y = -1;\n\n        if (y != 0) {\n            for (int x : L) score[x] += y;\n            for (int x : R) score[x] -= y;\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    if (!(cin >> N >> D >> Q)) return 0;\n\n    uint64_t seed = 123456789ULL;\n    seed ^= (uint64_t)N * 1000003ULL;\n    seed ^= (uint64_t)D * 10007ULL;\n    seed ^= (uint64_t)Q * 998244353ULL;\n    rng.seed(seed);\n\n    itemCmp.assign(N, vector<char>(N, '?'));\n    for (int i = 0; i < N; i++) itemCmp[i][i] = '=';\n\n    vector<double> score(N, 0.0);\n\n    int qRefine = min(Q / 5, 2 * N);\n    int qRandom = Q - qRefine;\n\n    randomBalancedQueries(qRandom, score);\n\n    vector<double> est = estimateWeights(score, qRandom);\n\n    Solution sol = partitionEstimated(est);\n\n    actualRefine(sol, est);\n\n    postRepartitionRefine(sol, est);\n\n    while (qUsed < Q) {\n        vector<int> L{0}, R{1};\n        ask(L, R);\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << sol.assign[i];\n    }\n    cout << '\\n' << flush;\n\n    return 0;\n}","ahc026":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MMAX = 10;\nstatic const int INF = 1000000000;\n\nint nG, mG;\nusing StackArray = array<vector<int>, MMAX>;\n\nstatic bool g_useClearBeam = true;\nstatic int g_clearMaxBlockers = 40;\n\nstruct XorShift {\n    uint64_t x;\n    XorShift(uint64_t seed = 88172645463325252ULL) { x = seed ? seed : 88172645463325252ULL; }\n    uint64_t next() { x ^= x << 7; x ^= x >> 9; return x; }\n    int nextInt(int n) { return (int)(next() % (uint64_t)n); }\n    double nextDouble() { return (double)(next() >> 11) * (1.0 / (double)(1ULL << 53)); }\n};\n\nstruct Params {\n    int mode = 2, badMode = 0, goodMode = 0, thresholdMode = 0, destMode = 0;\n    double noise = 0.0;\n    double lenW = 0.06, dirtyW = 1.5, badW = 3.0, amountW = 0.05;\n    double slackW = 0.02, heightW = 0.0, gW = 0.05;\n    int initA = -1, initB = -1;\n};\n\nstruct Result {\n    vector<pair<int,int>> ops;\n    int cost = INF;\n    bool ok = false;\n};\n\nstruct Stats {\n    int len = 0, maxv = -1, minv = INF, internalBad = 0;\n};\n\nResult invalidResult() { return Result{{}, INF, false}; }\n\npair<int,int> findBox(const StackArray& st, int v) {\n    for (int i = 0; i < mG; 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\nint minStackValue(const StackArray& st, int s) {\n    if (st[s].empty()) return INF;\n    int mn = INF;\n    for (int x : st[s]) mn = min(mn, x);\n    return mn;\n}\n\nint thresholdValue(const StackArray& st, int s, int mode) {\n    if (st[s].empty()) return INF;\n    if (mode == 1) return st[s].back();\n    return minStackValue(st, s);\n}\n\nint aboveMinCountOne(const vector<int>& a) {\n    if (a.empty()) return 0;\n    int mn = INF, pos = -1;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i] < mn) mn = a[i], pos = i;\n    }\n    return (int)a.size() - pos - 1;\n}\n\nStats blockStats(const vector<int>& a, int cut) {\n    Stats s;\n    s.len = (int)a.size() - cut;\n    for (int i = cut; i < (int)a.size(); i++) {\n        s.maxv = max(s.maxv, a[i]);\n        s.minv = min(s.minv, a[i]);\n        if (i + 1 < (int)a.size() && a[i] < a[i + 1]) s.internalBad++;\n    }\n    return s;\n}\n\nint countGreaterThan(const vector<int>& a, int cut, int g) {\n    int c = 0;\n    for (int i = cut; i < (int)a.size(); i++) if (a[i] > g) c++;\n    return c;\n}\n\nint topCleanStart(const vector<int>& a, int targetPos) {\n    int c = (int)a.size() - 1;\n    while (c - 1 > targetPos && a[c - 1] > a[c]) c--;\n    return c;\n}\n\nbool existsGoodDest(const StackArray& st, int src, const Stats& bs, const Params& p) {\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        if (bs.maxv < thresholdValue(st, d, p.thresholdMode)) return true;\n    }\n    return false;\n}\n\nint chooseDest(const StackArray& st, int src, int cut, const Params& p, XorShift& rng) {\n    Stats bs = blockStats(st[src], cut);\n    int bestDst = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        int g = thresholdValue(st, d, p.thresholdMode);\n        double normG = (g >= INF / 2 ? 1000.0 : (double)g);\n        bool good = (bs.maxv < g);\n        int badCnt = countGreaterThan(st[src], cut, g);\n        int h = (int)st[d].size();\n        int aboveMin = aboveMinCountOne(st[d]);\n\n        double score;\n        if (p.destMode == 0) {\n            score = good ? normG * 10.0 + h * 0.01\n                         : 100000.0 - normG * 10.0 + badCnt * 100.0 + h * 0.01;\n        } else if (p.destMode == 1) {\n            score = good ? normG * 10.0 - h * 0.05\n                         : 100000.0 - normG * 10.0 - aboveMin * 5.0 + h * 0.01;\n        } else if (p.destMode == 2) {\n            score = good ? (g >= INF / 2 ? 0.0 : normG * 10.0) + h * 0.02\n                         : 100000.0 + badCnt * 1000.0 - normG * 20.0 - aboveMin * 5.0;\n        } else {\n            score = good ? (normG - bs.maxv) * 10.0 + h * 0.1\n                         : 100000.0 + badCnt * 500.0\n                         + max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g)) * 5.0\n                         - normG * 10.0 + h * 0.1;\n        }\n\n        if (p.noise > 0.0) score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n        if (score < bestScore) bestScore = score, bestDst = d;\n    }\n\n    if (bestDst == -1) for (int d = 0; d < mG; d++) if (d != src) return d;\n    return bestDst;\n}\n\nbool applyMove(StackArray& st, vector<pair<int,int>>& ops, int& cost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    int label = st[src][cut];\n\n    ops.push_back({label, dst + 1});\n    cost += len + 1;\n    if (cost >= cutoff) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    return (int)ops.size() <= 5000;\n}\n\nstruct Choice { int cut = -1, dst = -1; };\n\nChoice chooseEnumMove(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    int blockers = h - pos - 1;\n\n    vector<int> cuts;\n    auto addCut = [&](int c) { if (c > pos && c < h) cuts.push_back(c); };\n\n    addCut(h - 1);\n    addCut(pos + 1);\n    int c0 = topCleanStart(a, pos);\n    addCut(c0);\n\n    for (int c = c0; c < h; c++) addCut(c);\n\n    int cur = h - 1, added = 0;\n    while (cur > pos && added < 12) {\n        int r = cur;\n        while (r - 1 > pos && a[r - 1] > a[r]) r--;\n        addCut(r);\n        cur = r - 1;\n        added++;\n    }\n\n    if (blockers <= 25) {\n        for (int c = pos + 1; c < h; c++) addCut(c);\n    } else {\n        for (int t = 1; t <= 10; t++) {\n            int c = pos + 1 + (int)((long long)(blockers - 1) * t / 11);\n            addCut(c);\n        }\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    Choice best;\n    double bestScore = 1e100;\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(a, cut);\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            int g = thresholdValue(st, d, p.thresholdMode);\n            int badCnt = countGreaterThan(a, cut, g);\n            double normG = (g >= INF / 2 ? 250.0 : (double)g);\n\n            double score = 1.0 - p.lenW * bs.len + p.dirtyW * bs.internalBad;\n\n            if (badCnt == 0) {\n                score += p.slackW * (normG - bs.maxv);\n                score += p.heightW * (int)st[d].size();\n            } else {\n                score += p.badW * badCnt;\n                score += p.amountW * max(0, bs.maxv - (g >= INF / 2 ? bs.maxv : g));\n                score -= p.gW * normG;\n                score += p.heightW * (int)st[d].size();\n            }\n\n            if (p.noise > 0.0) score += (rng.nextDouble() * 2.0 - 1.0) * p.noise;\n\n            if (score < bestScore) {\n                bestScore = score;\n                best.cut = cut;\n                best.dst = d;\n            }\n        }\n    }\n\n    if (best.cut == -1) {\n        best.cut = h - 1;\n        best.dst = (src == 0 ? 1 : 0);\n    }\n    return best;\n}\n\nChoice chooseActionByParams(const StackArray& st, int src, int pos, const Params& p, XorShift& rng) {\n    int h = (int)st[src].size();\n\n    if (p.mode == 3) return chooseEnumMove(st, src, pos, p, rng);\n\n    int cut = -1;\n\n    if (p.mode == 0) {\n        cut = pos + 1;\n    } else if (p.mode == 1) {\n        cut = h - 1;\n    } else {\n        int c0 = topCleanStart(st[src], pos);\n        bool selected = false;\n\n        if (p.goodMode == 0) {\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(st[src], c);\n                if (existsGoodDest(st, src, bs, p)) {\n                    cut = c;\n                    selected = true;\n                    break;\n                }\n            }\n        } else if (p.goodMode == 1) {\n            Stats bs = blockStats(st[src], c0);\n            if (existsGoodDest(st, src, bs, p)) {\n                cut = c0;\n                selected = true;\n            }\n        } else {\n            cut = c0;\n            selected = true;\n        }\n\n        if (!selected) {\n            if (p.badMode == 3) return chooseEnumMove(st, src, pos, p, rng);\n            if (p.badMode == 0) cut = c0;\n            else if (p.badMode == 1) cut = pos + 1;\n            else cut = h - 1;\n        }\n    }\n\n    int dst = chooseDest(st, src, cut, p, rng);\n    return {cut, dst};\n}\n\nbool applyMoveCostOnly(StackArray& st, int& cost, int& opCnt,\n                       int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    cost += len + 1;\n    opCnt++;\n\n    if (cost >= cutoff || opCnt > 5000) return false;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n    return true;\n}\n\nint completeCostPolicy(const StackArray& initial, int startV, Params p, int limit) {\n    if (limit <= 0) return INF;\n\n    StackArray st = initial;\n    int cost = 0, opCnt = 0;\n    XorShift rng(123456789ULL + (uint64_t)p.mode * 10007ULL\n                 + (uint64_t)p.badMode * 1009ULL\n                 + (uint64_t)p.goodMode * 9176ULL\n                 + (uint64_t)p.destMode * 13331ULL);\n\n    for (int v = startV; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return INF;\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) return INF;\n\n            if (!applyMoveCostOnly(st, cost, opCnt, src, ch.cut, ch.dst, limit)) return INF;\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return INF;\n\n        st[src].pop_back();\n        opCnt++;\n        if (opCnt > 5000) return INF;\n    }\n\n    return cost;\n}\n\nResult completeOpsPolicy(const StackArray& initial, int startV, Params p, int cutoff) {\n    StackArray st = initial;\n    vector<pair<int,int>> ops;\n    ops.reserve(5000);\n    int cost = 0;\n    XorShift rng(987654321ULL + (uint64_t)p.mode * 10007ULL);\n\n    for (int v = startV; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n                return invalidResult();\n            }\n\n            if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) return invalidResult();\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    return Result{ops, cost, true};\n}\n\nint completeCostMulti(const StackArray& st, int startV, const vector<Params>& policies, int limit) {\n    if (startV > nG) return 0;\n    int best = INF;\n    for (const Params& p : policies) {\n        int c = completeCostPolicy(st, startV, p, min(limit, best));\n        if (c < best) best = c;\n    }\n    if (best >= limit) return INF;\n    return best;\n}\n\nResult simulateGreedy(const StackArray& init, Params p, uint64_t seed, int cutoff) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n    XorShift rng(seed);\n\n    if (p.initA >= 0 && p.initA < mG && p.initB >= 0 && p.initB < mG &&\n        p.initA != p.initB && !st[p.initA].empty()) {\n        if (!applyMove(st, ops, cost, p.initA, 0, p.initB, cutoff)) return invalidResult();\n    }\n\n    for (int v = 1; v <= nG; v++) {\n        while (true) {\n            auto [src, pos] = findBox(st, v);\n            if (src < 0) return invalidResult();\n\n            int h = (int)st[src].size();\n            if (pos == h - 1) break;\n\n            Choice ch = chooseActionByParams(st, src, pos, p, rng);\n            if (!applyMove(st, ops, cost, src, ch.cut, ch.dst, cutoff)) return invalidResult();\n        }\n\n        auto [src, pos] = findBox(st, v);\n        if (src < 0 || pos != (int)st[src].size() - 1) return invalidResult();\n\n        ops.push_back({v, 0});\n        st[src].pop_back();\n        if ((int)ops.size() > 5000) return invalidResult();\n    }\n\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return invalidResult();\n    return Result{ops, cost, true};\n}\n\nint stateBadCount(const StackArray& st) {\n    int cnt = 0;\n    for (int i = 0; i < mG; i++) {\n        int mn = INF;\n        for (int x : st[i]) {\n            if (x > mn) cnt++;\n            mn = min(mn, x);\n        }\n    }\n    return cnt;\n}\n\nint aboveMinTotal(const StackArray& st) {\n    int s = 0;\n    for (int i = 0; i < mG; i++) s += aboveMinCountOne(st[i]);\n    return s;\n}\n\ndouble beamEval(const StackArray& st, int cost, double alpha) {\n    return cost + alpha * stateBadCount(st) + 0.30 * alpha * aboveMinTotal(st);\n}\n\nstruct BeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateBeamWhole(const StackArray& init, int W, double alpha, int cutoff) {\n    BeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n    first.eval = beamEval(first.st, first.cost, alpha);\n\n    vector<BeamState> beam;\n    beam.push_back(first);\n\n    for (int v = 1; v <= nG; v++) {\n        vector<BeamState> cand;\n        cand.reserve(beam.size() * mG);\n\n        for (const auto& bs : beam) {\n            if (bs.cost >= cutoff) continue;\n\n            auto [src, pos] = findBox(bs.st, v);\n            if (src < 0) continue;\n\n            int h = (int)bs.st[src].size();\n\n            if (pos == h - 1) {\n                BeamState ns = bs;\n                ns.ops.push_back({v, 0});\n                ns.st[src].pop_back();\n                if ((int)ns.ops.size() > 5000) continue;\n                ns.eval = beamEval(ns.st, ns.cost, alpha);\n                cand.push_back(std::move(ns));\n            } else {\n                int cut = pos + 1;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n\n                    BeamState ns = bs;\n                    if (!applyMove(ns.st, ns.ops, ns.cost, src, cut, d, cutoff)) continue;\n                    if (ns.st[src].empty() || ns.st[src].back() != v) continue;\n\n                    ns.ops.push_back({v, 0});\n                    ns.st[src].pop_back();\n                    if ((int)ns.ops.size() > 5000) continue;\n\n                    ns.eval = beamEval(ns.st, ns.cost, alpha);\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const BeamState& a, const BeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        if ((int)cand.size() > W) cand.resize(W);\n        beam = std::move(cand);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n    if (best == -1) return invalidResult();\n\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nint validateCost(const StackArray& init, const vector<pair<int,int>>& ops) {\n    if ((int)ops.size() > 5000) return -1;\n\n    StackArray st = init;\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (auto [v, to] : ops) {\n        if (v < 1 || v > nG) return -1;\n\n        if (to == 0) {\n            if (v != nextRemove) return -1;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!st[s].empty() && st[s].back() == v) {\n                    st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n\n            if (!ok) return -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return -1;\n            int dst = to - 1;\n\n            int src = -1, pos = -1;\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)st[s].size(); j++) {\n                    if (st[s][j] == v) {\n                        src = s;\n                        pos = j;\n                    }\n                }\n            }\n\n            if (src == -1) return -1;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n\n            if (src != dst) {\n                st[dst].insert(st[dst].end(), st[src].begin() + pos, st[src].end());\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return -1;\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return -1;\n    return cost;\n}\n\nParams randomParams(XorShift& rng) {\n    Params p;\n\n    int r = rng.nextInt(100);\n    if (r < 12) p.mode = 0;\n    else if (r < 30) p.mode = 1;\n    else if (r < 82) p.mode = 2;\n    else p.mode = 3;\n\n    p.badMode = rng.nextInt(4);\n    p.goodMode = rng.nextInt(3);\n    p.thresholdMode = (rng.nextInt(100) < 85 ? 0 : 1);\n    p.destMode = rng.nextInt(4);\n\n    p.noise = rng.nextDouble() * 4.0;\n\n    p.lenW = 0.02 + rng.nextDouble() * 0.18;\n    p.dirtyW = 0.5 + rng.nextDouble() * 4.0;\n    p.badW = 1.0 + rng.nextDouble() * 6.0;\n    p.amountW = rng.nextDouble() * 0.25;\n    p.slackW = rng.nextDouble() * 0.08;\n    p.heightW = (rng.nextDouble() - 0.5) * 0.06;\n    p.gW = rng.nextDouble() * 0.20;\n\n    if (mG >= 2 && rng.nextInt(100) < 12) {\n        p.initA = rng.nextInt(mG);\n        p.initB = rng.nextInt(mG - 1);\n        if (p.initB >= p.initA) p.initB++;\n    }\n\n    return p;\n}\n\n/* ---------- Feature-based macro candidates ---------- */\n\nstruct Feature {\n    int bad = 0, above = 0, runs = 0, inc = 0, empty = 0;\n};\n\nFeature& operator+=(Feature& a, const Feature& b) {\n    a.bad += b.bad; a.above += b.above; a.runs += b.runs; a.inc += b.inc; a.empty += b.empty;\n    return a;\n}\n\nFeature& operator-=(Feature& a, const Feature& b) {\n    a.bad -= b.bad; a.above -= b.above; a.runs -= b.runs; a.inc -= b.inc; a.empty -= b.empty;\n    return a;\n}\n\nFeature calcFeatureParts(const vector<int>& A, int l1, int r1,\n                         const vector<int>& B, int l2, int r2) {\n    Feature f;\n    int len = (r1 - l1) + (r2 - l2);\n    if (len == 0) {\n        f.empty = 1;\n        return f;\n    }\n\n    int idx = 0, mnBelow = INF, minVal = INF, minPos = -1;\n    int prevVal = -1;\n    bool hasPrev = false, prevBad = false;\n\n    auto process = [&](int x) {\n        if (hasPrev && prevVal < x) f.inc++;\n\n        bool isBad = (x > mnBelow);\n        if (isBad) {\n            f.bad++;\n            if (!prevBad) f.runs++;\n        }\n        prevBad = isBad;\n\n        if (x < minVal) minVal = x, minPos = idx;\n\n        mnBelow = min(mnBelow, x);\n        prevVal = x;\n        hasPrev = true;\n        idx++;\n    };\n\n    for (int i = l1; i < r1; i++) process(A[i]);\n    for (int i = l2; i < r2; i++) process(B[i]);\n\n    f.above = len - minPos - 1;\n    return f;\n}\n\nFeature totalFeatures(const StackArray& st, array<Feature, MMAX>* per = nullptr) {\n    Feature total;\n    for (int i = 0; i < mG; i++) {\n        Feature fi = calcFeatureParts(st[i], 0, (int)st[i].size(), st[i], 0, 0);\n        if (per) (*per)[i] = fi;\n        total += fi;\n    }\n    return total;\n}\n\nstruct EvalParam {\n    double A = 2.7, B = 0.9, C = 1.2, D = 0.25, E = 2.0, F = 1.5, beta = 0.75;\n};\n\ndouble heuristicFeature(const Feature& f, const EvalParam& ep) {\n    return ep.A * f.bad + ep.B * f.above + ep.C * f.runs\n         + ep.D * f.inc - ep.E * f.empty;\n}\n\nint aboveBoxCount(const StackArray& st, int v) {\n    if (v > nG) return 0;\n    auto [s, p] = findBox(st, v);\n    if (s < 0) return 0;\n    return (int)st[s].size() - p - 1;\n}\n\ndouble heuristicState(const StackArray& st, int nextv, const EvalParam& ep) {\n    Feature f = totalFeatures(st, nullptr);\n    double h = heuristicFeature(f, ep);\n    if (nextv <= nG) h += ep.F * aboveBoxCount(st, nextv);\n    return h;\n}\n\nFeature featureAfterMoveContext(const StackArray& st,\n                                const array<Feature, MMAX>& sf,\n                                const Feature& total,\n                                int src, int pos, int cut, int dst,\n                                bool popIfExpose) {\n    int h = (int)st[src].size();\n    int srcEnd = cut;\n    if (popIfExpose && cut == pos + 1) srcEnd = pos;\n\n    Feature fsrc = calcFeatureParts(st[src], 0, srcEnd, st[src], 0, 0);\n    Feature fdst = calcFeatureParts(st[dst], 0, (int)st[dst].size(), st[src], cut, h);\n\n    Feature nf = total;\n    nf -= sf[src];\n    nf -= sf[dst];\n    nf += fsrc;\n    nf += fdst;\n    return nf;\n}\n\nuint64_t hashState(const StackArray& st) {\n    uint64_t h = 1469598103934665603ULL;\n    for (int i = 0; i < mG; i++) {\n        h ^= (uint64_t)(239 + i);\n        h *= 1099511628211ULL;\n        for (int x : st[i]) {\n            h ^= (uint64_t)(x + 1009);\n            h *= 1099511628211ULL;\n        }\n    }\n    return h;\n}\n\nstruct Macro {\n    StackArray st;\n    int addCost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n    bool ok = false;\n};\n\nMacro invalidMacro() {\n    Macro m;\n    m.ok = false;\n    m.addCost = INF;\n    return m;\n}\n\nbool macroMove(StackArray& st, vector<pair<int,int>>& ops, int& addCost,\n               int src, int cut, int dst, int cutoff) {\n    if (src == dst) return false;\n    if (src < 0 || src >= mG || dst < 0 || dst >= mG) return false;\n    if (cut < 0 || cut >= (int)st[src].size()) return false;\n\n    int len = (int)st[src].size() - cut;\n    if (addCost + len + 1 >= cutoff) return false;\n\n    int label = st[src][cut];\n    ops.push_back({label, dst + 1});\n    addCost += len + 1;\n\n    st[dst].insert(st[dst].end(), st[src].begin() + cut, st[src].end());\n    st[src].erase(st[src].begin() + cut, st[src].end());\n\n    return (int)ops.size() <= 5000;\n}\n\nbool macroRemove(StackArray& st, vector<pair<int,int>>& ops, int v) {\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return false;\n    if (pos != (int)st[src].size() - 1) return false;\n\n    ops.push_back({v, 0});\n    st[src].pop_back();\n    return (int)ops.size() <= 5000;\n}\n\nint bestDestByFeature(const StackArray& st, int src, int pos, int cut, const EvalParam& ep) {\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n    Stats bs = blockStats(st[src], cut);\n\n    int best = -1;\n    double bestScore = 1e100;\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n\n        Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n        double score = heuristicFeature(nf, ep);\n\n        int thr = minStackValue(st, d);\n        double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n\n        if (bs.maxv < thr) score += 0.0005 * thrNorm;\n        else score -= 0.0005 * thrNorm;\n\n        score += 0.00001 * (int)st[d].size();\n\n        if (score < bestScore) bestScore = score, best = d;\n    }\n\n    if (best == -1) for (int d = 0; d < mG; d++) if (d != src) return d;\n    return best;\n}\n\nvector<int> generateCutsForAction(const StackArray& st, int src, int pos, int maxCuts = 16) {\n    const auto& a = st[src];\n    int h = (int)a.size();\n    vector<int> cuts;\n\n    auto add = [&](int c) {\n        if (c > pos && c < h) cuts.push_back(c);\n    };\n\n    int c0 = topCleanStart(a, pos);\n    add(pos + 1);\n    add(h - 1);\n    add(c0);\n\n    int runLen = h - c0;\n    if (runLen <= 16) {\n        for (int c = c0; c < h; c++) add(c);\n    } else {\n        for (int t = 0; t < 10; t++) {\n            int c = c0 + (int)((long long)(runLen - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    int end = h, cnt = 0;\n    while (end > pos + 1 && cnt < 12) {\n        int start = end - 1;\n        while (start - 1 > pos && a[start - 1] > a[start]) start--;\n        add(start);\n        end = start;\n        cnt++;\n    }\n\n    int r = h - pos - 1;\n    if (r <= 18) {\n        for (int c = pos + 1; c < h; c++) add(c);\n    } else {\n        for (int t = 1; t <= 8; t++) {\n            int c = pos + 1 + (int)((long long)(r - 1) * t / 9);\n            add(c);\n        }\n    }\n\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        int thr = minStackValue(st, d);\n        int mx = -1, best = -1;\n        for (int c = h - 1; c > pos; c--) {\n            mx = max(mx, a[c]);\n            if (mx < thr) best = c;\n            else break;\n        }\n        if (best != -1) add(best);\n    }\n\n    sort(cuts.begin(), cuts.end());\n    cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n    if ((int)cuts.size() > maxCuts) {\n        vector<int> old = cuts, nc;\n        auto add2 = [&](int c) {\n            if (c > pos && c < h) nc.push_back(c);\n        };\n\n        add2(pos + 1);\n        add2(h - 1);\n        add2(c0);\n\n        int samples = max(1, maxCuts - 3);\n        for (int t = 0; t < samples; t++) {\n            int idx = (int)((long long)(old.size() - 1) * t / max(1, samples - 1));\n            add2(old[idx]);\n        }\n\n        sort(nc.begin(), nc.end());\n        nc.erase(unique(nc.begin(), nc.end()), nc.end());\n        cuts = nc;\n    }\n\n    return cuts;\n}\n\nstruct Action {\n    int cut = -1, dst = -1;\n    double score = 1e100;\n};\n\nvector<Action> getTopActions(const StackArray& st, int src, int pos,\n                             const EvalParam& ep, double beta, int limit) {\n    vector<Action> actions;\n    if (limit <= 0) return actions;\n\n    auto cuts = generateCutsForAction(st, src, pos, 16);\n    array<Feature, MMAX> sf;\n    Feature total = totalFeatures(st, &sf);\n    int h = (int)st[src].size();\n\n    for (int cut : cuts) {\n        Stats bs = blockStats(st[src], cut);\n        int len = h - cut;\n\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n\n            Feature nf = featureAfterMoveContext(st, sf, total, src, pos, cut, d, true);\n            double sc = (len + 1) + beta * heuristicFeature(nf, ep);\n\n            int thr = minStackValue(st, d);\n            double thrNorm = (thr >= INF / 2 ? 300.0 : (double)thr);\n            int badCnt = countGreaterThan(st[src], cut, thr);\n\n            if (bs.maxv < thr) {\n                sc += 0.0002 * thrNorm;\n                if (bs.internalBad == 0) sc -= 0.05 * bs.len;\n            } else {\n                sc += 0.20 * badCnt;\n                sc -= 0.0002 * thrNorm;\n            }\n\n            sc += 0.10 * bs.internalBad;\n            actions.push_back({cut, d, sc});\n        }\n    }\n\n    sort(actions.begin(), actions.end(), [](const Action& a, const Action& b) {\n        if (a.score != b.score) return a.score < b.score;\n        if (a.cut != b.cut) return a.cut < b.cut;\n        return a.dst < b.dst;\n    });\n\n    if ((int)actions.size() > limit) actions.resize(limit);\n    return actions;\n}\n\nvector<Macro> generateClearBeamMacros(const StackArray& st, int v, const EvalParam& ep,\n                                      int cutoff, int beamW, int outLimit, int actionLimit) {\n    vector<Macro> done;\n\n    auto [s0, p0] = findBox(st, v);\n    if (s0 < 0) return done;\n\n    int initialBlockers = (int)st[s0].size() - p0 - 1;\n    if (initialBlockers <= 0 || initialBlockers > g_clearMaxBlockers) return done;\n\n    struct Node {\n        StackArray st;\n        int cost = 0;\n        vector<pair<int,int>> ops;\n        double eval = 0.0;\n    };\n\n    Node first;\n    first.st = st;\n    first.eval = heuristicState(first.st, v, ep);\n\n    vector<Node> beam;\n    beam.push_back(std::move(first));\n\n    int maxSteps = min(initialBlockers, 10);\n\n    for (int step = 0; step <= maxSteps; step++) {\n        vector<Node> nxt;\n\n        for (const Node& nd : beam) {\n            auto [src, pos] = findBox(nd.st, v);\n            if (src < 0) continue;\n\n            int h = (int)nd.st[src].size();\n\n            if (pos == h - 1) {\n                Macro mo;\n                mo.st = nd.st;\n                mo.addCost = nd.cost;\n                mo.ops = nd.ops;\n\n                if (macroRemove(mo.st, mo.ops, v)) {\n                    mo.ok = true;\n                    mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n                    done.push_back(std::move(mo));\n                }\n                continue;\n            }\n\n            if (step == maxSteps) continue;\n\n            vector<Action> acts = getTopActions(nd.st, src, pos, ep, ep.beta, actionLimit);\n\n            auto addAction = [&](int cut) {\n                if (cut <= pos || cut >= h) return;\n                int dst = bestDestByFeature(nd.st, src, pos, cut, ep);\n                acts.push_back({cut, dst, 1e50});\n            };\n\n            addAction(pos + 1);\n            addAction(h - 1);\n            addAction(topCleanStart(nd.st[src], pos));\n\n            sort(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                if (a.cut != b.cut) return a.cut < b.cut;\n                return a.dst < b.dst;\n            });\n\n            acts.erase(unique(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                return a.cut == b.cut && a.dst == b.dst;\n            }), acts.end());\n\n            sort(acts.begin(), acts.end(), [](const Action& a, const Action& b) {\n                return a.score < b.score;\n            });\n\n            if ((int)acts.size() > actionLimit + 3) acts.resize(actionLimit + 3);\n\n            for (const Action& ac : acts) {\n                if (ac.cut <= pos || ac.cut >= h || ac.dst == src || ac.dst < 0 || ac.dst >= mG) continue;\n\n                Node nn = nd;\n                if (!macroMove(nn.st, nn.ops, nn.cost, src, ac.cut, ac.dst, cutoff)) continue;\n\n                nn.eval = nn.cost + 0.65 * heuristicState(nn.st, v, ep)\n                        + 0.40 * aboveBoxCount(nn.st, v);\n                nxt.push_back(std::move(nn));\n            }\n        }\n\n        if (nxt.empty()) break;\n\n        sort(nxt.begin(), nxt.end(), [](const Node& a, const Node& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            return a.cost < b.cost;\n        });\n\n        vector<Node> nb;\n        nb.reserve(beamW);\n        unordered_set<uint64_t> seen;\n        seen.reserve(nxt.size() * 2 + 10);\n\n        for (auto& x : nxt) {\n            uint64_t hs = hashState(x.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(x));\n                if ((int)nb.size() >= beamW) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    sort(done.begin(), done.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.addCost < b.addCost;\n    });\n\n    vector<Macro> out;\n    out.reserve(outLimit);\n    unordered_set<uint64_t> seen;\n    seen.reserve(done.size() * 2 + 10);\n\n    for (auto& mo : done) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= outLimit) break;\n        }\n    }\n\n    return out;\n}\n\nMacro completePolicy(const StackArray& input, int v, int policy,\n                     const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        int cut = -1, dst = -1;\n\n        if (policy == 0) {\n            int c0 = topCleanStart(mo.st[src], pos);\n            for (int c = c0; c < h; c++) {\n                Stats bs = blockStats(mo.st[src], c);\n                bool good = false;\n                for (int d = 0; d < mG; d++) {\n                    if (d == src) continue;\n                    if (bs.maxv < minStackValue(mo.st, d)) {\n                        good = true;\n                        break;\n                    }\n                }\n                if (good) {\n                    cut = c;\n                    break;\n                }\n            }\n            if (cut == -1) cut = c0;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 1) {\n            cut = topCleanStart(mo.st[src], pos);\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 2) {\n            cut = h - 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else if (policy == 3) {\n            cut = pos + 1;\n            dst = bestDestByFeature(mo.st, src, pos, cut, ep);\n        } else {\n            auto acts = getTopActions(mo.st, src, pos, ep, ep.beta, 1);\n            if (acts.empty()) return invalidMacro();\n            cut = acts[0].cut;\n            dst = acts[0].dst;\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, cut, dst, cutoff)) return invalidMacro();\n    }\n}\n\nMacro completeCurrentByParams(const StackArray& input, int v, Params p,\n                              const EvalParam& ep, int cutoff) {\n    Macro mo;\n    mo.st = input;\n    mo.addCost = 0;\n    mo.ops.reserve(256);\n    mo.ok = false;\n\n    XorShift rng(5555555ULL + (uint64_t)p.mode * 10007ULL + (uint64_t)p.destMode * 101ULL);\n\n    int guard = 0;\n    while (true) {\n        if (++guard > 1000) return invalidMacro();\n\n        auto [src, pos] = findBox(mo.st, v);\n        if (src < 0) return invalidMacro();\n\n        int h = (int)mo.st[src].size();\n\n        if (pos == h - 1) {\n            if (!macroRemove(mo.st, mo.ops, v)) return invalidMacro();\n            mo.ok = true;\n            mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n            return mo;\n        }\n\n        Choice ch = chooseActionByParams(mo.st, src, pos, p, rng);\n        if (ch.cut <= pos || ch.cut >= h || ch.dst == src || ch.dst < 0 || ch.dst >= mG) {\n            return invalidMacro();\n        }\n\n        if (!macroMove(mo.st, mo.ops, mo.addCost, src, ch.cut, ch.dst, cutoff)) return invalidMacro();\n    }\n}\n\nvector<Macro> generateMacros(const StackArray& st, int v,\n                             const EvalParam& ep, int cutoff, int limit) {\n    vector<Macro> res;\n\n    auto [src, pos] = findBox(st, v);\n    if (src < 0) return res;\n\n    int h = (int)st[src].size();\n\n    auto pushMacro = [&](Macro&& mo) {\n        if (!mo.ok) return;\n        if (mo.addCost >= cutoff) return;\n        if ((int)mo.ops.size() > 5000) return;\n        mo.eval = mo.addCost + heuristicState(mo.st, v + 1, ep);\n        res.push_back(std::move(mo));\n    };\n\n    if (pos == h - 1) {\n        Macro mo;\n        mo.st = st;\n        if (macroRemove(mo.st, mo.ops, v)) {\n            mo.ok = true;\n            pushMacro(std::move(mo));\n        }\n        return res;\n    }\n\n    int r = h - pos - 1;\n\n    pushMacro(completePolicy(st, v, 0, ep, cutoff));\n    pushMacro(completePolicy(st, v, 1, ep, cutoff));\n    pushMacro(completePolicy(st, v, 2, ep, cutoff));\n    if (r <= 60) pushMacro(completePolicy(st, v, 4, ep, cutoff));\n\n    auto addFirstFinish = [&](int cut, int dst, int finishPolicy) {\n        StackArray tmp = st;\n        vector<pair<int,int>> ops;\n        ops.reserve(256);\n        int cst = 0;\n\n        if (!macroMove(tmp, ops, cst, src, cut, dst, cutoff)) return;\n\n        Macro rest = completePolicy(tmp, v, finishPolicy, ep, cutoff - cst);\n        if (!rest.ok) return;\n\n        Macro mo;\n        mo.st = rest.st;\n        mo.addCost = cst + rest.addCost;\n        mo.ops = std::move(ops);\n        mo.ops.insert(mo.ops.end(), rest.ops.begin(), rest.ops.end());\n        mo.ok = true;\n        pushMacro(std::move(mo));\n    };\n\n    int wholeCut = pos + 1;\n    for (int d = 0; d < mG; d++) {\n        if (d == src) continue;\n        addFirstFinish(wholeCut, d, 0);\n    }\n\n    int cleanCut = topCleanStart(st[src], pos);\n    if (cleanCut != wholeCut) {\n        for (int d = 0; d < mG; d++) {\n            if (d == src) continue;\n            addFirstFinish(cleanCut, d, 0);\n        }\n    }\n\n    int firstLimit = (r <= 8 ? 8 : 6);\n    auto acts = getTopActions(st, src, pos, ep, ep.beta, firstLimit);\n    for (const auto& ac : acts) addFirstFinish(ac.cut, ac.dst, 0);\n\n    if (g_useClearBeam && r <= g_clearMaxBlockers) {\n        int bw = (r <= 35 ? 6 : 4);\n        int ol = (r <= 35 ? 6 : 4);\n        int al = (r <= 35 ? 6 : 5);\n        auto bm = generateClearBeamMacros(st, v, ep, cutoff, bw, ol, al);\n        for (auto& mo : bm) pushMacro(std::move(mo));\n    }\n\n    sort(res.begin(), res.end(), [](const Macro& a, const Macro& b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        if (a.addCost != b.addCost) return a.addCost < b.addCost;\n        return a.ops.size() < b.ops.size();\n    });\n\n    vector<Macro> out;\n    out.reserve(min(limit, (int)res.size()));\n    unordered_set<uint64_t> seen;\n    seen.reserve(res.size() * 2 + 10);\n\n    for (auto& mo : res) {\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) {\n            out.push_back(std::move(mo));\n            if ((int)out.size() >= limit) break;\n        }\n    }\n\n    return out;\n}\n\nvector<Macro> collectMacroCandidates(const StackArray& st, int v,\n                                     const vector<Params>& macroParams,\n                                     const EvalParam& ep,\n                                     int remainCutoff,\n                                     int currentOpsSize,\n                                     int candidateLimit) {\n    vector<Macro> candidates;\n    candidates.reserve(candidateLimit + (int)macroParams.size() + 5);\n\n    unordered_set<uint64_t> seen;\n    seen.reserve(128);\n\n    auto addCandidate = [&](Macro&& mo) {\n        if (!mo.ok) return;\n        if (mo.addCost >= remainCutoff) return;\n        if (currentOpsSize + (int)mo.ops.size() > 5000) return;\n\n        uint64_t hs = hashState(mo.st);\n        if (seen.insert(hs).second) candidates.push_back(std::move(mo));\n    };\n\n    for (const Params& p : macroParams) {\n        Macro mo = completeCurrentByParams(st, v, p, ep, remainCutoff);\n        addCandidate(std::move(mo));\n    }\n\n    auto base = generateMacros(st, v, ep, remainCutoff, candidateLimit);\n    for (auto& mo : base) {\n        if ((int)candidates.size() >= candidateLimit) break;\n        addCandidate(std::move(mo));\n    }\n\n    return candidates;\n}\n\nstruct MacroBeamState {\n    StackArray st;\n    int cost = 0;\n    vector<pair<int,int>> ops;\n    double eval = 0.0;\n};\n\nResult simulateMacroRollout(const StackArray& init,\n                            const vector<Params>& macroParams,\n                            const vector<Params>& evalParams,\n                            const EvalParam& ep,\n                            int cutoff,\n                            chrono::steady_clock::time_point deadline,\n                            int candidateLimit,\n                            int startV = 1) {\n    StackArray st = init;\n    for (auto& v : st) v.reserve(nG);\n\n    vector<pair<int,int>> ops;\n    ops.reserve(6000);\n    int cost = 0;\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) {\n            if (!evalParams.empty()) {\n                Result tail = completeOpsPolicy(st, v, evalParams[0], cutoff - cost);\n                if (tail.ok) {\n                    ops.insert(ops.end(), tail.ops.begin(), tail.ops.end());\n                    if ((int)ops.size() <= 5000) return Result{ops, cost + tail.cost, true};\n                }\n            }\n            return invalidResult();\n        }\n\n        int remainCutoff = cutoff - cost;\n        if (remainCutoff <= 0) return invalidResult();\n\n        vector<Macro> candidates = collectMacroCandidates(\n            st, v, macroParams, ep, remainCutoff, (int)ops.size(), candidateLimit\n        );\n\n        if (candidates.empty()) return invalidResult();\n\n        int bestIdx = -1;\n        int bestEval = INF;\n\n        for (int i = 0; i < (int)candidates.size(); i++) {\n            if (chrono::steady_clock::now() > deadline) break;\n\n            const Macro& mo = candidates[i];\n            if (mo.addCost >= remainCutoff) continue;\n\n            int remLimit = remainCutoff - mo.addCost;\n            int cc = completeCostMulti(mo.st, v + 1, evalParams, remLimit);\n            if (cc >= INF) continue;\n\n            int val = mo.addCost + cc;\n            if (val < bestEval) bestEval = val, bestIdx = i;\n        }\n\n        if (bestIdx == -1) {\n            if (!evalParams.empty()) {\n                Result tail = completeOpsPolicy(st, v, evalParams[0], cutoff - cost);\n                if (tail.ok) {\n                    ops.insert(ops.end(), tail.ops.begin(), tail.ops.end());\n                    if ((int)ops.size() <= 5000) return Result{ops, cost + tail.cost, true};\n                }\n            }\n            return invalidResult();\n        }\n\n        Macro& ch = candidates[bestIdx];\n        cost += ch.addCost;\n        ops.insert(ops.end(), ch.ops.begin(), ch.ops.end());\n\n        if (cost >= cutoff || (int)ops.size() > 5000) return invalidResult();\n\n        st = std::move(ch.st);\n    }\n\n    for (int i = 0; i < mG; i++) if (!st[i].empty()) return invalidResult();\n    return Result{ops, cost, true};\n}\n\nResult simulateMacroRolloutBeam(const StackArray& init,\n                                int startV,\n                                int W,\n                                const vector<Params>& macroParams,\n                                const vector<Params>& evalParams,\n                                const EvalParam& ep,\n                                int cutoff,\n                                chrono::steady_clock::time_point deadline,\n                                int candidateLimit) {\n    MacroBeamState first;\n    first.st = init;\n    for (auto& v : first.st) v.reserve(nG);\n\n    vector<MacroBeamState> beam;\n    beam.push_back(std::move(first));\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) return invalidResult();\n\n        vector<MacroBeamState> cand;\n        cand.reserve(W * candidateLimit);\n\n        for (const auto& bs : beam) {\n            if (chrono::steady_clock::now() > deadline) return invalidResult();\n            if (bs.cost >= cutoff) continue;\n\n            int remainCutoff = cutoff - bs.cost;\n            auto macros = collectMacroCandidates(bs.st, v, macroParams, ep, remainCutoff,\n                                                 (int)bs.ops.size(), candidateLimit);\n\n            for (auto& mo : macros) {\n                int nc = bs.cost + mo.addCost;\n                if (nc >= cutoff) continue;\n\n                int cc = completeCostMulti(mo.st, v + 1, evalParams, cutoff - nc);\n                if (cc >= INF) continue;\n\n                MacroBeamState ns;\n                ns.st = std::move(mo.st);\n                ns.cost = nc;\n                ns.ops = bs.ops;\n                ns.ops.insert(ns.ops.end(), mo.ops.begin(), mo.ops.end());\n                if ((int)ns.ops.size() > 5000) continue;\n\n                ns.eval = nc + cc;\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const MacroBeamState& a, const MacroBeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.ops.size() < b.ops.size();\n        });\n\n        vector<MacroBeamState> nb;\n        nb.reserve(W);\n        unordered_set<uint64_t> seen;\n        seen.reserve(cand.size() * 2 + 10);\n\n        for (auto& c : cand) {\n            uint64_t hs = hashState(c.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(c));\n                if ((int)nb.size() >= W) break;\n            }\n        }\n\n        if (nb.empty()) return invalidResult();\n        beam = std::move(nb);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n\n    if (best == -1) return invalidResult();\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nResult simulateTailMacroBeam(const StackArray& initState, int startV, int W,\n                             const EvalParam& ep, int cutoff,\n                             chrono::steady_clock::time_point deadline,\n                             int perStateLimit) {\n    if (startV > nG) return Result{{}, 0, true};\n\n    MacroBeamState first;\n    first.st = initState;\n    for (auto& v : first.st) v.reserve(nG);\n    first.eval = heuristicState(first.st, startV, ep);\n\n    vector<MacroBeamState> beam;\n    beam.push_back(std::move(first));\n\n    for (int v = startV; v <= nG; v++) {\n        if (chrono::steady_clock::now() > deadline) return invalidResult();\n\n        vector<MacroBeamState> cand;\n        cand.reserve(beam.size() * perStateLimit);\n\n        for (const auto& bs : beam) {\n            if (chrono::steady_clock::now() > deadline) return invalidResult();\n            if (bs.cost >= cutoff) continue;\n\n            auto macros = generateMacros(bs.st, v, ep, cutoff - bs.cost, perStateLimit);\n\n            for (auto& mo : macros) {\n                int nc = bs.cost + mo.addCost;\n                if (nc >= cutoff) continue;\n\n                MacroBeamState ns;\n                ns.st = std::move(mo.st);\n                ns.cost = nc;\n                ns.ops = bs.ops;\n                ns.ops.insert(ns.ops.end(), mo.ops.begin(), mo.ops.end());\n\n                if ((int)ns.ops.size() > 5000) continue;\n\n                ns.eval = ns.cost + heuristicState(ns.st, v + 1, ep);\n                cand.push_back(std::move(ns));\n            }\n        }\n\n        if (cand.empty()) return invalidResult();\n\n        sort(cand.begin(), cand.end(), [](const MacroBeamState& a, const MacroBeamState& b) {\n            if (a.eval != b.eval) return a.eval < b.eval;\n            if (a.cost != b.cost) return a.cost < b.cost;\n            return a.ops.size() < b.ops.size();\n        });\n\n        vector<MacroBeamState> nb;\n        nb.reserve(W);\n        unordered_set<uint64_t> seen;\n        seen.reserve(cand.size() * 2 + 10);\n\n        for (auto& c : cand) {\n            uint64_t hs = hashState(c.st);\n            if (seen.insert(hs).second) {\n                nb.push_back(std::move(c));\n                if ((int)nb.size() >= W) break;\n            }\n        }\n\n        if (nb.empty()) return invalidResult();\n        beam = std::move(nb);\n    }\n\n    int best = -1;\n    for (int i = 0; i < (int)beam.size(); i++) {\n        if (best == -1 || beam[i].cost < beam[best].cost) best = i;\n    }\n\n    if (best == -1) return invalidResult();\n    return Result{beam[best].ops, beam[best].cost, true};\n}\n\nstruct PrefixResult {\n    StackArray st;\n    vector<pair<int,int>> ops;\n    int cost = 0;\n    bool ok = false;\n};\n\nPrefixResult extractPrefix(const StackArray& init, const vector<pair<int,int>>& fullOps, int stopV) {\n    PrefixResult pr;\n    pr.st = init;\n    pr.ops.reserve(fullOps.size());\n\n    if (stopV == 0) {\n        pr.ok = true;\n        return pr;\n    }\n\n    int nextRemove = 1;\n\n    for (auto [v, to] : fullOps) {\n        if (to == 0) {\n            if (v != nextRemove) return pr;\n\n            bool ok = false;\n            for (int s = 0; s < mG; s++) {\n                if (!pr.st[s].empty() && pr.st[s].back() == v) {\n                    pr.st[s].pop_back();\n                    ok = true;\n                    break;\n                }\n            }\n\n            if (!ok) return pr;\n\n            pr.ops.push_back({v, 0});\n            nextRemove++;\n\n            if (v == stopV) {\n                pr.ok = true;\n                return pr;\n            }\n        } else {\n            int dst = to - 1;\n            int src = -1, pos = -1;\n\n            for (int s = 0; s < mG; s++) {\n                for (int j = 0; j < (int)pr.st[s].size(); j++) {\n                    if (pr.st[s][j] == v) src = s, pos = j;\n                }\n            }\n\n            if (src < 0) return pr;\n\n            int len = (int)pr.st[src].size() - pos;\n            pr.cost += len + 1;\n            pr.ops.push_back({v, to});\n\n            if (src != dst) {\n                pr.st[dst].insert(pr.st[dst].end(), pr.st[src].begin() + pos, pr.st[src].end());\n                pr.st[src].erase(pr.st[src].begin() + pos, pr.st[src].end());\n            }\n        }\n    }\n\n    return pr;\n}\n\n/* ---------- Fast fixed-sequence simulator and local optimizer ---------- */\n\nstruct FastMoveInfo {\n    int idx = -1, len = 0, src = -1, dst = -1, v = -1, to = -1;\n    vector<int> block;\n    vector<int> below;\n};\n\nint simulateOpsFast(const StackArray& init,\n                    const vector<pair<int,int>>& ops,\n                    int changeIdx = -1,\n                    int newV = -1,\n                    int newTo = -1,\n                    int skipIdx = -1,\n                    int cutoff = INF,\n                    vector<FastMoveInfo>* rec = nullptr) {\n    if ((int)ops.size() > 5000) return INF;\n\n    StackArray st = init;\n    array<int, 205> ps, pi;\n    ps.fill(-1);\n    pi.fill(-1);\n\n    for (int s = 0; s < mG; s++) {\n        for (int j = 0; j < (int)st[s].size(); j++) {\n            int x = st[s][j];\n            ps[x] = s;\n            pi[x] = j;\n        }\n    }\n\n    if (rec) rec->clear();\n\n    int nextRemove = 1;\n    int cost = 0;\n\n    for (int k = 0; k < (int)ops.size(); k++) {\n        if (k == skipIdx) continue;\n\n        int v = ops[k].first;\n        int to = ops[k].second;\n\n        if (k == changeIdx) {\n            if (newV != -1) v = newV;\n            if (newTo != -1) to = newTo;\n        }\n\n        if (v < 1 || v > nG) return INF;\n\n        if (to == 0) {\n            if (v != nextRemove) return INF;\n\n            int s = ps[v];\n            if (s < 0) return INF;\n\n            int idx = pi[v];\n            if (idx != (int)st[s].size() - 1) return INF;\n\n            st[s].pop_back();\n            ps[v] = pi[v] = -1;\n            nextRemove++;\n        } else {\n            if (to < 1 || to > mG) return INF;\n\n            int dst = to - 1;\n            int src = ps[v];\n            if (src < 0) return INF;\n\n            int pos = pi[v];\n            if (pos < 0 || pos >= (int)st[src].size() || st[src][pos] != v) return INF;\n\n            int len = (int)st[src].size() - pos;\n            cost += len + 1;\n            if (cost >= cutoff) return INF;\n\n            vector<int> moved;\n            if (rec || src != dst) {\n                moved.assign(st[src].begin() + pos, st[src].end());\n            }\n\n            if (rec) {\n                FastMoveInfo info;\n                info.idx = k;\n                info.len = len;\n                info.src = src;\n                info.dst = dst;\n                info.v = v;\n                info.to = to;\n                info.block = moved;\n\n                int maxBelow = min(pos, 8);\n                for (int d = 1; d <= maxBelow; d++) {\n                    info.below.push_back(st[src][pos - d]);\n                }\n\n                int cleanStart = pos;\n                while (cleanStart - 1 >= 0 && st[src][cleanStart - 1] > st[src][cleanStart]) {\n                    cleanStart--;\n                }\n                if (cleanStart < pos) info.below.push_back(st[src][cleanStart]);\n\n                if (pos > 8) info.below.push_back(st[src][max(0, pos - 12)]);\n                if (pos > 0) info.below.push_back(st[src][0]);\n\n                rec->push_back(std::move(info));\n            }\n\n            if (src != dst) {\n                int oldDst = (int)st[dst].size();\n\n                st[dst].insert(st[dst].end(), moved.begin(), moved.end());\n                for (int t = 0; t < (int)moved.size(); t++) {\n                    int x = moved[t];\n                    ps[x] = dst;\n                    pi[x] = oldDst + t;\n                }\n\n                st[src].erase(st[src].begin() + pos, st[src].end());\n            }\n        }\n    }\n\n    if (nextRemove != nG + 1) return INF;\n    for (int s = 0; s < mG; s++) if (!st[s].empty()) return INF;\n\n    return cost;\n}\n\nvoid improveByLocalDest(const StackArray& init,\n                        Result& best,\n                        chrono::steady_clock::time_point deadline) {\n    if (!best.ok) return;\n\n    for (int iter = 0; iter < 78; iter++) {\n        if (chrono::steady_clock::now() > deadline) return;\n\n        vector<FastMoveInfo> rec;\n        int cur = simulateOpsFast(init, best.ops, -1, -1, -1, -1, INF, &rec);\n        if (cur >= INF) return;\n        best.cost = cur;\n\n        sort(rec.begin(), rec.end(), [](const FastMoveInfo& a, const FastMoveInfo& b) {\n            if (a.len != b.len) return a.len > b.len;\n            return a.idx > b.idx;\n        });\n\n        bool changed = false;\n\n        // 1. Delete one redundant move.\n        for (const auto& info : rec) {\n            if (chrono::steady_clock::now() > deadline) return;\n\n            int nc = simulateOpsFast(init, best.ops, -1, -1, -1, info.idx, best.cost, nullptr);\n            if (nc < best.cost) {\n                best.ops.erase(best.ops.begin() + info.idx);\n                best.cost = nc;\n                changed = true;\n                break;\n            }\n        }\n        if (changed) continue;\n\n        // 1b. New: delete two moves simultaneously.\n        {\n            int tested = 0;\n            int limA = min((int)rec.size(), 34);\n\n            for (int a = 0; a < limA; a++) {\n                if (chrono::steady_clock::now() > deadline) return;\n\n                for (int b = a + 1; b < min((int)rec.size(), a + 18); b++) {\n                    if (chrono::steady_clock::now() > deadline) return;\n\n                    int i = rec[a].idx, j = rec[b].idx;\n                    if (i == j) continue;\n                    if (i > j) swap(i, j);\n\n                    vector<pair<int,int>> cand = best.ops;\n                    cand.erase(cand.begin() + j);\n                    cand.erase(cand.begin() + i);\n\n                    int nc = simulateOpsFast(init, cand, -1, -1, -1, -1, best.cost, nullptr);\n                    tested++;\n\n                    if (nc < best.cost) {\n                        best.ops = std::move(cand);\n                        best.cost = nc;\n                        changed = true;\n                        break;\n                    }\n\n                    if (tested >= 170) break;\n                }\n\n                if (changed || tested >= 170) break;\n            }\n        }\n        if (changed) continue;\n\n        // 2. Redirect/shorten earlier move and delete a later move together.\n        {\n            int tested = 0;\n\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n                if (info.block.empty()) continue;\n\n                bool inBlock[205] = {};\n                for (int x : info.block) if (1 <= x && x <= nG) inBlock[x] = true;\n\n                int end = min((int)best.ops.size(), info.idx + 130);\n\n                for (int j = info.idx + 1; j < end; j++) {\n                    if (chrono::steady_clock::now() > deadline) return;\n                    if (best.ops[j].second == 0) continue;\n\n                    int lbl = best.ops[j].first;\n                    if (lbl < 1 || lbl > nG) continue;\n                    if (!inBlock[lbl]) continue;\n\n                    vector<int> tos;\n                    tos.push_back(best.ops[j].second);\n                    tos.push_back(info.dst + 1);\n                    sort(tos.begin(), tos.end());\n                    tos.erase(unique(tos.begin(), tos.end()), tos.end());\n\n                    for (int to : tos) {\n                        if (to < 1 || to > mG) continue;\n                        if (to == info.src + 1) continue;\n\n                        int nc = simulateOpsFast(init, best.ops, info.idx, -1, to, j, best.cost, nullptr);\n                        tested++;\n                        if (nc < best.cost) {\n                            best.ops[info.idx].second = to;\n                            best.ops.erase(best.ops.begin() + j);\n                            best.cost = nc;\n                            changed = true;\n                            break;\n                        }\n\n                        if (lbl != info.v) {\n                            nc = simulateOpsFast(init, best.ops, info.idx, lbl, to, j, best.cost, nullptr);\n                            tested++;\n                            if (nc < best.cost) {\n                                best.ops[info.idx].first = lbl;\n                                best.ops[info.idx].second = to;\n                                best.ops.erase(best.ops.begin() + j);\n                                best.cost = nc;\n                                changed = true;\n                                break;\n                            }\n                        }\n\n                        if (tested >= 220) break;\n                    }\n\n                    if (changed || tested >= 220) break;\n                }\n\n                if (changed || tested >= 220) break;\n            }\n        }\n        if (changed) continue;\n\n        // 3. Pull a later suffix move before a larger earlier move.\n        {\n            int tested = 0;\n\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n                if (info.len <= 1 || info.block.empty()) continue;\n\n                bool inBlock[205] = {};\n                for (int x : info.block) if (1 <= x && x <= nG) inBlock[x] = true;\n\n                int end = min((int)best.ops.size(), info.idx + 90);\n\n                for (int j = info.idx + 1; j < end; j++) {\n                    if (chrono::steady_clock::now() > deadline) return;\n                    if (best.ops[j].second == 0) continue;\n\n                    int lbl = best.ops[j].first;\n                    if (lbl < 1 || lbl > nG) continue;\n                    if (!inBlock[lbl] || lbl == info.v) continue;\n\n                    vector<pair<int,int>> cand = best.ops;\n                    auto opB = cand[j];\n                    cand.erase(cand.begin() + j);\n                    cand.insert(cand.begin() + info.idx, opB);\n\n                    int nc = simulateOpsFast(init, cand, -1, -1, -1, -1, best.cost, nullptr);\n                    tested++;\n\n                    if (nc < best.cost) {\n                        best.ops = std::move(cand);\n                        best.cost = nc;\n                        changed = true;\n                        break;\n                    }\n\n                    if (tested >= 180) break;\n                }\n\n                if (changed || tested >= 180) break;\n            }\n        }\n        if (changed) continue;\n\n        // 4. General local reorder.\n        {\n            int tested = 0;\n\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n\n                int i = info.idx;\n                int end = min((int)best.ops.size(), i + 55);\n\n                for (int j = i + 1; j < end; j++) {\n                    if (chrono::steady_clock::now() > deadline) return;\n                    if (best.ops[j].second == 0) continue;\n\n                    vector<pair<int,int>> cand = best.ops;\n                    auto opB = cand[j];\n                    cand.erase(cand.begin() + j);\n                    cand.insert(cand.begin() + i, opB);\n\n                    int nc = simulateOpsFast(init, cand, -1, -1, -1, -1, best.cost, nullptr);\n                    tested++;\n\n                    if (nc < best.cost) {\n                        best.ops = std::move(cand);\n                        best.cost = nc;\n                        changed = true;\n                        break;\n                    }\n\n                    if (tested >= 90) break;\n                }\n\n                if (changed || tested >= 90) break;\n            }\n        }\n        if (changed) continue;\n\n        // 5. Lengthen/group a move by choosing a slightly lower label.\n        {\n            int tested = 0;\n\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n                if (info.below.empty()) continue;\n\n                bool seenLabel[205] = {};\n                vector<int> labels;\n\n                for (int x : info.below) {\n                    if (x < 1 || x > nG) continue;\n                    if (x == info.v) continue;\n                    if (!seenLabel[x]) {\n                        seenLabel[x] = true;\n                        labels.push_back(x);\n                    }\n                }\n\n                int bestV = -1, bestTo = -1, bestNc = best.cost;\n                int labelTry = 0;\n\n                for (int nv : labels) {\n                    if (++labelTry > 8) break;\n\n                    auto tryTo = [&](int to) {\n                        if (to < 1 || to > mG) return;\n                        if (to == info.src + 1) return;\n                        if (chrono::steady_clock::now() > deadline) return;\n\n                        int nc = simulateOpsFast(init, best.ops, info.idx, nv, to, -1, bestNc, nullptr);\n                        tested++;\n\n                        if (nc < bestNc) {\n                            bestNc = nc;\n                            bestV = nv;\n                            bestTo = to;\n                        }\n                    };\n\n                    tryTo(info.dst + 1);\n\n                    if (labelTry <= 3) {\n                        for (int to = 1; to <= mG; to++) {\n                            if (to == info.dst + 1) continue;\n                            tryTo(to);\n                            if (tested >= 180) break;\n                        }\n                    }\n\n                    if (tested >= 180) break;\n                }\n\n                if (bestV != -1) {\n                    best.ops[info.idx].first = bestV;\n                    best.ops[info.idx].second = bestTo;\n                    best.cost = bestNc;\n                    changed = true;\n                    break;\n                }\n\n                if (tested >= 180) break;\n            }\n        }\n        if (changed) continue;\n\n        // 6. Shorten a move by changing its label to an upper box.\n        {\n            int tested = 0;\n\n            for (const auto& info : rec) {\n                if (chrono::steady_clock::now() > deadline) return;\n                if (info.len <= 1 || (int)info.block.size() != info.len) continue;\n\n                vector<int> offs;\n\n                auto addOff = [&](int x) {\n                    if (x > 0 && x < info.len) offs.push_back(x);\n                };\n\n                for (int x = 1; x <= min(info.len - 1, 5); x++) addOff(x);\n                addOff(info.len / 2);\n                addOff(info.len - 1);\n\n                int clean = info.len - 1;\n                while (clean - 1 >= 0 && info.block[clean - 1] > info.block[clean]) clean--;\n                addOff(clean);\n\n                sort(offs.begin(), offs.end());\n                offs.erase(unique(offs.begin(), offs.end()), offs.end());\n\n                int bestV = -1, bestTo = -1, bestNc = best.cost;\n\n                for (int off : offs) {\n                    if (chrono::steady_clock::now() > deadline) return;\n\n                    int nv = info.block[off];\n\n                    auto tryTo = [&](int to) {\n                        if (to < 1 || to > mG) return;\n                        if (to == info.src + 1) return;\n                        if (chrono::steady_clock::now() > deadline) return;\n\n                        int nc = simulateOpsFast(init, best.ops, info.idx, nv, to, -1, bestNc, nullptr);\n                        tested++;\n\n                        if (nc < bestNc) {\n                            bestNc = nc;\n                            bestV = nv;\n                            bestTo = to;\n                        }\n                    };\n\n                    tryTo(info.dst + 1);\n\n                    if (off == 1 || off == clean || off == info.len - 1) {\n                        for (int to = 1; to <= mG; to++) {\n                            if (to == info.dst + 1) continue;\n                            tryTo(to);\n                            if (tested >= 220) break;\n                        }\n                    }\n\n                    if (tested >= 220) break;\n                }\n\n                if (bestV != -1) {\n                    best.ops[info.idx].first = bestV;\n                    best.ops[info.idx].second = bestTo;\n                    best.cost = bestNc;\n                    changed = true;\n                    break;\n                }\n\n                if (tested >= 220) break;\n            }\n        }\n        if (changed) continue;\n\n        // 7. Destination-only change.\n        for (const auto& info : rec) {\n            if (chrono::steady_clock::now() > deadline) return;\n\n            int bestTo = -1;\n            int bestNc = best.cost;\n\n            for (int to = 1; to <= mG; to++) {\n                if (to == info.dst + 1) continue;\n                if (to == info.src + 1) continue;\n\n                int nc = simulateOpsFast(init, best.ops, info.idx, -1, to, -1, bestNc, nullptr);\n                if (nc < bestNc) {\n                    bestNc = nc;\n                    bestTo = to;\n                }\n            }\n\n            if (bestTo != -1) {\n                best.ops[info.idx].second = bestTo;\n                best.cost = bestNc;\n                changed = true;\n                break;\n            }\n        }\n        if (changed) continue;\n\n        // 8. New: insert a split move before an expensive move.\n        {\n            if ((int)best.ops.size() < 5000) {\n                int tested = 0;\n\n                for (const auto& info : rec) {\n                    if (chrono::steady_clock::now() > deadline) return;\n                    if (info.len <= 2 || (int)info.block.size() != info.len) continue;\n\n                    vector<int> offs;\n                    auto addOff = [&](int x) {\n                        if (x > 0 && x < info.len) offs.push_back(x);\n                    };\n\n                    addOff(1);\n                    addOff(2);\n                    addOff(3);\n                    addOff(info.len / 2);\n                    addOff(info.len - 1);\n\n                    int clean = info.len - 1;\n                    while (clean - 1 >= 0 && info.block[clean - 1] > info.block[clean]) clean--;\n                    addOff(clean);\n\n                    sort(offs.begin(), offs.end());\n                    offs.erase(unique(offs.begin(), offs.end()), offs.end());\n\n                    for (int off : offs) {\n                        if (chrono::steady_clock::now() > deadline) return;\n\n                        int lbl = info.block[off];\n                        if (lbl < 1 || lbl > nG) continue;\n\n                        vector<int> tos;\n                        tos.push_back(info.dst + 1);\n\n                        // Try destinations seen in nearby future moves of the same block.\n                        bool inBlock[205] = {};\n                        for (int x : info.block) if (1 <= x && x <= nG) inBlock[x] = true;\n                        int end = min((int)best.ops.size(), info.idx + 80);\n                        for (int j = info.idx + 1; j < end; j++) {\n                            int vv = best.ops[j].first;\n                            int tt = best.ops[j].second;\n                            if (tt != 0 && 1 <= vv && vv <= nG && inBlock[vv]) tos.push_back(tt);\n                        }\n\n                        if (off == 1 || off == clean || off == info.len - 1) {\n                            for (int to = 1; to <= mG; to++) tos.push_back(to);\n                        }\n\n                        sort(tos.begin(), tos.end());\n                        tos.erase(unique(tos.begin(), tos.end()), tos.end());\n\n                        for (int to : tos) {\n                            if (to < 1 || to > mG) continue;\n                            if (to == info.src + 1) continue;\n\n                            vector<pair<int,int>> cand = best.ops;\n                            cand.insert(cand.begin() + info.idx, {lbl, to});\n\n                            int nc = simulateOpsFast(init, cand, -1, -1, -1, -1, best.cost, nullptr);\n                            tested++;\n\n                            if (nc < best.cost) {\n                                best.ops = std::move(cand);\n                                best.cost = nc;\n                                changed = true;\n                                break;\n                            }\n\n                            if (tested >= 150) break;\n                        }\n\n                        if (changed || tested >= 150) break;\n                    }\n\n                    if (changed || tested >= 150) break;\n                }\n            }\n        }\n        if (changed) continue;\n\n        break;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> nG >> mG;\n\n    StackArray init;\n    for (int i = 0; i < mG; i++) {\n        init[i].reserve(nG);\n        for (int j = 0; j < nG / mG; j++) {\n            int x;\n            cin >> x;\n            init[i].push_back(x);\n        }\n    }\n\n    uint64_t seed = 1234567891234567ULL;\n    for (int i = 0; i < mG; i++) {\n        for (int x : init[i]) {\n            seed = seed * 1000003ULL + (uint64_t)x + 97ULL;\n        }\n    }\n\n    XorShift master(seed);\n\n    auto startTime = chrono::steady_clock::now();\n\n    auto elapsed = [&]() -> double {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    };\n\n    auto timeUp = [&]() -> bool {\n        return elapsed() > 1.93;\n    };\n\n    Result best;\n\n    auto consider = [&](Result r) {\n        if (!r.ok) return;\n        if ((int)r.ops.size() > 5000) return;\n        if (best.ok && r.cost >= best.cost) return;\n\n        int vc = validateCost(init, r.ops);\n        if (vc < 0 || vc != r.cost) return;\n\n        best = std::move(r);\n    };\n\n    Params pClean;\n    pClean.mode = 2;\n    pClean.goodMode = 0;\n    pClean.badMode = 0;\n    pClean.thresholdMode = 0;\n    pClean.destMode = 0;\n\n    Params pCleanBad = pClean;\n    pCleanBad.badMode = 1;\n\n    Params pCleanD1 = pClean;\n    pCleanD1.destMode = 1;\n\n    Params pWhole;\n    pWhole.mode = 0;\n    pWhole.thresholdMode = 0;\n    pWhole.destMode = 0;\n\n    Params pSingle;\n    pSingle.mode = 1;\n    pSingle.thresholdMode = 0;\n    pSingle.destMode = 0;\n\n    Params pEnum;\n    pEnum.mode = 3;\n    pEnum.thresholdMode = 0;\n    pEnum.lenW = 0.07;\n    pEnum.dirtyW = 1.8;\n    pEnum.badW = 3.0;\n    pEnum.gW = 0.08;\n    pEnum.slackW = 0.02;\n\n    Params pCleanEnum = pClean;\n    pCleanEnum.badMode = 3;\n    pCleanEnum.lenW = 0.07;\n    pCleanEnum.dirtyW = 1.8;\n    pCleanEnum.badW = 3.0;\n    pCleanEnum.gW = 0.08;\n    pCleanEnum.slackW = 0.02;\n\n    vector<Params> macroParams = {pClean, pCleanBad, pCleanD1, pWhole, pSingle, pEnum, pCleanEnum};\n\n    vector<pair<EvalParam, vector<Params>>> rollCfgs;\n    rollCfgs.push_back({\n        EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75},\n        vector<Params>{pClean}\n    });\n    rollCfgs.push_back({\n        EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65},\n        vector<Params>{pClean, pEnum}\n    });\n    rollCfgs.push_back({\n        EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85},\n        vector<Params>{pCleanBad}\n    });\n    rollCfgs.push_back({\n        EvalParam{3.0, 1.0, 2.0, 0.18, 2.8, 2.4, 0.70},\n        vector<Params>{pClean, pCleanD1, pEnum}\n    });\n    rollCfgs.push_back({\n        EvalParam{2.4, 1.2, 1.4, 0.20, 2.2, 1.8, 0.80},\n        vector<Params>{pCleanEnum, pClean}\n    });\n\n    consider(simulateGreedy(init, pWhole, master.next(), INF));\n\n    auto runParam = [&](Params p) {\n        if (timeUp()) return;\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    for (int th = 0; th <= 1; th++) {\n        for (int dm = 0; dm < 4; dm++) {\n            Params p;\n\n            p = Params();\n            p.mode = 0;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            p = Params();\n            p.mode = 1;\n            p.thresholdMode = th;\n            p.destMode = dm;\n            runParam(p);\n\n            for (int bad = 0; bad <= 2; bad++) {\n                for (int good = 0; good <= 2; good++) {\n                    p = Params();\n                    p.mode = 2;\n                    p.badMode = bad;\n                    p.goodMode = good;\n                    p.thresholdMode = th;\n                    p.destMode = dm;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    runParam(pCleanEnum);\n\n    for (int th = 0; th <= 1; th++) {\n        for (double lw : {0.03, 0.07, 0.13}) {\n            for (double dw : {0.8, 1.8, 3.0}) {\n                Params p;\n                p.mode = 3;\n                p.thresholdMode = th;\n                p.lenW = lw;\n                p.dirtyW = dw;\n                p.badW = 3.0;\n                p.gW = 0.08;\n                p.slackW = 0.02;\n                runParam(p);\n            }\n        }\n    }\n\n    {\n        vector<Params> initPool = {pClean, pCleanBad, pCleanD1, pWhole, pSingle, pEnum, pCleanEnum};\n\n        for (Params base : initPool) {\n            if (timeUp()) break;\n\n            for (int a = 0; a < mG && !timeUp(); a++) {\n                for (int b = 0; b < mG && !timeUp(); b++) {\n                    if (a == b) continue;\n\n                    Params p = base;\n                    p.initA = a;\n                    p.initB = b;\n                    runParam(p);\n                }\n            }\n        }\n    }\n\n    for (double alpha : {0.0, 1.0, 2.0, 4.0, 6.0}) {\n        if (timeUp()) break;\n\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateBeamWhole(init, 55, alpha, cutoff));\n    }\n\n    {\n        auto rollEnd = startTime + chrono::milliseconds(1600);\n\n        for (int idx = 0; idx < (int)rollCfgs.size(); idx++) {\n            if (timeUp()) break;\n            if (chrono::steady_clock::now() > rollEnd) break;\n\n            int cutoff = best.ok ? best.cost + 350 : INF;\n\n            g_useClearBeam = true;\n            consider(simulateMacroRollout(init, macroParams, rollCfgs[idx].second, rollCfgs[idx].first,\n                                          cutoff, rollEnd, 20, 1));\n\n            if (idx < 2 && !timeUp() && chrono::steady_clock::now() < rollEnd) {\n                g_useClearBeam = false;\n                consider(simulateMacroRollout(init, macroParams, rollCfgs[idx].second, rollCfgs[idx].first,\n                                              cutoff, rollEnd, 14, 1));\n            }\n\n            g_useClearBeam = true;\n        }\n    }\n\n    if (!timeUp() && best.ok) {\n        auto initRollEnd = startTime + chrono::milliseconds(1740);\n\n        vector<tuple<int,int,int>> candInit;\n        vector<Params> initEval = {pClean, pEnum, pCleanEnum};\n        int roughLimit = best.cost + 500;\n\n        for (int a = 0; a < mG; a++) {\n            for (int b = 0; b < mG; b++) {\n                if (a == b) continue;\n\n                StackArray st = init;\n                int c0 = (int)st[a].size() + 1;\n\n                st[b].insert(st[b].end(), st[a].begin(), st[a].end());\n                st[a].clear();\n\n                int tail = completeCostMulti(st, 1, initEval, roughLimit - c0);\n                if (tail < INF) candInit.push_back({c0 + tail, a, b});\n            }\n        }\n\n        sort(candInit.begin(), candInit.end());\n\n        int tried = 0;\n        for (auto [est, a, b] : candInit) {\n            if (tried >= 3) break;\n            if (timeUp() || chrono::steady_clock::now() > initRollEnd) break;\n\n            StackArray st = init;\n            int label = st[a][0];\n            int c0 = (int)st[a].size() + 1;\n\n            st[b].insert(st[b].end(), st[a].begin(), st[a].end());\n            st[a].clear();\n\n            int cutoffTail = (best.ok ? best.cost + 350 - c0 : INF);\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[(tried + 1) % rollCfgs.size()];\n            g_useClearBeam = true;\n\n            Result tail = simulateMacroRollout(st, macroParams, cfg.second, cfg.first,\n                                               cutoffTail, initRollEnd, 15, 1);\n\n            if (tail.ok) {\n                Result r;\n                r.ok = true;\n                r.cost = c0 + tail.cost;\n                r.ops.reserve(tail.ops.size() + 1);\n                r.ops.push_back({label, b + 1});\n                r.ops.insert(r.ops.end(), tail.ops.begin(), tail.ops.end());\n                consider(std::move(r));\n            }\n\n            tried++;\n        }\n    }\n\n    if (!timeUp() && best.ok) {\n        auto sufEnd = startTime + chrono::milliseconds(1815);\n\n        vector<int> starts = {121, 141, 161, 181};\n\n        for (int idx = 0; idx < (int)starts.size(); idx++) {\n            if (timeUp() || chrono::steady_clock::now() > sufEnd) break;\n\n            int startV = starts[idx];\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost + 220;\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[idx % rollCfgs.size()];\n            g_useClearBeam = (idx % 2 == 0);\n\n            Result tail = simulateMacroRollout(pref.st, macroParams, cfg.second, cfg.first,\n                                               cutoffTail, sufEnd, 12, startV);\n\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n\n        g_useClearBeam = true;\n    }\n\n    if (!timeUp() && best.ok) {\n        auto rbEnd = startTime + chrono::milliseconds(1840);\n\n        vector<int> starts = {141, 161, 181};\n\n        for (int idx = 0; idx < (int)starts.size(); idx++) {\n            if (timeUp() || chrono::steady_clock::now() > rbEnd) break;\n\n            int startV = starts[idx];\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost + 180;\n            if (cutoffTail <= 0) continue;\n\n            auto& cfg = rollCfgs[(idx + 1) % rollCfgs.size()];\n            g_useClearBeam = true;\n\n            Result tail = simulateMacroRolloutBeam(pref.st, startV, 3,\n                                                   macroParams, cfg.second, cfg.first,\n                                                   cutoffTail, rbEnd, 10);\n\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n    }\n\n    if (!timeUp() && best.ok) {\n        auto tailEnd = startTime + chrono::milliseconds(1850);\n\n        vector<tuple<int,int,int,EvalParam>> tailCfgs;\n        tailCfgs.push_back({151, 45, 10, EvalParam{2.7, 0.9, 1.2, 0.25, 2.0, 1.5, 0.75}});\n        tailCfgs.push_back({161, 60, 12, EvalParam{3.6, 0.45, 1.8, 0.12, 2.5, 2.0, 0.65}});\n        tailCfgs.push_back({171, 80, 14, EvalParam{2.0, 1.6, 0.8, 0.30, 1.5, 2.8, 0.85}});\n        tailCfgs.push_back({181, 100, 16, EvalParam{3.0, 1.0, 2.0, 0.18, 2.8, 2.4, 0.70}});\n\n        for (auto [startV, W, perLimit, ep] : tailCfgs) {\n            if (timeUp() || chrono::steady_clock::now() > tailEnd) break;\n\n            PrefixResult pref = extractPrefix(init, best.ops, startV - 1);\n            if (!pref.ok) continue;\n\n            int cutoffTail = best.cost - pref.cost;\n            if (cutoffTail <= 0) continue;\n\n            Result tail = simulateTailMacroBeam(pref.st, startV, W, ep,\n                                                cutoffTail, tailEnd, perLimit);\n\n            if (!tail.ok) continue;\n\n            Result comb;\n            comb.ok = true;\n            comb.cost = pref.cost + tail.cost;\n            comb.ops = std::move(pref.ops);\n            comb.ops.insert(comb.ops.end(), tail.ops.begin(), tail.ops.end());\n            consider(std::move(comb));\n        }\n    }\n\n    auto runRandomOnce = [&]() {\n        Params p = randomParams(master);\n        int cutoff = best.ok ? best.cost : INF;\n        consider(simulateGreedy(init, p, master.next(), cutoff));\n    };\n\n    {\n        auto randEnd = startTime + chrono::milliseconds(1858);\n        while (!timeUp() && chrono::steady_clock::now() < randEnd) {\n            runRandomOnce();\n        }\n    }\n\n    if (!timeUp() && best.ok) {\n        auto localEnd = startTime + chrono::milliseconds(1922);\n        improveByLocalDest(init, best, localEnd);\n    }\n\n    int vc = best.ok ? validateCost(init, best.ops) : -1;\n    if (!best.ok || vc < 0) {\n        best = simulateGreedy(init, pWhole, seed, INF);\n    } else {\n        best.cost = vc;\n    }\n\n    for (auto [v, to] : best.ops) {\n        cout << v << ' ' << to << '\\n';\n    }\n\n    return 0;\n}","ahc027":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int LIMIT_LEN = 100000;\nstatic const int INTERNAL_LIMIT = 150000;\nstatic const unsigned short INF_DIST = 30000;\n\nint N, V;\nvector<string> hwall, vwall;\nvector<int> dirtv;\nvector<double> rootDirt;\ndouble meanRootDirt = 1.0;\n\nstruct Edge {\n    int to;\n    char ch;\n};\n\nvector<vector<Edge>> adjg;\nvector<unsigned short> distAll;\nvector<int> dist0;\nvector<vector<int>> nearList;\n\n// Reused buffers for faster exact evaluation.\nvector<int> evalFirstBuf, evalPrevBuf;\nvector<long long> evalGapBuf;\n\ninline int D(int a, int b) {\n    return distAll[a * V + b];\n}\n\ninline char moveChar(int from, int to) {\n    int diff = to - from;\n    if (diff == 1) return 'R';\n    if (diff == -1) return 'L';\n    if (diff == N) return 'D';\n    return 'U';\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 RouteBuilder {\n    int cur = 0;\n    int t = 0;\n    vector<int> seq;\n    string moves;\n    vector<int> last;\n    vector<char> seen;\n    int unseen = 0;\n\n    void init() {\n        cur = 0;\n        t = 0;\n        seq.clear();\n        moves.clear();\n        last.assign(V, 0);\n        seen.assign(V, 0);\n        seen[0] = 1;\n        unseen = V - 1;\n    }\n\n    void addMove(int nb) {\n        moves.push_back(moveChar(cur, nb));\n        cur = nb;\n        ++t;\n        seq.push_back(nb);\n        last[nb] = t;\n        if (!seen[nb]) {\n            seen[nb] = 1;\n            --unseen;\n        }\n    }\n};\n\nvoid computeAllPairsDistances() {\n    distAll.assign(V * V, INF_DIST);\n    vector<int> q(V);\n\n    for (int s = 0; s < V; ++s) {\n        unsigned short* ds = &distAll[s * V];\n        int head = 0, tail = 0;\n        ds[s] = 0;\n        q[tail++] = s;\n\n        while (head < tail) {\n            int x = q[head++];\n            unsigned short nd = ds[x] + 1;\n            for (const auto& e : adjg[x]) {\n                if (ds[e.to] == INF_DIST) {\n                    ds[e.to] = nd;\n                    q[tail++] = e.to;\n                }\n            }\n        }\n    }\n\n    dist0.assign(V, 0);\n    for (int i = 0; i < V; ++i) dist0[i] = D(i, 0);\n}\n\nint chooseNextOnShortestPath(const RouteBuilder& b, int target, bool preferUnseen) {\n    int cur = b.cur;\n    int cd = D(target, cur);\n    int best = -1;\n    long double bestVal = -1e100L;\n\n    for (const auto& e : adjg[cur]) {\n        int nb = e.to;\n        if (D(target, nb) + 1 != cd) continue;\n\n        long long age = (long long)b.t + 1 - b.last[nb];\n        long double val = (long double)dirtv[nb] * age * age;\n\n        if (preferUnseen && !b.seen[nb]) val += 1e30L;\n        val += (long double)(nb % 23) * 1e-9L;\n\n        if (val > bestVal) {\n            bestVal = val;\n            best = nb;\n        }\n    }\n\n    if (best == -1) {\n        for (const auto& e : adjg[cur]) {\n            if (D(target, e.to) + 1 == cd) return e.to;\n        }\n    }\n    return best;\n}\n\nvoid appendPath(RouteBuilder& b, int target, bool preferUnseen) {\n    while (b.cur != target) {\n        int nb = chooseNextOnShortestPath(b, target, preferUnseen);\n        if (nb < 0) break;\n        b.addMove(nb);\n        if (b.t > INTERNAL_LIMIT) break;\n    }\n}\n\nlong double evaluateRange(const vector<int>& seq, int l, int r) {\n    int L = r - l;\n    if (L <= 0 || L > LIMIT_LEN) return 1e100L;\n    if (l < 0 || r > (int)seq.size()) return 1e100L;\n    if (seq[r - 1] != 0) return 1e100L;\n\n    if ((int)evalFirstBuf.size() != V) {\n        evalFirstBuf.assign(V, -1);\n        evalPrevBuf.assign(V, -1);\n        evalGapBuf.assign(V, 0);\n    } else {\n        fill(evalFirstBuf.begin(), evalFirstBuf.end(), -1);\n        fill(evalPrevBuf.begin(), evalPrevBuf.end(), -1);\n        fill(evalGapBuf.begin(), evalGapBuf.end(), 0);\n    }\n\n    int* first = evalFirstBuf.data();\n    int* prev = evalPrevBuf.data();\n    long long* gapSum = evalGapBuf.data();\n\n    for (int idx = l; idx < r; ++idx) {\n        int tt = idx - l + 1;\n        int id = seq[idx];\n\n        if (first[id] == -1) {\n            first[id] = tt;\n        } else {\n            long long g = tt - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = tt;\n    }\n\n    long double total = 0;\n    for (int id = 0; id < V; ++id) {\n        if (first[id] == -1) return 1e100L;\n        long long g = (long long)L - prev[id] + first[id];\n        gapSum[id] += g * (g - 1) / 2;\n        total += (long double)gapSum[id] * dirtv[id];\n    }\n\n    return total / L;\n}\n\nlong double evaluateSeq(const vector<int>& seq, int L) {\n    return evaluateRange(seq, 0, L);\n}\n\nvector<double> computeContributionVector(const vector<int>& seq) {\n    int L = (int)seq.size();\n    vector<double> res(V, 1.0);\n    if (L <= 0) {\n        for (int id = 0; id < V; ++id) res[id] = dirtv[id];\n        return res;\n    }\n\n    vector<int> first(V, -1), prev(V, -1);\n    vector<long long> gapSum(V, 0);\n\n    for (int t = 1; t <= L; ++t) {\n        int id = seq[t - 1];\n        if (first[id] == -1) {\n            first[id] = t;\n        } else {\n            long long g = t - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = t;\n    }\n\n    for (int id = 0; id < V; ++id) {\n        if (first[id] == -1) {\n            res[id] = 1e30;\n        } else {\n            long long g = (long long)L - prev[id] + first[id];\n            gapSum[id] += g * (g - 1) / 2;\n            res[id] = (double)((long double)gapSum[id] * dirtv[id] / max(1, L));\n        }\n    }\n\n    return res;\n}\n\nvector<int> rowOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int i = 0; i < N; ++i) {\n        if (i % 2 == 0) {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        } else {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> rowOrderBottom() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int ii = 0; ii < N; ++ii) {\n        int i = N - 1 - ii;\n        if (ii % 2 == 0) {\n            for (int j = N - 1; j >= 0; --j) ord.push_back(i * N + j);\n        } else {\n            for (int j = 0; j < N; ++j) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrder() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int j = 0; j < N; ++j) {\n        if (j % 2 == 0) {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        } else {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvector<int> colOrderRight() {\n    vector<int> ord;\n    ord.reserve(V);\n    for (int jj = 0; jj < N; ++jj) {\n        int j = N - 1 - jj;\n        if (jj % 2 == 0) {\n            for (int i = N - 1; i >= 0; --i) ord.push_back(i * N + j);\n        } else {\n            for (int i = 0; i < N; ++i) ord.push_back(i * N + j);\n        }\n    }\n    return ord;\n}\n\nvoid rotHilbert(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\nlong long hilbertIndex(int x, int y) {\n    int S = 1;\n    while (S < N) S <<= 1;\n\n    long long d = 0;\n    for (int s = S / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n        d += 1LL * s * s * ((3 * rx) ^ ry);\n        rotHilbert(s, x, y, rx, ry);\n    }\n    return d;\n}\n\nvector<int> hilbertOrder() {\n    vector<pair<long long, int>> a;\n    a.reserve(V);\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            a.push_back({hilbertIndex(j, i), i * N + j});\n        }\n    }\n\n    sort(a.begin(), a.end());\n    vector<int> ord;\n    ord.reserve(V);\n    for (auto [_, id] : a) ord.push_back(id);\n    return ord;\n}\n\nvector<int> metricNearestOrder(double beta, double expv) {\n    vector<double> attr(V);\n    for (int id = 0; id < V; ++id) {\n        attr[id] = pow((double)dirtv[id], expv);\n    }\n\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    int cur = 0;\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int step = 1; step < V; ++step) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (used[id]) continue;\n            double key = (double)D(cur, id) - beta * attr[id] + 0.002 * dist0[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n    }\n\n    return ord;\n}\n\nvector<int> metricInsertionOrder(int mode) {\n    vector<int> ids;\n    ids.reserve(V - 1);\n    for (int id = 1; id < V; ++id) ids.push_back(id);\n\n    if (mode == 0) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return dist0[a] > dist0[b];\n        });\n    } else if (mode == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return dirtv[a] > dirtv[b];\n        });\n    } else if (mode == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return rootDirt[a] * (dist0[a] + 1) > rootDirt[b] * (dist0[b] + 1);\n        });\n    } else {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            unsigned ha = (unsigned)(a * 1103515245u + 12345u);\n            unsigned hb = (unsigned)(b * 1103515245u + 12345u);\n            return ha < hb;\n        });\n    }\n\n    vector<int> ord;\n    ord.push_back(0);\n\n    for (int x : ids) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = (i + 1 < m ? ord[i + 1] : 0);\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        ord.insert(ord.begin() + bestPos, x);\n    }\n\n    return ord;\n}\n\nvector<int> metricInsertionFromScore(const vector<double>& score) {\n    vector<int> ids;\n    ids.reserve(V - 1);\n    for (int id = 1; id < V; ++id) ids.push_back(id);\n\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        if (score[a] != score[b]) return score[a] > score[b];\n        return dirtv[a] > dirtv[b];\n    });\n\n    vector<int> ord;\n    ord.push_back(0);\n\n    for (int x : ids) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = (i + 1 < m ? ord[i + 1] : 0);\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        ord.insert(ord.begin() + bestPos, x);\n    }\n\n    return ord;\n}\n\nvector<int> highBackboneOrder(double frac, double beta) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<char> high(V, 0);\n    for (int i = 0; i < K; ++i) high[ids[i]] = 1;\n    high[0] = 1;\n\n    vector<int> ord;\n    vector<char> used(V, 0);\n    ord.push_back(0);\n    used[0] = 1;\n\n    int rem = 0;\n    for (int id = 0; id < V; ++id) if (high[id] && !used[id]) ++rem;\n\n    int cur = 0;\n    while (rem > 0) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (!high[id] || used[id]) continue;\n            double key = (double)D(cur, id) - beta * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        used[best] = 1;\n        ord.push_back(best);\n        cur = best;\n        --rem;\n    }\n\n    vector<int> lows;\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) lows.push_back(id);\n    }\n    sort(lows.begin(), lows.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    for (int x : lows) {\n        int m = (int)ord.size();\n        int bestPos = m;\n        int bestDelta = INT_MAX;\n\n        for (int i = 0; i < m; ++i) {\n            int a = ord[i];\n            int b = ord[(i + 1) % m];\n            int delta = D(a, x) + D(x, b) - D(a, b);\n            if (delta < bestDelta) {\n                bestDelta = delta;\n                bestPos = i + 1;\n            }\n        }\n\n        if (bestPos >= (int)ord.size()) ord.push_back(x);\n        else ord.insert(ord.begin() + bestPos, x);\n        used[x] = 1;\n    }\n\n    return ord;\n}\n\nRouteBuilder makeRouteByOrder(const vector<int>& ord) {\n    RouteBuilder b;\n    b.init();\n\n    for (int id : ord) {\n        if (!b.seen[id]) appendPath(b, id, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeNearestCover(int variant) {\n    RouteBuilder b;\n    b.init();\n\n    while (b.unseen > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n\n            int r = D(b.cur, id);\n            double key;\n\n            if (variant == 0) {\n                key = r * 1000000.0 + dist0[id];\n            } else if (variant == 1) {\n                key = r * 1000000.0 - dirtv[id] * 200.0;\n            } else if (variant == 2) {\n                key = (r + 0.20 * dist0[id]) * 1000000.0 - dirtv[id] * 10.0;\n            } else if (variant == 3) {\n                unsigned x = (unsigned)(id * 1103515245u + 12345u);\n                key = r * 1000000.0 + (x % 10000) * 0.01;\n            } else {\n                int degUnseen = 0;\n                for (auto& e : adjg[id]) if (!b.seen[e.to]) ++degUnseen;\n                key = r * 1000000.0 + degUnseen * 1000.0 - dirtv[id] * 0.05;\n            }\n\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best == -1) break;\n        appendPath(b, best, true);\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder makeDFSRoute(const string& dirOrder, int sortMode) {\n    RouteBuilder b;\n    b.init();\n\n    vector<int> rankDir(256, 0);\n    for (int i = 0; i < 4; ++i) rankDir[(unsigned char)dirOrder[i]] = i;\n\n    vector<char> vis(V, 0);\n\n    function<void(int)> dfs = [&](int u) {\n        vis[u] = 1;\n        vector<Edge> es = adjg[u];\n\n        sort(es.begin(), es.end(), [&](const Edge& a, const Edge& c) {\n            if (sortMode == 1 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] > dirtv[c.to];\n            }\n            if (sortMode == 2 && dirtv[a.to] != dirtv[c.to]) {\n                return dirtv[a.to] < dirtv[c.to];\n            }\n            return rankDir[(unsigned char)a.ch] < rankDir[(unsigned char)c.ch];\n        });\n\n        for (auto& e : es) {\n            if (!vis[e.to]) {\n                b.addMove(e.to);\n                dfs(e.to);\n                b.addMove(u);\n            }\n        }\n    };\n\n    dfs(0);\n    return b;\n}\n\nRouteBuilder makePrimTreeRoute(int mode, int childSort) {\n    struct PQNode {\n        double key;\n        int u, v;\n        bool operator<(const PQNode& other) const {\n            return key < other.key;\n        }\n    };\n\n    auto edgeScore = [&](int u, int v) -> double {\n        double tie = ((v * 1103515245u + u * 12345u) & 1023) * 1e-6;\n        if (mode == 0) {\n            return (double)dirtv[v] + 0.15 * dirtv[u] - 0.05 * dist0[v] + tie;\n        } else if (mode == 1) {\n            return rootDirt[v] * (dist0[v] + 1.0) + 0.2 * rootDirt[u] + tie;\n        } else if (mode == 2) {\n            return -1000.0 * dist0[v] + (double)dirtv[v] + tie;\n        } else {\n            unsigned h = (unsigned)(v * 2654435761u + u * 97531u);\n            return rootDirt[v] + (h % 10000) * 0.001 + tie;\n        }\n    };\n\n    vector<vector<int>> tree(V);\n    vector<char> used(V, 0);\n    priority_queue<PQNode> pq;\n\n    auto pushFrontier = [&](int u) {\n        for (auto& e : adjg[u]) {\n            int v = e.to;\n            if (!used[v]) pq.push({edgeScore(u, v), u, v});\n        }\n    };\n\n    used[0] = 1;\n    int cnt = 1;\n    pushFrontier(0);\n\n    while (cnt < V && !pq.empty()) {\n        auto cur = pq.top();\n        pq.pop();\n\n        if (used[cur.v]) continue;\n\n        used[cur.v] = 1;\n        ++cnt;\n        tree[cur.u].push_back(cur.v);\n        tree[cur.v].push_back(cur.u);\n        pushFrontier(cur.v);\n    }\n\n    vector<int> parent(V, -2), order;\n    parent[0] = -1;\n    order.push_back(0);\n\n    for (int qi = 0; qi < (int)order.size(); ++qi) {\n        int u = order[qi];\n        for (int v : tree[u]) {\n            if (v == parent[u]) continue;\n            parent[v] = u;\n            order.push_back(v);\n        }\n    }\n\n    vector<double> sub(V, 0.0);\n    for (int id = 0; id < V; ++id) sub[id] = rootDirt[id];\n\n    for (int idx = (int)order.size() - 1; idx >= 1; --idx) {\n        int u = order[idx];\n        if (parent[u] >= 0) sub[parent[u]] += sub[u];\n    }\n\n    RouteBuilder b;\n    b.init();\n\n    function<void(int)> dfs = [&](int u) {\n        vector<int> ch;\n        for (int v : tree[u]) {\n            if (v != parent[u]) ch.push_back(v);\n        }\n\n        sort(ch.begin(), ch.end(), [&](int a, int c) {\n            if (childSort == 0) {\n                if (sub[a] != sub[c]) return sub[a] > sub[c];\n            } else if (childSort == 1) {\n                if (sub[a] != sub[c]) return sub[a] < sub[c];\n            } else if (childSort == 2) {\n                if (dirtv[a] != dirtv[c]) return dirtv[a] > dirtv[c];\n            } else {\n                if (dist0[a] != dist0[c]) return dist0[a] > dist0[c];\n            }\n            return a < c;\n        });\n\n        for (int v : ch) {\n            b.addMove(v);\n            dfs(v);\n            b.addMove(u);\n        }\n    };\n\n    dfs(0);\n    return b;\n}\n\nvector<int> firstVisitOrder(const RouteBuilder& b) {\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int id : b.seq) {\n        if (!used[id]) {\n            used[id] = 1;\n            ord.push_back(id);\n        }\n    }\n\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) ord.push_back(id);\n    }\n\n    return ord;\n}\n\nvector<int> firstVisitOrderFromSeq(const vector<int>& seq) {\n    vector<int> ord;\n    ord.reserve(V);\n    vector<char> used(V, 0);\n\n    ord.push_back(0);\n    used[0] = 1;\n\n    for (int id : seq) {\n        if (!used[id]) {\n            used[id] = 1;\n            ord.push_back(id);\n        }\n    }\n\n    for (int id = 0; id < V; ++id) {\n        if (!used[id]) ord.push_back(id);\n    }\n\n    return ord;\n}\n\nvoid buildNearLists(int K) {\n    K = min(K, V - 1);\n    nearList.assign(V, {});\n\n    for (int a = 0; a < V; ++a) {\n        vector<pair<unsigned short, int>> tmp;\n        tmp.reserve(V - 1);\n\n        for (int b = 0; b < V; ++b) {\n            if (a != b) tmp.push_back({(unsigned short)D(a, b), b});\n        }\n\n        if (K < (int)tmp.size()) {\n            nth_element(tmp.begin(), tmp.begin() + K, tmp.end());\n            tmp.resize(K);\n        }\n\n        sort(tmp.begin(), tmp.end());\n        nearList[a].reserve(K);\n        for (auto [_, id] : tmp) nearList[a].push_back(id);\n    }\n}\n\nvoid rotateZeroFront(vector<int>& ord) {\n    auto it = find(ord.begin(), ord.end(), 0);\n    if (it != ord.end()) rotate(ord.begin(), it, ord.end());\n}\n\nvector<int> improveOrder2Opt(vector<int> ord, double lambda, const Timer& timer,\n                             double deadline, int maxImp) {\n    if (nearList.empty() || (int)ord.size() != V) return ord;\n    rotateZeroFront(ord);\n\n    int n = (int)ord.size();\n    vector<int> pos(V);\n    for (int i = 0; i < n; ++i) pos[ord[i]] = i;\n\n    auto edgeCost = [&](int a, int b) -> double {\n        double base = (double)D(a, b);\n        if (lambda <= 0.0) return base;\n        double w = min(rootDirt[a], rootDirt[b]) / meanRootDirt;\n        return base * (1.0 + lambda * w);\n    };\n\n    int imp = 0;\n\n    while (imp < maxImp && timer.elapsed() < deadline) {\n        bool changed = false;\n\n        for (int i = 0; i < n - 1 && !changed && timer.elapsed() < deadline; ++i) {\n            int a = ord[i];\n            int b = ord[i + 1];\n            double oldAB = edgeCost(a, b);\n\n            auto tryK = [&](int k) -> bool {\n                if (k <= i + 1 || k >= n) return false;\n                if (i == 0 && k == n - 1) return false;\n\n                int c = ord[k];\n                int d = ord[(k + 1) % n];\n\n                double delta = edgeCost(a, c) + edgeCost(b, d) - oldAB - edgeCost(c, d);\n                if (delta < -1e-9) {\n                    reverse(ord.begin() + i + 1, ord.begin() + k + 1);\n                    for (int p = i + 1; p <= k; ++p) pos[ord[p]] = p;\n                    ++imp;\n                    return true;\n                }\n                return false;\n            };\n\n            for (int cnode : nearList[a]) {\n                int k = pos[cnode];\n                if (tryK(k)) {\n                    changed = true;\n                    break;\n                }\n            }\n            if (changed) break;\n\n            for (int dnode : nearList[b]) {\n                int k = pos[dnode] - 1;\n                if (k < 0) k = n - 1;\n                if (tryK(k)) {\n                    changed = true;\n                    break;\n                }\n            }\n        }\n\n        if (!changed) break;\n    }\n\n    return ord;\n}\n\nvector<int> makeCounts(const vector<double>& weight, double scale, int& M) {\n    vector<int> cnt(V);\n    M = 1;\n\n    for (int id = 0; id < V; ++id) {\n        int c = max(1, (int)(scale * weight[id] + 0.5));\n        cnt[id] = c;\n        M = max(M, c);\n    }\n\n    return cnt;\n}\n\nint initialAccumulator(int pos, int id, int M, int mode) {\n    if (M <= 1) return 0;\n    if (mode == 0) return 0;\n\n    int desired = 0;\n\n    if (mode == 1) {\n        desired = (int)((long long)pos * M / V);\n    } else if (mode == 2) {\n        desired = (int)((long long)(V - 1 - pos) * M / V);\n    } else if (mode == 3) {\n        unsigned x = (unsigned)(pos * 2654435761u + 1013904223u);\n        desired = x % M;\n    } else {\n        unsigned x = (unsigned)(id * 1103515245u + pos * 12345u + 24691u);\n        desired = x % M;\n    }\n\n    int a = M - 1 - desired;\n    a %= M;\n    if (a < 0) a += M;\n    return a;\n}\n\nvector<vector<int>> buildEvents(const vector<int>& ord, const vector<int>& cnt, int M, int mode) {\n    vector<vector<int>> events(M);\n\n    for (int k = 0; k < V; ++k) {\n        int id = ord[k];\n        int c = cnt[id];\n        int a = initialAccumulator(k, id, M, mode);\n\n        for (int m = 1; m <= c; ++m) {\n            long long num = 1LL * m * M - a;\n            int p = (int)((num + c - 1) / c - 1);\n            if (p < 0) p = 0;\n            if (p >= M) p = M - 1;\n            events[p].push_back(id);\n        }\n    }\n\n    return events;\n}\n\nlong long phaseLength(const vector<int>& ord, const vector<double>& weight,\n                      double scale, int mode, long long cap) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    long long len = 0;\n    int cur = 0;\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) {\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                int id = ev[idx];\n                len += D(cur, id);\n                cur = id;\n                if (len > cap) return len;\n            }\n        }\n    }\n\n    len += D(cur, 0);\n    return len;\n}\n\nRouteBuilder buildPhaseRoute(const vector<int>& ord, const vector<double>& weight,\n                             double scale, int mode) {\n    int M;\n    vector<int> cnt = makeCounts(weight, scale, M);\n    auto events = buildEvents(ord, cnt, M, mode);\n\n    RouteBuilder b;\n    b.init();\n\n    for (int p = 0; p < M; ++p) {\n        auto& ev = events[p];\n\n        if ((p & 1) == 0) {\n            for (int id : ev) appendPath(b, id, true);\n        } else {\n            for (int idx = (int)ev.size() - 1; idx >= 0; --idx) {\n                appendPath(b, ev[idx], true);\n            }\n        }\n\n        if (b.t > LIMIT_LEN + 2000) break;\n    }\n\n    appendPath(b, 0, true);\n    return b;\n}\n\ndouble findPhaseScale(const vector<int>& ord, const vector<double>& weight, int mode) {\n    double lo = 0.0, hi = 1.0;\n\n    while (hi < 2048.0 && phaseLength(ord, weight, hi, mode, LIMIT_LEN + 1) <= LIMIT_LEN) {\n        lo = hi;\n        hi *= 2.0;\n    }\n\n    for (int it = 0; it < 13; ++it) {\n        double mid = (lo + hi) * 0.5;\n        if (phaseLength(ord, weight, mid, mode, LIMIT_LEN + 1) <= LIMIT_LEN) lo = mid;\n        else hi = mid;\n    }\n\n    return lo;\n}\n\nRouteBuilder buildChunkGreedy(RouteBuilder prefix, double offset, int minTargetDist,\n                              int chunk, int maxLen, const Timer& timer, double timeLimit) {\n    RouteBuilder b = std::move(prefix);\n\n    auto selectTarget = [&](int md) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (b.t + r + dist0[id] > maxLen) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n\n    while (b.t + D(b.cur, 0) < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        int target = selectTarget(minTargetDist);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n            if (b.t > INTERNAL_LIMIT) break;\n        }\n\n        if (b.t > INTERNAL_LIMIT) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n    return b;\n}\n\nvoid finishCoverAndReturn(RouteBuilder& b, int maxLen) {\n    while (b.unseen > 0 && b.t < maxLen) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (b.seen[id]) continue;\n            int r = D(b.cur, id);\n            if (b.t + r + dist0[id] > maxLen) continue;\n            double key = r + 0.15 * dist0[id] - 0.02 * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        appendPath(b, best, true);\n        if (b.t > maxLen) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= maxLen) appendPath(b, 0, false);\n}\n\nRouteBuilder buildIntegratedGreedy(double offset, int minTargetDist, int chunk,\n                                   int maxLen, double unseenBonus, double unseenMult,\n                                   const Timer& timer, double timeLimit) {\n    RouteBuilder b;\n    b.init();\n\n    auto selectTarget = [&](int md, bool forceUnseen) -> int {\n        int best = -1;\n        double bestScore = -1.0;\n        const unsigned short* row = &distAll[b.cur * V];\n\n        for (int id = 0; id < V; ++id) {\n            int r = row[id];\n            if (r == 0 || r < md) continue;\n            if (forceUnseen && b.seen[id]) continue;\n            if (b.t + r + dist0[id] + 2 * b.unseen > maxLen + 1000) continue;\n\n            long long age = (long long)b.t - b.last[id] + r;\n            double score = (double)dirtv[id] * (double)age * (double)age / (r + offset);\n\n            if (!b.seen[id]) {\n                score = score * unseenMult + unseenBonus / (r + 1.0);\n            }\n\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        return best;\n    };\n\n    int iter = 0;\n    while (b.t + D(b.cur, 0) + 2 * V + 30 < maxLen) {\n        if ((iter++ & 63) == 0 && timer.elapsed() > timeLimit) break;\n\n        bool force = (b.unseen > 0 && b.t + D(b.cur, 0) + 2 * V + 1500 > maxLen);\n        int target = selectTarget(minTargetDist, force);\n        if (target == -1 && minTargetDist > 1) target = selectTarget(1, force);\n        if (target == -1 && force) target = selectTarget(1, false);\n        if (target == -1) break;\n\n        int steps = 0;\n        while (b.cur != target && steps < chunk) {\n            int nb = chooseNextOnShortestPath(b, target, false);\n            if (nb < 0) break;\n            b.addMove(nb);\n            ++steps;\n            if (b.t + D(b.cur, 0) >= maxLen) break;\n        }\n    }\n\n    finishCoverAndReturn(b, maxLen);\n    return b;\n}\n\nRouteBuilder buildHighSubsetLoop(double frac) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<char> need(V, 0);\n    for (int i = 0; i < K; ++i) need[ids[i]] = 1;\n\n    RouteBuilder b;\n    b.init();\n\n    auto remaining = [&]() {\n        int r = 0;\n        for (int id = 0; id < V; ++id) {\n            if (need[id] && !b.seen[id]) ++r;\n        }\n        return r;\n    };\n\n    while (remaining() > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id = 0; id < V; ++id) {\n            if (!need[id] || b.seen[id]) continue;\n            double key = (double)D(b.cur, id) - 0.35 * rootDirt[id] + 0.01 * dist0[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        appendPath(b, best, true);\n        if (b.t + D(b.cur, 0) > LIMIT_LEN) break;\n    }\n\n    if (b.t + D(b.cur, 0) <= LIMIT_LEN) appendPath(b, 0, true);\n    return b;\n}\n\nRouteBuilder composeLoops(const RouteBuilder& cover, const RouteBuilder& loop, int reps) {\n    RouteBuilder b;\n    b.init();\n\n    for (int nb : cover.seq) b.addMove(nb);\n\n    for (int r = 0; r < reps; ++r) {\n        for (int nb : loop.seq) b.addMove(nb);\n    }\n\n    return b;\n}\n\nvector<int> topCellsByDirt(double frac) {\n    vector<int> ids(V);\n    iota(ids.begin(), ids.end(), 0);\n    sort(ids.begin(), ids.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    ids.resize(K);\n    return ids;\n}\n\nvector<int> topCellsByContribution(const RouteBuilder& b, double frac) {\n    int L = b.t;\n    if (L <= 0 || (int)b.seq.size() < L) return topCellsByDirt(frac);\n\n    vector<int> first(V, -1), prev(V, -1);\n    vector<long long> gapSum(V, 0);\n\n    for (int t = 1; t <= L; ++t) {\n        int id = b.seq[t - 1];\n        if (first[id] == -1) {\n            first[id] = t;\n        } else {\n            long long g = t - prev[id];\n            gapSum[id] += g * (g - 1) / 2;\n        }\n        prev[id] = t;\n    }\n\n    vector<pair<long double, int>> vals;\n    vals.reserve(V);\n\n    for (int id = 0; id < V; ++id) {\n        long double c;\n        if (first[id] == -1) {\n            c = 1e80L;\n        } else {\n            long long g = (long long)L - prev[id] + first[id];\n            gapSum[id] += g * (g - 1) / 2;\n            c = (long double)gapSum[id] * dirtv[id];\n        }\n        vals.push_back({c, id});\n    }\n\n    sort(vals.begin(), vals.end(), [&](const auto& a, const auto& b) {\n        return a.first > b.first;\n    });\n\n    int K = max(1, min(V, (int)(frac * V + 0.5)));\n    vector<int> res;\n    res.reserve(K);\n    for (int i = 0; i < K; ++i) res.push_back(vals[i].second);\n    return res;\n}\n\nint chooseMedoid(const vector<int>& cells) {\n    if (cells.empty()) return 0;\n\n    vector<int> cand = cells;\n    sort(cand.begin(), cand.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n    if ((int)cand.size() > 40) cand.resize(40);\n\n    int best = cand[0];\n    long double bestCost = 1e100L;\n\n    for (int a : cand) {\n        long double cost = 0;\n        for (int x : cells) {\n            cost += (long double)D(a, x) * rootDirt[x];\n        }\n        if (cost < bestCost) {\n            bestCost = cost;\n            best = a;\n        }\n    }\n\n    return best;\n}\n\nRouteBuilder makeLocalLoop(int anchor, const vector<int>& cells, double beta) {\n    RouteBuilder b;\n    b.init();\n    b.cur = anchor;\n    b.seen.assign(V, 1);\n    b.unseen = 0;\n    b.last.assign(V, 0);\n\n    vector<char> need(V, 0), done(V, 0);\n    int rem = 0;\n\n    for (int id : cells) {\n        if (!need[id]) {\n            need[id] = 1;\n            ++rem;\n        }\n    }\n\n    if (need[anchor]) {\n        done[anchor] = 1;\n        --rem;\n    }\n\n    auto markNew = [&](int fromIdx) {\n        for (int i = fromIdx; i < b.t; ++i) {\n            int id = b.seq[i];\n            if (need[id] && !done[id]) {\n                done[id] = 1;\n                --rem;\n            }\n        }\n    };\n\n    while (rem > 0 && b.t < LIMIT_LEN) {\n        int best = -1;\n        double bestKey = 1e100;\n\n        for (int id : cells) {\n            if (!need[id] || done[id]) continue;\n            double key = D(b.cur, id) + 0.08 * D(id, anchor) - beta * rootDirt[id];\n            if (key < bestKey) {\n                bestKey = key;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n\n        int oldT = b.t;\n        appendPath(b, best, false);\n        markNew(oldT);\n\n        if (b.t > LIMIT_LEN) break;\n    }\n\n    appendPath(b, anchor, false);\n    return b;\n}\n\nvector<int> selectAnchors(const vector<int>& cells, int C) {\n    vector<int> sorted = cells;\n    sort(sorted.begin(), sorted.end(), [&](int a, int b) {\n        return dirtv[a] > dirtv[b];\n    });\n\n    vector<int> anchors;\n    if (sorted.empty()) return anchors;\n\n    anchors.push_back(sorted[0]);\n\n    while ((int)anchors.size() < C && (int)anchors.size() < (int)sorted.size()) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int id : sorted) {\n            bool used = false;\n            for (int a : anchors) if (a == id) used = true;\n            if (used) continue;\n\n            int md = 1000000;\n            for (int a : anchors) md = min(md, D(id, a));\n\n            double score = rootDirt[id] * (md + 1);\n            if (score > bestScore) {\n                bestScore = score;\n                best = id;\n            }\n        }\n\n        if (best < 0) break;\n        anchors.push_back(best);\n    }\n\n    return anchors;\n}\n\nRouteBuilder composeLocalInsertion(const RouteBuilder& cover, int anchor,\n                                   const RouteBuilder& loop, int reps) {\n    RouteBuilder invalid;\n    if (loop.t <= 0 || reps <= 0) return invalid;\n    if (cover.t + 1LL * reps * loop.t > LIMIT_LEN) return invalid;\n\n    int p = -2;\n    if (anchor == 0) {\n        p = -1;\n    } else {\n        for (int i = 0; i < cover.t; ++i) {\n            if (cover.seq[i] == anchor) {\n                p = i;\n                break;\n            }\n        }\n    }\n\n    if (p == -2) return invalid;\n\n    RouteBuilder b;\n    b.init();\n\n    for (int i = 0; i <= p; ++i) b.addMove(cover.seq[i]);\n\n    for (int r = 0; r < reps; ++r) {\n        for (int nb : loop.seq) b.addMove(nb);\n    }\n\n    for (int i = p + 1; i < cover.t; ++i) b.addMove(cover.seq[i]);\n\n    return b;\n}\n\nRouteBuilder composeMultiLocal(const RouteBuilder& cover,\n                               const vector<int>& anchors,\n                               const vector<RouteBuilder>& loops,\n                               const vector<int>& reps) {\n    RouteBuilder invalid;\n\n    int m = loops.size();\n    long long len = cover.t;\n    for (int i = 0; i < m; ++i) len += 1LL * reps[i] * loops[i].t;\n    if (len <= 0 || len > LIMIT_LEN) return invalid;\n\n    vector<int> pos(m, -2);\n    for (int k = 0; k < m; ++k) {\n        if (anchors[k] == 0) {\n            pos[k] = -1;\n        } else {\n            for (int i = 0; i < cover.t; ++i) {\n                if (cover.seq[i] == anchors[k]) {\n                    pos[k] = i;\n                    break;\n                }\n            }\n        }\n        if (pos[k] == -2) return invalid;\n    }\n\n    RouteBuilder b;\n    b.init();\n\n    for (int k = 0; k < m; ++k) {\n        if (pos[k] == -1) {\n            for (int r = 0; r < reps[k]; ++r) {\n                for (int nb : loops[k].seq) b.addMove(nb);\n            }\n        }\n    }\n\n    for (int i = 0; i < cover.t; ++i) {\n        b.addMove(cover.seq[i]);\n\n        for (int k = 0; k < m; ++k) {\n            if (pos[k] == i) {\n                for (int r = 0; r < reps[k]; ++r) {\n                    for (int nb : loops[k].seq) b.addMove(nb);\n                }\n            }\n        }\n    }\n\n    return b;\n}\n\nuint64_t hashOrder(const vector<int>& ord) {\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\nuint64_t hashStringRoute(const string& s) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)s.size();\n    h *= 1099511628211ULL;\n    for (unsigned char c : s) {\n        h ^= (uint64_t)c;\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nstruct SavedRoute {\n    long double sc;\n    vector<int> seq;\n    string moves;\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Timer timer;\n\n    cin >> N;\n    V = N * N;\n\n    hwall.resize(N - 1);\n    for (int i = 0; i < N - 1; ++i) cin >> hwall[i];\n\n    vwall.resize(N);\n    for (int i = 0; i < N; ++i) cin >> vwall[i];\n\n    dirtv.assign(V, 0);\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            cin >> dirtv[i * N + j];\n        }\n    }\n\n    adjg.assign(V, {});\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = i * N + j;\n\n            if (i + 1 < N && hwall[i][j] == '0') {\n                int to = (i + 1) * N + j;\n                adjg[id].push_back({to, 'D'});\n                adjg[to].push_back({id, 'U'});\n            }\n\n            if (j + 1 < N && vwall[i][j] == '0') {\n                int to = i * N + (j + 1);\n                adjg[id].push_back({to, 'R'});\n                adjg[to].push_back({id, 'L'});\n            }\n        }\n    }\n\n    computeAllPairsDistances();\n\n    rootDirt.assign(V, 1.0);\n    meanRootDirt = 0.0;\n    for (int id = 0; id < V; ++id) {\n        rootDirt[id] = sqrt((double)dirtv[id]);\n        meanRootDirt += rootDirt[id];\n    }\n    meanRootDirt /= V;\n    if (meanRootDirt <= 0) meanRootDirt = 1.0;\n\n    long double bestScore = 1e100L;\n    string bestMoves;\n    vector<int> bestSeq;\n\n    vector<SavedRoute> savedRoutes;\n    const int SAVE_K = 12;\n\n    auto addSaved = [&](long double sc, const vector<int>& seq, const string& moves, int l, int r) {\n        if (sc > 9e99L) return;\n        if (l < 0 || r > (int)seq.size() || l >= r) return;\n        if (r - l > LIMIT_LEN) return;\n        if ((int)moves.size() < r) return;\n\n        int pos = -1;\n        if ((int)savedRoutes.size() < SAVE_K) {\n            pos = savedRoutes.size();\n        } else {\n            int worst = 0;\n            for (int i = 1; i < (int)savedRoutes.size(); ++i) {\n                if (savedRoutes[i].sc > savedRoutes[worst].sc) worst = i;\n            }\n            if (sc < savedRoutes[worst].sc) pos = worst;\n        }\n\n        if (pos == -1) return;\n\n        SavedRoute sr;\n        sr.sc = sc;\n        sr.seq.assign(seq.begin() + l, seq.begin() + r);\n        sr.moves = moves.substr(l, r - l);\n\n        if (pos == (int)savedRoutes.size()) savedRoutes.push_back(std::move(sr));\n        else savedRoutes[pos] = std::move(sr);\n    };\n\n    RouteBuilder bestShort;\n    long double bestShortScore = 1e100L;\n\n    RouteBuilder shortestShort;\n    int shortestLen = INT_MAX;\n\n    auto considerSegment = [&](const RouteBuilder& b, int l, int r) {\n        if (l < 0 || r > b.t || l >= r) return;\n        if (r - l > LIMIT_LEN) return;\n        if (l > 0 && b.seq[l - 1] != 0) return;\n        if (b.seq[r - 1] != 0) return;\n\n        long double sc = evaluateRange(b.seq, l, r);\n        addSaved(sc, b.seq, b.moves, l, r);\n\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestMoves = b.moves.substr(l, r - l);\n            bestSeq.assign(b.seq.begin() + l, b.seq.begin() + r);\n        }\n    };\n\n    auto considerFull = [&](const RouteBuilder& b) {\n        considerSegment(b, 0, b.t);\n    };\n\n    auto considerShort = [&](const RouteBuilder& b) {\n        if (b.t <= LIMIT_LEN && b.cur == 0 && b.unseen == 0) {\n            long double sc = evaluateSeq(b.seq, b.t);\n            addSaved(sc, b.seq, b.moves, 0, b.t);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = b.moves;\n                bestSeq = b.seq;\n            }\n\n            if (sc < bestShortScore) {\n                bestShortScore = sc;\n                bestShort = b;\n            }\n\n            if (b.t < shortestLen) {\n                shortestLen = b.t;\n                shortestShort = b;\n            }\n        }\n    };\n\n    vector<int> ordRow = rowOrder();\n    vector<int> ordCol = colOrder();\n    vector<int> ordRowB = rowOrderBottom();\n    vector<int> ordColR = colOrderRight();\n    vector<int> ordHilbert = hilbertOrder();\n\n    vector<int> ordMet0 = metricNearestOrder(0.0, 0.5);\n    vector<int> ordMet1 = metricNearestOrder(0.25, 0.5);\n    vector<int> ordMet2 = metricNearestOrder(0.55, 0.5);\n    vector<int> ordMet3 = metricNearestOrder(0.95, 0.55);\n    vector<int> ordHigh25 = highBackboneOrder(0.25, 0.20);\n    vector<int> ordHigh50 = highBackboneOrder(0.50, 0.10);\n    vector<int> ordIns0 = metricInsertionOrder(0);\n    vector<int> ordIns1 = metricInsertionOrder(1);\n    vector<int> ordIns2 = metricInsertionOrder(2);\n    vector<int> ordIns3 = metricInsertionOrder(3);\n\n    vector<RouteBuilder> shortCandidates;\n\n    vector<string> dirs = {\"RDLU\", \"DRUL\", \"LURD\", \"ULDR\", \"RULD\", \"DLUR\"};\n    for (int i = 0; i < (int)dirs.size(); ++i) {\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 0));\n        shortCandidates.push_back(makeDFSRoute(dirs[i], 1));\n        if (i < 2) shortCandidates.push_back(makeDFSRoute(dirs[i], 2));\n    }\n\n    for (int mode = 0; mode < 4; ++mode) {\n        shortCandidates.push_back(makePrimTreeRoute(mode, 0));\n        shortCandidates.push_back(makePrimTreeRoute(mode, 1));\n        if (mode < 2) shortCandidates.push_back(makePrimTreeRoute(mode, 2));\n    }\n\n    shortCandidates.push_back(makeRouteByOrder(ordRow));\n    shortCandidates.push_back(makeRouteByOrder(ordCol));\n    shortCandidates.push_back(makeRouteByOrder(ordRowB));\n    shortCandidates.push_back(makeRouteByOrder(ordColR));\n    shortCandidates.push_back(makeRouteByOrder(ordMet0));\n    shortCandidates.push_back(makeRouteByOrder(ordMet1));\n    shortCandidates.push_back(makeRouteByOrder(ordMet3));\n    shortCandidates.push_back(makeRouteByOrder(ordHigh25));\n    shortCandidates.push_back(makeRouteByOrder(ordHigh50));\n    shortCandidates.push_back(makeRouteByOrder(ordIns0));\n    shortCandidates.push_back(makeRouteByOrder(ordIns1));\n    shortCandidates.push_back(makeRouteByOrder(ordIns2));\n    shortCandidates.push_back(makeRouteByOrder(ordIns3));\n\n    for (int v = 0; v < 5; ++v) {\n        shortCandidates.push_back(makeNearestCover(v));\n    }\n\n    for (auto& b : shortCandidates) considerShort(b);\n\n    if (bestShort.t == 0) {\n        bestShort = shortCandidates[0];\n        shortestShort = shortCandidates[0];\n        shortestLen = shortestShort.t;\n        considerFull(bestShort);\n    }\n\n    vector<vector<int>> optOrders;\n\n    if (timer.elapsed() < 0.32) {\n        buildNearLists(34);\n\n        vector<vector<int>> bases;\n        bases.push_back(firstVisitOrder(bestShort));\n        bases.push_back(ordMet0);\n        bases.push_back(ordMet1);\n        bases.push_back(ordMet2);\n        bases.push_back(ordMet3);\n        bases.push_back(ordHigh25);\n        bases.push_back(ordHigh50);\n        bases.push_back(ordIns0);\n        bases.push_back(ordIns1);\n        bases.push_back(ordIns2);\n        bases.push_back(ordIns3);\n        bases.push_back(ordRow);\n        bases.push_back(ordCol);\n\n        for (int i = 0; i < (int)bases.size() && timer.elapsed() < 0.64; ++i) {\n            vector<int> op = improveOrder2Opt(bases[i], 0.0, timer, 0.64, 260);\n            optOrders.push_back(op);\n\n            RouteBuilder rb = makeRouteByOrder(op);\n            shortCandidates.push_back(rb);\n            considerShort(rb);\n\n            if (i < 7 && timer.elapsed() < 0.70) {\n                vector<int> opw = improveOrder2Opt(bases[i], 0.85, timer, 0.70, 180);\n                optOrders.push_back(opw);\n\n                RouteBuilder rbw = makeRouteByOrder(opw);\n                shortCandidates.push_back(rbw);\n                considerShort(rbw);\n            }\n        }\n    }\n\n    if (shortestShort.t == 0) shortestShort = bestShort;\n\n    vector<vector<int>> orders;\n    unordered_set<uint64_t> orderHashes;\n\n    auto addOrder = [&](vector<int> ord) {\n        if ((int)ord.size() != V) return;\n\n        vector<char> seen(V, 0);\n        for (int x : ord) {\n            if (x < 0 || x >= V || seen[x]) return;\n            seen[x] = 1;\n        }\n\n        uint64_t h = hashOrder(ord);\n        if (orderHashes.insert(h).second) orders.push_back(ord);\n    };\n\n    addOrder(firstVisitOrder(bestShort));\n    addOrder(firstVisitOrder(shortestShort));\n    for (auto& o : optOrders) addOrder(o);\n\n    addOrder(ordMet0);\n    addOrder(ordMet1);\n    addOrder(ordMet2);\n    addOrder(ordMet3);\n    addOrder(ordHigh25);\n    addOrder(ordHigh50);\n    addOrder(ordIns0);\n    addOrder(ordIns1);\n    addOrder(ordIns2);\n    addOrder(ordIns3);\n    addOrder(ordRow);\n    addOrder(ordCol);\n    addOrder(ordRowB);\n    addOrder(ordColR);\n    addOrder(ordHilbert);\n\n    for (auto& b : shortCandidates) {\n        addOrder(firstVisitOrder(b));\n    }\n\n    int initialOrderCount = orders.size();\n    for (int i = 0; i < initialOrderCount; ++i) {\n        vector<int> rev = orders[i];\n        reverse(rev.begin(), rev.end());\n        addOrder(rev);\n    }\n\n    vector<double> baseExps = {0.36, 0.44, 0.52, 0.62};\n    vector<double> richExps = {0.28, 0.36, 0.44, 0.52, 0.60, 0.70};\n    vector<double> muls = {1.00, 0.98, 0.94, 0.88, 0.80, 0.70, 0.58, 0.46, 0.36, 0.28, 1.05};\n\n    double phaseEnd = 1.40;\n\n    for (int oi = 0; oi < (int)orders.size(); ++oi) {\n        if (timer.elapsed() > phaseEnd) break;\n\n        const vector<int>& ord = orders[oi];\n        const vector<double>& exps = (oi < 12 ? richExps : baseExps);\n\n        vector<int> modes;\n        if (oi < 7) modes = {0, 1, 2, 3, 4};\n        else if (oi < 16) modes = {0, 1, 2, 3};\n        else modes = {0, 1};\n\n        for (double ep : exps) {\n            if (timer.elapsed() > phaseEnd) break;\n\n            vector<double> weight(V);\n            for (int id = 0; id < V; ++id) {\n                weight[id] = pow((double)dirtv[id], ep);\n            }\n\n            for (int mode : modes) {\n                if (timer.elapsed() > phaseEnd + 0.02) break;\n\n                double scale = findPhaseScale(ord, weight, mode);\n\n                for (double m : muls) {\n                    double sca = scale * m;\n                    if (sca < 0.0) continue;\n\n                    long long len = phaseLength(ord, weight, sca, mode, LIMIT_LEN + 1);\n                    if (len <= LIMIT_LEN) {\n                        RouteBuilder b = buildPhaseRoute(ord, weight, sca, mode);\n                        if (b.t <= LIMIT_LEN && b.cur == 0) {\n                            considerFull(b);\n                        }\n                    }\n\n                    if (timer.elapsed() > phaseEnd + 0.03) break;\n                }\n            }\n        }\n    }\n\n    if (timer.elapsed() < 1.43 && !bestSeq.empty()) {\n        double adaptiveEnd = 1.455;\n\n        vector<double> contrib = computeContributionVector(bestSeq);\n        vector<double> gapScore(V);\n\n        double meanC = 0.0, meanG = 0.0;\n        for (int id = 0; id < V; ++id) {\n            meanC += contrib[id];\n            gapScore[id] = contrib[id] / max(1, dirtv[id]);\n            meanG += gapScore[id];\n        }\n        meanC /= max(1, V);\n        meanG /= max(1, V);\n        if (meanC <= 0) meanC = 1.0;\n        if (meanG <= 0) meanG = 1.0;\n\n        vector<double> w0(V), w1(V), w2(V), w3(V);\n        for (int id = 0; id < V; ++id) {\n            double cr = contrib[id] / meanC;\n            double gr = gapScore[id] / meanG;\n            cr = max(0.05, min(30.0, cr));\n            gr = max(0.05, min(30.0, gr));\n\n            w0[id] = pow((double)dirtv[id], 0.50);\n            w1[id] = pow((double)dirtv[id], 0.50) * pow(cr, 0.22);\n            w2[id] = pow((double)dirtv[id], 0.42) * pow(gr, 0.30);\n            w3[id] = pow((double)dirtv[id], 0.58) * pow(cr, 0.12);\n        }\n\n        vector<vector<double>> aws = {w1, w2, w0, w3};\n\n        vector<vector<int>> aorders;\n        unordered_set<uint64_t> ah;\n\n        auto addAOrder = [&](vector<int> ord) {\n            if ((int)ord.size() != V) return;\n            uint64_t h = hashOrder(ord);\n            if (ah.insert(h).second) aorders.push_back(ord);\n        };\n\n        addAOrder(firstVisitOrderFromSeq(bestSeq));\n        addAOrder(metricInsertionFromScore(contrib));\n        if (!orders.empty()) addAOrder(orders[0]);\n        if ((int)orders.size() > 1) addAOrder(orders[1]);\n        if (timer.elapsed() < adaptiveEnd - 0.005) {\n            addAOrder(metricInsertionFromScore(gapScore));\n        }\n\n        vector<double> amuls = {1.00, 0.94, 0.84, 0.70, 0.55};\n        for (int oi = 0; oi < (int)aorders.size() && timer.elapsed() < adaptiveEnd; ++oi) {\n            vector<int> modes = (oi < 2 ? vector<int>{0, 1, 3} : vector<int>{0, 1});\n            for (auto& weight : aws) {\n                if (timer.elapsed() > adaptiveEnd) break;\n\n                for (int mode : modes) {\n                    if (timer.elapsed() > adaptiveEnd) break;\n\n                    double scale = findPhaseScale(aorders[oi], weight, mode);\n\n                    for (double m : amuls) {\n                        double sca = scale * m;\n                        long long len = phaseLength(aorders[oi], weight, sca, mode, LIMIT_LEN + 1);\n                        if (len <= LIMIT_LEN) {\n                            RouteBuilder b = buildPhaseRoute(aorders[oi], weight, sca, mode);\n                            if (b.t <= LIMIT_LEN && b.cur == 0) {\n                                considerFull(b);\n                            }\n                        }\n                        if (timer.elapsed() > adaptiveEnd) break;\n                    }\n                }\n            }\n        }\n    }\n\n    if (timer.elapsed() < 1.47) {\n        vector<double> fracs = {0.03, 0.06, 0.10, 0.18};\n\n        auto processLocalCells = [&](const RouteBuilder& cover, const vector<int>& cells, double deadline) {\n            if (timer.elapsed() > deadline) return;\n\n            int anchor = chooseMedoid(cells);\n            RouteBuilder loop = makeLocalLoop(anchor, cells, 0.35);\n\n            if (loop.t <= 0 || loop.cur != anchor) return;\n            int maxR = (LIMIT_LEN - cover.t) / loop.t;\n            if (maxR <= 0) return;\n\n            vector<int> rs = {1, 2, 3, 5, 8, 13, 21, maxR / 8, maxR / 5, maxR / 3, maxR / 2, maxR};\n            sort(rs.begin(), rs.end());\n            rs.erase(unique(rs.begin(), rs.end()), rs.end());\n\n            for (int r : rs) {\n                if (r <= 0 || r > maxR) continue;\n                RouteBuilder c = composeLocalInsertion(cover, anchor, loop, r);\n                if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n                if (timer.elapsed() > deadline) break;\n            }\n        };\n\n        auto tryLocalCover = [&](const RouteBuilder& cover, double deadline) {\n            for (double f : fracs) {\n                if (timer.elapsed() > deadline) break;\n                processLocalCells(cover, topCellsByDirt(f), deadline);\n                if (timer.elapsed() > deadline) break;\n                processLocalCells(cover, topCellsByContribution(cover, f), deadline);\n            }\n        };\n\n        tryLocalCover(shortestShort, 1.50);\n        if (bestShort.moves != shortestShort.moves && timer.elapsed() < 1.50) {\n            tryLocalCover(bestShort, 1.52);\n        }\n    }\n\n    if (timer.elapsed() < 1.51) {\n        vector<double> fracs = {0.10, 0.20};\n\n        for (double f : fracs) {\n            if (timer.elapsed() > 1.55) break;\n\n            vector<int> cells = topCellsByContribution(shortestShort, f);\n            vector<int> anchors = selectAnchors(cells, 3);\n            if (anchors.empty()) continue;\n\n            vector<vector<int>> groups(anchors.size());\n            for (int x : cells) {\n                int bi = 0;\n                int bd = D(x, anchors[0]);\n                for (int i = 1; i < (int)anchors.size(); ++i) {\n                    int dd = D(x, anchors[i]);\n                    if (dd < bd) {\n                        bd = dd;\n                        bi = i;\n                    }\n                }\n                groups[bi].push_back(x);\n            }\n\n            vector<int> useAnchors;\n            vector<RouteBuilder> loops;\n            vector<double> vals;\n\n            for (int i = 0; i < (int)anchors.size(); ++i) {\n                if ((int)groups[i].size() <= 1) continue;\n                RouteBuilder lp = makeLocalLoop(anchors[i], groups[i], 0.25);\n                if (lp.t <= 0 || lp.cur != anchors[i]) continue;\n\n                double val = 0;\n                for (int x : groups[i]) val += rootDirt[x];\n\n                useAnchors.push_back(anchors[i]);\n                loops.push_back(lp);\n                vals.push_back(val);\n            }\n\n            int m = loops.size();\n            if (m == 0) continue;\n\n            vector<double> ratios = {0.18, 0.35, 0.55};\n            for (double ratio : ratios) {\n                int budget = max(0, (int)((LIMIT_LEN - shortestShort.t) * ratio));\n                vector<int> reps(m, 0);\n                int used = 0;\n\n                while (true) {\n                    int bj = -1;\n                    double bs = -1;\n\n                    for (int j = 0; j < m; ++j) {\n                        if (used + loops[j].t > budget) continue;\n                        double s = vals[j] / ((reps[j] + 1.0) * (reps[j] + 1.0) * loops[j].t);\n                        if (s > bs) {\n                            bs = s;\n                            bj = j;\n                        }\n                    }\n\n                    if (bj < 0) break;\n                    ++reps[bj];\n                    used += loops[bj].t;\n                }\n\n                bool any = false;\n                for (int r : reps) if (r > 0) any = true;\n                if (!any) continue;\n\n                RouteBuilder c = composeMultiLocal(shortestShort, useAnchors, loops, reps);\n                if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n\n                if (timer.elapsed() > 1.55) break;\n            }\n        }\n    }\n\n    if (timer.elapsed() < 1.54) {\n        vector<double> fracs = {0.05, 0.10, 0.20, 0.35};\n\n        for (double f : fracs) {\n            if (timer.elapsed() > 1.58) break;\n\n            RouteBuilder loop = buildHighSubsetLoop(f);\n            if (loop.t <= 0 || loop.cur != 0) continue;\n\n            auto tryCover = [&](const RouteBuilder& cover) {\n                if (cover.t <= 0 || loop.t <= 0) return;\n                int maxR = (LIMIT_LEN - cover.t) / loop.t;\n                if (maxR <= 0) return;\n\n                vector<int> rs = {1, 2, 3, 5, 8, 13, 21, maxR / 4, maxR / 2, maxR};\n                sort(rs.begin(), rs.end());\n                rs.erase(unique(rs.begin(), rs.end()), rs.end());\n\n                for (int r : rs) {\n                    if (r <= 0 || r > maxR) continue;\n                    if (cover.t + 1LL * r * loop.t > LIMIT_LEN) continue;\n\n                    RouteBuilder c = composeLoops(cover, loop, r);\n                    if (c.t <= LIMIT_LEN && c.cur == 0) considerFull(c);\n                    if (timer.elapsed() > 1.58) break;\n                }\n            };\n\n            tryCover(shortestShort);\n            if (bestShort.moves != shortestShort.moves) tryCover(bestShort);\n        }\n    }\n\n    auto considerSegments = [&](const RouteBuilder& b, int minGap) {\n        vector<int> zeros;\n        zeros.push_back(0);\n        for (int t = 1; t <= b.t; ++t) {\n            if (b.seq[t - 1] == 0) zeros.push_back(t);\n        }\n\n        int lastPrefix = 0;\n        for (int z : zeros) {\n            if (z > 0 && z - lastPrefix >= minGap) {\n                considerSegment(b, 0, z);\n                lastPrefix = z;\n                if (timer.elapsed() > 1.94) return;\n            }\n        }\n\n        int lastS = -1000000000;\n        int cnt = 0;\n        for (int z : zeros) {\n            int L = b.t - z;\n            if (L <= 0 || L > LIMIT_LEN) continue;\n            if (z - lastS >= max(2000, minGap / 2)) {\n                considerSegment(b, z, b.t);\n                lastS = z;\n                ++cnt;\n                if (cnt >= 30 || timer.elapsed() > 1.94) return;\n            }\n        }\n\n        vector<int> targets = {minGap, 20000, 35000, 50000, 70000, 90000, 100000};\n        unordered_set<unsigned long long> usedPairs;\n        int evals = 0;\n\n        for (int ei = 1; ei < (int)zeros.size() && evals < 45; ++ei) {\n            int e = zeros[ei];\n\n            for (int TL : targets) {\n                int want = e - TL;\n                auto it = lower_bound(zeros.begin(), zeros.begin() + ei, want);\n\n                for (int rep = 0; rep < 2; ++rep) {\n                    if (it == zeros.begin() + ei) {\n                        if (it == zeros.begin()) break;\n                        --it;\n                    }\n\n                    int s = *it;\n                    int L = e - s;\n                    if (L >= max(1000, minGap / 2) && L <= LIMIT_LEN) {\n                        unsigned long long key = ((unsigned long long)(unsigned int)s << 32) ^ (unsigned int)e;\n                        if (usedPairs.insert(key).second) {\n                            considerSegment(b, s, e);\n                            ++evals;\n                            if (timer.elapsed() > 1.94) return;\n                        }\n                    }\n\n                    if (it == zeros.begin()) break;\n                    --it;\n                }\n            }\n        }\n    };\n\n    if (timer.elapsed() < 1.58) {\n        RouteBuilder ig = buildIntegratedGreedy(28.0, 1, 8, 70000, 8e9, 5.0, timer, 1.66);\n        if (ig.cur == 0) {\n            considerFull(ig);\n            considerSegments(ig, 10000);\n        }\n    }\n\n    if (timer.elapsed() < 1.66) {\n        RouteBuilder ig = buildIntegratedGreedy(45.0, 1, 10, LIMIT_LEN, 1.2e10, 7.0, timer, 1.74);\n        if (ig.cur == 0) {\n            considerFull(ig);\n            considerSegments(ig, 12000);\n        }\n    }\n\n    if (timer.elapsed() < 1.74) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 20.0, 1, 4, LIMIT_LEN, timer, 1.82);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 12000);\n            if (bestShort.t < g.t) considerSegment(g, bestShort.t, g.t);\n        }\n    }\n\n    if (timer.elapsed() < 1.82) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 25.0, 1, 1,\n                                          bestShort.t + LIMIT_LEN, timer, 1.89);\n        if (g.cur == 0) {\n            if (bestShort.t < g.t) considerSegment(g, bestShort.t, g.t);\n            considerSegments(g, 14000);\n        }\n    }\n\n    if (timer.elapsed() < 1.89) {\n        RouteBuilder g = buildChunkGreedy(shortestShort, 36.0, 1, 2,\n                                          LIMIT_LEN, timer, 1.94);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 12000);\n            if (shortestShort.t < g.t) considerSegment(g, shortestShort.t, g.t);\n        }\n    }\n\n    if (timer.elapsed() < 1.94) {\n        RouteBuilder g = buildChunkGreedy(bestShort, 70.0, 3, 5,\n                                          76000, timer, 1.97);\n        if (g.cur == 0) {\n            considerFull(g);\n            considerSegments(g, 9000);\n        }\n    }\n\n    auto optimizeRouteSegments = [&](const vector<int>& seq, const string& moves, double deadline) {\n        if (seq.empty() || moves.size() != seq.size()) return;\n\n        int L = (int)seq.size();\n        vector<int> zeros;\n        zeros.push_back(0);\n        for (int t = 1; t <= L; ++t) {\n            if (seq[t - 1] == 0) zeros.push_back(t);\n        }\n        if ((int)zeros.size() <= 2) return;\n\n        int evals = 0;\n        const int EVAL_LIMIT = 60;\n        int minLen = max(1000, min(12000, L / 5));\n\n        auto tryContig = [&](int s, int e) {\n            if (timer.elapsed() > deadline || evals >= EVAL_LIMIT) return;\n            if (s < 0 || e > L || s >= e) return;\n            if (e - s > LIMIT_LEN) return;\n            if (s > 0 && seq[s - 1] != 0) return;\n            if (seq[e - 1] != 0) return;\n            ++evals;\n\n            long double sc = evaluateRange(seq, s, e);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = moves.substr(s, e - s);\n                bestSeq.assign(seq.begin() + s, seq.begin() + e);\n            }\n        };\n\n        auto tryComplement = [&](int s, int e) {\n            if (timer.elapsed() > deadline || evals >= EVAL_LIMIT) return;\n            if (s < 0 || e > L || s >= e) return;\n\n            int len = L - (e - s);\n            if (len <= 0 || len > LIMIT_LEN) return;\n            if (seq[e - 1] != 0) return;\n            if (s > 0 && seq[s - 1] != 0) return;\n            ++evals;\n\n            vector<int> tmp;\n            tmp.reserve(len);\n            for (int i = e; i < L; ++i) tmp.push_back(seq[i]);\n            for (int i = 0; i < s; ++i) tmp.push_back(seq[i]);\n            if (tmp.empty() || tmp.back() != 0) return;\n\n            long double sc = evaluateSeq(tmp, len);\n            if (sc < bestScore) {\n                bestScore = sc;\n                bestMoves = moves.substr(e) + moves.substr(0, s);\n                bestSeq = std::move(tmp);\n            }\n        };\n\n        for (int z : zeros) {\n            if (timer.elapsed() > deadline || evals >= EVAL_LIMIT) break;\n            if (z >= minLen && z < L) tryContig(0, z);\n            if (L - z >= minLen && z > 0) tryContig(z, L);\n        }\n\n        vector<int> targets = {\n            L, (int)(L * 0.9), (int)(L * 0.8), (int)(L * 0.7),\n            (int)(L * 0.6), (int)(L * 0.5), 90000, 70000, 50000,\n            35000, 25000, 16000\n        };\n\n        unordered_set<unsigned long long> usedPairs;\n\n        for (int ei = 1; ei < (int)zeros.size() && evals < EVAL_LIMIT; ++ei) {\n            int e = zeros[ei];\n\n            for (int TL : targets) {\n                if (timer.elapsed() > deadline || evals >= EVAL_LIMIT) break;\n                if (TL <= 0) continue;\n\n                int want = e - TL;\n                auto it = lower_bound(zeros.begin(), zeros.begin() + ei, want);\n\n                for (int rep = 0; rep < 3; ++rep) {\n                    if (timer.elapsed() > deadline || evals >= EVAL_LIMIT) break;\n\n                    if (it == zeros.begin() + ei) {\n                        if (it == zeros.begin()) break;\n                        --it;\n                    }\n\n                    int s = *it;\n                    int len = e - s;\n                    if (len >= minLen && len <= LIMIT_LEN) {\n                        unsigned long long key = ((unsigned long long)(unsigned int)s << 32) ^ (unsigned int)e;\n                        if (usedPairs.insert(key).second) {\n                            tryContig(s, e);\n                            if (L - len >= minLen) tryComplement(s, e);\n                        }\n                    }\n\n                    if (it == zeros.begin()) break;\n                    --it;\n                }\n            }\n        }\n    };\n\n    if (timer.elapsed() < 1.955) {\n        vector<SavedRoute> snap = savedRoutes;\n        sort(snap.begin(), snap.end(), [&](const SavedRoute& a, const SavedRoute& b) {\n            return a.sc < b.sc;\n        });\n\n        vector<SavedRoute> uniq;\n        unordered_set<uint64_t> seenHash;\n        for (auto& sr : snap) {\n            uint64_t h = hashStringRoute(sr.moves);\n            if (seenHash.insert(h).second) uniq.push_back(std::move(sr));\n        }\n\n        for (auto& sr : uniq) {\n            if (timer.elapsed() > 1.985) break;\n            optimizeRouteSegments(sr.seq, sr.moves, 1.985);\n        }\n\n        if (timer.elapsed() < 1.985 && !bestSeq.empty()) {\n            optimizeRouteSegments(bestSeq, bestMoves, 1.985);\n        }\n    }\n\n    if (bestMoves.empty()) {\n        bestMoves = shortCandidates[0].moves;\n    }\n\n    cout << bestMoves << '\\n';\n    return 0;\n}","ahc028":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\n    Timer() { reset(); }\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 XorShift {\n    uint64_t x = 88172645463325252ull;\n    uint32_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return (uint32_t)x;\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n    double nextDouble() { return (next() >> 8) * (1.0 / 16777216.0); }\n};\n\nstruct Solver {\n    static constexpr unsigned short USINF = 30000;\n\n    int N, M;\n    int si, sj, startId;\n    vector<string> grid, words;\n    vector<array<int, 5>> wch;\n\n    vector<int> letterPos[26];\n    unsigned char distCell[225][225];\n\n    vector<int> lastChar;\n    vector<unsigned char> overlap;\n\n    vector<int> initOff;\n    vector<unsigned short> initData;\n    vector<int> startMinCost, startMin10, startAvg10;\n\n    vector<int> edgeOff;\n    vector<unsigned short> edgeData;\n    vector<int> edgeMin10, edgeAvg10;\n\n    int maxOcc = 0;\n\n    struct Mode {\n        vector<int> edge, start;\n    };\n    vector<Mode> modes;\n\n    struct Move {\n        int type;\n        int a, b;\n        long long delta;\n        int c;\n    };\n\n    struct Candidate {\n        int cost;\n        vector<int> order;\n    };\n\n    struct ExactCtx {\n        int n;\n        vector<int> cnt;\n        vector<int> foff, roff;\n        vector<unsigned short> fdata, rdata;\n        vector<int> prefOff, suffOff;\n        vector<unsigned short> prefData, suffData;\n        int current = 0;\n    };\n\n    Timer timer;\n    XorShift rng;\n\n    vector<int> bestOrder;\n    int bestCost = INT_MAX;\n\n    unordered_map<int, int> targetMap;\n    int pow4 = 456976;\n\n    void readInput() {\n        cin >> N >> M;\n        cin >> si >> sj;\n        startId = si * N + sj;\n\n        grid.resize(N);\n        for (int c = 0; c < 26; c++) letterPos[c].clear();\n\n        for (int i = 0; i < N; i++) {\n            cin >> grid[i];\n            for (int j = 0; j < N; j++) {\n                letterPos[grid[i][j] - 'A'].push_back(i * N + j);\n            }\n        }\n\n        words.resize(M);\n        wch.resize(M);\n        for (int i = 0; i < M; i++) {\n            cin >> words[i];\n            for (int k = 0; k < 5; k++) wch[i][k] = words[i][k] - 'A';\n        }\n    }\n\n    int encodeWord(const string& s) const {\n        int code = 0;\n        for (char ch : s) code = code * 26 + (ch - 'A');\n        return code;\n    }\n\n    int calcOverlap(int a, int b) const {\n        for (int k = 4; k >= 1; k--) {\n            bool ok = true;\n            for (int p = 0; p < k; p++) {\n                if (words[a][5 - k + p] != words[b][p]) {\n                    ok = false;\n                    break;\n                }\n            }\n            if (ok) return k;\n        }\n        return 0;\n    }\n\n    inline int wordCnt(int w) const {\n        return (int)letterPos[lastChar[w]].size();\n    }\n\n    void precompute() {\n        int V = N * N;\n        for (int a = 0; a < V; a++) {\n            int ai = a / N, aj = a % N;\n            for (int b = 0; b < V; b++) {\n                int bi = b / N, bj = b % N;\n                distCell[a][b] = (unsigned char)(abs(ai - bi) + abs(aj - bj));\n            }\n        }\n\n        maxOcc = 0;\n        for (int c = 0; c < 26; c++) maxOcc = max(maxOcc, (int)letterPos[c].size());\n\n        lastChar.assign(M, 0);\n        for (int i = 0; i < M; i++) lastChar[i] = wch[i][4];\n\n        overlap.assign(M * M, 0);\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                overlap[i * M + j] = (unsigned char)calcOverlap(i, j);\n            }\n        }\n\n        targetMap.clear();\n        targetMap.reserve(512);\n        for (int i = 0; i < M; i++) targetMap[encodeWord(words[i])] = i;\n\n        long long sumOccLast = 0;\n        for (int i = 0; i < M; i++) sumOccLast += wordCnt(i);\n\n        initOff.assign(M, 0);\n        startMinCost.assign(M, 0);\n        startMin10.assign(M, 0);\n        startAvg10.assign(M, 0);\n        initData.clear();\n        initData.reserve((size_t)sumOccLast);\n\n        vector<int> cur(maxOcc), nxt(maxOcc);\n        const int INF = 1e9;\n\n        for (int i = 0; i < M; i++) {\n            int c0 = wch[i][0];\n            int cnt = (int)letterPos[c0].size();\n\n            for (int p = 0; p < cnt; p++) {\n                cur[p] = (int)distCell[startId][letterPos[c0][p]] + 1;\n            }\n\n            int prevC = c0, prevCnt = cnt;\n            for (int h = 1; h < 5; h++) {\n                int nc = wch[i][h];\n                int nextCnt = (int)letterPos[nc].size();\n\n                for (int q = 0; q < nextCnt; q++) {\n                    int best = INF;\n                    int qid = letterPos[nc][q];\n                    for (int p = 0; p < prevCnt; p++) {\n                        int v = cur[p] + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                        if (v < best) best = v;\n                    }\n                    nxt[q] = best;\n                }\n\n                for (int q = 0; q < nextCnt; q++) cur[q] = nxt[q];\n                prevC = nc;\n                prevCnt = nextCnt;\n            }\n\n            initOff[i] = (int)initData.size();\n            int mn = INF;\n            long long sum = 0;\n            for (int p = 0; p < prevCnt; p++) {\n                mn = min(mn, cur[p]);\n                sum += cur[p];\n                initData.push_back((unsigned short)cur[p]);\n            }\n            startMinCost[i] = mn;\n            startMin10[i] = 10 * mn;\n            startAvg10[i] = (int)((10 * sum + prevCnt / 2) / prevCnt);\n        }\n\n        edgeOff.assign(M * M, 0);\n        edgeAvg10.assign(M * M, 0);\n        edgeMin10.assign(M * M, 0);\n        edgeData.clear();\n\n        long long totalMat = sumOccLast * sumOccLast;\n        if (totalMat < 100000000LL) edgeData.reserve((size_t)totalMat);\n\n        vector<int> mat(maxOcc * maxOcc), mat2(maxOcc * maxOcc);\n\n        for (int i = 0; i < M; i++) {\n            int cStart = lastChar[i];\n            int rows = (int)letterPos[cStart].size();\n\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int k = overlap[idx];\n\n                int prevC = cStart, prevCnt = rows;\n\n                fill(mat.begin(), mat.begin() + rows * prevCnt, INF);\n                for (int r = 0; r < rows; r++) mat[r * prevCnt + r] = 0;\n\n                for (int h = k; h < 5; h++) {\n                    int nc = wch[j][h];\n                    int nextCnt = (int)letterPos[nc].size();\n\n                    for (int r = 0; r < rows; r++) {\n                        int baseIdx = r * prevCnt;\n                        int outIdx = r * nextCnt;\n                        for (int q = 0; q < nextCnt; q++) {\n                            int best = INF;\n                            int qid = letterPos[nc][q];\n                            for (int p = 0; p < prevCnt; p++) {\n                                int v = mat[baseIdx + p]\n                                      + (int)distCell[letterPos[prevC][p]][qid] + 1;\n                                if (v < best) best = v;\n                            }\n                            mat2[outIdx + q] = best;\n                        }\n                    }\n\n                    mat.swap(mat2);\n                    prevC = nc;\n                    prevCnt = nextCnt;\n                }\n\n                int cols = wordCnt(j);\n                edgeOff[idx] = (int)edgeData.size();\n                edgeData.resize(edgeData.size() + rows * cols);\n\n                int globalMin = INF;\n                long long sumRowMin = 0;\n                int off = edgeOff[idx];\n\n                for (int r = 0; r < rows; r++) {\n                    int rowMin = INF;\n                    for (int q = 0; q < cols; q++) {\n                        int v = mat[r * cols + q];\n                        edgeData[off + r * cols + q] = (unsigned short)v;\n                        rowMin = min(rowMin, v);\n                        globalMin = min(globalMin, v);\n                    }\n                    sumRowMin += rowMin;\n                }\n\n                edgeMin10[idx] = 10 * globalMin;\n                edgeAvg10[idx] = (int)((10 * sumRowMin + rows / 2) / rows);\n            }\n        }\n    }\n\n    void buildModes() {\n        modes.clear();\n        modes.resize(4);\n\n        for (auto& mo : modes) {\n            mo.edge.assign(M * M, 0);\n            mo.start.assign(M, 0);\n        }\n\n        for (int i = 0; i < M; i++) {\n            modes[0].start[i] = startAvg10[i];\n            modes[1].start[i] = startMin10[i];\n            modes[2].start[i] = startAvg10[i];\n            modes[3].start[i] = startAvg10[i];\n        }\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                int idx = i * M + j;\n                int len = 5 - (int)overlap[idx];\n                modes[0].edge[idx] = edgeAvg10[idx];\n                modes[1].edge[idx] = edgeMin10[idx];\n                modes[2].edge[idx] = len * 1000 + edgeAvg10[idx];\n                modes[3].edge[idx] = len * 10000 + edgeAvg10[idx];\n            }\n        }\n    }\n\n    inline long long arc(const Mode& mode, int u, int v) const {\n        if (u < 0 && v < 0) return 0;\n        if (u < 0) return mode.start[v];\n        if (v < 0) return 0;\n        return mode.edge[u * M + v];\n    }\n\n    int exactCost(const vector<int>& ord) const {\n        if (ord.empty()) return 0;\n\n        const int INF = 1e9;\n        int dp[225], ndp[225];\n\n        int first = ord[0];\n        int cnt = wordCnt(first);\n        int off0 = initOff[first];\n\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off0 + i];\n\n        for (int idx = 1; idx < (int)ord.size(); idx++) {\n            int a = ord[idx - 1];\n            int b = ord[idx];\n\n            int rows = wordCnt(a);\n            int cols = wordCnt(b);\n\n            fill(ndp, ndp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[a * M + b]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)mr[c];\n                    if (v < ndp[c]) ndp[c] = v;\n                }\n            }\n\n            for (int c = 0; c < cols; c++) dp[c] = ndp[c];\n        }\n\n        int last = ord.back();\n        int lastCnt = wordCnt(last);\n        int ans = INF;\n        for (int i = 0; i < lastCnt; i++) ans = min(ans, dp[i]);\n        return ans;\n    }\n\n    vector<int> hungarian(const vector<vector<int>>& a) const {\n        int n = (int)a.size();\n        const long long INF = (1LL << 60);\n\n        vector<long long> u(n + 1), v(n + 1);\n        vector<int> p(n + 1), way(n + 1);\n\n        for (int i = 1; i <= n; i++) {\n            p[0] = i;\n            int j0 = 0;\n            vector<long long> minv(n + 1, INF);\n            vector<char> used(n + 1, false);\n\n            do {\n                used[j0] = true;\n                int i0 = p[j0];\n                int j1 = 0;\n                long long delta = INF;\n\n                for (int j = 1; j <= n; j++) {\n                    if (used[j]) continue;\n                    long long cur = (long long)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\n                for (int j = 0; j <= n; j++) {\n                    if (used[j]) {\n                        u[p[j]] += delta;\n                        v[j] -= delta;\n                    } else {\n                        minv[j] -= delta;\n                    }\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);\n        for (int j = 1; j <= n; j++) ans[p[j] - 1] = j - 1;\n        return ans;\n    }\n\n    vector<int> patchAssignment(const vector<int>& succ, const Mode& mode) const {\n        int D = M;\n        int n = M + 1;\n\n        vector<char> visited(n, false);\n        vector<int> path;\n\n        int cur = succ[D];\n        visited[D] = true;\n        while (cur != D && !visited[cur]) {\n            visited[cur] = true;\n            path.push_back(cur);\n            cur = succ[cur];\n        }\n\n        vector<vector<int>> cycles;\n        for (int i = 0; i < M; i++) {\n            if (visited[i]) continue;\n\n            vector<int> cyc;\n            cur = i;\n            while (!visited[cur]) {\n                visited[cur] = true;\n                cyc.push_back(cur);\n                cur = succ[cur];\n            }\n            if (!cyc.empty()) cycles.push_back(cyc);\n        }\n\n        auto costArc = [&](int u, int v) -> long long {\n            if (u == D && v == D) return 0;\n            if (u == D) return mode.start[v];\n            if (v == D) return 0;\n            return mode.edge[u * M + v];\n        };\n\n        while (!cycles.empty()) {\n            long long bestDelta = (1LL << 60);\n            int bestC = -1, bestE = -1, bestBreak = -1;\n\n            for (int ci = 0; ci < (int)cycles.size(); ci++) {\n                const auto& C = cycles[ci];\n                int k = (int)C.size();\n\n                for (int e = 0; e <= (int)path.size(); e++) {\n                    int u = (e == 0 ? D : path[e - 1]);\n                    int v = (e == (int)path.size() ? D : path[e]);\n                    long long oldCost = costArc(u, v);\n\n                    for (int bidx = 0; bidx < k; bidx++) {\n                        int a = C[bidx];\n                        int b = C[(bidx + 1) % k];\n\n                        long long delta = costArc(u, b) + costArc(a, v)\n                                        - oldCost - costArc(a, b);\n\n                        if (delta < bestDelta) {\n                            bestDelta = delta;\n                            bestC = ci;\n                            bestE = e;\n                            bestBreak = bidx;\n                        }\n                    }\n                }\n            }\n\n            const auto& C = cycles[bestC];\n            int k = (int)C.size();\n            vector<int> seg;\n            seg.reserve(k);\n            for (int t = 0; t < k; t++) seg.push_back(C[(bestBreak + 1 + t) % k]);\n\n            path.insert(path.begin() + bestE, seg.begin(), seg.end());\n            cycles.erase(cycles.begin() + bestC);\n        }\n\n        return path;\n    }\n\n    vector<int> hungarianPatch(const Mode& mode) const {\n        int n = M + 1;\n        int D = M;\n        const int INF = 100000000;\n\n        vector<vector<int>> cost(n, vector<int>(n, INF));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                cost[i][j] = (i == j ? INF : mode.edge[i * M + j]);\n            }\n            cost[i][D] = 0;\n        }\n\n        for (int j = 0; j < M; j++) cost[D][j] = mode.start[j];\n        cost[D][D] = INF;\n\n        vector<int> assign = hungarian(cost);\n        return patchAssignment(assign, mode);\n    }\n\n    vector<int> cheapestInsertion(const Mode& mode) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestDelta = (1LL << 60);\n            int bestX = -1, bestPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n                    if (delta < bestDelta) {\n                        bestDelta = delta;\n                        bestX = x;\n                        bestPos = pos;\n                    }\n                }\n            }\n\n            path.insert(path.begin() + bestPos, bestX);\n            used[bestX] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> regretInsertion(const Mode& mode, int regretW) const {\n        if (M == 1) return vector<int>{0};\n\n        long long best = (1LL << 60);\n        int bi = 0, bj = 1;\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                long long v = mode.start[i] + mode.edge[i * M + j];\n                if (v < best) {\n                    best = v;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        vector<int> path = {bi, bj};\n        vector<char> used(M, false);\n        used[bi] = used[bj] = true;\n\n        while ((int)path.size() < M) {\n            long long bestScore = (1LL << 60);\n            int chosen = -1, chosenPos = -1;\n\n            for (int x = 0; x < M; x++) {\n                if (used[x]) continue;\n\n                long long b1 = (1LL << 60), b2 = (1LL << 60);\n                int pos1 = 0;\n\n                for (int pos = 0; pos <= (int)path.size(); pos++) {\n                    int u = (pos == 0 ? -1 : path[pos - 1]);\n                    int v = (pos == (int)path.size() ? -1 : path[pos]);\n\n                    long long delta = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n\n                    if (delta < b1) {\n                        b2 = b1;\n                        b1 = delta;\n                        pos1 = pos;\n                    } else if (delta < b2) {\n                        b2 = delta;\n                    }\n                }\n\n                if (b2 >= (1LL << 50)) b2 = b1 + 1000000;\n                long long regret = b2 - b1;\n                long long score = b1 * 10 - (long long)regretW * regret;\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    chosen = x;\n                    chosenPos = pos1;\n                }\n            }\n\n            path.insert(path.begin() + chosenPos, chosen);\n            used[chosen] = true;\n        }\n\n        return path;\n    }\n\n    vector<int> nearestNeighborBest(const Mode& mode) const {\n        vector<int> bestPath;\n        long long bestScore = (1LL << 60);\n\n        for (int s = 0; s < M; s++) {\n            vector<char> used(M, false);\n            vector<int> path;\n            path.reserve(M);\n\n            path.push_back(s);\n            used[s] = true;\n\n            long long score = mode.start[s];\n            int last = s;\n\n            for (int step = 1; step < M; step++) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (used[j]) continue;\n                    int c = mode.edge[last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                path.push_back(bestJ);\n                used[bestJ] = true;\n                score += bestC;\n                last = bestJ;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestPath = path;\n            }\n        }\n\n        return bestPath;\n    }\n\n    struct DSU {\n        vector<int> p;\n        DSU(int n = 0) { init(n); }\n        void init(int n) {\n            p.resize(n);\n            iota(p.begin(), p.end(), 0);\n        }\n        int find(int x) {\n            return p[x] == x ? x : p[x] = find(p[x]);\n        }\n        bool unite(int a, int b) {\n            a = find(a);\n            b = find(b);\n            if (a == b) return false;\n            p[b] = a;\n            return true;\n        }\n    };\n\n    vector<int> greedyPathCover(const Mode& mode, bool overlapKey) const {\n        struct E {\n            int u, v, ov, cost;\n        };\n\n        vector<E> es;\n        es.reserve(M * (M - 1));\n\n        for (int i = 0; i < M; i++) {\n            for (int j = 0; j < M; j++) {\n                if (i == j) continue;\n                es.push_back({i, j, (int)overlap[i * M + j], mode.edge[i * M + j]});\n            }\n        }\n\n        if (overlapKey) {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                if (a.ov != b.ov) return a.ov > b.ov;\n                return a.cost < b.cost;\n            });\n        } else {\n            sort(es.begin(), es.end(), [](const E& a, const E& b) {\n                return a.cost < b.cost;\n            });\n        }\n\n        vector<int> out(M, -1), in(M, -1);\n        DSU dsu(M);\n        int added = 0;\n\n        for (const auto& e : es) {\n            if (out[e.u] != -1 || in[e.v] != -1) continue;\n            if (dsu.find(e.u) == dsu.find(e.v)) continue;\n\n            out[e.u] = e.v;\n            in[e.v] = e.u;\n            dsu.unite(e.u, e.v);\n\n            added++;\n            if (added == M - 1) break;\n        }\n\n        int head = -1;\n        for (int i = 0; i < M; i++) {\n            if (in[i] == -1) {\n                head = i;\n                break;\n            }\n        }\n\n        vector<int> path;\n        while (head != -1) {\n            path.push_back(head);\n            head = out[head];\n        }\n\n        if ((int)path.size() != M) {\n            path.resize(M);\n            iota(path.begin(), path.end(), 0);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedy(int startWord) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = wordCnt(curWord);\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            int bestScore = INF;\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = wordCnt(j);\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                if (minv < bestScore) {\n                    bestScore = minv;\n                    bestJ = j;\n                }\n            }\n\n            int cols = wordCnt(bestJ);\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateGreedyLookahead(int startWord, int futureWeight) const {\n        vector<int> path;\n        path.reserve(M);\n\n        vector<char> used(M, false);\n        path.push_back(startWord);\n        used[startWord] = true;\n\n        int curWord = startWord;\n        int cnt = wordCnt(curWord);\n        vector<int> dp(cnt);\n\n        int off = initOff[curWord];\n        for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n        const int INF = 1e9;\n\n        for (int step = 1; step < M; step++) {\n            int bestJ = -1;\n            long long bestScore = (1LL << 60);\n\n            for (int j = 0; j < M; j++) {\n                if (used[j]) continue;\n\n                int rows = (int)dp.size();\n                int cols = wordCnt(j);\n                const unsigned short* mat = &edgeData[edgeOff[curWord * M + j]];\n\n                int minv = INF;\n                for (int q = 0; q < cols; q++) {\n                    int b = INF;\n                    for (int r = 0; r < rows; r++) {\n                        int v = dp[r] + (int)mat[r * cols + q];\n                        if (v < b) b = v;\n                    }\n                    if (b < minv) minv = b;\n                }\n\n                int fut = 0;\n                if (step + 1 < M && futureWeight != 0) {\n                    fut = INF;\n                    for (int k = 0; k < M; k++) {\n                        if (!used[k] && k != j) fut = min(fut, modes[0].edge[j * M + k]);\n                    }\n                    if (fut == INF) fut = 0;\n                }\n\n                long long score = (long long)minv * 10 + (long long)futureWeight * fut;\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestJ = j;\n                }\n            }\n\n            int cols = wordCnt(bestJ);\n            int rows = (int)dp.size();\n            const unsigned short* mat = &edgeData[edgeOff[curWord * M + bestJ]];\n\n            vector<int> ndp(cols, INF);\n            for (int q = 0; q < cols; q++) {\n                int b = INF;\n                for (int r = 0; r < rows; r++) {\n                    int v = dp[r] + (int)mat[r * cols + q];\n                    if (v < b) b = v;\n                }\n                ndp[q] = b;\n            }\n\n            dp.swap(ndp);\n            curWord = bestJ;\n            used[bestJ] = true;\n            path.push_back(bestJ);\n        }\n\n        return path;\n    }\n\n    vector<int> coordinateBeam(vector<int> starts, int beamW, int expandK, int futureWeight, double deadline) {\n        const int INF = 1e9;\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n        if (starts.empty()) return {};\n\n        struct BState {\n            vector<int> path;\n            bitset<200> used;\n            int last;\n            vector<int> dp;\n            int cost;\n            long long score;\n        };\n\n        auto initState = [&](int st) {\n            BState s;\n            s.path = {st};\n            s.used.reset();\n            s.used.set(st);\n            s.last = st;\n\n            int cnt = wordCnt(st);\n            s.dp.resize(cnt);\n\n            int off = initOff[st];\n            int mn = INF;\n            for (int i = 0; i < cnt; i++) {\n                s.dp[i] = initData[off + i];\n                mn = min(mn, s.dp[i]);\n            }\n\n            int fut = INF;\n            for (int k = 0; k < M; k++) if (k != st) fut = min(fut, modes[0].edge[st * M + k]);\n            if (fut == INF) fut = 0;\n\n            s.cost = mn;\n            s.score = (long long)mn * 10 + (long long)futureWeight * fut;\n            return s;\n        };\n\n        auto transMin = [&](const vector<int>& dp, int u, int v) {\n            int rows = (int)dp.size();\n            int cols = wordCnt(v);\n            int tmp[225];\n            fill(tmp, tmp + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < tmp[c]) tmp[c] = val;\n                }\n            }\n\n            int mn = INF;\n            for (int c = 0; c < cols; c++) mn = min(mn, tmp[c]);\n            return mn;\n        };\n\n        auto transVec = [&](const vector<int>& dp, int u, int v) {\n            int rows = (int)dp.size();\n            int cols = wordCnt(v);\n            vector<int> ndp(cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < ndp[c]) ndp[c] = val;\n                }\n            }\n\n            return ndp;\n        };\n\n        auto finishFast = [&](BState s) {\n            while ((int)s.path.size() < M) {\n                int bestJ = -1;\n                int bestC = INT_MAX;\n\n                for (int j = 0; j < M; j++) {\n                    if (s.used.test(j)) continue;\n                    int c = modes[0].edge[s.last * M + j];\n                    if (c < bestC) {\n                        bestC = c;\n                        bestJ = j;\n                    }\n                }\n\n                if (bestJ < 0) break;\n                s.path.push_back(bestJ);\n                s.used.set(bestJ);\n                s.last = bestJ;\n            }\n            return s.path;\n        };\n\n        vector<BState> beam;\n        for (int st : starts) beam.push_back(initState(st));\n\n        sort(beam.begin(), beam.end(), [](const BState& a, const BState& b) {\n            return a.score < b.score;\n        });\n        if ((int)beam.size() > beamW) beam.resize(beamW);\n\n        for (int step = 1; step < M; step++) {\n            if (timer.elapsed() > deadline) {\n                if (beam.empty()) return {};\n                return finishFast(beam[0]);\n            }\n\n            struct Opt {\n                long long score;\n                int j;\n                int cost;\n            };\n\n            vector<BState> nxtStates;\n            nxtStates.reserve(beamW * expandK);\n\n            for (const auto& s : beam) {\n                vector<Opt> opts;\n                opts.reserve(M);\n\n                for (int j = 0; j < M; j++) {\n                    if (s.used.test(j)) continue;\n\n                    int mn = transMin(s.dp, s.last, j);\n\n                    int fut = 0;\n                    if (futureWeight && step + 1 < M) {\n                        fut = INF;\n                        for (int k = 0; k < M; k++) {\n                            if (!s.used.test(k) && k != j) fut = min(fut, modes[0].edge[j * M + k]);\n                        }\n                        if (fut == INF) fut = 0;\n                    }\n\n                    long long score = (long long)mn * 10 + (long long)futureWeight * fut;\n                    opts.push_back({score, j, mn});\n                }\n\n                sort(opts.begin(), opts.end(), [](const Opt& a, const Opt& b) {\n                    return a.score < b.score;\n                });\n                if ((int)opts.size() > expandK) opts.resize(expandK);\n\n                for (const auto& op : opts) {\n                    BState ns;\n                    ns.path = s.path;\n                    ns.path.push_back(op.j);\n                    ns.used = s.used;\n                    ns.used.set(op.j);\n                    ns.last = op.j;\n                    ns.dp = transVec(s.dp, s.last, op.j);\n                    ns.cost = op.cost;\n                    ns.score = op.score;\n                    nxtStates.push_back(std::move(ns));\n                }\n            }\n\n            sort(nxtStates.begin(), nxtStates.end(), [](const BState& a, const BState& b) {\n                return a.score < b.score;\n            });\n\n            if ((int)nxtStates.size() > beamW) nxtStates.resize(beamW);\n            beam.swap(nxtStates);\n            if (beam.empty()) return {};\n        }\n\n        int best = 0;\n        for (int i = 1; i < (int)beam.size(); i++) {\n            if (beam[i].cost < beam[best].cost) best = i;\n        }\n        return beam[best].path;\n    }\n\n    long long relocateDelta(const vector<int>& ord, int i, int p, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (p == i) return 0;\n\n        int x = ord[i];\n\n        int L = (i > 0 ? ord[i - 1] : -1);\n        int R = (i + 1 < n ? ord[i + 1] : -1);\n\n        long long rem = arc(mode, L, R) - arc(mode, L, x) - arc(mode, x, R);\n\n        auto getRemoved = [&](int idx) -> int {\n            return ord[idx < i ? idx : idx + 1];\n        };\n\n        int left = (p > 0 ? getRemoved(p - 1) : -1);\n        int right = (p < n - 1 ? getRemoved(p) : -1);\n\n        long long ins = arc(mode, left, x) + arc(mode, x, right) - arc(mode, left, right);\n        return rem + ins;\n    }\n\n    long long blockRelocateDelta(const vector<int>& ord, int l, int r, int q, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (q >= l && q <= r + 1) return 0;\n\n        int A = ord[l];\n        int B = ord[r];\n\n        int L = (l > 0 ? ord[l - 1] : -1);\n        int R = (r + 1 < n ? ord[r + 1] : -1);\n\n        int P = (q > 0 ? ord[q - 1] : -1);\n        int Q = (q < n ? ord[q] : -1);\n\n        long long oldCost = arc(mode, L, A) + arc(mode, B, R) + arc(mode, P, Q);\n        long long newCost = arc(mode, L, R) + arc(mode, P, A) + arc(mode, B, Q);\n        return newCost - oldCost;\n    }\n\n    long long blockSwapDelta(const vector<int>& ord, int l1, int r1, int l2, int r2, const Mode& mode) const {\n        int n = (int)ord.size();\n        if (l1 > r1 || l2 > r2 || r1 >= l2) return 0;\n\n        int A = ord[l1], B = ord[r1];\n        int C = ord[l2], D = ord[r2];\n\n        int L = (l1 > 0 ? ord[l1 - 1] : -1);\n        int R = (r2 + 1 < n ? ord[r2 + 1] : -1);\n\n        long long oldCost = 0, newCost = 0;\n\n        if (r1 + 1 == l2) {\n            oldCost = arc(mode, L, A) + arc(mode, B, C) + arc(mode, D, R);\n            newCost = arc(mode, L, C) + arc(mode, D, A) + arc(mode, B, R);\n        } else {\n            int E = ord[r1 + 1];\n            int F = ord[l2 - 1];\n\n            oldCost = arc(mode, L, A) + arc(mode, B, E) + arc(mode, F, C) + arc(mode, D, R);\n            newCost = arc(mode, L, C) + arc(mode, D, E) + arc(mode, F, A) + arc(mode, B, R);\n        }\n\n        return newCost - oldCost;\n    }\n\n    long long swapDelta(const vector<int>& ord, int i, int j, const Mode& mode) const {\n        if (i == j) return 0;\n        if (i > j) swap(i, j);\n\n        int n = (int)ord.size();\n        vector<int> ks;\n        int arr[4] = {i - 1, i, j - 1, j};\n\n        for (int t = 0; t < 4; t++) {\n            int k = arr[t];\n            if (k < -1 || k > n - 1) continue;\n            if (find(ks.begin(), ks.end(), k) == ks.end()) ks.push_back(k);\n        }\n\n        auto nodeNew = [&](int idx) -> int {\n            if (idx == i) return ord[j];\n            if (idx == j) return ord[i];\n            return ord[idx];\n        };\n\n        auto edgeOld = [&](int k) -> long long {\n            if (k == -1) return mode.start[ord[0]];\n            if (k >= n - 1) return 0;\n            return mode.edge[ord[k] * M + ord[k + 1]];\n        };\n\n        auto edgeNew = [&](int k) -> long long {\n            if (k == -1) return mode.start[nodeNew(0)];\n            if (k >= n - 1) return 0;\n            return mode.edge[nodeNew(k) * M + nodeNew(k + 1)];\n        };\n\n        long long oldSum = 0, newSum = 0;\n        for (int k : ks) {\n            oldSum += edgeOld(k);\n            newSum += edgeNew(k);\n        }\n        return newSum - oldSum;\n    }\n\n    long long reverseDeltaSlow(const vector<int>& ord, int l, int r, const Mode& mode) const {\n        int n = (int)ord.size();\n        long long oldCost = 0, newCost = 0;\n\n        if (l == 0) {\n            oldCost += mode.start[ord[l]];\n            newCost += mode.start[ord[r]];\n        } else {\n            oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n            newCost += mode.edge[ord[l - 1] * M + ord[r]];\n        }\n\n        if (r + 1 < n) {\n            oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n            newCost += mode.edge[ord[l] * M + ord[r + 1]];\n        }\n\n        for (int k = l; k < r; k++) {\n            oldCost += mode.edge[ord[k] * M + ord[k + 1]];\n            newCost += mode.edge[ord[k + 1] * M + ord[k]];\n        }\n\n        return newCost - oldCost;\n    }\n\n    void applyMove(vector<int>& ord, const Move& mv) const {\n        if (mv.type == 0) {\n            int x = ord[mv.a];\n            ord.erase(ord.begin() + mv.a);\n            ord.insert(ord.begin() + mv.b, x);\n        } else if (mv.type == 1) {\n            swap(ord[mv.a], ord[mv.b]);\n        } else if (mv.type == 2) {\n            reverse(ord.begin() + mv.a, ord.begin() + mv.b + 1);\n        } else if (mv.type == 3) {\n            int l = mv.a, r = mv.b, q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos = (q < l ? q : q - len);\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        } else if (mv.type == 4) {\n            int l1 = mv.a, r1 = mv.b;\n            int l2 = mv.c / 256;\n            int r2 = mv.c % 256;\n\n            vector<int> res;\n            res.reserve(ord.size());\n\n            res.insert(res.end(), ord.begin(), ord.begin() + l1);\n            res.insert(res.end(), ord.begin() + l2, ord.begin() + r2 + 1);\n            res.insert(res.end(), ord.begin() + r1 + 1, ord.begin() + l2);\n            res.insert(res.end(), ord.begin() + l1, ord.begin() + r1 + 1);\n            res.insert(res.end(), ord.begin() + r2 + 1, ord.end());\n\n            ord.swap(res);\n        } else if (mv.type == 5) {\n            int l = mv.a, r = mv.b, q = mv.c;\n            int len = r - l + 1;\n\n            vector<int> block(ord.begin() + l, ord.begin() + r + 1);\n            reverse(block.begin(), block.end());\n\n            ord.erase(ord.begin() + l, ord.begin() + r + 1);\n\n            int pos = (q < l ? q : q - len);\n            ord.insert(ord.begin() + pos, block.begin(), block.end());\n        } else if (mv.type == 6) {\n            int l1 = mv.a, r1 = mv.b;\n            int bits = mv.c & 3;\n            int code = mv.c >> 2;\n            int l2 = code / 256;\n            int r2 = code % 256;\n\n            bool rev1 = bits & 1;\n            bool rev2 = bits & 2;\n\n            vector<int> res;\n            res.reserve(ord.size());\n\n            res.insert(res.end(), ord.begin(), ord.begin() + l1);\n\n            if (rev2) {\n                for (int i = r2; i >= l2; i--) res.push_back(ord[i]);\n            } else {\n                res.insert(res.end(), ord.begin() + l2, ord.begin() + r2 + 1);\n            }\n\n            res.insert(res.end(), ord.begin() + r1 + 1, ord.begin() + l2);\n\n            if (rev1) {\n                for (int i = r1; i >= l1; i--) res.push_back(ord[i]);\n            } else {\n                res.insert(res.end(), ord.begin() + l1, ord.begin() + r1 + 1);\n            }\n\n            res.insert(res.end(), ord.begin() + r2 + 1, ord.end());\n            ord.swap(res);\n        }\n    }\n\n    void improveAdditive(vector<int>& ord, const Mode& mode, int maxIter = 40, int maxBlockLen = 3) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if ((iter & 1) == 0 && timer.elapsed() > 1.48) break;\n\n            long long bestDelta = 0;\n            Move bestMove{-1, 0, 0, 0};\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {0, i, p, d};\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {1, i, j, d};\n                    }\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    long long d = newCost - oldCost;\n                    if (d < bestDelta) {\n                        bestDelta = d;\n                        bestMove = {2, l, r, d};\n                    }\n                }\n            }\n\n            bool stopBlock = false;\n            int limLen = min(maxBlockLen, n - 1);\n            for (int len = 2; len <= limLen && !stopBlock; len++) {\n                for (int l = 0; l + len <= n && !stopBlock; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        if (d < bestDelta) {\n                            bestDelta = d;\n                            bestMove = {3, l, r, d, q};\n                        }\n                    }\n                    if ((l & 15) == 0 && timer.elapsed() > 1.48) stopBlock = true;\n                }\n            }\n\n            if (bestDelta < 0) applyMove(ord, bestMove);\n            else break;\n        }\n    }\n\n    Candidate exactRefine(vector<int> ord, double deadline, int rounds, int K) {\n        int cur = exactCost(ord);\n        if (cur < bestCost) {\n            bestCost = cur;\n            bestOrder = ord;\n        }\n\n        const Mode& mode = modes[0];\n        int n = (int)ord.size();\n\n        for (int round = 0; round < rounds; round++) {\n            if (timer.elapsed() > deadline) break;\n\n            vector<Move> moves;\n            moves.reserve(n * n * 3);\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    long long d = relocateDelta(ord, i, p, mode);\n                    moves.push_back({0, i, p, d});\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    long long d = swapDelta(ord, i, j, mode);\n                    moves.push_back({1, i, j, d});\n                }\n            }\n\n            vector<long long> pf(n, 0), pr(n, 0);\n            for (int k = 0; k + 1 < n; k++) {\n                pf[k + 1] = pf[k] + mode.edge[ord[k] * M + ord[k + 1]];\n                pr[k + 1] = pr[k] + mode.edge[ord[k + 1] * M + ord[k]];\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    long long oldCost = pf[r] - pf[l];\n                    long long newCost = pr[r] - pr[l];\n\n                    if (l == 0) {\n                        oldCost += mode.start[ord[l]];\n                        newCost += mode.start[ord[r]];\n                    } else {\n                        oldCost += mode.edge[ord[l - 1] * M + ord[l]];\n                        newCost += mode.edge[ord[l - 1] * M + ord[r]];\n                    }\n\n                    if (r + 1 < n) {\n                        oldCost += mode.edge[ord[r] * M + ord[r + 1]];\n                        newCost += mode.edge[ord[l] * M + ord[r + 1]];\n                    }\n\n                    moves.push_back({2, l, r, newCost - oldCost});\n                }\n            }\n\n            int limLen = min(4, n - 1);\n            for (int len = 2; len <= limLen; len++) {\n                for (int l = 0; l + len <= n; l++) {\n                    int r = l + len - 1;\n                    for (int q = 0; q <= n; q++) {\n                        if (q >= l && q <= r + 1) continue;\n                        long long d = blockRelocateDelta(ord, l, r, q, mode);\n                        moves.push_back({3, l, r, d, q});\n                    }\n                }\n            }\n\n            if (timer.elapsed() < deadline - 0.04) {\n                int maxSwapLen = min(3, n);\n                bool stop = false;\n                for (int len1 = 1; len1 <= maxSwapLen && !stop; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n && !stop; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxSwapLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n                                long long d = blockSwapDelta(ord, l1, r1, l2, r2, mode);\n                                if (d < 0) moves.push_back({4, l1, r1, d, l2 * 256 + r2});\n                            }\n                        }\n                        if ((l1 & 15) == 0 && timer.elapsed() > deadline - 0.03) stop = true;\n                    }\n                }\n            }\n\n            sort(moves.begin(), moves.end(), [](const Move& a, const Move& b) {\n                return a.delta < b.delta;\n            });\n\n            int bestLocal = cur;\n            Move bestMv{-1, 0, 0, 0};\n            int lim = min(K, (int)moves.size());\n\n            for (int i = 0; i < lim; i++) {\n                if ((i & 31) == 0 && timer.elapsed() > deadline) break;\n\n                vector<int> cand = ord;\n                applyMove(cand, moves[i]);\n                int nc = exactCost(cand);\n\n                if (nc < bestLocal) {\n                    bestLocal = nc;\n                    bestMv = moves[i];\n                }\n            }\n\n            if (bestMv.type != -1) {\n                applyMove(ord, bestMv);\n                cur = bestLocal;\n\n                if (cur < bestCost) {\n                    bestCost = cur;\n                    bestOrder = ord;\n                }\n            } else {\n                break;\n            }\n        }\n\n        return {cur, ord};\n    }\n\n    void buildExactCtx(const vector<int>& ord, ExactCtx& ctx, bool needRev) const {\n        int n = (int)ord.size();\n        ctx.n = n;\n        ctx.cnt.assign(n, 0);\n        for (int i = 0; i < n; i++) ctx.cnt[i] = wordCnt(ord[i]);\n\n        ctx.foff.assign(n * n, -1);\n        ctx.fdata.clear();\n        ctx.fdata.reserve((size_t)n * n * 90);\n\n        vector<unsigned short> prev, cur;\n\n        for (int l = 0; l < n; l++) {\n            int rows = ctx.cnt[l];\n            prev.assign(rows * rows, USINF);\n            for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n            ctx.foff[l * n + l] = (int)ctx.fdata.size();\n            ctx.fdata.insert(ctx.fdata.end(), prev.begin(), prev.end());\n\n            for (int r = l + 1; r < n; r++) {\n                int mid = ctx.cnt[r - 1];\n                int cols = ctx.cnt[r];\n                cur.assign(rows * cols, USINF);\n\n                const unsigned short* e = &edgeData[edgeOff[ord[r - 1] * M + ord[r]]];\n\n                for (int i = 0; i < rows; i++) {\n                    for (int k = 0; k < mid; k++) {\n                        int base = prev[i * mid + k];\n                        if (base >= USINF) continue;\n                        const unsigned short* er = e + k * cols;\n                        int outBase = i * cols;\n                        for (int j = 0; j < cols; j++) {\n                            int v = base + (int)er[j];\n                            if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                        }\n                    }\n                }\n\n                ctx.foff[l * n + r] = (int)ctx.fdata.size();\n                ctx.fdata.insert(ctx.fdata.end(), cur.begin(), cur.end());\n                prev.swap(cur);\n            }\n        }\n\n        ctx.roff.assign(n * n, -1);\n        ctx.rdata.clear();\n        if (needRev) {\n            ctx.rdata.reserve((size_t)n * n * 90);\n\n            for (int r = 0; r < n; r++) {\n                int rows = ctx.cnt[r];\n                prev.assign(rows * rows, USINF);\n                for (int d = 0; d < rows; d++) prev[d * rows + d] = 0;\n\n                ctx.roff[r * n + r] = (int)ctx.rdata.size();\n                ctx.rdata.insert(ctx.rdata.end(), prev.begin(), prev.end());\n\n                for (int l = r - 1; l >= 0; l--) {\n                    int mid = ctx.cnt[l + 1];\n                    int cols = ctx.cnt[l];\n                    cur.assign(rows * cols, USINF);\n\n                    const unsigned short* e = &edgeData[edgeOff[ord[l + 1] * M + ord[l]]];\n\n                    for (int i = 0; i < rows; i++) {\n                        for (int k = 0; k < mid; k++) {\n                            int base = prev[i * mid + k];\n                            if (base >= USINF) continue;\n                            const unsigned short* er = e + k * cols;\n                            int outBase = i * cols;\n                            for (int j = 0; j < cols; j++) {\n                                int v = base + (int)er[j];\n                                if (v < cur[outBase + j]) cur[outBase + j] = (unsigned short)v;\n                            }\n                        }\n                    }\n\n                    ctx.roff[l * n + r] = (int)ctx.rdata.size();\n                    ctx.rdata.insert(ctx.rdata.end(), cur.begin(), cur.end());\n                    prev.swap(cur);\n                }\n            }\n        }\n\n        ctx.prefOff.assign(n, 0);\n        ctx.prefData.clear();\n        ctx.prefData.reserve(n * maxOcc);\n\n        vector<unsigned short> dp, ndp;\n\n        {\n            int w = ord[0];\n            int cnt = ctx.cnt[0];\n            dp.resize(cnt);\n            int off = initOff[w];\n            for (int i = 0; i < cnt; i++) dp[i] = initData[off + i];\n\n            ctx.prefOff[0] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        for (int pos = 1; pos < n; pos++) {\n            int rows = ctx.cnt[pos - 1];\n            int cols = ctx.cnt[pos];\n            ndp.assign(cols, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos - 1] * M + ord[pos]]];\n\n            for (int r = 0; r < rows; r++) {\n                int base = dp[r];\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = base + (int)er[c];\n                    if (v < ndp[c]) ndp[c] = (unsigned short)v;\n                }\n            }\n\n            dp.swap(ndp);\n            ctx.prefOff[pos] = (int)ctx.prefData.size();\n            ctx.prefData.insert(ctx.prefData.end(), dp.begin(), dp.end());\n        }\n\n        ctx.current = USINF;\n        for (unsigned short v : dp) ctx.current = min(ctx.current, (int)v);\n\n        vector<vector<unsigned short>> sv(n);\n        sv[n - 1].assign(ctx.cnt[n - 1], 0);\n\n        for (int pos = n - 2; pos >= 0; pos--) {\n            int rows = ctx.cnt[pos];\n            int cols = ctx.cnt[pos + 1];\n            sv[pos].assign(rows, USINF);\n\n            const unsigned short* e = &edgeData[edgeOff[ord[pos] * M + ord[pos + 1]]];\n\n            for (int r = 0; r < rows; r++) {\n                int best = USINF;\n                const unsigned short* er = e + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int v = (int)er[c] + (int)sv[pos + 1][c];\n                    if (v < best) best = v;\n                }\n                sv[pos][r] = (unsigned short)best;\n            }\n        }\n\n        ctx.suffOff.assign(n, 0);\n        ctx.suffData.clear();\n        ctx.suffData.reserve(n * maxOcc);\n        for (int pos = 0; pos < n; pos++) {\n            ctx.suffOff[pos] = (int)ctx.suffData.size();\n            ctx.suffData.insert(ctx.suffData.end(), sv[pos].begin(), sv[pos].end());\n        }\n    }\n\n    inline void loadInitWord(int w, int* a, int& cnt) const {\n        cnt = wordCnt(w);\n        const unsigned short* p = &initData[initOff[w]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void loadPrefPos(const ExactCtx& ctx, int pos, int* a, int& cnt) const {\n        cnt = ctx.cnt[pos];\n        const unsigned short* p = &ctx.prefData[ctx.prefOff[pos]];\n        for (int i = 0; i < cnt; i++) a[i] = p[i];\n    }\n\n    inline void applyEdgeArr(int* a, int& cnt, int u, int v, int* tmp) const {\n        const int INF = 1e9;\n        int rows = cnt;\n        int cols = wordCnt(v);\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n        for (int r = 0; r < rows; r++) {\n            int base = a[r];\n            const unsigned short* mr = mat + r * cols;\n            for (int c = 0; c < cols; c++) {\n                int val = base + (int)mr[c];\n                if (val < tmp[c]) tmp[c] = val;\n            }\n        }\n\n        for (int c = 0; c < cols; c++) a[c] = tmp[c];\n        cnt = cols;\n    }\n\n    inline void applyFInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[r];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[l];\n        int cols = ctx.cnt[r];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.fdata[ctx.foff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline void applyRInterval(const ExactCtx& ctx, int l, int r, int* a, int& cnt, int* tmp) const {\n        if (l == r) {\n            cnt = ctx.cnt[l];\n            return;\n        }\n\n        const int INF = 1e9;\n        int n = ctx.n;\n        int rows = ctx.cnt[r];\n        int cols = ctx.cnt[l];\n        fill(tmp, tmp + cols, INF);\n\n        const unsigned short* mat = &ctx.rdata[ctx.roff[l * n + r]];\n        for (int i = 0; i < rows; i++) {\n            int base = a[i];\n            const unsigned short* mr = mat + i * cols;\n            for (int j = 0; j < cols; j++) {\n                if (mr[j] >= USINF) continue;\n                int val = base + (int)mr[j];\n                if (val < tmp[j]) tmp[j] = val;\n            }\n        }\n\n        for (int j = 0; j < cols; j++) a[j] = tmp[j];\n        cnt = cols;\n    }\n\n    inline int finishAt(const ExactCtx& ctx, int pos, int* a, int cnt) const {\n        const unsigned short* s = &ctx.suffData[ctx.suffOff[pos]];\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) {\n            int v = a[i] + (int)s[i];\n            if (v < ans) ans = v;\n        }\n        return ans;\n    }\n\n    inline int minArr(int* a, int cnt) const {\n        int ans = 1e9;\n        for (int i = 0; i < cnt; i++) ans = min(ans, a[i]);\n        return ans;\n    }\n\n    int evalBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[l], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            }\n\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[q - 1], ord[l], tmp);\n            applyFInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[r], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    int evalRelocateExact(const vector<int>& ord, const ExactCtx& ctx, int i, int p) const {\n        if (i == p) return ctx.current;\n        int q = (p < i ? p : p + 1);\n        return evalBlockExact(ord, ctx, i, i, q);\n    }\n\n    int evalSwapExact(const vector<int>& ord, const ExactCtx& ctx, int i, int j) const {\n        if (i > j) swap(i, j);\n        int n = ctx.n;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (i == 0) {\n            loadInitWord(ord[j], a, cnt);\n        } else {\n            loadPrefPos(ctx, i - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[i - 1], ord[j], tmp);\n        }\n\n        if (j == i + 1) {\n            applyEdgeArr(a, cnt, ord[j], ord[i], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[j], ord[i + 1], tmp);\n            applyFInterval(ctx, i + 1, j - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[j - 1], ord[i], tmp);\n        }\n\n        if (j + 1 < n) {\n            applyEdgeArr(a, cnt, ord[i], ord[j + 1], tmp);\n            return finishAt(ctx, j + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalReverseExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r) const {\n        int n = ctx.n;\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l == 0) {\n            loadInitWord(ord[r], a, cnt);\n        } else {\n            loadPrefPos(ctx, l - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l - 1], ord[r], tmp);\n        }\n\n        applyRInterval(ctx, l, r, a, cnt, tmp);\n\n        if (r + 1 < n) {\n            applyEdgeArr(a, cnt, ord[l], ord[r + 1], tmp);\n            return finishAt(ctx, r + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalBlockSwapExact(const vector<int>& ord, const ExactCtx& ctx, int l1, int r1, int l2, int r2) const {\n        int n = ctx.n;\n        if (r1 >= l2) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (l1 == 0) {\n            loadInitWord(ord[l2], a, cnt);\n        } else {\n            loadPrefPos(ctx, l1 - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l1 - 1], ord[l2], tmp);\n        }\n\n        applyFInterval(ctx, l2, r2, a, cnt, tmp);\n\n        if (r1 + 1 < l2) {\n            applyEdgeArr(a, cnt, ord[r2], ord[r1 + 1], tmp);\n            applyFInterval(ctx, r1 + 1, l2 - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l2 - 1], ord[l1], tmp);\n        } else {\n            applyEdgeArr(a, cnt, ord[r2], ord[l1], tmp);\n        }\n\n        applyFInterval(ctx, l1, r1, a, cnt, tmp);\n\n        if (r2 + 1 < n) {\n            applyEdgeArr(a, cnt, ord[r1], ord[r2 + 1], tmp);\n            return finishAt(ctx, r2 + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalBlockSwapOrientExact(\n        const vector<int>& ord,\n        const ExactCtx& ctx,\n        int l1,\n        int r1,\n        int l2,\n        int r2,\n        bool rev1,\n        bool rev2\n    ) const {\n        int n = ctx.n;\n        if (r1 >= l2) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        int start2 = rev2 ? ord[r2] : ord[l2];\n        int end2 = rev2 ? ord[l2] : ord[r2];\n        int start1 = rev1 ? ord[r1] : ord[l1];\n        int end1 = rev1 ? ord[l1] : ord[r1];\n\n        if (l1 == 0) {\n            loadInitWord(start2, a, cnt);\n        } else {\n            loadPrefPos(ctx, l1 - 1, a, cnt);\n            applyEdgeArr(a, cnt, ord[l1 - 1], start2, tmp);\n        }\n\n        if (rev2) applyRInterval(ctx, l2, r2, a, cnt, tmp);\n        else applyFInterval(ctx, l2, r2, a, cnt, tmp);\n\n        if (r1 + 1 < l2) {\n            applyEdgeArr(a, cnt, end2, ord[r1 + 1], tmp);\n            applyFInterval(ctx, r1 + 1, l2 - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l2 - 1], start1, tmp);\n        } else {\n            applyEdgeArr(a, cnt, end2, start1, tmp);\n        }\n\n        if (rev1) applyRInterval(ctx, l1, r1, a, cnt, tmp);\n        else applyFInterval(ctx, l1, r1, a, cnt, tmp);\n\n        if (r2 + 1 < n) {\n            applyEdgeArr(a, cnt, end1, ord[r2 + 1], tmp);\n            return finishAt(ctx, r2 + 1, a, cnt);\n        } else {\n            return minArr(a, cnt);\n        }\n    }\n\n    int evalRevBlockExact(const vector<int>& ord, const ExactCtx& ctx, int l, int r, int q) const {\n        int n = ctx.n;\n        if (q >= l && q <= r + 1) return 1e9;\n\n        int a[225], tmp[225];\n        int cnt;\n\n        if (q < l) {\n            if (q == 0) {\n                loadInitWord(ord[r], a, cnt);\n            } else {\n                loadPrefPos(ctx, q - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[q - 1], ord[r], tmp);\n            }\n\n            applyRInterval(ctx, l, r, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[l], ord[q], tmp);\n            applyFInterval(ctx, q, l - 1, a, cnt, tmp);\n\n            if (r + 1 < n) {\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n                return finishAt(ctx, r + 1, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        } else {\n            if (l == 0) {\n                loadInitWord(ord[r + 1], a, cnt);\n            } else {\n                loadPrefPos(ctx, l - 1, a, cnt);\n                applyEdgeArr(a, cnt, ord[l - 1], ord[r + 1], tmp);\n            }\n\n            applyFInterval(ctx, r + 1, q - 1, a, cnt, tmp);\n            applyEdgeArr(a, cnt, ord[q - 1], ord[r], tmp);\n            applyRInterval(ctx, l, r, a, cnt, tmp);\n\n            if (q < n) {\n                applyEdgeArr(a, cnt, ord[l], ord[q], tmp);\n                return finishAt(ctx, q, a, cnt);\n            } else {\n                return minArr(a, cnt);\n            }\n        }\n    }\n\n    void improveExactInterval(vector<int>& ord, double deadline, int maxIter) {\n        int n = (int)ord.size();\n        if (n <= 1) return;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            if (timer.elapsed() > deadline - 0.07) break;\n\n            ExactCtx ctx;\n            buildExactCtx(ord, ctx, true);\n\n            int cur = ctx.current;\n            if (cur < bestCost) {\n                bestCost = cur;\n                bestOrder = ord;\n            }\n\n            int bestVal = cur;\n            Move bestMv{-1, 0, 0, 0};\n\n            int checks = 0;\n            bool timeout = false;\n\n            for (int i = 0; i < n; i++) {\n                for (int p = 0; p < n; p++) {\n                    if (p == i) continue;\n                    int val = evalRelocateExact(ord, ctx, i, p);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {0, i, p, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int i = 0; i < n; i++) {\n                for (int j = i + 1; j < n; j++) {\n                    int val = evalSwapExact(ord, ctx, i, j);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {1, i, j, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            for (int l = 0; l < n; l++) {\n                for (int r = l + 2; r < n; r++) {\n                    int val = evalReverseExact(ord, ctx, l, r);\n                    if (val < bestVal) {\n                        bestVal = val;\n                        bestMv = {2, l, r, val - cur};\n                    }\n                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                        timeout = true;\n                        goto ENUM_DONE;\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(10, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {3, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(9, n - 1);\n                for (int len = 2; len <= maxLen; len++) {\n                    for (int l = 0; l + len <= n; l++) {\n                        int r = l + len - 1;\n                        for (int q = 0; q <= n; q++) {\n                            if (q >= l && q <= r + 1) continue;\n                            int val = evalRevBlockExact(ord, ctx, l, r, q);\n                            if (val < bestVal) {\n                                bestVal = val;\n                                bestMv = {5, l, r, val - cur, q};\n                            }\n                            if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                timeout = true;\n                                goto ENUM_DONE;\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(4, n);\n                for (int len1 = 1; len1 <= maxLen; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n\n                                int val = evalBlockSwapExact(ord, ctx, l1, r1, l2, r2);\n                                if (val < bestVal) {\n                                    bestVal = val;\n                                    bestMv = {4, l1, r1, val - cur, l2 * 256 + r2};\n                                }\n\n                                if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                    timeout = true;\n                                    goto ENUM_DONE;\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            {\n                int maxLen = min(3, n);\n                for (int len1 = 1; len1 <= maxLen; len1++) {\n                    for (int l1 = 0; l1 + len1 <= n; l1++) {\n                        int r1 = l1 + len1 - 1;\n                        for (int len2 = 1; len2 <= maxLen; len2++) {\n                            for (int l2 = r1 + 1; l2 + len2 <= n; l2++) {\n                                int r2 = l2 + len2 - 1;\n                                if (len1 == 1 && len2 == 1) continue;\n\n                                for (int bits = 1; bits < 4; bits++) {\n                                    if ((bits & 1) && len1 == 1) continue;\n                                    if ((bits & 2) && len2 == 1) continue;\n\n                                    bool rev1 = bits & 1;\n                                    bool rev2 = bits & 2;\n                                    int val = evalBlockSwapOrientExact(ord, ctx, l1, r1, l2, r2, rev1, rev2);\n                                    if (val < bestVal) {\n                                        int code = ((l2 * 256 + r2) << 2) | bits;\n                                        bestVal = val;\n                                        bestMv = {6, l1, r1, val - cur, code};\n                                    }\n\n                                    if (((++checks) & 2047) == 0 && timer.elapsed() > deadline) {\n                                        timeout = true;\n                                        goto ENUM_DONE;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n        ENUM_DONE:\n            if (bestMv.type != -1 && bestVal < cur) {\n                applyMove(ord, bestMv);\n                int real = exactCost(ord);\n                if (real < bestCost) {\n                    bestCost = real;\n                    bestOrder = ord;\n                }\n                if (real >= cur) break;\n            } else {\n                break;\n            }\n\n            if (timeout || timer.elapsed() > deadline) break;\n        }\n    }\n\n    void buildPrefSuffSmall(const vector<int>& path, vector<vector<int>>& pref, vector<vector<int>>& suff) const {\n        const int INF = 1e9;\n        int n = (int)path.size();\n        pref.clear();\n        suff.clear();\n        if (n == 0) return;\n\n        pref.resize(n);\n        suff.resize(n);\n\n        pref[0].resize(wordCnt(path[0]));\n        {\n            int off = initOff[path[0]];\n            for (int i = 0; i < (int)pref[0].size(); i++) pref[0][i] = initData[off + i];\n        }\n\n        for (int i = 1; i < n; i++) {\n            int u = path[i - 1], v = path[i];\n            int rows = wordCnt(u), cols = wordCnt(v);\n            pref[i].assign(cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n            for (int r = 0; r < rows; r++) {\n                int base = pref[i - 1][r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < pref[i][c]) pref[i][c] = val;\n                }\n            }\n        }\n\n        suff[n - 1].assign(wordCnt(path[n - 1]), 0);\n\n        for (int i = n - 2; i >= 0; i--) {\n            int u = path[i], v = path[i + 1];\n            int rows = wordCnt(u), cols = wordCnt(v);\n            suff[i].assign(rows, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + v]];\n            for (int r = 0; r < rows; r++) {\n                int best = INF;\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = (int)mr[c] + suff[i + 1][c];\n                    if (val < best) best = val;\n                }\n                suff[i][r] = best;\n            }\n        }\n    }\n\n    int evalInsertExactSmall(\n        const vector<int>& path,\n        const vector<vector<int>>& pref,\n        const vector<vector<int>>& suff,\n        int x,\n        int pos\n    ) const {\n        const int INF = 1e9;\n        int n = (int)path.size();\n\n        int tmp1[225], tmp2[225];\n\n        if (n == 0) {\n            int cnt = wordCnt(x);\n            int off = initOff[x];\n            int ans = INF;\n            for (int i = 0; i < cnt; i++) ans = min(ans, (int)initData[off + i]);\n            return ans;\n        }\n\n        if (pos == 0) {\n            int cntX = wordCnt(x);\n            int off = initOff[x];\n            for (int i = 0; i < cntX; i++) tmp1[i] = initData[off + i];\n\n            int v = path[0];\n            int cols = wordCnt(v);\n            fill(tmp2, tmp2 + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[x * M + v]];\n            for (int r = 0; r < cntX; r++) {\n                int base = tmp1[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < tmp2[c]) tmp2[c] = val;\n                }\n            }\n\n            int ans = INF;\n            for (int c = 0; c < cols; c++) ans = min(ans, tmp2[c] + suff[0][c]);\n            return ans;\n        }\n\n        if (pos == n) {\n            int u = path[n - 1];\n            int rows = wordCnt(u), cols = wordCnt(x);\n            fill(tmp1, tmp1 + cols, INF);\n\n            const unsigned short* mat = &edgeData[edgeOff[u * M + x]];\n            for (int r = 0; r < rows; r++) {\n                int base = pref[n - 1][r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < tmp1[c]) tmp1[c] = val;\n                }\n            }\n\n            int ans = INF;\n            for (int c = 0; c < cols; c++) ans = min(ans, tmp1[c]);\n            return ans;\n        }\n\n        int u = path[pos - 1];\n        int v = path[pos];\n\n        int rows = wordCnt(u);\n        int cntX = wordCnt(x);\n\n        fill(tmp1, tmp1 + cntX, INF);\n        {\n            const unsigned short* mat = &edgeData[edgeOff[u * M + x]];\n            for (int r = 0; r < rows; r++) {\n                int base = pref[pos - 1][r];\n                const unsigned short* mr = mat + r * cntX;\n                for (int c = 0; c < cntX; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < tmp1[c]) tmp1[c] = val;\n                }\n            }\n        }\n\n        int cols = wordCnt(v);\n        fill(tmp2, tmp2 + cols, INF);\n        {\n            const unsigned short* mat = &edgeData[edgeOff[x * M + v]];\n            for (int r = 0; r < cntX; r++) {\n                int base = tmp1[r];\n                const unsigned short* mr = mat + r * cols;\n                for (int c = 0; c < cols; c++) {\n                    int val = base + (int)mr[c];\n                    if (val < tmp2[c]) tmp2[c] = val;\n                }\n            }\n        }\n\n        int ans = INF;\n        for (int c = 0; c < cols; c++) ans = min(ans, tmp2[c] + suff[pos][c]);\n        return ans;\n    }\n\n    vector<int> exactRepair(vector<int> path, vector<int> removed) {\n        int regretW = 2 + rng.nextInt(8);\n\n        while (!removed.empty()) {\n            vector<vector<int>> pref, suff;\n            buildPrefSuffSmall(path, pref, suff);\n\n            long long bestScore = (1LL << 60);\n            int bestRi = 0, bestPos = 0;\n\n            for (int ri = 0; ri < (int)removed.size(); ri++) {\n                int x = removed[ri];\n\n                int b1 = INT_MAX, b2 = INT_MAX;\n                int pos1 = 0;\n\n                for (int p = 0; p <= (int)path.size(); p++) {\n                    int val = evalInsertExactSmall(path, pref, suff, x, p);\n\n                    if (val < b1) {\n                        b2 = b1;\n                        b1 = val;\n                        pos1 = p;\n                    } else if (val < b2) {\n                        b2 = val;\n                    }\n                }\n\n                if (b2 == INT_MAX) b2 = b1 + 1000000;\n                long long regret = (long long)b2 - b1;\n                long long score = (long long)b1 * 10 - (long long)regretW * regret + rng.nextInt(20);\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestRi = ri;\n                    bestPos = pos1;\n                }\n            }\n\n            int x = removed[bestRi];\n            path.insert(path.begin() + bestPos, x);\n            removed.erase(removed.begin() + bestRi);\n        }\n\n        return path;\n    }\n\n    vector<int> destroyRepairOrder(const vector<int>& ord, int k, const Mode& mode, bool useExactRepair = false) {\n        int n = (int)ord.size();\n        if (n <= 2) return ord;\n\n        k = max(1, min(k, n - 1));\n\n        vector<int> pos;\n        vector<char> mark(n, false);\n\n        auto addPos = [&](int p) {\n            if (0 <= p && p < n && !mark[p]) {\n                mark[p] = true;\n                pos.push_back(p);\n            }\n        };\n\n        auto buildBadEdges = [&]() {\n            vector<pair<long long, int>> badEdge;\n            badEdge.reserve(n);\n            badEdge.push_back({-(long long)mode.start[ord[0]] - rng.nextInt(50), 0});\n            for (int i = 0; i + 1 < n; i++) {\n                long long v = mode.edge[ord[i] * M + ord[i + 1]] + rng.nextInt(50);\n                badEdge.push_back({-v, i + 1});\n            }\n            sort(badEdge.begin(), badEdge.end());\n            return badEdge;\n        };\n\n        int tp = rng.nextInt(100);\n\n        if (tp < 22) {\n            int len = k;\n            int st = rng.nextInt(n - len + 1);\n            for (int i = 0; i < len; i++) addPos(st + i);\n        } else if (tp < 50) {\n            vector<pair<long long, int>> bad;\n            bad.reserve(n);\n            for (int i = 0; i < n; i++) {\n                int L = (i > 0 ? ord[i - 1] : -1);\n                int x = ord[i];\n                int R = (i + 1 < n ? ord[i + 1] : -1);\n                long long v = arc(mode, L, x) + arc(mode, x, R) - arc(mode, L, R);\n                v += rng.nextInt(50);\n                bad.push_back({-v, i});\n            }\n            sort(bad.begin(), bad.end());\n            for (auto [neg, p] : bad) {\n                addPos(p);\n                if ((int)pos.size() >= k) break;\n            }\n        } else if (tp < 72) {\n            auto badEdge = buildBadEdges();\n            int top = min(6, (int)badEdge.size());\n            int center = badEdge[rng.nextInt(top)].second;\n            int st = max(0, min(n - k, center - k / 2));\n            for (int i = 0; i < k; i++) addPos(st + i);\n        } else if (tp < 90) {\n            auto badEdge = buildBadEdges();\n            int remaining = k;\n            int clusters = 2;\n\n            for (int c = 0; c < clusters; c++) {\n                int top = min(10, (int)badEdge.size());\n                int center = badEdge[rng.nextInt(top)].second;\n                int len = max(1, remaining / (clusters - c));\n                len = min(len, n);\n\n                int st = max(0, min(n - len, center - len / 2));\n                for (int i = 0; i < len; i++) addPos(st + i);\n\n                remaining = k - (int)pos.size();\n                if (remaining <= 0) break;\n            }\n        } else {\n            while ((int)pos.size() < k) addPos(rng.nextInt(n));\n        }\n\n        while ((int)pos.size() < k) addPos(rng.nextInt(n));\n\n        sort(pos.rbegin(), pos.rend());\n\n        vector<int> path = ord;\n        vector<int> removed;\n        removed.reserve(k);\n\n        for (int p : pos) {\n            removed.push_back(path[p]);\n            path.erase(path.begin() + p);\n        }\n\n        for (int i = (int)removed.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(removed[i], removed[j]);\n        }\n\n        if (useExactRepair) return exactRepair(path, removed);\n\n        int regretW = 2 + rng.nextInt(8);\n\n        while (!removed.empty()) {\n            long long bestScore = (1LL << 60);\n            int bestRi = 0, bestPos = 0;\n\n            for (int ri = 0; ri < (int)removed.size(); ri++) {\n                int x = removed[ri];\n\n                long long b1 = (1LL << 60), b2 = (1LL << 60);\n                int pos1 = 0;\n\n                for (int p = 0; p <= (int)path.size(); p++) {\n                    int u = (p == 0 ? -1 : path[p - 1]);\n                    int v = (p == (int)path.size() ? -1 : path[p]);\n\n                    long long d = arc(mode, u, x) + arc(mode, x, v) - arc(mode, u, v);\n\n                    if (d < b1) {\n                        b2 = b1;\n                        b1 = d;\n                        pos1 = p;\n                    } else if (d < b2) {\n                        b2 = d;\n                    }\n                }\n\n                if (b2 >= (1LL << 50)) b2 = b1 + 1000000;\n\n                long long regret = b2 - b1;\n                long long score = b1 * 10 - (long long)regretW * regret + rng.nextInt(30);\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bestRi = ri;\n                    bestPos = pos1;\n                }\n            }\n\n            int x = removed[bestRi];\n            path.insert(path.begin() + bestPos, x);\n            removed.erase(removed.begin() + bestRi);\n        }\n\n        return path;\n    }\n\n    void intensiveLNS(double deadline) {\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            int mi;\n            int r = rng.nextInt(100);\n            if (r < 65) mi = 0;\n            else if (r < 80) mi = 1;\n            else if (r < 90) mi = 2;\n            else mi = 3;\n\n            int k;\n            if (rng.nextInt(100) < 75) k = 3 + rng.nextInt(8);\n            else k = 10 + rng.nextInt(8);\n\n            bool useExact = (rng.nextInt(100) < 28 && k <= 12 && timer.elapsed() < deadline - 0.006);\n            vector<int> cand = destroyRepairOrder(bestOrder, k, modes[mi], useExact);\n            int c = exactCost(cand);\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = cand;\n            }\n\n            iter++;\n            if ((iter & 63) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    void simulatedAnnealing(double deadline) {\n        if (timer.elapsed() > deadline) return;\n\n        vector<int> curOrd = bestOrder;\n        int curCost = bestCost;\n        const Mode& mode = modes[0];\n\n        double st = timer.elapsed();\n        int n = (int)curOrd.size();\n        if (n <= 1) return;\n\n        int iter = 0;\n        while (timer.elapsed() < deadline) {\n            double progress = (timer.elapsed() - st) / max(1e-9, deadline - st);\n            double temp = 18.0 * pow(0.05, progress) + 0.4;\n\n            auto acceptCandidate = [&](vector<int>& cand, int nc) {\n                int diff = nc - curCost;\n                if (diff <= 0 || rng.nextDouble() < exp(-diff / temp)) {\n                    curOrd.swap(cand);\n                    curCost = nc;\n\n                    if (curCost < bestCost) {\n                        bestCost = curCost;\n                        bestOrder = curOrd;\n                    }\n                }\n            };\n\n            int typ = rng.nextInt(100);\n\n            if (typ >= 88) {\n                int mi;\n                int rr = rng.nextInt(100);\n                if (rr < 65) mi = 0;\n                else if (rr < 78) mi = 1;\n                else if (rr < 89) mi = 2;\n                else mi = 3;\n\n                int k = 3 + rng.nextInt(10);\n                bool useExact = (rng.nextInt(100) < 22 && k <= 10 && timer.elapsed() < deadline - 0.006);\n                vector<int> cand = destroyRepairOrder(curOrd, k, modes[mi], useExact);\n                int nc = exactCost(cand);\n                acceptCandidate(cand, nc);\n\n                iter++;\n                if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n                continue;\n            }\n\n            Move mv{-1, 0, 0, 0};\n\n            if (typ < 23) {\n                int i = rng.nextInt(n);\n                int p = rng.nextInt(n);\n                if (p == i) continue;\n                long long d = relocateDelta(curOrd, i, p, mode);\n                mv = {0, i, p, d};\n            } else if (typ < 42) {\n                int i = rng.nextInt(n);\n                int j = rng.nextInt(n);\n                if (i == j) continue;\n                if (i > j) swap(i, j);\n                long long d = swapDelta(curOrd, i, j, mode);\n                mv = {1, i, j, d};\n            } else if (typ < 58) {\n                int l = rng.nextInt(n);\n                int r = rng.nextInt(n);\n                if (l == r) continue;\n                if (l > r) swap(l, r);\n                long long d = reverseDeltaSlow(curOrd, l, r, mode);\n                mv = {2, l, r, d};\n            } else if (typ < 70) {\n                if (n <= 3) continue;\n                int maxL = min(7, n - 1);\n                int len = 2 + rng.nextInt(maxL - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                long long d = blockRelocateDelta(curOrd, l, r, q, mode);\n                mv = {3, l, r, d, q};\n            } else if (typ < 77) {\n                if (n <= 3) continue;\n                int maxL = min(7, n - 1);\n                int len = 2 + rng.nextInt(maxL - 1);\n                int l = rng.nextInt(n - len + 1);\n                int r = l + len - 1;\n                int q = rng.nextInt(n + 1);\n                if (q >= l && q <= r + 1) continue;\n                mv = {5, l, r, 0, q};\n            } else if (typ < 84) {\n                if (n <= 3) continue;\n                int maxL = min(5, n - 1);\n                int len1 = 1 + rng.nextInt(maxL);\n                int len2 = 1 + rng.nextInt(maxL);\n                int l1 = rng.nextInt(n - len1 + 1);\n                int r1 = l1 + len1 - 1;\n                int l2 = rng.nextInt(n - len2 + 1);\n                int r2 = l2 + len2 - 1;\n\n                if (l2 < l1) {\n                    swap(l1, l2);\n                    swap(r1, r2);\n                }\n                if (r1 >= l2) continue;\n                if (len1 == 1 && len2 == 1) continue;\n\n                long long d = blockSwapDelta(curOrd, l1, r1, l2, r2, mode);\n                mv = {4, l1, r1, d, l2 * 256 + r2};\n            } else {\n                if (n <= 3) continue;\n                int maxL = min(4, n - 1);\n                int len1 = 1 + rng.nextInt(maxL);\n                int len2 = 1 + rng.nextInt(maxL);\n                int l1 = rng.nextInt(n - len1 + 1);\n                int r1 = l1 + len1 - 1;\n                int l2 = rng.nextInt(n - len2 + 1);\n                int r2 = l2 + len2 - 1;\n\n                if (l2 < l1) {\n                    swap(l1, l2);\n                    swap(r1, r2);\n                }\n                if (r1 >= l2) continue;\n                if (len1 == 1 && len2 == 1) continue;\n\n                int bits = 1 + rng.nextInt(3);\n                if ((bits & 1) && len1 == 1) continue;\n                if ((bits & 2) && len2 == 1) continue;\n\n                int code = ((l2 * 256 + r2) << 2) | bits;\n                mv = {6, l1, r1, 0, code};\n            }\n\n            if (mv.delta > 3000) continue;\n            if (mv.delta > 800 && rng.nextInt(100) < 95) continue;\n\n            vector<int> cand = curOrd;\n            applyMove(cand, mv);\n            int nc = exactCost(cand);\n            acceptCandidate(cand, nc);\n\n            iter++;\n            if ((iter & 255) == 0 && timer.elapsed() > deadline) break;\n        }\n    }\n\n    string buildString(const vector<int>& ord) const {\n        if (ord.empty()) return \"\";\n\n        string s = words[ord[0]];\n        for (int i = 1; i < (int)ord.size(); i++) {\n            int a = ord[i - 1];\n            int b = ord[i];\n            int k = overlap[a * M + b];\n            s += words[b].substr(k);\n        }\n        return s;\n    }\n\n    bool containsAll(const string& s) const {\n        if ((int)s.size() < 5) return false;\n\n        vector<char> seen(M, false);\n        int got = 0;\n\n        int code = 0;\n        for (int i = 0; i < 5; i++) code = code * 26 + (s[i] - 'A');\n\n        auto mark = [&](int cd) {\n            auto it = targetMap.find(cd);\n            if (it != targetMap.end()) {\n                int id = it->second;\n                if (!seen[id]) {\n                    seen[id] = true;\n                    got++;\n                }\n            }\n        };\n\n        mark(code);\n\n        for (int i = 5; i < (int)s.size(); i++) {\n            code = (code % pow4) * 26 + (s[i] - 'A');\n            mark(code);\n        }\n\n        return got == M;\n    }\n\n    void tryRemoveRedundant(double deadline) {\n        bool improved = true;\n\n        while (improved && timer.elapsed() < deadline) {\n            improved = false;\n\n            for (int p = 0; p < (int)bestOrder.size(); p++) {\n                if (timer.elapsed() > deadline) break;\n                if ((int)bestOrder.size() <= 1) break;\n\n                vector<int> cand = bestOrder;\n                cand.erase(cand.begin() + p);\n\n                string s = buildString(cand);\n                if (!containsAll(s)) continue;\n\n                int c = exactCost(cand);\n                if (c < bestCost) {\n                    bestCost = c;\n                    bestOrder = cand;\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n\n    void outputStringPath(const string& s) const {\n        int L = (int)s.size();\n        const int INF = 1e9;\n\n        vector<vector<int>> pred(L);\n        vector<int> dpPrev, dpCur;\n\n        for (int idx = 0; idx < L; idx++) {\n            int c = s[idx] - 'A';\n            int cnt = (int)letterPos[c].size();\n\n            dpCur.assign(cnt, INF);\n            pred[idx].assign(cnt, -1);\n\n            if (idx == 0) {\n                for (int q = 0; q < cnt; q++) {\n                    int id = letterPos[c][q];\n                    dpCur[q] = (int)distCell[startId][id] + 1;\n                }\n            } else {\n                int pc = s[idx - 1] - 'A';\n                int pcnt = (int)letterPos[pc].size();\n\n                for (int q = 0; q < cnt; q++) {\n                    int qid = letterPos[c][q];\n                    int best = INF;\n                    int bestP = -1;\n\n                    for (int p = 0; p < pcnt; p++) {\n                        int pid = letterPos[pc][p];\n                        int v = dpPrev[p] + (int)distCell[pid][qid] + 1;\n                        if (v < best) {\n                            best = v;\n                            bestP = p;\n                        }\n                    }\n\n                    dpCur[q] = best;\n                    pred[idx][q] = bestP;\n                }\n            }\n\n            dpPrev.swap(dpCur);\n        }\n\n        int bestIdx = 0;\n        for (int i = 1; i < (int)dpPrev.size(); i++) {\n            if (dpPrev[i] < dpPrev[bestIdx]) bestIdx = i;\n        }\n\n        vector<int> outIds(L);\n        for (int idx = L - 1; idx >= 0; idx--) {\n            int c = s[idx] - 'A';\n            outIds[idx] = letterPos[c][bestIdx];\n            bestIdx = pred[idx][bestIdx];\n        }\n\n        for (int id : outIds) cout << id / N << ' ' << id % N << '\\n';\n    }\n\n    void solve() {\n        timer.reset();\n\n        precompute();\n        buildModes();\n\n        bestOrder.resize(M);\n        iota(bestOrder.begin(), bestOrder.end(), 0);\n        bestCost = exactCost(bestOrder);\n\n        vector<Candidate> candidates;\n\n        auto consider = [&](const vector<int>& ord) {\n            if ((int)ord.size() != M) return;\n            int c = exactCost(ord);\n            candidates.push_back({c, ord});\n            if (c < bestCost) {\n                bestCost = c;\n                bestOrder = ord;\n            }\n        };\n\n        consider(bestOrder);\n\n        for (int mi = 0; mi < (int)modes.size(); mi++) {\n            if (timer.elapsed() > 1.25) break;\n\n            {\n                vector<int> ord = hungarianPatch(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = cheapestInsertion(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n            {\n                vector<int> ord = nearestNeighborBest(modes[mi]);\n                improveAdditive(ord, modes[mi], 35, 3);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes[0], false);\n            improveAdditive(ord, modes[0], 35, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.35) {\n            vector<int> ord = greedyPathCover(modes.back(), true);\n            improveAdditive(ord, modes.back(), 35, 3);\n            consider(ord);\n        }\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return startMinCost[a] < startMinCost[b];\n        });\n\n        if (timer.elapsed() < 1.37) {\n            vector<int> bstarts;\n            for (int i = 0; i < min(M, 10); i++) bstarts.push_back(ids[i]);\n\n            vector<int> ord = coordinateBeam(bstarts, 7, 4, 2, 1.44);\n            if (!ord.empty()) {\n                consider(ord);\n                improveAdditive(ord, modes[0], 18, 3);\n                consider(ord);\n            }\n        }\n\n        if (timer.elapsed() < 1.39) {\n            vector<int> ord = regretInsertion(modes[0], 10);\n            improveAdditive(ord, modes[0], 24, 3);\n            consider(ord);\n        }\n\n        if (timer.elapsed() < 1.42) {\n            vector<int> ord = regretInsertion(modes[3], 12);\n            improveAdditive(ord, modes[3], 22, 3);\n            consider(ord);\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<int> starts;\n        for (int i = 0; i < min(M, 10); i++) starts.push_back(ids[i]);\n        for (int i = 0; i < min((int)candidates.size(), 8); i++) {\n            if (!candidates[i].order.empty()) starts.push_back(candidates[i].order[0]);\n        }\n\n        sort(starts.begin(), starts.end());\n        starts.erase(unique(starts.begin(), starts.end()), starts.end());\n\n        if (timer.elapsed() < 1.445) {\n            vector<int> bstarts = starts;\n            if ((int)bstarts.size() > 10) bstarts.resize(10);\n\n            vector<int> ord = coordinateBeam(bstarts, 6, 4, 1, 1.485);\n            if (!ord.empty()) {\n                consider(ord);\n                improveAdditive(ord, modes[0], 14, 3);\n                consider(ord);\n            }\n        }\n\n        int greedyRuns = 0;\n        int lookRuns = 0;\n        for (int stWord : starts) {\n            if (greedyRuns >= 10 || timer.elapsed() > 1.49) break;\n\n            vector<int> ord = coordinateGreedy(stWord);\n            consider(ord);\n\n            improveAdditive(ord, modes[0], 22, 3);\n            consider(ord);\n\n            if (lookRuns < 4 && timer.elapsed() < 1.485) {\n                vector<int> ord2 = coordinateGreedyLookahead(stWord, 1);\n                consider(ord2);\n                improveAdditive(ord2, modes[0], 16, 3);\n                consider(ord2);\n                lookRuns++;\n            }\n\n            greedyRuns++;\n        }\n\n        sort(candidates.begin(), candidates.end(), [](const Candidate& a, const Candidate& b) {\n            return a.cost < b.cost;\n        });\n\n        vector<vector<int>> refineList;\n        for (const auto& cand : candidates) {\n            bool dup = false;\n            for (const auto& v : refineList) {\n                if (v == cand.order) {\n                    dup = true;\n                    break;\n                }\n            }\n            if (!dup) refineList.push_back(cand.order);\n            if ((int)refineList.size() >= 3) break;\n        }\n\n        for (auto& ord : refineList) {\n            if (timer.elapsed() > 1.60) break;\n            Candidate r = exactRefine(ord, 1.60, 3, 350);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.64) {\n            Candidate r = exactRefine(bestOrder, 1.64, 3, 500);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        if (timer.elapsed() < 1.87) {\n            improveExactInterval(bestOrder, 1.87, 3);\n        }\n\n        int beforeLNS = bestCost;\n        intensiveLNS(1.915);\n\n        if (bestCost < beforeLNS && timer.elapsed() < 1.925) {\n            Candidate r = exactRefine(bestOrder, 1.935, 1, 300);\n            if (r.cost < bestCost) {\n                bestCost = r.cost;\n                bestOrder = r.order;\n            }\n        }\n\n        simulatedAnnealing(1.960);\n        intensiveLNS(1.980);\n        tryRemoveRedundant(1.985);\n\n        string finalS = buildString(bestOrder);\n\n        if (!containsAll(finalS) || (int)finalS.size() > 5000) {\n            bestOrder.resize(M);\n            iota(bestOrder.begin(), bestOrder.end(), 0);\n            finalS = buildString(bestOrder);\n        }\n\n        outputStringPath(finalS);\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.solve();\n\n    return 0;\n}","ahc030":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXC = 400;\nstatic constexpr double EXACT_W = 1e7;\nstatic constexpr double BAN_W = 1e8;\n\nstruct Placement {\n    int di, dj;\n    vector<int> cells;\n    bitset<MAXC> bits;\n};\n\nstruct Field {\n    int area = 0;\n    int h = 0, w = 0;\n    vector<pair<int,int>> rel;\n    vector<Placement> placements;\n    vector<uint16_t> contrib;\n};\n\nstruct Observation {\n    vector<int> cells;\n    int k;\n    int y;\n};\n\nstruct State {\n    bool valid = false;\n    vector<int> pos;\n    vector<int> pred;\n    vector<int> cnt;\n    double score = -1e300;\n};\n\nstruct Solver {\n    int N, M, C;\n    double eps, alpha;\n    int totalArea = 0;\n    int Q = 0;\n    int stride = 0;\n\n    vector<Field> fields;\n    vector<Observation> obs;\n\n    vector<double> scoreFlat;\n    vector<double> tHat, invVarT;\n\n    vector<unsigned char> drilled;\n    vector<int> drillVal;\n    vector<int> drilledCells;\n    int drilledCount = 0;\n    int knownReserveSum = 0;\n\n    vector<vector<unsigned char>> bannedEqMasks;\n    vector<vector<unsigned char>> subsetMasks;\n\n    vector<int> fallbackRank;\n    vector<int> poolSupport;\n    vector<State> lastPool;\n\n    int opCount = 0;\n    int maxInitialQueries = 0;\n    int adaptiveQueryUsed = 0;\n\n    mt19937 rng{123456789};\n    chrono::steady_clock::time_point startTime;\n\n    double elapsedMs() const {\n        return chrono::duration<double, milli>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    }\n\n    double normalCDF(double x) {\n        return 0.5 * erfc(-x / sqrt(2.0));\n    }\n\n    void readInput() {\n        cin >> N >> M >> eps;\n        C = N * N;\n        alpha = 1.0 - 2.0 * eps;\n        fields.resize(M);\n\n        for (int m = 0; m < M; m++) {\n            int d;\n            cin >> d;\n            fields[m].area = d;\n            fields[m].rel.resize(d);\n            int mx_i = 0, mx_j = 0;\n            for (int t = 0; t < d; t++) {\n                int i, j;\n                cin >> i >> j;\n                fields[m].rel[t] = {i, j};\n                mx_i = max(mx_i, i);\n                mx_j = max(mx_j, j);\n            }\n            fields[m].h = mx_i + 1;\n            fields[m].w = mx_j + 1;\n            totalArea += d;\n        }\n\n        generatePlacements();\n\n        drilled.assign(C, 0);\n        drillVal.assign(C, 0);\n        fallbackRank.assign(C, 0);\n        poolSupport.assign(C, 0);\n    }\n\n    void generatePlacements() {\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            for (int di = 0; di + f.h <= N; di++) {\n                for (int dj = 0; dj + f.w <= N; dj++) {\n                    Placement p;\n                    p.di = di;\n                    p.dj = dj;\n                    p.bits.reset();\n                    for (auto [ri, rj] : f.rel) {\n                        int c = (di + ri) * N + (dj + rj);\n                        p.cells.push_back(c);\n                        p.bits.set(c);\n                    }\n                    f.placements.push_back(std::move(p));\n                }\n            }\n        }\n    }\n\n    bool askDivination(vector<int> cells, bool initial) {\n        sort(cells.begin(), cells.end());\n        cells.erase(unique(cells.begin(), cells.end()), cells.end());\n        if ((int)cells.size() < 2) return false;\n        if (initial && (int)obs.size() >= maxInitialQueries) return false;\n\n        cout << \"q \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int y;\n        if (!(cin >> y)) exit(0);\n        if (y < 0) exit(0);\n\n        opCount++;\n        obs.push_back({cells, (int)cells.size(), y});\n        return true;\n    }\n\n    void maybeAskDiv(vector<int> cells) {\n        askDivination(std::move(cells), true);\n    }\n\n    void askInitialQueries() {\n        maxInitialQueries = max(0, C - 10);\n\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            maybeAskDiv(cells);\n        }\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            maybeAskDiv(cells);\n        }\n\n        int B = max(3, (N + 4) / 5);\n        for (int r = 0; r < N; r += B) {\n            for (int c = 0; c < N; c += B) {\n                vector<int> cells;\n                for (int i = r; i < min(N, r + B); i++) {\n                    for (int j = c; j < min(N, c + B); j++) {\n                        cells.push_back(i * N + j);\n                    }\n                }\n                maybeAskDiv(cells);\n            }\n        }\n\n        int off = B / 2;\n        if (off > 0) {\n            for (int r = off; r + B <= N; r += B) {\n                for (int c = off; c + B <= N; c += B) {\n                    vector<int> cells;\n                    for (int i = r; i < r + B; i++) {\n                        for (int j = c; j < c + B; j++) {\n                            cells.push_back(i * N + j);\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        }\n\n        auto addModQueries = [&](int mod) {\n            for (int a = 0; a < mod; a++) {\n                for (int b = 0; b < mod; b++) {\n                    vector<int> cells;\n                    for (int i = 0; i < N; i++) {\n                        for (int j = 0; j < N; j++) {\n                            if (i % mod == a && j % mod == b) {\n                                cells.push_back(i * N + j);\n                            }\n                        }\n                    }\n                    maybeAskDiv(cells);\n                }\n            }\n        };\n        addModQueries(2);\n        if (N >= 13) addModQueries(3);\n\n        int R = (N <= 12 ? N : 2 * N);\n        for (int r = 0; r < R; r++) {\n            vector<int> cells;\n            for (int attempt = 0; attempt < 100; attempt++) {\n                cells.clear();\n                for (int c = 0; c < C; c++) {\n                    if ((int)(rng() % 10000) < 2500) cells.push_back(c);\n                }\n                if ((int)cells.size() >= 2) break;\n            }\n            if ((int)cells.size() < 2) cells = {0, C - 1};\n            maybeAskDiv(cells);\n        }\n    }\n\n    bool submitAnswer(vector<unsigned char> mask) {\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        vector<int> cells;\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) cells.push_back(c);\n        }\n\n        cout << \"a \" << cells.size();\n        for (int c : cells) {\n            cout << ' ' << c / N << ' ' << c % N;\n        }\n        cout << '\\n';\n        cout.flush();\n\n        int res;\n        if (!(cin >> res)) exit(0);\n        opCount++;\n\n        if (res == 1) exit(0);\n        if (res < 0) exit(0);\n        return false;\n    }\n\n    int drillCell(int c) {\n        if (drilled[c]) return drillVal[c];\n\n        cout << \"q 1 \" << c / N << ' ' << c % N << '\\n';\n        cout.flush();\n\n        int v;\n        if (!(cin >> v)) exit(0);\n        if (v < 0) exit(0);\n\n        opCount++;\n        drilled[c] = 1;\n        drillVal[c] = v;\n        drilledCount++;\n        drilledCells.push_back(c);\n        knownReserveSum += v;\n\n        if (knownReserveSum == totalArea) {\n            vector<unsigned char> mask(C, 0);\n            for (int x : drilledCells) {\n                if (drillVal[x] > 0) mask[x] = 1;\n            }\n            submitAnswer(mask);\n        }\n\n        return v;\n    }\n\n    bool canFallback() const {\n        return opCount + (C - drilledCount) + 1 <= 2 * C;\n    }\n\n    bool canWrongGuessAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    bool canExtraQueryAndFallback() const {\n        return opCount + (C - drilledCount) + 2 <= 2 * C;\n    }\n\n    void buildContrib() {\n        Q = (int)obs.size();\n        vector<vector<int>> obsOfCell(C);\n\n        for (int q = 0; q < Q; q++) {\n            for (int c : obs[q].cells) obsOfCell[c].push_back(q);\n        }\n\n        for (int m = 0; m < M; m++) {\n            auto &f = fields[m];\n            int P = (int)f.placements.size();\n            f.contrib.assign(P * Q, 0);\n\n            for (int p = 0; p < P; p++) {\n                uint16_t *arr = Q ? &f.contrib[p * Q] : nullptr;\n                for (int c : f.placements[p].cells) {\n                    for (int q : obsOfCell[c]) {\n                        arr[q]++;\n                    }\n                }\n            }\n        }\n    }\n\n    void buildScoreTables() {\n        stride = totalArea + 1;\n        scoreFlat.assign(Q * stride, 0.0);\n        tHat.assign(Q, 0.0);\n        invVarT.assign(Q, 1.0);\n\n        for (int q = 0; q < Q; q++) {\n            int k = obs[q].k;\n            int y = obs[q].y;\n\n            double sigma = sqrt(k * eps * (1.0 - eps));\n            double varT = k * eps * (1.0 - eps) / (alpha * alpha)\n                        + 0.25 / (alpha * alpha);\n            invVarT[q] = 1.0 / max(1e-9, varT);\n\n            double th = (y - eps * k) / alpha;\n            th = min<double>(totalArea, max<double>(0.0, th));\n            tHat[q] = th;\n\n            for (int t = 0; t <= totalArea; t++) {\n                double mu = eps * k + alpha * t;\n                double prob;\n\n                if (y == 0) {\n                    prob = normalCDF((0.5 - mu) / sigma);\n                } else {\n                    double lo = (y - 0.5 - mu) / sigma;\n                    double hi = (y + 0.5 - mu) / sigma;\n                    prob = normalCDF(hi) - normalCDF(lo);\n                }\n\n                if (!(prob > 1e-300)) prob = 1e-300;\n                scoreFlat[q * stride + t] = log(prob);\n            }\n        }\n    }\n\n    void addToState(State &s, int m, int p, int sign) {\n        if (Q) {\n            const uint16_t *arr = &fields[m].contrib[p * Q];\n            for (int q = 0; q < Q; q++) s.pred[q] += sign * (int)arr[q];\n        }\n\n        for (int c : fields[m].placements[p].cells) {\n            s.cnt[c] += sign;\n        }\n    }\n\n    double computeExactScore(const vector<int> &cnt) const {\n        long long sq = 0;\n        for (int c : drilledCells) {\n            int diff = cnt[c] - drillVal[c];\n            sq += 1LL * diff * diff;\n        }\n        return -EXACT_W * (double)sq;\n    }\n\n    double computeBanPenalty(const vector<int> &cnt) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = cnt[c] > 0;\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (cnt[c] > 0 && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeBanPenaltyBits(const bitset<MAXC> &uni) const {\n        double pen = 0.0;\n\n        for (const auto &mask : bannedEqMasks) {\n            int diff = 0;\n            for (int c = 0; c < C; c++) {\n                bool cov = uni.test(c);\n                if (cov != (bool)mask[c]) diff++;\n            }\n            if (diff == 0) pen -= BAN_W;\n        }\n\n        for (const auto &mask : subsetMasks) {\n            int outside = 0;\n            for (int c = 0; c < C; c++) {\n                if (uni.test(c) && !mask[c]) outside++;\n            }\n            if (outside == 0) pen -= BAN_W;\n        }\n\n        return pen;\n    }\n\n    double computeScore(const State &s) const {\n        double sc = 0.0;\n\n        for (int q = 0; q < Q; q++) {\n            sc += scoreFlat[q * stride + s.pred[q]];\n        }\n\n        sc += computeExactScore(s.cnt);\n        sc += computeBanPenalty(s.cnt);\n        return sc;\n    }\n\n    State buildState(const vector<int> &pos) {\n        State s;\n        s.valid = true;\n        s.pos = pos;\n        s.pred.assign(Q, 0);\n        s.cnt.assign(C, 0);\n\n        for (int m = 0; m < M; m++) {\n            addToState(s, m, s.pos[m], +1);\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    bool sameUnionState(const State &a, const State &b) const {\n        if (!a.valid || !b.valid) return false;\n        for (int c = 0; c < C; c++) {\n            if ((a.cnt[c] > 0) != (b.cnt[c] > 0)) return false;\n        }\n        return true;\n    }\n\n    void insertPool(vector<State> &pool, const State &s, int maxKeep) {\n        if (!s.valid) return;\n\n        for (auto &e : pool) {\n            if (sameUnionState(e, s)) {\n                if (s.score > e.score) e = s;\n                return;\n            }\n        }\n\n        pool.push_back(s);\n        sort(pool.begin(), pool.end(), [](const State &a, const State &b) {\n            return a.score > b.score;\n        });\n        if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n    }\n\n    bool placementCoversKnownZero(int m, int p) const {\n        for (int c : fields[m].placements[p].cells) {\n            if (drilled[c] && drillVal[c] == 0) return true;\n        }\n        return false;\n    }\n\n    int randomPlacement(int m) {\n        int P = (int)fields[m].placements.size();\n\n        for (int t = 0; t < 50; t++) {\n            int p = (int)(rng() % P);\n            if (!placementCoversKnownZero(m, p)) return p;\n        }\n\n        vector<int> valid;\n        for (int p = 0; p < P; p++) {\n            if (!placementCoversKnownZero(m, p)) valid.push_back(p);\n        }\n\n        if (!valid.empty()) {\n            return valid[(int)(rng() % valid.size())];\n        }\n        return (int)(rng() % P);\n    }\n\n    State makeRandomState() {\n        vector<int> pos(M);\n        for (int m = 0; m < M; m++) {\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makePerturbedState(const State &base, int changes) {\n        vector<int> pos = base.pos;\n        for (int t = 0; t < changes; t++) {\n            int m = (int)(rng() % M);\n            pos[m] = randomPlacement(m);\n        }\n        return buildState(pos);\n    }\n\n    State makeGreedyState() {\n        vector<int> pos(M, -1);\n        vector<int> pred(Q, 0);\n        vector<int> cnt(C, 0);\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].area > fields[b].area;\n        });\n\n        int placedArea = 0;\n\n        for (int m : order) {\n            int P = (int)fields[m].placements.size();\n            int newArea = placedArea + fields[m].area;\n\n            double bestVal = 1e300;\n            int bestP = 0;\n\n            for (int p = 0; p < P; p++) {\n                double val = 0.0;\n                const uint16_t *arr = Q ? &fields[m].contrib[p * Q] : nullptr;\n\n                for (int q = 0; q < Q; q++) {\n                    double target = tHat[q] * (double)newArea / (double)totalArea;\n                    double diff = (double)(pred[q] + arr[q]) - target;\n                    val += diff * diff * invVarT[q];\n                }\n\n                for (int c : fields[m].placements[p].cells) {\n                    if (drilled[c]) {\n                        if (drillVal[c] == 0) val += 1e9;\n                        if (cnt[c] + 1 > drillVal[c]) val += 1e9;\n                    }\n                }\n\n                if (val < bestVal - 1e-9 ||\n                    (fabs(val - bestVal) <= 1e-9 && (rng() & 1))) {\n                    bestVal = val;\n                    bestP = p;\n                }\n            }\n\n            pos[m] = bestP;\n            if (Q) {\n                const uint16_t *arr = &fields[m].contrib[bestP * Q];\n                for (int q = 0; q < Q; q++) pred[q] += arr[q];\n            }\n            for (int c : fields[m].placements[bestP].cells) cnt[c]++;\n            placedArea = newArea;\n        }\n\n        return buildState(pos);\n    }\n\n    struct ExactCand {\n        double sc;\n        int p0, p1, p2;\n    };\n\n    struct ExactCandCmp {\n        bool operator()(const ExactCand &a, const ExactCand &b) const {\n            return a.sc > b.sc;\n        }\n    };\n\n    State optimizeExactSmall() {\n        State invalid;\n        const int HEAP_KEEP = 36;\n        const int POOL_KEEP = 12;\n\n        if (M == 2) {\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            priority_queue<ExactCand, vector<ExactCand>, ExactCandCmp> pq;\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    double sc = 0.0;\n                    for (int q = 0; q < Q; q++) {\n                        int t = a0[q] + a1[q];\n                        sc += scoreFlat[q * stride + t];\n                    }\n\n                    if (drilledCount > 0) {\n                        long long sq = 0;\n                        for (int c : drilledCells) {\n                            int cntv = (b0.test(c) ? 1 : 0) + (b1.test(c) ? 1 : 0);\n                            int diff = cntv - drillVal[c];\n                            sq += 1LL * diff * diff;\n                        }\n                        sc -= EXACT_W * (double)sq;\n                    }\n\n                    if (hasBan) {\n                        bitset<MAXC> uni = b0 | b1;\n                        sc += computeBanPenaltyBits(uni);\n                    }\n\n                    ExactCand cand{sc, p0, p1, -1};\n                    if ((int)pq.size() < HEAP_KEEP) {\n                        pq.push(cand);\n                    } else if (sc > pq.top().sc) {\n                        pq.pop();\n                        pq.push(cand);\n                    }\n                }\n            }\n\n            vector<ExactCand> nodes;\n            while (!pq.empty()) {\n                nodes.push_back(pq.top());\n                pq.pop();\n            }\n            sort(nodes.begin(), nodes.end(), [](const ExactCand &a, const ExactCand &b) {\n                return a.sc > b.sc;\n            });\n\n            vector<State> pool;\n            for (auto &nd : nodes) {\n                vector<int> pos = {nd.p0, nd.p1};\n                insertPool(pool, buildState(pos), POOL_KEEP);\n            }\n\n            if (pool.empty()) return invalid;\n            lastPool = pool;\n            return pool[0];\n        }\n\n        if (M == 3) {\n            long long prod = 1;\n            for (int m = 0; m < 3; m++) {\n                prod *= (long long)fields[m].placements.size();\n            }\n            if (prod > 250000) return invalid;\n\n            int P0 = (int)fields[0].placements.size();\n            int P1 = (int)fields[1].placements.size();\n            int P2 = (int)fields[2].placements.size();\n\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n            vector<int> pred01(Q);\n            priority_queue<ExactCand, vector<ExactCand>, ExactCandCmp> pq;\n\n            for (int p0 = 0; p0 < P0; p0++) {\n                const uint16_t *a0 = Q ? &fields[0].contrib[p0 * Q] : nullptr;\n                const auto &b0 = fields[0].placements[p0].bits;\n\n                for (int p1 = 0; p1 < P1; p1++) {\n                    const uint16_t *a1 = Q ? &fields[1].contrib[p1 * Q] : nullptr;\n                    const auto &b1 = fields[1].placements[p1].bits;\n\n                    for (int q = 0; q < Q; q++) pred01[q] = a0[q] + a1[q];\n\n                    bitset<MAXC> bits01;\n                    if (hasBan) bits01 = b0 | b1;\n\n                    for (int p2 = 0; p2 < P2; p2++) {\n                        const uint16_t *a2 = Q ? &fields[2].contrib[p2 * Q] : nullptr;\n                        const auto &b2 = fields[2].placements[p2].bits;\n\n                        double sc = 0.0;\n                        for (int q = 0; q < Q; q++) {\n                            int t = pred01[q] + a2[q];\n                            sc += scoreFlat[q * stride + t];\n                        }\n\n                        if (drilledCount > 0) {\n                            long long sq = 0;\n                            for (int c : drilledCells) {\n                                int cntv = (b0.test(c) ? 1 : 0)\n                                         + (b1.test(c) ? 1 : 0)\n                                         + (b2.test(c) ? 1 : 0);\n                                int diff = cntv - drillVal[c];\n                                sq += 1LL * diff * diff;\n                            }\n                            sc -= EXACT_W * (double)sq;\n                        }\n\n                        if (hasBan) {\n                            bitset<MAXC> uni = bits01 | b2;\n                            sc += computeBanPenaltyBits(uni);\n                        }\n\n                        ExactCand cand{sc, p0, p1, p2};\n                        if ((int)pq.size() < HEAP_KEEP) {\n                            pq.push(cand);\n                        } else if (sc > pq.top().sc) {\n                            pq.pop();\n                            pq.push(cand);\n                        }\n                    }\n                }\n            }\n\n            vector<ExactCand> nodes;\n            while (!pq.empty()) {\n                nodes.push_back(pq.top());\n                pq.pop();\n            }\n            sort(nodes.begin(), nodes.end(), [](const ExactCand &a, const ExactCand &b) {\n                return a.sc > b.sc;\n            });\n\n            vector<State> pool;\n            for (auto &nd : nodes) {\n                vector<int> pos = {nd.p0, nd.p1, nd.p2};\n                insertPool(pool, buildState(pos), POOL_KEEP);\n            }\n\n            if (pool.empty()) return invalid;\n            lastPool = pool;\n            return pool[0];\n        }\n\n        return invalid;\n    }\n\n    State coordinateDescent(State s, int sweeps, double deadlineMs) {\n        vector<int> order(M);\n        iota(order.begin(), order.end(), 0);\n\n        for (int sw = 0; sw < sweeps; sw++) {\n            shuffle(order.begin(), order.end(), rng);\n            bool changed = false;\n\n            for (int m : order) {\n                if (elapsedMs() > deadlineMs) {\n                    s.score = computeScore(s);\n                    return s;\n                }\n\n                int oldP = s.pos[m];\n                addToState(s, m, oldP, -1);\n\n                double baseExact = computeExactScore(s.cnt);\n\n                vector<int> baseDiff(bannedEqMasks.size(), 0);\n                vector<int> baseOut(subsetMasks.size(), 0);\n\n                for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                    const auto &mask = bannedEqMasks[f];\n                    int diff = 0;\n                    for (int c = 0; c < C; c++) {\n                        bool cov = s.cnt[c] > 0;\n                        if (cov != (bool)mask[c]) diff++;\n                    }\n                    baseDiff[f] = diff;\n                }\n\n                for (size_t f = 0; f < subsetMasks.size(); f++) {\n                    const auto &mask = subsetMasks[f];\n                    int out = 0;\n                    for (int c = 0; c < C; c++) {\n                        if (s.cnt[c] > 0 && !mask[c]) out++;\n                    }\n                    baseOut[f] = out;\n                }\n\n                int P = (int)fields[m].placements.size();\n                int bestP = oldP;\n                double bestSc = -1e300;\n\n                for (int p = 0; p < P; p++) {\n                    const auto &pl = fields[m].placements[p];\n                    double total = baseExact;\n\n                    if (Q) {\n                        const uint16_t *arr = &fields[m].contrib[p * Q];\n                        for (int q = 0; q < Q; q++) {\n                            int t = s.pred[q] + arr[q];\n                            total += scoreFlat[q * stride + t];\n                        }\n                    }\n\n                    if (drilledCount > 0) {\n                        for (int c : pl.cells) {\n                            if (drilled[c]) {\n                                int diff = s.cnt[c] - drillVal[c];\n                                total += -EXACT_W *\n                                    (double)((diff + 1) * (diff + 1) - diff * diff);\n                            }\n                        }\n                    }\n\n                    for (size_t f = 0; f < bannedEqMasks.size(); f++) {\n                        int diff = baseDiff[f];\n                        const auto &mask = bannedEqMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0) {\n                                if (mask[c]) diff--;\n                                else diff++;\n                            }\n                        }\n\n                        if (diff == 0) total -= BAN_W;\n                    }\n\n                    for (size_t f = 0; f < subsetMasks.size(); f++) {\n                        int out = baseOut[f];\n                        const auto &mask = subsetMasks[f];\n\n                        for (int c : pl.cells) {\n                            if (s.cnt[c] == 0 && !mask[c]) out++;\n                        }\n\n                        if (out == 0) total -= BAN_W;\n                    }\n\n                    if (total > bestSc + 1e-9 ||\n                        (fabs(total - bestSc) <= 1e-9 && (rng() & 1))) {\n                        bestSc = total;\n                        bestP = p;\n                    }\n                }\n\n                addToState(s, m, bestP, +1);\n                s.pos[m] = bestP;\n                s.score = bestSc;\n                if (bestP != oldP) changed = true;\n            }\n\n            if (!changed) break;\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    State pairRefine(State s, double deadlineMs, int maxPairs) {\n        if (!s.valid || M < 4) return s;\n\n        vector<pair<int,int>> pairs;\n        for (int i = 0; i < M; i++) {\n            for (int j = i + 1; j < M; j++) pairs.push_back({i, j});\n        }\n        shuffle(pairs.begin(), pairs.end(), rng);\n\n        long long prodLimit = (M <= 6 ? 70000LL : 45000LL);\n        int done = 0;\n\n        for (auto [a, b] : pairs) {\n            if (done >= maxPairs) break;\n            if (elapsedMs() > deadlineMs - 10.0) break;\n\n            int Pa = (int)fields[a].placements.size();\n            int Pb = (int)fields[b].placements.size();\n            if (1LL * Pa * Pb > prodLimit) continue;\n\n            int oldA = s.pos[a];\n            int oldB = s.pos[b];\n\n            addToState(s, a, oldA, -1);\n            addToState(s, b, oldB, -1);\n\n            bitset<MAXC> baseBits;\n            for (int c = 0; c < C; c++) {\n                if (s.cnt[c] > 0) baseBits.set(c);\n            }\n\n            int bestA = oldA;\n            int bestB = oldB;\n            double bestSc = -1e300;\n            bool hasBan = !bannedEqMasks.empty() || !subsetMasks.empty();\n\n            for (int pa = 0; pa < Pa; pa++) {\n                const uint16_t *arrA = Q ? &fields[a].contrib[pa * Q] : nullptr;\n                const auto &bitsA = fields[a].placements[pa].bits;\n\n                for (int pb = 0; pb < Pb; pb++) {\n                    const uint16_t *arrB = Q ? &fields[b].contrib[pb * Q] : nullptr;\n                    const auto &bitsB = fields[b].placements[pb].bits;\n\n                    double sc = 0.0;\n\n                    for (int q = 0; q < Q; q++) {\n                        int t = s.pred[q] + arrA[q] + arrB[q];\n                        sc += scoreFlat[q * stride + t];\n                    }\n\n                    if (drilledCount > 0) {\n                        long long sq = 0;\n                        for (int c : drilledCells) {\n                            int cntv = s.cnt[c]\n                                     + (bitsA.test(c) ? 1 : 0)\n                                     + (bitsB.test(c) ? 1 : 0);\n                            int diff = cntv - drillVal[c];\n                            sq += 1LL * diff * diff;\n                        }\n                        sc -= EXACT_W * (double)sq;\n                    }\n\n                    if (hasBan) {\n                        bitset<MAXC> uni = baseBits | bitsA | bitsB;\n                        sc += computeBanPenaltyBits(uni);\n                    }\n\n                    if (sc > bestSc + 1e-9 ||\n                        (fabs(sc - bestSc) <= 1e-9 && (rng() & 1))) {\n                        bestSc = sc;\n                        bestA = pa;\n                        bestB = pb;\n                    }\n                }\n            }\n\n            addToState(s, a, bestA, +1);\n            addToState(s, b, bestB, +1);\n            s.pos[a] = bestA;\n            s.pos[b] = bestB;\n            done++;\n        }\n\n        s.score = computeScore(s);\n        return s;\n    }\n\n    State optimize(const State *prev, bool first) {\n        State exact = optimizeExactSmall();\n        if (exact.valid) return exact;\n\n        double now = elapsedMs();\n        double req = first ? 1200.0 : 450.0;\n        double deadline = min(2450.0, now + req);\n        if (deadline < now + 30.0) deadline = now + 30.0;\n\n        double reserve = 0.0;\n        if (M >= 4 && M <= 8) reserve = first ? 100.0 : 60.0;\n        double searchDeadline = deadline;\n        if (deadline - now > reserve + 60.0) {\n            searchDeadline = deadline - reserve;\n        }\n\n        int maxRestarts;\n        if (first) {\n            if (M <= 4) maxRestarts = 80;\n            else if (M <= 10) maxRestarts = 50;\n            else maxRestarts = 35;\n        } else {\n            if (M <= 4) maxRestarts = 40;\n            else if (M <= 10) maxRestarts = 25;\n            else maxRestarts = 18;\n        }\n\n        int sweeps = first ? 7 : 5;\n\n        State best;\n        vector<State> pool;\n\n        for (int r = 0; r < maxRestarts && elapsedMs() < searchDeadline; r++) {\n            State s;\n\n            if (r == 0 && prev && prev->valid) {\n                s = buildState(prev->pos);\n            } else if ((r == 0 && (!prev || !prev->valid)) ||\n                       (r == 1 && prev && prev->valid)) {\n                s = makeGreedyState();\n            } else if (prev && prev->valid && r < 6) {\n                int changes = 1 + (r % max(1, M / 2));\n                s = makePerturbedState(*prev, changes);\n            } else {\n                s = makeRandomState();\n            }\n\n            s = coordinateDescent(s, sweeps, searchDeadline);\n            insertPool(pool, s, 12);\n\n            if (!best.valid || s.score > best.score) {\n                best = std::move(s);\n            }\n        }\n\n        if (!best.valid) {\n            if (prev && prev->valid) best = buildState(prev->pos);\n            else best = makeGreedyState();\n        }\n\n        if (elapsedMs() < deadline - 20.0) {\n            int pairs = first ? (M <= 6 ? 5 : 3) : (M <= 6 ? 3 : 2);\n            State refined = pairRefine(best, deadline, pairs);\n            if (refined.score > best.score) best = refined;\n        }\n\n        insertPool(pool, best, 12);\n        if (pool.empty()) insertPool(pool, best, 12);\n        lastPool = pool;\n\n        return best;\n    }\n\n    int countExactMismatch(const State &s) const {\n        int mism = 0;\n        for (int c : drilledCells) {\n            if (s.cnt[c] != drillVal[c]) mism++;\n        }\n        return mism;\n    }\n\n    vector<unsigned char> unionMask(const State &s) const {\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) mask[c] = 1;\n        }\n        return mask;\n    }\n\n    bool allVerifiedPositive(const vector<unsigned char> &mask) const {\n        for (int c = 0; c < C; c++) {\n            if (mask[c]) {\n                if (!drilled[c]) return false;\n                if (drillVal[c] <= 0) return false;\n            }\n        }\n        return true;\n    }\n\n    bool sameMask(const vector<unsigned char> &a,\n                  const vector<unsigned char> &b) const {\n        return a == b;\n    }\n\n    bool isBannedEq(const vector<unsigned char> &mask) const {\n        for (const auto &x : bannedEqMasks) {\n            if (sameMask(x, mask)) return true;\n        }\n        return false;\n    }\n\n    bool violatesSubsetBan(const vector<unsigned char> &mask) const {\n        for (const auto &s : subsetMasks) {\n            bool outside = false;\n            for (int c = 0; c < C; c++) {\n                if (mask[c] && !s[c]) {\n                    outside = true;\n                    break;\n                }\n            }\n            if (!outside) return true;\n        }\n        return false;\n    }\n\n    void addBannedEq(const vector<unsigned char> &mask) {\n        if (!isBannedEq(mask)) bannedEqMasks.push_back(mask);\n    }\n\n    void addSubsetMask(const vector<unsigned char> &mask) {\n        for (const auto &x : subsetMasks) {\n            if (sameMask(x, mask)) return;\n        }\n        subsetMasks.push_back(mask);\n    }\n\n    int boundaryScore(int c, const vector<unsigned char> &mask) const {\n        int i = c / N;\n        int j = c % N;\n        int score = 0;\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) {\n                score++;\n            } else {\n                int nc = ni * N + nj;\n                if (!mask[nc]) score++;\n            }\n        }\n\n        return score;\n    }\n\n    vector<int> cellsToDrillInUnion(const vector<unsigned char> &U) {\n        vector<pair<int,int>> order;\n\n        for (int c = 0; c < C; c++) {\n            if (U[c] && !drilled[c]) {\n                int support = min(100000, poolSupport[c] * 100);\n                int uncertainty = 100000 - support;\n                int key = boundaryScore(c, U) * 150000\n                        + uncertainty\n                        + (int)(rng() % 1000);\n                order.push_back({-key, c});\n            }\n        }\n\n        sort(order.begin(), order.end());\n\n        vector<int> res;\n        for (auto [_, c] : order) res.push_back(c);\n        return res;\n    }\n\n    int adaptiveQueryLimit() const {\n        if (N >= 15) return 10;\n        if (N >= 12) return 7;\n        return 5;\n    }\n\n    void addAdaptiveQueries(const vector<unsigned char> &A) {\n        if (adaptiveQueryUsed >= adaptiveQueryLimit()) return;\n        if (elapsedMs() > 2350.0) return;\n\n        bool added = false;\n\n        auto tryAsk = [&](vector<int> cells) {\n            if (adaptiveQueryUsed >= adaptiveQueryLimit()) return;\n            if (elapsedMs() > 2380.0) return;\n            if (!canExtraQueryAndFallback()) return;\n            if ((int)cells.size() < 2) return;\n            if (askDivination(std::move(cells), false)) {\n                adaptiveQueryUsed++;\n                added = true;\n            }\n        };\n\n        vector<int> inside, outside;\n        inside.reserve(C);\n        outside.reserve(C);\n\n        for (int c = 0; c < C; c++) {\n            if (A[c]) inside.push_back(c);\n            else outside.push_back(c);\n        }\n\n        tryAsk(inside);\n\n        if ((int)lastPool.size() >= 2) {\n            vector<int> freq(C, 0);\n            int K = min<int>(lastPool.size(), 12);\n            for (int t = 0; t < K; t++) {\n                const State &s = lastPool[t];\n                for (int c = 0; c < C; c++) {\n                    if (s.cnt[c] > 0) freq[c]++;\n                }\n            }\n\n            vector<int> uncertain;\n            for (int c = 0; c < C; c++) {\n                if (freq[c] > 0 && freq[c] < K) uncertain.push_back(c);\n            }\n            tryAsk(uncertain);\n        }\n\n        vector<unsigned char> isRing(C, 0);\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int c = 0; c < C; c++) {\n            if (!A[c]) continue;\n            int i = c / N;\n            int j = c % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!A[nc]) isRing[nc] = 1;\n            }\n        }\n\n        vector<int> ring;\n        for (int c = 0; c < C; c++) {\n            if (isRing[c]) ring.push_back(c);\n        }\n        tryAsk(ring);\n\n        tryAsk(outside);\n\n        if (added) {\n            buildContrib();\n            buildScoreTables();\n        }\n    }\n\n    void updateFallbackRank(const State &s) {\n        fallbackRank.assign(C, 0);\n        poolSupport.assign(C, 0);\n\n        for (int idx = 0; idx < (int)lastPool.size(); idx++) {\n            const State &st = lastPool[idx];\n            int w = max(1, 24 - idx * 2);\n            for (int c = 0; c < C; c++) {\n                if (st.cnt[c] > 0) {\n                    poolSupport[c] += w * st.cnt[c];\n                    fallbackRank[c] += w * 4000 * st.cnt[c];\n                }\n            }\n        }\n\n        vector<unsigned char> U(C, 0);\n\n        for (int c = 0; c < C; c++) {\n            if (s.cnt[c] > 0) {\n                U[c] = 1;\n                fallbackRank[c] += 100000 + 1000 * s.cnt[c];\n            }\n        }\n\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        for (int c = 0; c < C; c++) {\n            if (!U[c]) continue;\n            int i = c / N;\n            int j = c % N;\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!U[nc]) fallbackRank[nc] += 10000;\n            }\n        }\n\n        for (int c : drilledCells) {\n            if (drillVal[c] <= 0) continue;\n            int i = c / N;\n            int j = c % N;\n            int base = 15000 + 3000 * min(drillVal[c], 3);\n\n            for (int d = 0; d < 4; d++) {\n                int ni = i + di[d];\n                int nj = j + dj[d];\n                if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n                int nc = ni * N + nj;\n                if (!drilled[nc]) fallbackRank[nc] += base;\n            }\n        }\n    }\n\n    bool maskForStateGuess(const State &s, vector<unsigned char> &mask) {\n        if (!s.valid) return false;\n        if (countExactMismatch(s) > 0) return false;\n\n        mask = unionMask(s);\n        for (int c = 0; c < C; c++) {\n            if (drilled[c] && drillVal[c] > 0) mask[c] = 1;\n        }\n\n        if (isBannedEq(mask)) return false;\n        if (violatesSubsetBan(mask)) return false;\n        return true;\n    }\n\n    void tryLastChanceGuesses() {\n        if ((int)lastPool.size() < 2) return;\n\n        sort(lastPool.begin(), lastPool.end(), [](const State &a, const State &b) {\n            return a.score > b.score;\n        });\n\n        int tries = 0;\n        double firstScore = -1e300;\n        bool haveFirst = false;\n\n        for (const auto &s : lastPool) {\n            if (tries >= 3) break;\n            if (!canWrongGuessAndFallback()) break;\n\n            vector<unsigned char> mask;\n            if (!maskForStateGuess(s, mask)) continue;\n\n            if (!haveFirst) {\n                haveFirst = true;\n                firstScore = s.score;\n            } else {\n                double gap = firstScore - s.score;\n                if (tries == 1 && gap > 100.0) break;\n                if (tries >= 2 && gap > 60.0) break;\n            }\n\n            submitAnswer(mask);\n            addBannedEq(mask);\n            tries++;\n        }\n    }\n\n    void addNeighborFallbackBonus(int c, int v) {\n        const int di[4] = {-1, 1, 0, 0};\n        const int dj[4] = {0, 0, -1, 1};\n\n        int i = c / N;\n        int j = c % N;\n\n        int nearBonus = 220000 + 50000 * min(v, 3);\n        int farBonus = 8000 + 2000 * min(v, 3);\n\n        for (int d = 0; d < 4; d++) {\n            int ni = i + di[d];\n            int nj = j + dj[d];\n            if (ni < 0 || ni >= N || nj < 0 || nj >= N) continue;\n            int nc = ni * N + nj;\n            if (!drilled[nc]) fallbackRank[nc] += nearBonus;\n\n            for (int e = 0; e < 4; e++) {\n                int mi = ni + di[e];\n                int mj = nj + dj[e];\n                if (mi < 0 || mi >= N || mj < 0 || mj >= N) continue;\n                int mc = mi * N + mj;\n                if (!drilled[mc]) fallbackRank[mc] += farBonus;\n            }\n        }\n    }\n\n    void fallback() {\n        tryLastChanceGuesses();\n\n        while (drilledCount < C) {\n            int bestC = -1;\n            int bestKey = INT_MIN;\n\n            for (int c = 0; c < C; c++) {\n                if (drilled[c]) continue;\n                int key = fallbackRank[c] + (int)(rng() % 1000);\n                if (key > bestKey) {\n                    bestKey = key;\n                    bestC = c;\n                }\n            }\n\n            if (bestC == -1) break;\n            int v = drillCell(bestC);\n            if (v > 0) addNeighborFallbackBonus(bestC, v);\n        }\n\n        vector<unsigned char> mask(C, 0);\n        for (int c = 0; c < C; c++) {\n            if (drillVal[c] > 0) mask[c] = 1;\n        }\n\n        submitAnswer(mask);\n        exit(0);\n    }\n\n    void run() {\n        startTime = chrono::steady_clock::now();\n\n        askInitialQueries();\n        buildContrib();\n        buildScoreTables();\n\n        State best = optimize(nullptr, true);\n\n        int maxUnverifiedGuesses = (N >= 15 ? 3 : 2);\n        int unverifiedUsed = 0;\n        int mismatchRetries = 0;\n\n        int probeGuessUsed = 0;\n        int maxProbeGuesses = (N >= 18 ? 3 : (N >= 15 ? 2 : 1));\n\n        while (true) {\n            updateFallbackRank(best);\n\n            if (!canFallback()) fallback();\n            if (elapsedMs() > 2600.0) fallback();\n            if (drilledCount == C) fallback();\n\n            int mism = countExactMismatch(best);\n            if (mism > 0) {\n                if (mismatchRetries < 3 && elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    mismatchRetries++;\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n            mismatchRetries = 0;\n\n            vector<unsigned char> U = unionMask(best);\n            vector<unsigned char> A = U;\n            for (int c = 0; c < C; c++) {\n                if (drilled[c] && drillVal[c] > 0) A[c] = 1;\n            }\n\n            bool verified = allVerifiedPositive(A);\n\n            if (verified) {\n                submitAnswer(A);\n\n                addSubsetMask(A);\n                addBannedEq(A);\n                addAdaptiveQueries(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            if (unverifiedUsed < maxUnverifiedGuesses &&\n                canWrongGuessAndFallback() &&\n                !isBannedEq(A)) {\n                submitAnswer(A);\n                addBannedEq(A);\n                unverifiedUsed++;\n                addAdaptiveQueries(A);\n                best = optimize(&best, false);\n                continue;\n            }\n\n            vector<int> todo = cellsToDrillInUnion(U);\n\n            if (todo.empty()) {\n                if (elapsedMs() < 2400.0) {\n                    best = optimize(&best, false);\n                    continue;\n                } else {\n                    fallback();\n                }\n            }\n\n            bool contradiction = false;\n            int startIdx = 0;\n\n            if (probeGuessUsed < maxProbeGuesses &&\n                (int)todo.size() >= 10 &&\n                elapsedMs() < 2450.0 &&\n                !isBannedEq(A)) {\n                int probeK = min((int)todo.size(), (N >= 15 ? 5 : 4));\n\n                for (; startIdx < probeK; startIdx++) {\n                    int c = todo[startIdx];\n                    if (drilled[c]) continue;\n                    if (!canFallback()) fallback();\n\n                    int v = drillCell(c);\n                    if (v != best.cnt[c]) {\n                        contradiction = true;\n                        break;\n                    }\n                }\n\n                if (contradiction) {\n                    best = optimize(&best, false);\n                    continue;\n                }\n\n                vector<unsigned char> PA = U;\n                for (int c = 0; c < C; c++) {\n                    if (drilled[c] && drillVal[c] > 0) PA[c] = 1;\n                }\n\n                if (allVerifiedPositive(PA)) {\n                    submitAnswer(PA);\n                    addSubsetMask(PA);\n                    addBannedEq(PA);\n                    addAdaptiveQueries(PA);\n                    best = optimize(&best, false);\n                    continue;\n                }\n\n                if (canWrongGuessAndFallback() && !isBannedEq(PA)) {\n                    submitAnswer(PA);\n                    addBannedEq(PA);\n                    probeGuessUsed++;\n                    addAdaptiveQueries(PA);\n                    best = optimize(&best, false);\n                    continue;\n                }\n            }\n\n            for (int idx = startIdx; idx < (int)todo.size(); idx++) {\n                int c = todo[idx];\n                if (drilled[c]) continue;\n                if (!canFallback()) fallback();\n\n                int v = drillCell(c);\n                if (v != best.cnt[c]) {\n                    contradiction = true;\n                    break;\n                }\n            }\n\n            if (contradiction) {\n                best = optimize(&best, false);\n                continue;\n            }\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    Solver solver;\n    solver.readInput();\n    solver.run();\n\n    return 0;\n}","ahc031":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int W = 1000;\nstatic const int AREA = W * W;\nstatic const unsigned short INF = 30000;\nstatic const int SEG_INF = 1'000'000'000;\nstatic const int MAX_SEG_OPT = 4;\n\nenum { VERT = 0, HOR = 1 };\nenum { POLICY_STATIC_ABS = 0, POLICY_STATIC_RATIO = 1, POLICY_PREV = 2 };\n\nstruct Rect {\n    int y0, x0, y1, x1;\n};\n\nint D, N;\nvector<vector<int>> A;\nvector<int> globalMaxDemand, meanDemand, medDemand, p75Demand, p90Demand, optStaticDemand;\n\nint hMinSeg[55][55], hStaticSeg[55][55];\nint dayHSeg[55][55][55];\n\nint segOptCnt[55][55];\nint segOptH[55][55][MAX_SEG_OPT];\nlong long segOptCost[55][55][MAX_SEG_OPT];\nint segOptTarget[55][55][MAX_SEG_OPT];\nbool segOptSoft[55][55][MAX_SEG_OPT];\n\nvector<vector<vector<Rect>>> dayCand;\nvector<vector<Rect>> staticLibLayouts;\nbool dayCandReady = false;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nint clamp_int(int v, int lo, int hi) {\n    if (v < lo) return lo;\n    if (v > hi) return hi;\n    return v;\n}\n\nint ceil_div_int(int a, int b) {\n    return (a + b - 1) / b;\n}\n\nbool same_layout(const vector<Rect>& a, const vector<Rect>& b) {\n    if ((int)a.size() != (int)b.size()) return false;\n    for (int i = 0; i < (int)a.size(); i++) {\n        if (a[i].y0 != b[i].y0 || a[i].x0 != b[i].x0 ||\n            a[i].y1 != b[i].y1 || a[i].x1 != b[i].x1) return false;\n    }\n    return true;\n}\n\nbool add_unique_layout(vector<vector<Rect>>& cand, const vector<Rect>& layout) {\n    for (const auto& x : cand) {\n        if (same_layout(x, layout)) return false;\n    }\n    cand.push_back(layout);\n    return true;\n}\n\nbool add_unique_layout_cap(vector<vector<Rect>>& cand, const vector<Rect>& layout, int cap) {\n    for (const auto& x : cand) {\n        if (same_layout(x, layout)) return false;\n    }\n    if ((int)cand.size() >= cap) return false;\n    cand.push_back(layout);\n    return true;\n}\n\n/* ---------- exact evaluator, sparse boundary ---------- */\n\nstruct Bound {\n    array<vector<pair<int,int>>, W + 1> H, V;\n    vector<int> nonH, nonV;\n    long long total = 0;\n\n    void clear() {\n        for (int i : nonH) H[i].clear();\n        for (int i : nonV) V[i].clear();\n        nonH.clear();\n        nonV.clear();\n        total = 0;\n    }\n};\n\nvoid merge_intervals(vector<pair<int,int>>& v) {\n    if (v.empty()) return;\n    sort(v.begin(), v.end());\n    int m = 0;\n    for (auto p : v) {\n        if (m == 0 || p.first > v[m-1].second) {\n            v[m++] = p;\n        } else {\n            v[m-1].second = max(v[m-1].second, p.second);\n        }\n    }\n    v.resize(m);\n}\n\nvoid build_bound(const vector<Rect>& rs, Bound& b) {\n    b.clear();\n\n    auto addH = [&](int y, int l, int r) {\n        if (y <= 0 || y >= W || l >= r) return;\n        if (b.H[y].empty()) b.nonH.push_back(y);\n        b.H[y].push_back({l, r});\n    };\n    auto addV = [&](int x, int l, int r) {\n        if (x <= 0 || x >= W || l >= r) return;\n        if (b.V[x].empty()) b.nonV.push_back(x);\n        b.V[x].push_back({l, r});\n    };\n\n    for (const auto& r : rs) {\n        addH(r.y0, r.x0, r.x1);\n        addH(r.y1, r.x0, r.x1);\n        addV(r.x0, r.y0, r.y1);\n        addV(r.x1, r.y0, r.y1);\n    }\n\n    sort(b.nonH.begin(), b.nonH.end());\n    sort(b.nonV.begin(), b.nonV.end());\n\n    for (int i : b.nonH) {\n        merge_intervals(b.H[i]);\n        for (auto [l, r] : b.H[i]) b.total += r - l;\n    }\n    for (int i : b.nonV) {\n        merge_intervals(b.V[i]);\n        for (auto [l, r] : b.V[i]) b.total += r - l;\n    }\n}\n\nlong long inter_line(const vector<pair<int,int>>& a, const vector<pair<int,int>>& b) {\n    long long inter = 0;\n    int i = 0, j = 0;\n    while (i < (int)a.size() && j < (int)b.size()) {\n        int l = max(a[i].first, b[j].first);\n        int r = min(a[i].second, b[j].second);\n        if (l < r) inter += r - l;\n        if (a[i].second < b[j].second) i++;\n        else j++;\n    }\n    return inter;\n}\n\nlong long diff_bound(const Bound& a, const Bound& b) {\n    long long inter = 0;\n\n    int i = 0, j = 0;\n    while (i < (int)a.nonH.size() && j < (int)b.nonH.size()) {\n        int x = a.nonH[i], y = b.nonH[j];\n        if (x == y) {\n            inter += inter_line(a.H[x], b.H[y]);\n            i++;\n            j++;\n        } else if (x < y) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n\n    i = j = 0;\n    while (i < (int)a.nonV.size() && j < (int)b.nonV.size()) {\n        int x = a.nonV[i], y = b.nonV[j];\n        if (x == y) {\n            inter += inter_line(a.V[x], b.V[y]);\n            i++;\n            j++;\n        } else if (x < y) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n\n    return a.total + b.total - 2 * inter;\n}\n\nlong long transition_cost(const vector<Rect>& x, const vector<Rect>& y) {\n    Bound bx, by;\n    build_bound(x, bx);\n    build_bound(y, by);\n    return diff_bound(bx, by);\n}\n\nlong long shortage_day(const vector<Rect>& rs, int d) {\n    long long res = 0;\n    for (int k = 0; k < N; k++) {\n        long long area = 1LL * (rs[k].y1 - rs[k].y0) * (rs[k].x1 - rs[k].x0);\n        if (area < A[d][k]) res += 100LL * (A[d][k] - area);\n    }\n    return res;\n}\n\nlong long evaluate_solution(const vector<vector<Rect>>& sol, long long limit = LLONG_MAX) {\n    long long total = 0;\n    Bound prev, cur;\n    for (int d = 0; d < D; d++) {\n        total += shortage_day(sol[d], d);\n        if (total > limit) return total;\n        build_bound(sol[d], cur);\n        if (d > 0) {\n            total += diff_bound(prev, cur);\n            if (total > limit) return total;\n        }\n        swap(prev, cur);\n    }\n    return total;\n}\n\n/* ---------- slicing tree ---------- */\n\nstruct Node {\n    int l = 0, r = 0;\n    int left = -1, right = -1;\n    int orient = VERT;\n    double ratio = 0.5;\n    int target = 1;\n    int targetCoord = -1;\n\n    bool leaf() const { return left == -1; }\n};\n\nstruct Tree {\n    vector<Node> nodes;\n    int root = 0;\n    vector<int> order;\n};\n\nvoid build_order(Tree& t) {\n    t.order.clear();\n    function<void(int)> dfs = [&](int v) {\n        if (!t.nodes[v].leaf()) {\n            dfs(t.nodes[v].left);\n            dfs(t.nodes[v].right);\n        }\n        t.order.push_back(v);\n    };\n    dfs(t.root);\n}\n\nint choose_split(int l, int r, int mode, const vector<double>& pref) {\n    if (r - l <= 1) return l + 1;\n    if (mode == 1) return (l + r) / 2;\n\n    double total = pref[r] - pref[l];\n    int best = l + 1;\n    double bestScore = 1e100;\n\n    for (int m = l + 1; m <= r - 1; m++) {\n        double af = (pref[m] - pref[l]) / total;\n        double cf = double(m - l) / double(r - l);\n        double score;\n        if (mode == 0) score = fabs(af - 0.5);\n        else score = fabs(af - 0.5) + 0.35 * fabs(cf - 0.5);\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = m;\n        }\n    }\n    return best;\n}\n\nTree build_aspect_tree_box(const vector<int>& base, int splitMode, int orientMode, int rootH, int rootW) {\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    Tree t;\n    function<int(int,int,int,int,int)> rec = [&](int l, int r, int h, int w, int depth) -> int {\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].l = l;\n        t.nodes[idx].r = r;\n\n        if (r - l == 1) return idx;\n\n        int orient;\n        if (orientMode == 0) orient = (w >= h ? VERT : HOR);\n        else if (orientMode == 1) orient = (depth % 2 == 0 ? VERT : HOR);\n        else orient = (depth % 2 == 0 ? HOR : VERT);\n\n        int m = choose_split(l, r, splitMode, pref);\n        double sL = pref[m] - pref[l];\n        double sT = pref[r] - pref[l];\n        double ratio = sL / sT;\n\n        t.nodes[idx].orient = orient;\n        t.nodes[idx].ratio = ratio;\n\n        int hL = h, hR = h, wL = w, wR = w;\n        if (orient == VERT) {\n            int c = (w >= 2 ? clamp_int((int)llround(w * ratio), 1, w - 1) : 1);\n            wL = max(1, c);\n            wR = max(1, w - c);\n        } else {\n            int c = (h >= 2 ? clamp_int((int)llround(h * ratio), 1, h - 1) : 1);\n            hL = max(1, c);\n            hR = max(1, h - c);\n        }\n\n        int li = rec(l, m, hL, wL, depth + 1);\n        int ri = rec(m, r, hR, wR, depth + 1);\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        return idx;\n    };\n\n    t.root = rec(0, N, rootH, rootW, 0);\n    build_order(t);\n    return t;\n}\n\nTree build_aspect_tree(const vector<int>& base, int splitMode, int orientMode) {\n    return build_aspect_tree_box(base, splitMode, orientMode, W, W);\n}\n\nint build_fixed_rec(Tree& t, int l, int r, int orient, int splitMode, const vector<double>& pref) {\n    int idx = (int)t.nodes.size();\n    t.nodes.push_back(Node());\n    t.nodes[idx].l = l;\n    t.nodes[idx].r = r;\n    t.nodes[idx].orient = orient;\n\n    if (r - l == 1) return idx;\n\n    int m = choose_split(l, r, splitMode, pref);\n    double sL = pref[m] - pref[l];\n    double sT = pref[r] - pref[l];\n    t.nodes[idx].ratio = sL / sT;\n\n    int li = build_fixed_rec(t, l, m, orient, splitMode, pref);\n    int ri = build_fixed_rec(t, m, r, orient, splitMode, pref);\n    t.nodes[idx].left = li;\n    t.nodes[idx].right = ri;\n    return idx;\n}\n\nTree build_shelf_tree(const vector<int>& base, int R, int groupMode, int itemSplitMode) {\n    R = clamp_int(R, 1, N);\n\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> groups;\n    int prev = 0;\n    for (int g = 0; g < R; g++) {\n        int en;\n        if (g == R - 1) {\n            en = N;\n        } else {\n            int minEnd = prev + 1;\n            int maxEnd = N - (R - g - 1);\n            if (groupMode == 0) {\n                double target = pref[N] * double(g + 1) / double(R);\n                en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            } else {\n                en = (int)llround(double(N) * double(g + 1) / double(R));\n            }\n            en = clamp_int(en, minEnd, maxEnd);\n        }\n        groups.push_back({prev, en});\n        prev = en;\n    }\n\n    Tree t;\n    vector<int> rowRoot;\n    vector<double> rowPref(R + 1, 0);\n\n    for (int i = 0; i < R; i++) {\n        auto [l, r] = groups[i];\n        rowRoot.push_back(build_fixed_rec(t, l, r, VERT, itemSplitMode, pref));\n        rowPref[i+1] = rowPref[i] + (pref[r] - pref[l]);\n    }\n\n    function<int(int,int)> combine = [&](int lo, int hi) -> int {\n        if (hi - lo == 1) return rowRoot[lo];\n\n        int mid = lo + 1;\n        double total = rowPref[hi] - rowPref[lo];\n        double best = 1e100;\n        for (int m = lo + 1; m <= hi - 1; m++) {\n            double d = fabs((rowPref[m] - rowPref[lo]) - total * 0.5);\n            if (d < best) {\n                best = d;\n                mid = m;\n            }\n        }\n\n        int li = combine(lo, mid);\n        int ri = combine(mid, hi);\n\n        int idx = (int)t.nodes.size();\n        t.nodes.push_back(Node());\n        t.nodes[idx].left = li;\n        t.nodes[idx].right = ri;\n        t.nodes[idx].l = t.nodes[li].l;\n        t.nodes[idx].r = t.nodes[ri].r;\n        t.nodes[idx].orient = HOR;\n        t.nodes[idx].ratio = (rowPref[mid] - rowPref[lo]) / (rowPref[hi] - rowPref[lo]);\n        return idx;\n    };\n\n    t.root = combine(0, R);\n    build_order(t);\n    return t;\n}\n\n/* ---------- slicing DP ---------- */\n\nstruct DPComputer {\n    const Tree* tr;\n    bool freeOrient;\n    vector<array<unsigned short, W + 1>> dp;\n    vector<array<unsigned short, W + 1>> mh;\n\n    DPComputer(const Tree& t, bool f) : tr(&t), freeOrient(f) {\n        dp.resize(t.nodes.size());\n        mh.resize(t.nodes.size());\n    }\n\n    void compute_mh_from_dp(int idx) {\n        auto& P = dp[idx];\n        auto& M = mh[idx];\n        for (int i = 0; i <= W; i++) M[i] = INF;\n\n        int prev = W + 1;\n        for (int h = 1; h <= W; h++) {\n            int v = P[h];\n            if (v <= W && v < prev) {\n                for (int w = v; w < prev; w++) M[w] = h;\n                prev = v;\n            }\n        }\n    }\n\n    void horizontal_merge(int L, int R, array<unsigned short, W + 1>& out) {\n        for (int i = 0; i <= W; i++) out[i] = INF;\n        int prev = W + 1;\n        for (int w = 1; w <= W; w++) {\n            int hL = mh[L][w], hR = mh[R][w];\n            int req = (hL >= INF || hR >= INF ? INF : hL + hR);\n            if (req <= W && req < prev) {\n                for (int h = req; h < prev; h++) out[h] = w;\n                prev = req;\n            }\n        }\n    }\n\n    void compute(const vector<int>& demand) {\n        for (int idx : tr->order) {\n            const Node& nd = tr->nodes[idx];\n            auto& P = dp[idx];\n            auto& M = mh[idx];\n\n            if (nd.leaf()) {\n                long long a = demand[nd.l];\n                P[0] = M[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    long long v = (a + h - 1) / h;\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                for (int w = 1; w <= W; w++) {\n                    long long v = (a + w - 1) / w;\n                    M[w] = (v <= W ? (unsigned short)v : INF);\n                }\n                continue;\n            }\n\n            int L = nd.left, R = nd.right;\n\n            if (!freeOrient && nd.orient == VERT) {\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    P[h] = (v <= W ? (unsigned short)v : INF);\n                }\n                compute_mh_from_dp(idx);\n            } else if (!freeOrient && nd.orient == HOR) {\n                horizontal_merge(L, R, P);\n                compute_mh_from_dp(idx);\n            } else {\n                array<unsigned short, W + 1> HP;\n                horizontal_merge(L, R, HP);\n\n                P[0] = INF;\n                for (int h = 1; h <= W; h++) {\n                    int a = dp[L][h], b = dp[R][h];\n                    int v = (a >= INF || b >= INF ? INF : a + b);\n                    if (v > W) v = INF;\n                    P[h] = (unsigned short)min(v, (int)HP[h]);\n                }\n                compute_mh_from_dp(idx);\n            }\n        }\n    }\n};\n\n/* ---------- target assignment / reconstruction ---------- */\n\nbool assign_targets_dp_rec(Tree& t, int idx, int y, int x, int h, int w, const DPComputer& comp) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return true;\n\n    int L = nd.left, R = nd.right;\n\n    if (nd.orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(w * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        nd.target = c;\n        nd.targetCoord = x + c;\n        return assign_targets_dp_rec(t, L, y, x, h, c, comp) &&\n               assign_targets_dp_rec(t, R, y, x + c, h, w - c, comp);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int raw = (int)llround(h * nd.ratio);\n        int c = clamp_int(raw, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        nd.target = c;\n        nd.targetCoord = y + c;\n        return assign_targets_dp_rec(t, L, y, x, c, w, comp) &&\n               assign_targets_dp_rec(t, R, y + c, x, h - c, w, comp);\n    }\n}\n\nvoid assign_targets_ratio_rec(Tree& t, int idx, int y, int x, int h, int w) {\n    Node& nd = t.nodes[idx];\n    if (nd.leaf()) return;\n\n    if (nd.orient == VERT) {\n        int c = (w >= 2 ? clamp_int((int)llround(w * nd.ratio), 1, w - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = x + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, h, max(1, c));\n        assign_targets_ratio_rec(t, nd.right, y, x + c, h, max(1, w - c));\n    } else {\n        int c = (h >= 2 ? clamp_int((int)llround(h * nd.ratio), 1, h - 1) : 1);\n        nd.target = c;\n        nd.targetCoord = y + c;\n        assign_targets_ratio_rec(t, nd.left, y, x, max(1, c), w);\n        assign_targets_ratio_rec(t, nd.right, y + c, x, max(1, h - c), w);\n    }\n}\n\nvoid assign_targets_box(Tree& t, const vector<int>& demand, int rootH, int rootW) {\n    for (auto& nd : t.nodes) {\n        nd.target = 1;\n        nd.targetCoord = -1;\n    }\n\n    DPComputer comp(t, false);\n    comp.compute(demand);\n\n    bool ok = (comp.dp[t.root][rootH] <= rootW);\n    if (ok) ok = assign_targets_dp_rec(t, t.root, 0, 0, rootH, rootW, comp);\n\n    if (!ok) assign_targets_ratio_rec(t, t.root, 0, 0, rootH, rootW);\n}\n\nvoid assign_targets(Tree& t, const vector<int>& demand) {\n    assign_targets_box(t, demand, W, W);\n}\n\nbool feasible_vert(const DPComputer& comp, int L, int R, int h, int w) {\n    if (w < 2) return false;\n    int a = comp.dp[L][h], b = comp.dp[R][h];\n    return a < INF && b < INF && a + b <= w;\n}\n\nbool feasible_hor(const DPComputer& comp, int L, int R, int h, int w) {\n    if (h < 2) return false;\n    int a = comp.mh[L][w], b = comp.mh[R][w];\n    return a < INF && b < INF && a + b <= h;\n}\n\nint target_size_for(\n    const Tree& t,\n    int idx,\n    int orient,\n    int dim,\n    int originCoord,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (policy == POLICY_PREV && prevOrient[idx] == orient && prevCoord[idx] >= 0) {\n        return prevCoord[idx] - originCoord;\n    }\n\n    if (policy == POLICY_STATIC_RATIO || orient != nd.orient || nd.targetCoord < 0) {\n        return (int)llround(dim * nd.ratio);\n    }\n\n    return nd.targetCoord - originCoord;\n}\n\nbool reconstruct_rec(\n    const Tree& t,\n    int idx,\n    int y,\n    int x,\n    int h,\n    int w,\n    const DPComputer& comp,\n    vector<Rect>& rects,\n    bool freeOrient,\n    int policy,\n    const vector<int>& prevOrient,\n    const vector<int>& prevCoord,\n    vector<int>& curOrient,\n    vector<int>& curCoord\n) {\n    const Node& nd = t.nodes[idx];\n\n    if (nd.leaf()) {\n        if (h <= 0 || w <= 0) return false;\n        rects[nd.l] = {y, x, y + h, x + w};\n        return true;\n    }\n\n    int L = nd.left, R = nd.right;\n    bool canV = feasible_vert(comp, L, R, h, w);\n    bool canH = feasible_hor(comp, L, R, h, w);\n\n    int orient = nd.orient;\n    if (freeOrient) {\n        int po = (policy == POLICY_PREV ? prevOrient[idx] : -1);\n        if (po == VERT && canV) orient = VERT;\n        else if (po == HOR && canH) orient = HOR;\n        else if (nd.orient == VERT && canV) orient = VERT;\n        else if (nd.orient == HOR && canH) orient = HOR;\n        else if (canV) orient = VERT;\n        else if (canH) orient = HOR;\n        else return false;\n    } else {\n        if (orient == VERT && !canV) return false;\n        if (orient == HOR && !canH) return false;\n    }\n\n    if (orient == VERT) {\n        int lo = comp.dp[L][h];\n        int hi = w - comp.dp[R][h];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, VERT, w, x, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= w) return false;\n\n        curOrient[idx] = VERT;\n        curCoord[idx] = x + c;\n\n        return reconstruct_rec(t, L, y, x, h, c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y, x + c, h, w - c, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    } else {\n        int lo = comp.mh[L][w];\n        int hi = h - comp.mh[R][w];\n        if (lo > hi) return false;\n\n        int target = target_size_for(t, idx, HOR, h, y, policy, prevOrient, prevCoord);\n        int c = clamp_int(target, lo, hi);\n        if (c <= 0 || c >= h) return false;\n\n        curOrient[idx] = HOR;\n        curCoord[idx] = y + c;\n\n        return reconstruct_rec(t, L, y, x, c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord) &&\n               reconstruct_rec(t, R, y + c, x, h - c, w, comp, rects, freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord);\n    }\n}\n\nbool make_solution(const Tree& t, bool freeOrient, int policy, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n\n    DPComputer comp(t, freeOrient);\n    int M = (int)t.nodes.size();\n\n    vector<int> prevOrient(M, -1), prevCoord(M, -1);\n    for (int i = 0; i < M; i++) {\n        if (!t.nodes[i].leaf()) {\n            prevOrient[i] = t.nodes[i].orient;\n            prevCoord[i] = t.nodes[i].targetCoord;\n        }\n    }\n\n    for (int d = 0; d < D; d++) {\n        comp.compute(A[d]);\n        if (comp.dp[t.root][W] > W) return false;\n\n        vector<int> curOrient(M, -1), curCoord(M, -1);\n        bool ok = reconstruct_rec(\n            t, t.root, 0, 0, W, W, comp, sol[d],\n            freeOrient, policy, prevOrient, prevCoord, curOrient, curCoord\n        );\n        if (!ok) return false;\n\n        if (policy == POLICY_PREV) {\n            prevOrient.swap(curOrient);\n            prevCoord.swap(curCoord);\n        }\n    }\n    return true;\n}\n\nbool make_static_solution(const Tree& t, const vector<int>& demand, bool freeOrient, vector<vector<Rect>>& sol) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][W] > W) return false;\n\n    vector<Rect> one(N);\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    bool ok = reconstruct_rec(\n        t, t.root, 0, 0, W, W, comp, one,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n    if (!ok) return false;\n\n    sol.assign(D, one);\n    return true;\n}\n\n/* ---------- solution management ---------- */\n\nvector<vector<Rect>> bestSol;\nlong long bestScore = LLONG_MAX;\n\nvoid consider_solution(const vector<vector<Rect>>& sol) {\n    if (dayCandReady && (int)sol.size() == D) {\n        for (int d = 0; d < D; d++) {\n            add_unique_layout_cap(dayCand[d], sol[d], 160);\n        }\n    }\n\n    long long sc = evaluate_solution(sol, bestScore);\n    if (sc < bestScore) {\n        bestScore = sc;\n        bestSol = sol;\n    }\n}\n\nvector<vector<Rect>> make_fallback() {\n    vector<vector<Rect>> sol(D, vector<Rect>(N));\n\n    for (int d = 0; d < D; d++) {\n        vector<int> h(N, 1);\n        int rem = W - N;\n\n        auto gain = [&](int k) -> int {\n            long long covered = 1LL * h[k] * W;\n            if (covered >= A[d][k]) return 0;\n            return (int)min<long long>(W, A[d][k] - covered);\n        };\n\n        priority_queue<pair<int,int>> pq;\n        for (int k = 0; k < N; k++) pq.push({gain(k), k});\n\n        while (rem > 0 && !pq.empty()) {\n            auto [g, k] = pq.top();\n            pq.pop();\n            int cg = gain(k);\n            if (cg != g) {\n                pq.push({cg, k});\n                continue;\n            }\n            if (cg <= 0) break;\n            h[k]++;\n            rem--;\n            pq.push({gain(k), k});\n        }\n\n        h[N-1] += rem;\n\n        int y = 0;\n        for (int k = 0; k < N; k++) {\n            sol[d][k] = {y, 0, y + h[k], W};\n            y += h[k];\n        }\n    }\n\n    return sol;\n}\n\nvector<int> scale_to_limit(const vector<int>& v) {\n    long long s = 0;\n    for (int x : v) s += x;\n    if (s <= AREA) return v;\n\n    vector<int> r(N);\n    double f = double(AREA) / double(s);\n    long long sr = 0;\n    for (int i = 0; i < N; i++) {\n        r[i] = max(1, (int)floor(v[i] * f));\n        sr += r[i];\n    }\n\n    while (sr > AREA) {\n        int id = -1;\n        for (int i = 0; i < N; i++) {\n            if (r[i] > 1 && (id == -1 || r[i] > r[id])) id = i;\n        }\n        if (id == -1) break;\n        r[id]--;\n        sr--;\n    }\n    return r;\n}\n\nvector<int> compute_opt_static_area() {\n    struct Seg {\n        int slope, k, len;\n    };\n    vector<Seg> segs;\n\n    for (int k = 0; k < N; k++) {\n        vector<int> vals;\n        for (int d = 0; d < D; d++) vals.push_back(A[d][k]);\n        sort(vals.begin(), vals.end());\n\n        int prev = 0;\n        for (int i = 0; i < D; i++) {\n            int v = vals[i];\n            if (v > prev) {\n                segs.push_back({D - i, k, v - prev});\n                prev = v;\n            }\n        }\n    }\n\n    sort(segs.begin(), segs.end(), [](const Seg& a, const Seg& b) {\n        if (a.slope != b.slope) return a.slope > b.slope;\n        return a.k < b.k;\n    });\n\n    vector<int> c(N, 0);\n    long long rem = AREA;\n\n    for (int p = 0; p < (int)segs.size() && rem > 0; ) {\n        int q = p;\n        while (q < (int)segs.size() && segs[q].slope == segs[p].slope) q++;\n\n        long long totalLen = 0;\n        for (int i = p; i < q; i++) totalLen += segs[i].len;\n\n        if (totalLen <= rem) {\n            for (int i = p; i < q; i++) c[segs[i].k] += segs[i].len;\n            rem -= totalLen;\n        } else {\n            vector<pair<long double,int>> frac;\n            long long used = 0;\n            for (int i = p; i < q; i++) {\n                long double ideal = (long double)rem * segs[i].len / (long double)totalLen;\n                int add = (int)floor(ideal);\n                add = min(add, segs[i].len);\n                c[segs[i].k] += add;\n                used += add;\n                frac.push_back({ideal - add, i});\n            }\n            long long left = rem - used;\n            sort(frac.rbegin(), frac.rend());\n            for (int z = 0; z < (int)frac.size() && left > 0; z++) {\n                int i = frac[z].second;\n                if (c[segs[i].k] < globalMaxDemand[segs[i].k]) {\n                    c[segs[i].k]++;\n                    left--;\n                }\n            }\n            break;\n        }\n\n        p = q;\n    }\n\n    long long s = 0;\n    for (int k = 0; k < N; k++) {\n        c[k] = max(1, c[k]);\n        s += c[k];\n    }\n    while (s > AREA) {\n        int id = max_element(c.begin(), c.end()) - c.begin();\n        if (c[id] <= 1) break;\n        c[id]--;\n        s--;\n    }\n    return c;\n}\n\n/* ---------- per-day candidate pool ---------- */\n\nvoid init_day_candidates() {\n    dayCand.assign(D, {});\n    dayCandReady = true;\n    for (int d = 0; d < D; d++) add_unique_layout(dayCand[d], bestSol[d]);\n}\n\nbool try_single_tree_layout_box(\n    Tree t,\n    const vector<int>& demand,\n    bool freeOrient,\n    int rootH,\n    int rootW,\n    vector<Rect>& layout\n) {\n    if (rootH <= 0 || rootW <= 0 || rootH > W || rootW > W) return false;\n\n    assign_targets_box(t, demand, rootH, rootW);\n\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    if (comp.dp[t.root][rootH] > rootW) return false;\n\n    int M = (int)t.nodes.size();\n    vector<int> dummyO(M, -1), dummyC(M, -1), curO(M, -1), curC(M, -1);\n\n    layout.assign(N, Rect{0, 0, 1, 1});\n    return reconstruct_rec(\n        t, t.root, 0, 0, rootH, rootW, comp, layout,\n        freeOrient, POLICY_STATIC_ABS, dummyO, dummyC, curO, curC\n    );\n}\n\nint find_min_height_for_tree(const Tree& t, const vector<int>& demand, bool freeOrient) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    for (int h = 1; h <= W; h++) {\n        if (comp.dp[t.root][h] <= W) return h;\n    }\n    return -1;\n}\n\nint find_min_width_for_tree(const Tree& t, const vector<int>& demand, bool freeOrient) {\n    DPComputer comp(t, freeOrient);\n    comp.compute(demand);\n    int w = comp.dp[t.root][W];\n    if (w <= W) return w;\n    return -1;\n}\n\nbool make_single_tree_layout_relaxed_mode(\n    const Tree& baseTree,\n    const vector<int>& trueDemand,\n    bool freeOrient,\n    int compactMode,\n    vector<Rect>& layout\n) {\n    static const double factors[] = {1.0, 0.999, 0.997, 0.995, 0.990, 0.980, 0.960, 0.930, 0.900, 0.850};\n\n    vector<int> dem(N);\n    for (double f : factors) {\n        for (int k = 0; k < N; k++) dem[k] = max(1, (int)floor(trueDemand[k] * f));\n\n        int rootH = W, rootW = W;\n        if (compactMode == 1) {\n            rootH = find_min_height_for_tree(baseTree, dem, freeOrient);\n            rootW = W;\n            if (rootH < 0) continue;\n        } else if (compactMode == 2) {\n            rootH = W;\n            rootW = find_min_width_for_tree(baseTree, dem, freeOrient);\n            if (rootW < 0) continue;\n        }\n\n        if (try_single_tree_layout_box(baseTree, dem, freeOrient, rootH, rootW, layout)) return true;\n    }\n    return false;\n}\n\nvoid generate_day_slicing_candidates(double TL) {\n    if (dayCand.empty()) init_day_candidates();\n\n    vector<pair<int,int>> combos = {\n        {0, 0}, {2, 0}, {1, 0}, {0, 1}, {0, 2}\n    };\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) break;\n\n        long long sumA = 0;\n        for (int x : A[d]) sumA += x;\n        int approx = clamp_int((int)((sumA + W - 1) / W), 1, W);\n\n        for (int ci = 0; ci < (int)combos.size(); ci++) {\n            if (elapsed_sec() > TL) break;\n\n            auto [sm, om] = combos[ci];\n            vector<Rect> layout;\n\n            Tree fullT = build_aspect_tree_box(A[d], sm, om, W, W);\n            if (make_single_tree_layout_relaxed_mode(fullT, A[d], false, 0, layout)) {\n                add_unique_layout_cap(dayCand[d], layout, 160);\n            }\n            if (ci <= 1 && elapsed_sec() < TL) {\n                if (make_single_tree_layout_relaxed_mode(fullT, A[d], true, 0, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n            }\n\n            if (ci <= 2 && elapsed_sec() < TL) {\n                Tree topT = build_aspect_tree_box(A[d], sm, om, approx, W);\n                if (make_single_tree_layout_relaxed_mode(topT, A[d], false, 1, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n                if (ci == 0 && elapsed_sec() < TL) {\n                    if (make_single_tree_layout_relaxed_mode(topT, A[d], true, 1, layout)) {\n                        add_unique_layout_cap(dayCand[d], layout, 160);\n                    }\n                }\n            }\n\n            if (ci <= 1 && elapsed_sec() < TL) {\n                Tree leftT = build_aspect_tree_box(A[d], sm, om, W, approx);\n                if (make_single_tree_layout_relaxed_mode(leftT, A[d], false, 2, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n            }\n        }\n    }\n}\n\nlong long rough_perim_score(const vector<Rect>& layout) {\n    long long res = 0;\n    for (const auto& r : layout) {\n        int h = r.y1 - r.y0;\n        int w = r.x1 - r.x0;\n        if (r.y0 > 0) res += w;\n        if (r.y1 < W) res += w;\n        if (r.x0 > 0) res += h;\n        if (r.x1 < W) res += h;\n    }\n    return res;\n}\n\nvoid run_day_candidate_dp(bool addCurrentBest, double TL) {\n    if (dayCand.empty()) return;\n    if (addCurrentBest) {\n        for (int d = 0; d < D; d++) add_unique_layout_cap(dayCand[d], bestSol[d], 160);\n    }\n    if (elapsed_sec() > TL) return;\n\n    const int MAXC = 50;\n\n    for (int d = 0; d < D; d++) {\n        if ((int)dayCand[d].size() <= MAXC) continue;\n\n        int C = dayCand[d].size();\n        vector<int> keep;\n        auto pin = [&](int id) {\n            if (id < 0 || id >= C) return;\n            if (find(keep.begin(), keep.end(), id) == keep.end()) keep.push_back(id);\n        };\n\n        pin(0);\n        for (int i = 0; i < C; i++) {\n            if (same_layout(dayCand[d][i], bestSol[d])) pin(i);\n        }\n        for (const auto& lib : staticLibLayouts) {\n            for (int i = 0; i < C; i++) {\n                if (same_layout(dayCand[d][i], lib)) {\n                    pin(i);\n                    break;\n                }\n            }\n        }\n\n        vector<tuple<long long,long long,int>> ord;\n        ord.reserve(C);\n        for (int i = 0; i < C; i++) {\n            ord.push_back({shortage_day(dayCand[d][i], d), rough_perim_score(dayCand[d][i]), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        for (auto [sh, pe, id] : ord) {\n            if ((int)keep.size() >= MAXC) break;\n            pin(id);\n        }\n\n        sort(keep.begin(), keep.end());\n        vector<vector<Rect>> nd;\n        for (int id : keep) nd.push_back(dayCand[d][id]);\n        dayCand[d].swap(nd);\n    }\n\n    vector<vector<Bound>> bounds(D);\n    vector<vector<long long>> sh(D);\n    for (int d = 0; d < D; d++) {\n        int C = dayCand[d].size();\n        bounds[d].resize(C);\n        sh[d].resize(C);\n        for (int c = 0; c < C; c++) {\n            sh[d][c] = shortage_day(dayCand[d][c], d);\n            build_bound(dayCand[d][c], bounds[d][c]);\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(D);\n    vector<vector<int>> par(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = dayCand[d].size();\n        dp[d].assign(C, BIG);\n        par[d].assign(C, -1);\n    }\n\n    for (int c = 0; c < (int)dayCand[0].size(); c++) dp[0][c] = sh[0][c];\n\n    for (int d = 1; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n\n        for (int c = 0; c < (int)dayCand[d].size(); c++) {\n            for (int pc = 0; pc < (int)dayCand[d-1].size(); pc++) {\n                if (dp[d-1][pc] >= BIG / 2) continue;\n                long long tr = diff_bound(bounds[d-1][pc], bounds[d][c]);\n                long long nv = dp[d-1][pc] + sh[d][c] + tr;\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = -1;\n    long long best = BIG;\n    for (int c = 0; c < (int)dayCand[D-1].size(); c++) {\n        if (dp[D-1][c] < best) {\n            best = dp[D-1][c];\n            bestC = c;\n        }\n    }\n    if (bestC < 0) return;\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = dayCand[d][cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- shrink variants ---------- */\n\nRect shrink_one_rect(const Rect& r, int demand, int mode) {\n    int H = r.y1 - r.y0;\n    int B = r.x1 - r.x0;\n    long long area = 1LL * H * B;\n    if (area <= demand) return r;\n\n    int bestH = H, bestW = B, bestY = r.y0, bestX = r.x0;\n    long long bestScore = LLONG_MAX;\n\n    int minH = max(1, ceil_div_int(demand, B));\n    for (int h = minH; h <= H; h++) {\n        int w = ceil_div_int(demand, h);\n        if (w <= 0 || w > B) continue;\n\n        int y, x;\n        if (mode == 2) {\n            y = r.y0 + (H - h) / 2;\n            x = r.x0 + (B - w) / 2;\n        } else {\n            bool bottom = (mode == 1 && r.y1 == W && r.y0 != 0);\n            bool right = (mode == 1 && r.x1 == W && r.x0 != 0);\n            y = bottom ? r.y1 - h : r.y0;\n            x = right ? r.x1 - w : r.x0;\n        }\n\n        long long internal = 0;\n        if (y > 0) internal += w;\n        if (y + h < W) internal += w;\n        if (x > 0) internal += h;\n        if (x + w < W) internal += h;\n\n        long long surplus = 1LL * h * w - demand;\n        long long aspect = llabs(h - w);\n        long long score = internal * 1000000LL + surplus * 10LL + aspect;\n\n        if (score < bestScore) {\n            bestScore = score;\n            bestH = h;\n            bestW = w;\n            bestY = y;\n            bestX = x;\n        }\n    }\n\n    return {bestY, bestX, bestY + bestH, bestX + bestW};\n}\n\nvector<Rect> shrink_layout_day(const vector<Rect>& layout, int d, int mode) {\n    vector<Rect> out = layout;\n    for (int k = 0; k < N; k++) {\n        out[k] = shrink_one_rect(layout[k], A[d][k], mode);\n    }\n    return out;\n}\n\nvoid add_shrunk_day_candidates(double TL) {\n    if (dayCand.empty()) return;\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n\n        int C = dayCand[d].size();\n        vector<pair<long long,int>> ord;\n        for (int i = 0; i < C; i++) {\n            ord.push_back({shortage_day(dayCand[d][i], d), i});\n        }\n        sort(ord.begin(), ord.end());\n\n        int lim = min((int)ord.size(), 24);\n        for (int t = 0; t < lim; t++) {\n            if (elapsed_sec() > TL) return;\n            int id = ord[t].second;\n            long long baseSh = ord[t].first;\n            if (baseSh > 20000) continue;\n\n            for (int mode = 0; mode < 3; mode++) {\n                vector<Rect> shr = shrink_layout_day(dayCand[d][id], d, mode);\n                if (shortage_day(shr, d) <= baseSh) {\n                    add_unique_layout_cap(dayCand[d], shr, 160);\n                }\n            }\n        }\n    }\n}\n\nvoid final_shrink_dp(double TL) {\n    if (elapsed_sec() > TL) return;\n\n    vector<vector<vector<Rect>>> cand(D);\n    for (int d = 0; d < D; d++) {\n        cand[d].push_back(bestSol[d]);\n\n        for (int mode = 0; mode < 3; mode++) {\n            if (elapsed_sec() > TL) return;\n            vector<Rect> shr = shrink_layout_day(bestSol[d], d, mode);\n            add_unique_layout(cand[d], shr);\n        }\n    }\n\n    vector<vector<Bound>> bd(D);\n    vector<vector<long long>> sh(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = (int)cand[d].size();\n        bd[d].resize(C);\n        sh[d].resize(C);\n\n        for (int c = 0; c < C; c++) {\n            if (elapsed_sec() > TL) return;\n            sh[d][c] = shortage_day(cand[d][c], d);\n            build_bound(cand[d][c], bd[d][c]);\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(D);\n    vector<vector<int>> par(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = (int)cand[d].size();\n        dp[d].assign(C, BIG);\n        par[d].assign(C, -1);\n    }\n\n    for (int c = 0; c < (int)cand[0].size(); c++) {\n        dp[0][c] = sh[0][c];\n    }\n\n    for (int d = 1; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n\n        for (int c = 0; c < (int)cand[d].size(); c++) {\n            for (int pc = 0; pc < (int)cand[d - 1].size(); pc++) {\n                long long nv = dp[d - 1][pc] + sh[d][c] + diff_bound(bd[d - 1][pc], bd[d][c]);\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int c = 1; c < (int)cand[D - 1].size(); c++) {\n        if (dp[D - 1][c] < dp[D - 1][bestC]) {\n            bestC = c;\n        }\n    }\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = cand[d][cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- final symmetry DP ---------- */\n\nRect transform_rect(const Rect& r, int t) {\n    if (t == 0) return r;\n    if (t == 1) return {r.y0, W - r.x1, r.y1, W - r.x0};                 // mirror vertical axis\n    if (t == 2) return {W - r.y1, r.x0, W - r.y0, r.x1};                 // mirror horizontal axis\n    if (t == 3) return {W - r.y1, W - r.x1, W - r.y0, W - r.x0};         // rotate 180\n    if (t == 4) return {r.x0, r.y0, r.x1, r.y1};                         // main diagonal\n    if (t == 5) return {W - r.x1, W - r.y1, W - r.x0, W - r.y0};         // anti diagonal\n    if (t == 6) return {r.x0, W - r.y1, r.x1, W - r.y0};                 // rotate 90\n    return {W - r.x1, r.y0, W - r.x0, r.y1};                             // rotate 270\n}\n\nvector<Rect> transform_layout(const vector<Rect>& layout, int t) {\n    vector<Rect> res(layout.size());\n    for (int i = 0; i < (int)layout.size(); i++) res[i] = transform_rect(layout[i], t);\n    return res;\n}\n\nvoid final_symmetry_dp(double TL) {\n    if (elapsed_sec() > TL) return;\n\n    vector<vector<vector<Rect>>> cand(D);\n    for (int d = 0; d < D; d++) {\n        for (int t = 0; t < 8; t++) {\n            vector<Rect> tr = transform_layout(bestSol[d], t);\n            add_unique_layout(cand[d], tr);\n        }\n    }\n\n    vector<vector<Bound>> bd(D);\n    vector<vector<long long>> sh(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = cand[d].size();\n        bd[d].resize(C);\n        sh[d].resize(C);\n        for (int c = 0; c < C; c++) {\n            if (elapsed_sec() > TL) return;\n            sh[d][c] = shortage_day(cand[d][c], d);\n            build_bound(cand[d][c], bd[d][c]);\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(D);\n    vector<vector<int>> par(D);\n\n    for (int d = 0; d < D; d++) {\n        int C = cand[d].size();\n        dp[d].assign(C, BIG);\n        par[d].assign(C, -1);\n    }\n\n    for (int c = 0; c < (int)cand[0].size(); c++) dp[0][c] = sh[0][c];\n\n    for (int d = 1; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n        for (int c = 0; c < (int)cand[d].size(); c++) {\n            for (int pc = 0; pc < (int)cand[d - 1].size(); pc++) {\n                long long nv = dp[d - 1][pc] + sh[d][c] + diff_bound(bd[d - 1][pc], bd[d][c]);\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int c = 1; c < (int)cand[D - 1].size(); c++) {\n        if (dp[D - 1][c] < dp[D - 1][bestC]) bestC = c;\n    }\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = cand[d][cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- static library ---------- */\n\nstring layout_key(const vector<Rect>& layout) {\n    string s;\n    s.reserve(layout.size() * 24);\n    for (const auto& r : layout) {\n        s += to_string(r.y0); s.push_back(',');\n        s += to_string(r.x0); s.push_back(',');\n        s += to_string(r.y1); s.push_back(',');\n        s += to_string(r.x1); s.push_back(';');\n    }\n    return s;\n}\n\nlong long total_shortage_layout_all_days(const vector<Rect>& layout) {\n    vector<long long> area(N);\n    for (int k = 0; k < N; k++) {\n        area[k] = 1LL * (layout[k].y1 - layout[k].y0) * (layout[k].x1 - layout[k].x0);\n    }\n\n    long long res = 0;\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            if (area[k] < A[d][k]) res += 100LL * (A[d][k] - area[k]);\n        }\n    }\n    return res;\n}\n\nvoid add_static_library_candidates(int maxLib, double TL, bool addToDayCand) {\n    staticLibLayouts.clear();\n    if (dayCand.empty() || elapsed_sec() > TL) return;\n\n    unordered_set<string> seen;\n    vector<vector<Rect>> libs;\n\n    auto addLib = [&](const vector<Rect>& layout) {\n        string key = layout_key(layout);\n        if (seen.insert(key).second) libs.push_back(layout);\n    };\n\n    for (int d = 0; d < D; d++) addLib(bestSol[d]);\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) break;\n        for (const auto& layout : dayCand[d]) addLib(layout);\n    }\n\n    vector<pair<long long,int>> score;\n    for (int i = 0; i < (int)libs.size(); i++) {\n        if (elapsed_sec() > TL) break;\n        score.push_back({total_shortage_layout_all_days(libs[i]), i});\n    }\n    sort(score.begin(), score.end());\n\n    int lim = min(maxLib, (int)score.size());\n    for (int z = 0; z < lim; z++) {\n        int id = score[z].second;\n        long long sc = score[z].first;\n        staticLibLayouts.push_back(libs[id]);\n\n        if (sc < bestScore) {\n            bestScore = sc;\n            bestSol.assign(D, libs[id]);\n        }\n\n        if (addToDayCand) {\n            for (int d = 0; d < D; d++) {\n                add_unique_layout_cap(dayCand[d], libs[id], 160);\n            }\n        }\n    }\n}\n\nvoid copy_library_dp(double TL) {\n    if (elapsed_sec() > TL) return;\n\n    vector<vector<Rect>> lib;\n    unordered_set<string> seen;\n\n    auto addLib = [&](const vector<Rect>& layout) {\n        string key = layout_key(layout);\n        if (seen.insert(key).second) lib.push_back(layout);\n    };\n\n    for (int d = 0; d < D; d++) addLib(bestSol[d]);\n    for (const auto& layout : staticLibLayouts) addLib(layout);\n\n    const int MAX_LIB = 70;\n    if ((int)lib.size() > MAX_LIB) lib.resize(MAX_LIB);\n    int C = lib.size();\n    if (C == 0) return;\n\n    vector<Bound> bounds(C);\n    for (int i = 0; i < C; i++) {\n        if (elapsed_sec() > TL) return;\n        build_bound(lib[i], bounds[i]);\n    }\n\n    vector<vector<long long>> trans(C, vector<long long>(C, 0));\n    for (int i = 0; i < C; i++) {\n        if (elapsed_sec() > TL) return;\n        for (int j = 0; j < C; j++) trans[i][j] = diff_bound(bounds[i], bounds[j]);\n    }\n\n    vector<vector<long long>> sh(D, vector<long long>(C));\n    for (int d = 0; d < D; d++) {\n        for (int c = 0; c < C; c++) sh[d][c] = shortage_day(lib[c], d);\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(D, vector<long long>(C, BIG));\n    vector<vector<int>> par(D, vector<int>(C, -1));\n\n    for (int c = 0; c < C; c++) dp[0][c] = sh[0][c];\n\n    for (int d = 1; d < D; d++) {\n        if (elapsed_sec() > TL) return;\n        for (int c = 0; c < C; c++) {\n            for (int pc = 0; pc < C; pc++) {\n                long long nv = dp[d-1][pc] + trans[pc][c] + sh[d][c];\n                if (nv < dp[d][c]) {\n                    dp[d][c] = nv;\n                    par[d][c] = pc;\n                }\n            }\n        }\n    }\n\n    int bestC = 0;\n    for (int c = 1; c < C; c++) {\n        if (dp[D-1][c] < dp[D-1][bestC]) bestC = c;\n    }\n\n    vector<vector<Rect>> sol(D);\n    int cur = bestC;\n    for (int d = D - 1; d >= 0; d--) {\n        sol[d] = lib[cur];\n        cur = par[d][cur];\n        if (d > 0 && cur < 0) return;\n    }\n\n    consider_solution(sol);\n}\n\n/* ---------- shelf utilities ---------- */\n\nbool check_day_segment_h(int d, int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(A[d][k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_day_hmin_segment(int d, int l, int r) {\n    if (!check_day_segment_h(d, l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_day_segment_h(d, l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nvoid precompute_day_segments() {\n    for (int d = 0; d < D; d++) {\n        for (int l = 0; l < N; l++) {\n            for (int r = l + 1; r <= N; r++) {\n                dayHSeg[d][l][r] = compute_day_hmin_segment(d, l, r);\n            }\n        }\n    }\n}\n\nbool check_static_h(int l, int r, int h) {\n    int s = 0;\n    for (int k = l; k < r; k++) {\n        s += ceil_div_int(globalMaxDemand[k], h);\n        if (s > W) return false;\n    }\n    return true;\n}\n\nint compute_hstatic_segment(int l, int r) {\n    if (!check_static_h(l, r, W)) return SEG_INF;\n    int lo = 1, hi = W;\n    while (lo < hi) {\n        int mid = (lo + hi) / 2;\n        if (check_static_h(l, r, mid)) hi = mid;\n        else lo = mid + 1;\n    }\n    return lo;\n}\n\nint base_value_for_target(int type, int k) {\n    if (type == 0) return globalMaxDemand[k];\n    if (type == 1) return p90Demand[k];\n    if (type == 2) return p75Demand[k];\n    if (type == 3) return meanDemand[k];\n    if (type == 4) return optStaticDemand[k];\n    return medDemand[k];\n}\n\nvector<int> normalize_widths(vector<int> w) {\n    int m = (int)w.size();\n    int s = accumulate(w.begin(), w.end(), 0);\n    while (s < W) {\n        w[m - 1]++;\n        s++;\n    }\n    while (s > W) {\n        bool done = false;\n        for (int i = m - 1; i >= 0 && s > W; i--) {\n            if (w[i] > 1) {\n                w[i]--;\n                s--;\n                done = true;\n            }\n        }\n        if (!done) break;\n    }\n    return w;\n}\n\nvector<int> allocate_by_weights(const vector<int>& lower, const vector<double>& weights) {\n    int m = (int)lower.size();\n    int sumL = accumulate(lower.begin(), lower.end(), 0);\n    if (sumL > W) {\n        vector<int> w(m, 1);\n        int rem = W - m;\n        for (int i = 0; i < m && rem > 0; i++, rem--) w[i]++;\n        if (rem > 0) w[m-1] += rem;\n        return w;\n    }\n\n    vector<int> w = lower;\n    int rem = W - sumL;\n    if (rem == 0) return w;\n\n    double sw = 0;\n    for (double x : weights) sw += max(1e-9, x);\n    if (sw <= 0) sw = m;\n\n    vector<pair<double,int>> frac;\n    int used = 0;\n    for (int i = 0; i < m; i++) {\n        double ideal = rem * max(1e-9, weights[i]) / sw;\n        int add = (int)floor(ideal);\n        w[i] += add;\n        used += add;\n        frac.push_back({ideal - add, i});\n    }\n    int left = rem - used;\n    sort(frac.rbegin(), frac.rend());\n    for (int i = 0; i < left; i++) w[frac[i % m].second]++;\n    return normalize_widths(w);\n}\n\nvector<int> make_target_widths(int l, int r, int h, int targetType) {\n    int m = r - l;\n    vector<int> lower(m, 1);\n    long long sumL = 0;\n    for (int i = 0; i < m; i++) {\n        int b = base_value_for_target(targetType, l + i);\n        lower[i] = max(1, ceil_div_int(b, h));\n        sumL += lower[i];\n    }\n    if (sumL > W) fill(lower.begin(), lower.end(), 1);\n\n    vector<double> weights(m);\n    for (int i = 0; i < m; i++) weights[i] = max(1, base_value_for_target(targetType, l + i));\n    return allocate_by_weights(lower, weights);\n}\n\nvector<int> project_near(vector<int> ref, const vector<int>& lb) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    vector<int> w = ref;\n    for (int i = 0; i < m; i++) {\n        if (w[i] >= lb[i]) continue;\n        int need = lb[i] - w[i];\n        w[i] = lb[i];\n\n        while (need > 0) {\n            int best = -1;\n            for (int j = 0; j < m; j++) {\n                if (w[j] <= lb[j]) continue;\n                if (best == -1 ||\n                    abs(j - i) < abs(best - i) ||\n                    (abs(j - i) == abs(best - i) && w[j] - lb[j] > w[best] - lb[best])) {\n                    best = j;\n                }\n            }\n            if (best == -1) break;\n            int x = min(need, w[best] - lb[best]);\n            w[best] -= x;\n            need -= x;\n        }\n    }\n    return normalize_widths(w);\n}\n\nvoid make_day_lb(int l, int r, int h, int d, const vector<int>& ref, bool soft, vector<int>& lb) {\n    int m = r - l;\n    lb.assign(m, 1);\n    for (int i = 0; i < m; i++) {\n        int a = A[d][l + i];\n        int q = ceil_div_int(a, h);\n        if (soft && (int)ref.size() == m && ref[i] < q && q > 1) {\n            int rem = a - h * (q - 1);\n            if (100LL * rem < 2LL * h) q--;\n        }\n        lb[i] = max(1, q);\n    }\n}\n\nvector<int> shortage_widths(const vector<int>& refIn, int l, int r, int h, int d) {\n    int m = r - l;\n    vector<int> cur(m, 1);\n    int rem = W - m;\n    if (rem < 0) rem = 0;\n\n    auto gain = [&](int i) -> int {\n        long long covered = 1LL * cur[i] * h;\n        if (covered >= A[d][l + i]) return 0;\n        return (int)min<long long>(h, A[d][l + i] - covered);\n    };\n\n    using Tup = tuple<int,int,int,int>;\n    priority_queue<Tup> pq;\n    vector<int> ref = normalize_widths(refIn);\n    for (int i = 0; i < m; i++) {\n        int pref = (i < (int)ref.size() ? ref[i] - cur[i] : 0);\n        pq.push({gain(i), pref, -i, cur[i]});\n    }\n\n    while (rem > 0 && !pq.empty()) {\n        auto [g, pref, ni, old] = pq.top();\n        pq.pop();\n        int i = -ni;\n        if (old != cur[i]) continue;\n        int cg = gain(i);\n        if (cg <= 0) break;\n        cur[i]++;\n        rem--;\n        int np = (i < (int)ref.size() ? ref[i] - cur[i] : 0);\n        pq.push({gain(i), np, -i, cur[i]});\n    }\n    if (rem > 0) cur[m-1] += rem;\n    return normalize_widths(cur);\n}\n\nint symdiff_cut_count(const vector<int>& a, const vector<int>& b) {\n    int m = (int)a.size();\n    vector<int> ca, cb;\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += a[i];\n        ca.push_back(s);\n    }\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += b[i];\n        cb.push_back(s);\n    }\n    int i = 0, j = 0, common = 0;\n    while (i < (int)ca.size() && j < (int)cb.size()) {\n        if (ca[i] == cb[j]) {\n            common++;\n            i++;\n            j++;\n        } else if (ca[i] < cb[j]) {\n            i++;\n        } else {\n            j++;\n        }\n    }\n    return (int)ca.size() + (int)cb.size() - 2 * common;\n}\n\nlong long row_shortage_cost(int l, int r, int h, int d, const vector<int>& w) {\n    long long res = 0;\n    for (int i = 0; i < r - l; i++) {\n        long long area = 1LL * h * w[i];\n        if (area < A[d][l + i]) res += 100LL * (A[d][l + i] - area);\n    }\n    return res;\n}\n\nlong long simulate_row_fast(int l, int r, int h, int targetType, bool soft) {\n    vector<int> target = make_target_widths(l, r, h, targetType);\n    vector<int> prev;\n    long long cost = 0;\n\n    for (int d = 0; d < D; d++) {\n        vector<int> ref = (d == 0 ? target : prev);\n        vector<int> lb;\n        make_day_lb(l, r, h, d, ref, soft, lb);\n        int sumLB = accumulate(lb.begin(), lb.end(), 0);\n\n        vector<int> w;\n        if (sumLB <= W) w = project_near(ref, lb);\n        else w = shortage_widths(ref, l, r, h, d);\n\n        cost += row_shortage_cost(l, r, h, d, w);\n        if (d > 0) cost += 1LL * h * symdiff_cut_count(prev, w);\n        prev = w;\n    }\n    return cost;\n}\n\nvoid best_row_option(int l, int r, int h, long long& best, int& bestT, bool& bestS) {\n    if (hStaticSeg[l][r] < SEG_INF && h >= hStaticSeg[l][r]) {\n        best = 0;\n        bestT = 0;\n        bestS = false;\n        return;\n    }\n\n    best = (1LL << 62);\n    bestT = 0;\n    bestS = false;\n\n    for (int t = 0; t < 5; t++) {\n        for (int s = 0; s <= 1; s++) {\n            long long c = simulate_row_fast(l, r, h, t, s);\n            if (c < best) {\n                best = c;\n                bestT = t;\n                bestS = (bool)s;\n            }\n        }\n    }\n}\n\nvector<int> choose_widths_overlap(vector<int> ref, const vector<int>& lb, vector<int> target) {\n    int m = (int)ref.size();\n    ref = normalize_widths(ref);\n    target = normalize_widths(target);\n\n    if (m == 1) return vector<int>{W};\n\n    int sumLB = accumulate(lb.begin(), lb.end(), 0);\n    if (sumLB > W) return ref;\n\n    bool feasible = true;\n    for (int i = 0; i < m; i++) {\n        if (ref[i] < lb[i]) {\n            feasible = false;\n            break;\n        }\n    }\n    if (feasible) return ref;\n\n    vector<int> oldSet(W + 1, 0);\n    int s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += ref[i];\n        if (0 <= s && s <= W) oldSet[s] = 1;\n    }\n\n    vector<int> targetCut(m - 1);\n    s = 0;\n    for (int i = 0; i + 1 < m; i++) {\n        s += target[i];\n        targetCut[i] = s;\n    }\n\n    const int NEG = -1'000'000'000;\n    const int MATCH = 1'000'000;\n\n    vector<int> prev(W + 1, NEG), cur(W + 1, NEG);\n    vector<int> prefVal(W + 1), prefPos(W + 1);\n    vector<vector<short>> par(m, vector<short>(W + 1, -1));\n\n    prev[0] = 0;\n\n    vector<int> prefLB(m + 1, 0), suffLB(m + 1, 0);\n    for (int i = 0; i < m; i++) prefLB[i+1] = prefLB[i] + lb[i];\n    for (int i = m - 1; i >= 0; i--) suffLB[i] = suffLB[i+1] + lb[i];\n\n    for (int i = 1; i <= m - 1; i++) {\n        prefVal[0] = prev[0];\n        prefPos[0] = 0;\n        for (int x = 1; x <= W; x++) {\n            if (prev[x] > prefVal[x-1]) {\n                prefVal[x] = prev[x];\n                prefPos[x] = x;\n            } else {\n                prefVal[x] = prefVal[x-1];\n                prefPos[x] = prefPos[x-1];\n            }\n        }\n\n        fill(cur.begin(), cur.end(), NEG);\n\n        int minX = prefLB[i];\n        int maxX = W - suffLB[i];\n        for (int x = minX; x <= maxX; x++) {\n            int lim = x - lb[i-1];\n            if (lim < 0) continue;\n            int val = prefVal[lim];\n            if (val <= NEG / 2) continue;\n            int p = prefPos[lim];\n\n            int bonus = (oldSet[x] ? MATCH : 0) - abs(x - targetCut[i-1]);\n            int nv = val + bonus;\n            if (nv > cur[x]) {\n                cur[x] = nv;\n                par[i][x] = (short)p;\n            }\n        }\n        prev.swap(cur);\n    }\n\n    int bestP = -1, bestVal = NEG;\n    int maxP = W - lb[m-1];\n    for (int p = 0; p <= maxP; p++) {\n        if (prev[p] > bestVal) {\n            bestVal = prev[p];\n            bestP = p;\n        }\n    }\n\n    if (bestP < 0) return project_near(ref, lb);\n\n    vector<int> cuts(m + 1);\n    cuts[0] = 0;\n    cuts[m] = W;\n    cuts[m-1] = bestP;\n\n    for (int i = m - 1; i >= 1; i--) {\n        int p = par[i][cuts[i]];\n        if (p < 0) return project_near(ref, lb);\n        cuts[i-1] = p;\n    }\n\n    vector<int> w(m);\n    for (int i = 0; i < m; i++) {\n        w[i] = cuts[i+1] - cuts[i];\n        if (w[i] < lb[i] || w[i] <= 0) return project_near(ref, lb);\n    }\n    return normalize_widths(w);\n}\n\n/* ---------- daily shelves ---------- */\n\nstruct TmpRow {\n    int l, r, h;\n};\n\nbool get_daily_rows(int d, int mode, vector<TmpRow>& rows) {\n    rows.clear();\n\n    if (mode == 0) {\n        vector<int> dp(N + 1, SEG_INF), cnt(N + 1, SEG_INF), par(N + 1, -1);\n        dp[0] = 0;\n        cnt[0] = 0;\n\n        for (int j = 1; j <= N; j++) {\n            for (int i = 0; i < j; i++) {\n                int h = dayHSeg[d][i][j];\n                if (h >= SEG_INF || dp[i] >= SEG_INF) continue;\n                int nv = dp[i] + h;\n                int nc = cnt[i] + 1;\n                if (nv < dp[j] || (nv == dp[j] && nc < cnt[j])) {\n                    dp[j] = nv;\n                    cnt[j] = nc;\n                    par[j] = i;\n                }\n            }\n        }\n\n        if (dp[N] > W) return false;\n\n        int cur = N;\n        while (cur > 0) {\n            int p = par[cur];\n            if (p < 0) return false;\n            rows.push_back({p, cur, dayHSeg[d][p][cur]});\n            cur = p;\n        }\n        reverse(rows.begin(), rows.end());\n        return true;\n    } else {\n        const int BIG = 1'000'000'000;\n        vector<vector<int>> dp(N + 1, vector<int>(W + 1, BIG));\n        vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n        vector<vector<short>> parU(N + 1, vector<short>(W + 1, -1));\n\n        dp[0][0] = 0;\n\n        for (int i = 0; i < N; i++) {\n            for (int used = 0; used <= W; used++) {\n                if (dp[i][used] >= BIG) continue;\n\n                for (int j = i + 1; j <= N; j++) {\n                    int h = dayHSeg[d][i][j];\n                    if (h >= SEG_INF) continue;\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    int len = j - i;\n                    int add = 1000 + h * max(0, len - 1);\n                    int nv = dp[i][used] + add;\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parU[j][nu] = (short)used;\n                    }\n                }\n            }\n        }\n\n        int bestU = -1, best = BIG;\n        for (int u = 0; u <= W; u++) {\n            if (dp[N][u] < best) {\n                best = dp[N][u];\n                bestU = u;\n            }\n        }\n        if (bestU < 0) return false;\n\n        int cur = N, used = bestU;\n        while (cur > 0) {\n            int p = parI[cur][used];\n            int pu = parU[cur][used];\n            if (p < 0 || pu < 0) return false;\n            rows.push_back({p, cur, dayHSeg[d][p][cur]});\n            cur = p;\n            used = pu;\n        }\n        reverse(rows.begin(), rows.end());\n        return true;\n    }\n}\n\nbool make_daily_shelf_layout_day(int d, int mode, int slackMode, bool compact, vector<Rect>& layout) {\n    vector<TmpRow> rows;\n    if (!get_daily_rows(d, mode, rows)) return false;\n\n    int sumH = 0;\n    for (auto& row : rows) sumH += row.h;\n    if (sumH > W) return false;\n\n    int slack = W - sumH;\n    if (!compact && slack > 0) {\n        int idx = (int)rows.size() - 1;\n        if (slackMode == 1) {\n            int bestCnt = 1e9;\n            for (int i = 0; i < (int)rows.size(); i++) {\n                int cnt = rows[i].r - rows[i].l - 1;\n                if (cnt <= bestCnt) {\n                    bestCnt = cnt;\n                    idx = i;\n                }\n            }\n        }\n        rows[idx].h += slack;\n    }\n\n    layout.assign(N, Rect{0, 0, 1, 1});\n\n    int y = 0;\n    for (auto& row : rows) {\n        int m = row.r - row.l;\n        vector<int> lb(m);\n        vector<double> weights(m);\n\n        for (int i = 0; i < m; i++) {\n            int k = row.l + i;\n            lb[i] = max(1, ceil_div_int(A[d][k], row.h));\n            weights[i] = max(1, A[d][k]);\n        }\n\n        vector<int> w = allocate_by_weights(lb, weights);\n        int x = 0;\n        for (int i = 0; i < m; i++) {\n            int k = row.l + i;\n            layout[k] = {y, x, y + row.h, x + w[i]};\n            x += w[i];\n        }\n        if (x != W) return false;\n        y += row.h;\n    }\n\n    return y <= W;\n}\n\nvoid add_daily_shelf_candidates(double TL) {\n    if (dayCand.empty()) init_day_candidates();\n\n    for (int d = 0; d < D; d++) {\n        if (elapsed_sec() > TL) break;\n\n        vector<Rect> layout;\n        for (int mode = 0; mode <= 1; mode++) {\n            for (int slack = 0; slack <= 1; slack++) {\n                if (make_daily_shelf_layout_day(d, mode, slack, false, layout)) {\n                    add_unique_layout_cap(dayCand[d], layout, 160);\n                }\n            }\n            if (make_daily_shelf_layout_day(d, mode, 0, true, layout)) {\n                add_unique_layout_cap(dayCand[d], layout, 160);\n            }\n        }\n    }\n}\n\nbool make_daily_shelf_solution(int mode, int slackMode, vector<vector<Rect>>& sol) {\n    sol.assign(D, vector<Rect>(N));\n    for (int d = 0; d < D; d++) {\n        vector<Rect> layout;\n        if (!make_daily_shelf_layout_day(d, mode, slackMode, false, layout)) return false;\n        sol[d] = layout;\n    }\n    return true;\n}\n\n/* ---------- variable/fixed shelf candidates ---------- */\n\nvector<pair<int,int>> make_global_dp_partition(int type, int lambda) {\n    const long long BIG = (1LL << 60);\n    vector<long long> dp(N + 1, BIG);\n    vector<int> par(N + 1, -1);\n    dp[0] = 0;\n\n    for (int j = 1; j <= N; j++) {\n        for (int i = 0; i < j; i++) {\n            bool ok = true;\n            long long sumH = 0;\n            int maxH = 0;\n            for (int d = 0; d < D; d++) {\n                int h = dayHSeg[d][i][j];\n                if (h >= SEG_INF) {\n                    ok = false;\n                    break;\n                }\n                sumH += h;\n                maxH = max(maxH, h);\n            }\n            if (!ok || dp[i] >= BIG) continue;\n\n            long long segCost;\n            if (type == 0) segCost = sumH;\n            else if (type == 1) segCost = 1LL * maxH * D;\n            else segCost = sumH + 1LL * maxH * D / 2;\n\n            segCost += lambda;\n            long long nv = dp[i] + segCost;\n            if (nv < dp[j]) {\n                dp[j] = nv;\n                par[j] = i;\n            }\n        }\n    }\n\n    if (par[N] < 0) return {};\n\n    vector<pair<int,int>> g;\n    int cur = N;\n    while (cur > 0) {\n        int p = par[cur];\n        if (p < 0) return {};\n        g.push_back({p, cur});\n        cur = p;\n    }\n    reverse(g.begin(), g.end());\n    return g;\n}\n\nvector<pair<int,int>> make_equal_partition_groups(int R) {\n    R = clamp_int(R, 1, N);\n    vector<pair<int,int>> g;\n    int prev = 0;\n    for (int i = 0; i < R; i++) {\n        int en = (i == R - 1 ? N : (int)llround(1.0 * N * (i + 1) / R));\n        en = clamp_int(en, prev + 1, N - (R - i - 1));\n        g.push_back({prev, en});\n        prev = en;\n    }\n    return g;\n}\n\nvector<pair<int,int>> make_area_partition_groups(const vector<int>& base, int R) {\n    R = clamp_int(R, 1, N);\n    vector<double> pref(N + 1, 0);\n    for (int i = 0; i < N; i++) pref[i+1] = pref[i] + max(1, base[i]);\n\n    vector<pair<int,int>> g;\n    int prev = 0;\n    for (int i = 0; i < R; i++) {\n        int en;\n        if (i == R - 1) {\n            en = N;\n        } else {\n            double target = pref[N] * (i + 1) / R;\n            en = int(lower_bound(pref.begin(), pref.end(), target) - pref.begin());\n            en = clamp_int(en, prev + 1, N - (R - i - 1));\n        }\n        g.push_back({prev, en});\n        prev = en;\n    }\n    return g;\n}\n\nvector<pair<int,int>> make_daily_partition_groups(int d, int mode) {\n    vector<TmpRow> rows;\n    if (!get_daily_rows(d, mode, rows)) return {};\n    vector<pair<int,int>> g;\n    for (auto& row : rows) g.push_back({row.l, row.r});\n    return g;\n}\n\nbool valid_partition_groups(const vector<pair<int,int>>& g) {\n    if (g.empty()) return false;\n    int cur = 0;\n    for (auto [l, r] : g) {\n        if (l != cur || l >= r || r > N) return false;\n        cur = r;\n    }\n    return cur == N;\n}\n\nstring partition_key(const vector<pair<int,int>>& g) {\n    string s;\n    for (auto [l, r] : g) {\n        s += to_string(l);\n        s += '-';\n        s += to_string(r);\n        s += ',';\n    }\n    return s;\n}\n\nbool build_fixed_variable_shelf_solution(\n    const vector<pair<int,int>>& groups,\n    vector<vector<Rect>>& sol,\n    bool overlap,\n    int targetType\n) {\n    if (!valid_partition_groups(groups)) return false;\n\n    int R = (int)groups.size();\n    vector<int> maxH(R, 0);\n    vector<double> avgH(R, 1.0), weightH(R, 1.0);\n\n    for (int ri = 0; ri < R; ri++) {\n        auto [l, r] = groups[ri];\n        long long sum = 0;\n        for (int d = 0; d < D; d++) {\n            int h = dayHSeg[d][l][r];\n            if (h >= SEG_INF) return false;\n            maxH[ri] = max(maxH[ri], h);\n            sum += h;\n        }\n        avgH[ri] = max(1.0, (double)sum / D);\n        weightH[ri] = max(1.0, avgH[ri] * max(1, r - l - 1));\n    }\n\n    for (int d = 0; d < D; d++) {\n        int sumL = 0;\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            sumL += dayHSeg[d][l][r];\n        }\n        if (sumL > W) return false;\n    }\n\n    int sumMax = accumulate(maxH.begin(), maxH.end(), 0);\n    vector<int> staticTarget;\n    if (sumMax <= W) staticTarget = allocate_by_weights(maxH, weightH);\n    else {\n        vector<int> ones(R, 1);\n        staticTarget = allocate_by_weights(ones, avgH);\n    }\n\n    sol.assign(D, vector<Rect>(N));\n    vector<int> prevH;\n    vector<vector<int>> prevWidths(R);\n\n    for (int d = 0; d < D; d++) {\n        vector<int> lowerH(R);\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            lowerH[ri] = dayHSeg[d][l][r];\n        }\n\n        vector<int> h;\n        if (d == 0) h = project_near(staticTarget, lowerH);\n        else h = (overlap ? choose_widths_overlap(prevH, lowerH, staticTarget) : project_near(prevH, lowerH));\n\n        int y = 0;\n        for (int ri = 0; ri < R; ri++) {\n            auto [l, r] = groups[ri];\n            int m = r - l;\n            vector<int> lb(m);\n            int sumLB = 0;\n            for (int i = 0; i < m; i++) {\n                int k = l + i;\n                lb[i] = max(1, ceil_div_int(A[d][k], h[ri]));\n                sumLB += lb[i];\n            }\n            if (sumLB > W) return false;\n\n            vector<int> targetW = make_target_widths(l, r, h[ri], targetType);\n            vector<int> ref = (d == 0 || prevWidths[ri].empty() ? targetW : prevWidths[ri]);\n            vector<int> w = (overlap ? choose_widths_overlap(ref, lb, targetW) : project_near(ref, lb));\n\n            int x = 0;\n            for (int i = 0; i < m; i++) {\n                int k = l + i;\n                sol[d][k] = {y, x, y + h[ri], x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            y += h[ri];\n            prevWidths[ri] = w;\n        }\n        if (y != W) return false;\n        prevH = h;\n    }\n\n    return true;\n}\n\nvoid run_daily_variable_shelf_candidates() {\n    vector<vector<Rect>> sol;\n\n    for (int mode = 0; mode <= 1; mode++) {\n        for (int slack = 0; slack <= 1; slack++) {\n            if (bestScore == 0) return;\n            if (make_daily_shelf_solution(mode, slack, sol)) consider_solution(sol);\n        }\n    }\n\n    if (bestScore == 0) return;\n\n    vector<vector<pair<int,int>>> parts;\n    set<string> seen;\n\n    auto addPart = [&](const vector<pair<int,int>>& g) {\n        if (!valid_partition_groups(g)) return;\n        string key = partition_key(g);\n        if (seen.insert(key).second) parts.push_back(g);\n    };\n\n    vector<int> lambdas = {0, 300, 1000, 3000, 10000};\n    for (int lam : lambdas) {\n        addPart(make_global_dp_partition(0, lam));\n        addPart(make_global_dp_partition(1, lam));\n    }\n\n    vector<int> Rs;\n    auto addR = [&](int r) {\n        r = clamp_int(r, 1, N);\n        if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n    };\n\n    int sq = max(1, (int)llround(sqrt((double)N)));\n    addR(sq);\n    addR(sq + 1);\n    addR(N / 4);\n    addR(N / 3);\n    addR(N / 2);\n    addR(2 * sq);\n\n    for (int r : Rs) {\n        addPart(make_equal_partition_groups(r));\n        addPart(make_area_partition_groups(meanDemand, r));\n        addPart(make_area_partition_groups(p90Demand, r));\n        addPart(make_area_partition_groups(optStaticDemand, r));\n    }\n\n    addPart(make_daily_partition_groups(0, 1));\n    addPart(make_daily_partition_groups(D / 2, 1));\n    addPart(make_daily_partition_groups(D - 1, 1));\n\n    const double TL_NEW = 1.75;\n    int idx = 0;\n    for (auto& g : parts) {\n        if (bestScore == 0 || elapsed_sec() > TL_NEW) break;\n\n        if (build_fixed_variable_shelf_solution(g, sol, false, 1)) consider_solution(sol);\n        if (bestScore == 0) break;\n\n        if (idx < 7 && elapsed_sec() < TL_NEW) {\n            if (build_fixed_variable_shelf_solution(g, sol, true, 1)) consider_solution(sol);\n        }\n        idx++;\n    }\n}\n\nstruct ShelfRowChoice {\n    int l, r, h;\n    int targetType;\n    bool soft;\n};\n\nbool build_fixed_shelf_solution(const vector<ShelfRowChoice>& rows, vector<vector<Rect>>& sol, bool overlap) {\n    sol.assign(D, vector<Rect>(N));\n    int y = 0;\n\n    for (const auto& row : rows) {\n        if (y + row.h > W) return false;\n\n        vector<int> target = make_target_widths(row.l, row.r, row.h, row.targetType);\n        vector<int> prev;\n\n        for (int d = 0; d < D; d++) {\n            vector<int> ref = (d == 0 ? target : prev);\n            vector<int> lb;\n            make_day_lb(row.l, row.r, row.h, d, ref, row.soft, lb);\n\n            int sumLB = accumulate(lb.begin(), lb.end(), 0);\n            vector<int> w;\n            if (sumLB <= W) w = (overlap ? choose_widths_overlap(ref, lb, target) : project_near(ref, lb));\n            else w = shortage_widths(ref, row.l, row.r, row.h, d);\n\n            int x = 0;\n            for (int i = 0; i < row.r - row.l; i++) {\n                int k = row.l + i;\n                if (w[i] <= 0) return false;\n                sol[d][k] = {y, x, y + row.h, x + w[i]};\n                x += w[i];\n            }\n            if (x != W) return false;\n            prev = w;\n        }\n        y += row.h;\n    }\n\n    return y <= W;\n}\n\nvoid run_fixed_shelf_dp() {\n    for (int l = 0; l <= N; l++) {\n        for (int r = 0; r <= N; r++) {\n            hMinSeg[l][r] = hStaticSeg[l][r] = SEG_INF;\n            segOptCnt[l][r] = 0;\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            bool ok = true;\n            int mx = 0;\n            for (int d = 0; d < D; d++) {\n                if (dayHSeg[d][l][r] >= SEG_INF) {\n                    ok = false;\n                    break;\n                }\n                mx = max(mx, dayHSeg[d][l][r]);\n            }\n            hMinSeg[l][r] = ok ? mx : SEG_INF;\n            hStaticSeg[l][r] = compute_hstatic_segment(l, r);\n        }\n    }\n\n    for (int l = 0; l < N; l++) {\n        for (int r = l + 1; r <= N; r++) {\n            int hm = hMinSeg[l][r];\n            if (hm >= SEG_INF) continue;\n\n            vector<int> hs;\n            auto addH = [&](int h) {\n                if (h < 1 || h > W) return;\n                if (find(hs.begin(), hs.end(), h) == hs.end()) hs.push_back(h);\n            };\n\n            addH(hm);\n\n            int hsStatic = hStaticSeg[l][r];\n            if (hsStatic < SEG_INF) {\n                addH(hsStatic);\n                if (hsStatic - hm >= 2) addH((hm + hsStatic) / 2);\n            } else if (hm < W) {\n                addH((hm + W) / 2);\n            }\n\n            sort(hs.begin(), hs.end());\n            if ((int)hs.size() > MAX_SEG_OPT) hs.resize(MAX_SEG_OPT);\n\n            for (int h : hs) {\n                int idx = segOptCnt[l][r]++;\n                segOptH[l][r][idx] = h;\n\n                long long c;\n                int t;\n                bool s;\n                best_row_option(l, r, h, c, t, s);\n\n                segOptCost[l][r][idx] = c;\n                segOptTarget[l][r][idx] = t;\n                segOptSoft[l][r][idx] = s;\n            }\n        }\n    }\n\n    const long long BIG = (1LL << 62);\n    vector<vector<long long>> dp(N + 1, vector<long long>(W + 1, BIG));\n    vector<vector<short>> parI(N + 1, vector<short>(W + 1, -1));\n    vector<vector<short>> parUsed(N + 1, vector<short>(W + 1, -1));\n    vector<vector<signed char>> parOpt(N + 1, vector<signed char>(W + 1, -1));\n\n    dp[0][0] = 0;\n\n    for (int i = 0; i < N; i++) {\n        for (int used = 0; used <= W; used++) {\n            if (dp[i][used] >= BIG / 2) continue;\n\n            for (int j = i + 1; j <= N; j++) {\n                for (int oi = 0; oi < segOptCnt[i][j]; oi++) {\n                    int h = segOptH[i][j][oi];\n                    int nu = used + h;\n                    if (nu > W) continue;\n\n                    long long nv = dp[i][used] + segOptCost[i][j][oi];\n                    if (nv < dp[j][nu]) {\n                        dp[j][nu] = nv;\n                        parI[j][nu] = (short)i;\n                        parUsed[j][nu] = (short)used;\n                        parOpt[j][nu] = (signed char)oi;\n                    }\n                }\n            }\n        }\n    }\n\n    long long best = BIG;\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 < 0) return;\n\n    vector<ShelfRowChoice> rows;\n    int curI = N, curH = bestH;\n    while (curI > 0) {\n        int pi = parI[curI][curH];\n        int pu = parUsed[curI][curH];\n        int oi = parOpt[curI][curH];\n        if (pi < 0 || pu < 0 || oi < 0) return;\n\n        rows.push_back({\n            pi,\n            curI,\n            segOptH[pi][curI][oi],\n            segOptTarget[pi][curI][oi],\n            segOptSoft[pi][curI][oi]\n        });\n\n        curI = pi;\n        curH = pu;\n    }\n    reverse(rows.begin(), rows.end());\n\n    vector<vector<Rect>> sol;\n    if (build_fixed_shelf_solution(rows, sol, false)) consider_solution(sol);\n    if (bestScore == 0) return;\n    if (build_fixed_shelf_solution(rows, sol, true)) consider_solution(sol);\n}\n\n/* ---------- static horizontal strips ---------- */\n\nvoid consider_static_horizontal_knapsack() {\n    const long long BIG = (1LL << 62);\n\n    vector<vector<long long>> cost(N, vector<long long>(W + 1, 0));\n    for (int k = 0; k < N; k++) {\n        for (int h = 1; h <= W; h++) {\n            long long c = 0;\n            for (int d = 0; d < D; d++) {\n                long long area = 1LL * h * W;\n                if (area < A[d][k]) c += 100LL * (A[d][k] - area);\n            }\n            cost[k][h] = c;\n        }\n    }\n\n    vector<long long> dp(W + 1, BIG), ndp(W + 1, BIG);\n    vector<vector<short>> par(N + 1, vector<short>(W + 1, -1));\n    dp[0] = 0;\n\n    for (int k = 0; k < N; k++) {\n        fill(ndp.begin(), ndp.end(), BIG);\n        int remainItems = N - k - 1;\n        for (int used = 0; used <= W; used++) {\n            if (dp[used] >= BIG / 2) continue;\n            int maxh = W - used - remainItems;\n            for (int h = 1; h <= maxh; h++) {\n                long long nv = dp[used] + cost[k][h];\n                int nu = used + h;\n                if (nv < ndp[nu]) {\n                    ndp[nu] = nv;\n                    par[k+1][nu] = (short)h;\n                }\n            }\n        }\n        dp.swap(ndp);\n    }\n\n    long long best = BIG;\n    int bestUsed = -1;\n    for (int used = 0; used <= W; used++) {\n        if (dp[used] < best) {\n            best = dp[used];\n            bestUsed = used;\n        }\n    }\n    if (bestUsed < 0) return;\n\n    vector<int> h(N);\n    int used = bestUsed;\n    for (int k = N; k >= 1; k--) {\n        int x = par[k][used];\n        if (x <= 0) return;\n        h[k-1] = x;\n        used -= x;\n    }\n\n    vector<Rect> one(N);\n    int y = 0;\n    for (int k = 0; k < N; k++) {\n        one[k] = {y, 0, y + h[k], W};\n        y += h[k];\n    }\n\n    vector<vector<Rect>> sol(D, one);\n    consider_solution(sol);\n}\n\n/* ---------- old slicing candidate handling ---------- */\n\nconst double TL_CAND = 2.65;\nconst double TL_POST = 2.90;\n\nvoid process_tree(Tree t, const vector<int>& base, int level) {\n    if (elapsed_sec() > TL_CAND || bestScore == 0) return;\n\n    vector<int> target = scale_to_limit(base);\n    assign_targets(t, target);\n\n    vector<vector<Rect>> sol;\n\n    if (elapsed_sec() < TL_CAND && make_static_solution(t, target, false, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, globalMaxDemand, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_PREV, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 1 && elapsed_sec() < TL_CAND && make_solution(t, false, POLICY_STATIC_ABS, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_static_solution(t, target, true, sol)) {\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n\n    if (level >= 2 && elapsed_sec() < TL_CAND && make_solution(t, true, POLICY_PREV, sol)) {\n        consider_solution(sol);\n    }\n}\n\nvoid try_all_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto orig = bestSol;\n    for (int t = 0; t < D && elapsed_sec() < TL_POST; t++) {\n        vector<vector<Rect>> sol(D, orig[t]);\n        consider_solution(sol);\n        if (bestScore == 0) return;\n    }\n}\n\nvoid smooth_by_copy() {\n    if (bestScore == 0 || elapsed_sec() > TL_POST) return;\n\n    auto sol = bestSol;\n\n    auto local_cost = [&](int d, const vector<Rect>& cand) -> long long {\n        long long c = shortage_day(cand, d);\n        if (d > 0) c += transition_cost(sol[d-1], cand);\n        if (d + 1 < D) c += transition_cost(cand, sol[d+1]);\n        return c;\n    };\n\n    for (int pass = 0; pass < 5 && elapsed_sec() < TL_POST; pass++) {\n        bool improved = false;\n\n        for (int d = 0; d < D && elapsed_sec() < TL_POST; d++) {\n            long long old = local_cost(d, sol[d]);\n\n            if (d > 0) {\n                long long nw = local_cost(d, sol[d-1]);\n                if (nw < old) {\n                    sol[d] = sol[d-1];\n                    old = nw;\n                    improved = true;\n                }\n            }\n\n            if (d + 1 < D) {\n                long long nw = local_cost(d, sol[d+1]);\n                if (nw < old) {\n                    sol[d] = sol[d+1];\n                    old = nw;\n                    improved = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    long long curScore = evaluate_solution(sol);\n    if (curScore < bestScore) {\n        bestScore = curScore;\n        bestSol = sol;\n    }\n}\n\n/* ---------- main ---------- */\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int inputW;\n    cin >> inputW >> 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    globalMaxDemand.assign(N, 1);\n    meanDemand.assign(N, 1);\n    medDemand.assign(N, 1);\n    p75Demand.assign(N, 1);\n    p90Demand.assign(N, 1);\n\n    for (int k = 0; k < N; k++) {\n        long long s = 0;\n        vector<int> vals;\n        for (int d = 0; d < D; d++) {\n            s += A[d][k];\n            vals.push_back(A[d][k]);\n            globalMaxDemand[k] = max(globalMaxDemand[k], A[d][k]);\n        }\n        sort(vals.begin(), vals.end());\n        meanDemand[k] = max(1, (int)(s / D));\n        medDemand[k] = vals[D / 2];\n        p75Demand[k] = vals[min(D - 1, (int)llround(0.75 * (D - 1)))];\n        p90Demand[k] = vals[min(D - 1, (int)llround(0.90 * (D - 1)))];\n    }\n\n    optStaticDemand = compute_opt_static_area();\n\n    bestSol = make_fallback();\n    bestScore = evaluate_solution(bestSol);\n\n    consider_static_horizontal_knapsack();\n\n    precompute_day_segments();\n\n    init_day_candidates();\n    generate_day_slicing_candidates(1.23);\n    add_daily_shelf_candidates(1.36);\n    add_shrunk_day_candidates(1.43);\n    add_static_library_candidates(6, 1.50, true);\n    run_day_candidate_dp(false, 1.60);\n\n    if (bestScore != 0) run_daily_variable_shelf_candidates();\n    if (bestScore != 0) run_fixed_shelf_dp();\n\n    if (bestScore != 0) {\n        vector<pair<int,int>> quick = {{0,0}, {2,0}, {0,1}};\n        for (auto [sm, om] : quick) {\n            if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n            Tree t = build_aspect_tree(optStaticDemand, sm, om);\n            process_tree(t, optStaticDemand, 2);\n        }\n    }\n\n    if (bestScore != 0) {\n        vector<vector<int>> bases;\n        bases.push_back(globalMaxDemand);\n        bases.push_back(p90Demand);\n        bases.push_back(p75Demand);\n        bases.push_back(meanDemand);\n        bases.push_back(medDemand);\n\n        vector<pair<int,int>> combos = {\n            {0, 0}, {2, 0}, {1, 0}, {0, 1}, {0, 2}\n        };\n\n        for (int bi = 0; bi < (int)bases.size(); bi++) {\n            for (int ci = 0; ci < (int)combos.size(); ci++) {\n                if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n\n                int splitMode = combos[ci].first;\n                int orientMode = combos[ci].second;\n                Tree t = build_aspect_tree(bases[bi], splitMode, orientMode);\n\n                int level = 1;\n                if (ci == 0 && bi <= 3) level = 2;\n                process_tree(t, bases[bi], level);\n            }\n            if (bestScore == 0) break;\n        }\n\n        vector<int> Rs;\n        auto addR = [&](int r) {\n            r = clamp_int(r, 1, N);\n            if (find(Rs.begin(), Rs.end(), r) == Rs.end()) Rs.push_back(r);\n        };\n\n        int sq = max(1, (int)llround(sqrt((double)N)));\n        addR(sq);\n        addR(sq + 1);\n        addR(sq - 1);\n        addR(N / 4);\n        addR(N / 3);\n        addR(N / 2);\n        addR(2 * sq);\n        addR(5);\n        addR(8);\n        addR(10);\n        addR(15);\n        addR(20);\n        addR(N);\n        addR(1);\n\n        vector<int> shelfBaseIds = {0, 1, 3, 2};\n        for (int bi : shelfBaseIds) {\n            for (int groupMode = 0; groupMode <= 1; groupMode++) {\n                for (int r : Rs) {\n                    if (elapsed_sec() > TL_CAND || bestScore == 0) break;\n                    Tree t = build_shelf_tree(bases[bi], r, groupMode, 0);\n                    int level = (groupMode == 0 ? 1 : 0);\n                    process_tree(t, bases[bi], level);\n                }\n                if (bestScore == 0) break;\n            }\n            if (bestScore == 0) break;\n        }\n    }\n\n    add_shrunk_day_candidates(2.74);\n    add_static_library_candidates(12, 2.80, true);\n    run_day_candidate_dp(true, 2.86);\n    copy_library_dp(2.89);\n\n    try_all_copy();\n    smooth_by_copy();\n\n    final_symmetry_dp(2.925);\n    copy_library_dp(2.945);\n    final_shrink_dp(2.965);\n\n    for (int d = 0; d < D; d++) {\n        for (int k = 0; k < N; k++) {\n            const Rect& r = bestSol[d][k];\n            cout << r.y0 << ' ' << r.x0 << ' ' << r.y1 << ' ' << r.x1 << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc032":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int BN = 9;\nstatic const int AP = 7;\nstatic const int KMAX = 81;\nstatic const int MOD = 998244353;\nstatic const int MAX_MULTI = 6;\n\nint N, M, K;\narray<int, KMAX> initBoard;\nlong long initScore = 0;\nint stampVal[20][9];\n\nstruct Timer {\n    chrono::steady_clock::time_point st;\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} timer;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n} rng(123456789);\n\nstruct Action {\n    int m, p, q;\n    int anchor;\n    int idx[9];\n    int val[9];\n    uint64_t maskLo, maskHi;\n};\n\nstruct Option {\n    unsigned char cnt;\n    unsigned char s1, s2;\n    int val[9];\n};\n\nstruct MultiOption {\n    unsigned char cnt;\n    unsigned char st[MAX_MULTI];\n    int val[9];\n};\n\nstruct PairInfo {\n    unsigned short a, b;\n    unsigned char len;\n    unsigned char idx[18];\n    int val[18];\n};\n\nvector<Action> actions;\narray<array<int, 9>, 49> anchorCells;\nvector<int> cellCovers[81];\nvector<Option> options;\nvector<MultiOption> multiOpts[MAX_MULTI + 1];\nbool anchorOverlap[49][49];\nvector<PairInfo> overlapPairs;\nstatic int pairIndexMat[1000][1000];\n\ninline bool actionCoversCell(int aid, int cell) {\n    const Action& a = actions[aid];\n    if (cell < 64) return (a.maskLo >> cell) & 1ULL;\n    return (a.maskHi >> (cell - 64)) & 1ULL;\n}\n\ninline long long evalAdd(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalSub(const array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int old = b[a.idx[k]];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applyAdd(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old + a.val[k];\n        if (nv >= MOD) nv -= MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long applySub(array<int, KMAX>& b, int aid) {\n    const Action& a = actions[aid];\n    long long delta = 0;\n    for (int k = 0; k < 9; k++) {\n        int idx = a.idx[k];\n        int old = b[idx];\n        int nv = old - a.val[k];\n        if (nv < 0) nv += MOD;\n        b[idx] = nv;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalPairInfo(const array<int, KMAX>& b, const PairInfo& pi) {\n    long long delta = 0;\n    for (int t = 0; t < pi.len; t++) {\n        int idx = pi.idx[t];\n        int old = b[idx];\n        int nv = old + pi.val[t];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalAdd2(const array<int, KMAX>& b, int a, int c) {\n    if (a < 0 && c < 0) return 0;\n    if (a < 0) return evalAdd(b, c);\n    if (c < 0) return evalAdd(b, a);\n\n    if (!anchorOverlap[actions[a].anchor][actions[c].anchor]) {\n        return evalAdd(b, a) + evalAdd(b, c);\n    }\n\n    int id = pairIndexMat[a][c];\n    if (id >= 0) return evalPairInfo(b, overlapPairs[id]);\n\n    int idxs[18];\n    int vals[18];\n    int len = 0;\n\n    auto addCell = [&](int idx, int val) {\n        for (int t = 0; t < len; t++) {\n            if (idxs[t] == idx) {\n                int nv = vals[t] + val;\n                if (nv >= MOD) nv -= MOD;\n                vals[t] = nv;\n                return;\n            }\n        }\n        idxs[len] = idx;\n        vals[len] = val;\n        len++;\n    };\n\n    for (int k = 0; k < 9; k++) addCell(actions[a].idx[k], actions[a].val[k]);\n    for (int k = 0; k < 9; k++) addCell(actions[c].idx[k], actions[c].val[k]);\n\n    long long delta = 0;\n    for (int t = 0; t < len; t++) {\n        int old = b[idxs[t]];\n        int nv = old + vals[t];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\ninline long long evalMultiAtAnchor(const array<int, KMAX>& b, int anc, const MultiOption& op) {\n    long long delta = 0;\n    const auto& cells = anchorCells[anc];\n    for (int k = 0; k < 9; k++) {\n        int old = b[cells[k]];\n        int nv = old + op.val[k];\n        if (nv >= MOD) nv -= MOD;\n        delta += (long long)nv - old;\n    }\n    return delta;\n}\n\nlong long combLL(int n, int r) {\n    if (r < 0 || r > n) return 0;\n    r = min(r, n - r);\n    long long res = 1;\n    for (int i = 1; i <= r; i++) {\n        res = res * (n - r + i) / i;\n    }\n    return res;\n}\n\nvoid genMultiRec(int target, int start, vector<int>& chosen, array<int, 9>& vals) {\n    if ((int)chosen.size() == target) {\n        MultiOption op{};\n        op.cnt = (unsigned char)target;\n        for (int i = 0; i < MAX_MULTI; i++) op.st[i] = 0;\n        for (int i = 0; i < target; i++) op.st[i] = (unsigned char)chosen[i];\n        for (int k = 0; k < 9; k++) op.val[k] = vals[k];\n        multiOpts[target].push_back(op);\n        return;\n    }\n\n    for (int m = start; m < M; m++) {\n        auto oldVals = vals;\n        chosen.push_back(m);\n        for (int k = 0; k < 9; k++) {\n            int v = vals[k] + stampVal[m][k];\n            if (v >= MOD) v -= MOD;\n            vals[k] = v;\n        }\n        genMultiRec(target, m, chosen, vals);\n        chosen.pop_back();\n        vals = oldVals;\n    }\n}\n\nvoid precomputeMultiOptions() {\n    for (int c = 0; c <= MAX_MULTI; c++) multiOpts[c].clear();\n\n    MultiOption zero{};\n    zero.cnt = 0;\n    for (int i = 0; i < MAX_MULTI; i++) zero.st[i] = 0;\n    for (int k = 0; k < 9; k++) zero.val[k] = 0;\n    multiOpts[0].push_back(zero);\n\n    for (int target = 1; target <= MAX_MULTI; target++) {\n        multiOpts[target].reserve((size_t)combLL(M + target - 1, target));\n        vector<int> chosen;\n        array<int, 9> vals{};\n        genMultiRec(target, 0, chosen, vals);\n    }\n}\n\nvoid precomputeOverlapPairs() {\n    int A = (int)actions.size();\n    for (int i = 0; i < A; i++) {\n        for (int j = 0; j < A; j++) pairIndexMat[i][j] = -1;\n    }\n\n    overlapPairs.clear();\n    overlapPairs.reserve(180000);\n\n    for (int a = 0; a < A; a++) {\n        for (int b = a; b < A; b++) {\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) continue;\n\n            PairInfo pi{};\n            pi.a = (unsigned short)a;\n            pi.b = (unsigned short)b;\n            pi.len = 0;\n\n            auto addCell = [&](int idx, int val) {\n                for (int t = 0; t < pi.len; t++) {\n                    if (pi.idx[t] == idx) {\n                        int nv = pi.val[t] + val;\n                        if (nv >= MOD) nv -= MOD;\n                        pi.val[t] = nv;\n                        return;\n                    }\n                }\n                pi.idx[pi.len] = (unsigned char)idx;\n                pi.val[pi.len] = val;\n                pi.len++;\n            };\n\n            for (int k = 0; k < 9; k++) addCell(actions[a].idx[k], actions[a].val[k]);\n            for (int k = 0; k < 9; k++) addCell(actions[b].idx[k], actions[b].val[k]);\n\n            int id = (int)overlapPairs.size();\n            overlapPairs.push_back(pi);\n            pairIndexMat[a][b] = id;\n            pairIndexMat[b][a] = id;\n        }\n    }\n}\n\nvoid precompute() {\n    actions.reserve(49 * M);\n\n    for (int p = 0; p < AP; p++) {\n        for (int q = 0; q < AP; q++) {\n            int aid = p * AP + q;\n            int t = 0;\n            for (int di = 0; di < 3; di++) {\n                for (int dj = 0; dj < 3; dj++) {\n                    anchorCells[aid][t++] = (p + di) * BN + (q + dj);\n                }\n            }\n        }\n    }\n\n    for (int a = 0; a < 49; a++) {\n        int p1 = a / AP, q1 = a % AP;\n        for (int b = 0; b < 49; b++) {\n            int p2 = b / AP, q2 = b % AP;\n            anchorOverlap[a][b] = (abs(p1 - p2) <= 2 && abs(q1 - q2) <= 2);\n        }\n    }\n\n    for (int anc = 0; anc < 49; anc++) {\n        int p = anc / AP;\n        int q = anc % AP;\n\n        for (int m = 0; m < M; m++) {\n            Action a;\n            a.m = m;\n            a.p = p;\n            a.q = q;\n            a.anchor = anc;\n            a.maskLo = a.maskHi = 0;\n\n            for (int k = 0; k < 9; k++) {\n                int idx = anchorCells[anc][k];\n                a.idx[k] = idx;\n                a.val[k] = stampVal[m][k];\n                if (idx < 64) a.maskLo |= 1ULL << idx;\n                else a.maskHi |= 1ULL << (idx - 64);\n            }\n\n            actions.push_back(a);\n        }\n    }\n\n    for (int r = 0; r < BN; r++) {\n        for (int c = 0; c < BN; c++) {\n            int cell = r * BN + c;\n            for (int p = max(0, r - 2); p <= min(AP - 1, r); p++) {\n                for (int q = max(0, c - 2); q <= min(AP - 1, c); q++) {\n                    cellCovers[cell].push_back(p * AP + q);\n                }\n            }\n        }\n    }\n\n    Option none{};\n    none.cnt = 0;\n    none.s1 = none.s2 = 0;\n    for (int k = 0; k < 9; k++) none.val[k] = 0;\n    options.push_back(none);\n\n    for (int m = 0; m < M; m++) {\n        Option op{};\n        op.cnt = 1;\n        op.s1 = m;\n        op.s2 = 0;\n        for (int k = 0; k < 9; k++) op.val[k] = stampVal[m][k];\n        options.push_back(op);\n    }\n\n    for (int a = 0; a < M; a++) {\n        for (int b = a; b < M; b++) {\n            Option op{};\n            op.cnt = 2;\n            op.s1 = a;\n            op.s2 = b;\n            for (int k = 0; k < 9; k++) {\n                int v = stampVal[a][k] + stampVal[b][k];\n                if (v >= MOD) v -= MOD;\n                op.val[k] = v;\n            }\n            options.push_back(op);\n        }\n    }\n\n    precomputeMultiOptions();\n    precomputeOverlapPairs();\n}\n\nstruct Solution {\n    array<int, KMAX> board;\n    array<int, KMAX> slot;\n    long long score;\n};\n\nvoid rebuild(Solution& sol) {\n    sol.board = initBoard;\n    sol.score = initScore;\n    for (int i = 0; i < K; i++) {\n        if (sol.slot[i] >= 0) {\n            sol.score += applyAdd(sol.board, sol.slot[i]);\n        }\n    }\n}\n\nSolution makeSolutionFromOps(const vector<int>& ops) {\n    Solution sol;\n    sol.slot.fill(-1);\n    int L = min((int)ops.size(), K);\n    for (int i = 0; i < L; i++) sol.slot[i] = ops[i];\n    rebuild(sol);\n    return sol;\n}\n\nSolution greedySolution() {\n    Solution sol;\n    sol.board = initBoard;\n    sol.slot.fill(-1);\n    sol.score = initScore;\n\n    for (int step = 0; step < K; step++) {\n        long long bestDelta = 0;\n        int best = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long d = evalAdd(sol.board, aid);\n            if (d > bestDelta) {\n                bestDelta = d;\n                best = aid;\n            }\n        }\n\n        if (best == -1) break;\n\n        sol.slot[step] = best;\n        sol.score += applyAdd(sol.board, best);\n    }\n\n    return sol;\n}\n\nvoid coordinateDescent(Solution& sol, int maxSweeps, double timeLimit) {\n    array<int, KMAX> ord;\n    for (int i = 0; i < K; i++) ord[i] = i;\n\n    for (int sweep = 0; sweep < maxSweeps; sweep++) {\n        if (timer.elapsed() > timeLimit) break;\n\n        for (int i = K - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ord[i], ord[j]);\n        }\n\n        bool improved = false;\n\n        for (int oi = 0; oi < K; oi++) {\n            if ((oi & 15) == 0 && timer.elapsed() > timeLimit) return;\n\n            int pos = ord[oi];\n            int old = sol.slot[pos];\n            long long oldScore = sol.score;\n\n            if (old >= 0) {\n                sol.score += applySub(sol.board, old);\n            }\n\n            long long base = sol.score;\n            int best = old;\n            long long bestScore = oldScore;\n\n            if (base > bestScore) {\n                bestScore = base;\n                best = -1;\n            }\n\n            for (int aid = 0; aid < (int)actions.size(); aid++) {\n                long long cand = base + evalAdd(sol.board, aid);\n                if (cand > bestScore) {\n                    bestScore = cand;\n                    best = aid;\n                }\n            }\n\n            sol.score = base;\n\n            if (best >= 0) {\n                sol.score += applyAdd(sol.board, best);\n            }\n\n            sol.slot[pos] = best;\n\n            if (sol.score > oldScore) improved = true;\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid anchorGroupOptimize(Solution& sol, int maxPasses, double timeLimit) {\n    for (int pass = 0; pass < maxPasses; pass++) {\n        bool improved = false;\n\n        for (int ii = 0; ii < 49; ii++) {\n            if (timer.elapsed() > timeLimit) return;\n\n            int anc = (pass & 1) ? (48 - ii) : ii;\n\n            vector<int> slots;\n            for (int i = 0; i < K; i++) {\n                int a = sol.slot[i];\n                if (a >= 0 && actions[a].anchor == anc) slots.push_back(i);\n            }\n\n            int c = (int)slots.size();\n            if (c <= 1 || c > MAX_MULTI) continue;\n\n            vector<int> oldActs(c);\n            long long oldScore = sol.score;\n\n            for (int t = 0; t < c; t++) {\n                oldActs[t] = sol.slot[slots[t]];\n                sol.score += applySub(sol.board, oldActs[t]);\n                sol.slot[slots[t]] = -1;\n            }\n\n            long long base = sol.score;\n            long long bestScore = oldScore;\n            int bestCnt = -1;\n            int bestIdx = -1;\n            bool timedOut = false;\n            int chk = 0;\n\n            for (int cnt = 0; cnt <= c && !timedOut; cnt++) {\n                const auto& vec = multiOpts[cnt];\n                for (int oi = 0; oi < (int)vec.size(); oi++) {\n                    if ((chk++ & 8191) == 0 && timer.elapsed() > timeLimit) {\n                        timedOut = true;\n                        break;\n                    }\n\n                    long long cand = base + evalMultiAtAnchor(sol.board, anc, vec[oi]);\n                    if (cand > bestScore) {\n                        bestScore = cand;\n                        bestCnt = cnt;\n                        bestIdx = oi;\n                    }\n                }\n            }\n\n            sol.score = base;\n\n            if (timedOut) {\n                for (int t = 0; t < c; t++) {\n                    sol.slot[slots[t]] = oldActs[t];\n                    sol.score += applyAdd(sol.board, oldActs[t]);\n                }\n                return;\n            }\n\n            if (bestCnt >= 0) {\n                const MultiOption& op = multiOpts[bestCnt][bestIdx];\n                for (int t = 0; t < bestCnt; t++) {\n                    int aid = anc * M + (int)op.st[t];\n                    sol.slot[slots[t]] = aid;\n                    sol.score += applyAdd(sol.board, aid);\n                }\n                improved = true;\n            } else {\n                for (int t = 0; t < c; t++) {\n                    sol.slot[slots[t]] = oldActs[t];\n                    sol.score += applyAdd(sol.board, oldActs[t]);\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nlong long orderCost(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    int cnt[49] = {};\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        cnt[br]++;\n    }\n\n    int maxc = 0;\n    int sumsq = 0;\n    int zero = 0;\n\n    for (int i = 0; i < 49; i++) {\n        maxc = max(maxc, cnt[i]);\n        sumsq += cnt[i] * cnt[i];\n        if (cnt[i] == 0) zero++;\n    }\n\n    return (long long)maxc * 1000000LL + (long long)sumsq * 1000LL + zero;\n}\n\nvector<int> findBalancedOrder() {\n    vector<int> base(49);\n    iota(base.begin(), base.end(), 0);\n\n    vector<int> best = base;\n    long long bestCost = orderCost(best);\n\n    const int REPS = 10;\n    const int ITERS = 1300;\n\n    for (int rep = 0; rep < REPS; rep++) {\n        vector<int> perm = base;\n\n        for (int i = 48; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(perm[i], perm[j]);\n        }\n\n        long long cur = orderCost(perm);\n\n        for (int it = 0; it < ITERS; it++) {\n            int a = rng.nextInt(49);\n            int b = rng.nextInt(49);\n            if (a == b) continue;\n\n            swap(perm[a], perm[b]);\n            long long nc = orderCost(perm);\n\n            if (nc <= cur) {\n                cur = nc;\n            } else {\n                swap(perm[a], perm[b]);\n            }\n        }\n\n        if (cur < bestCost) {\n            bestCost = cur;\n            best = perm;\n        }\n    }\n\n    return best;\n}\n\nvector<vector<int>> computeFinalCells(const vector<int>& order) {\n    int rank[49];\n    for (int i = 0; i < 49; i++) rank[order[i]] = i;\n\n    vector<vector<int>> finalCells(49);\n\n    for (int cell = 0; cell < 81; cell++) {\n        int br = -1;\n        for (int aid : cellCovers[cell]) {\n            br = max(br, rank[aid]);\n        }\n        finalCells[br].push_back(cell);\n    }\n\n    return finalCells;\n}\n\nstruct BeamState {\n    array<int, KMAX> cell;\n    long long fin;\n    long long total;\n    long long key;\n    int parent;\n    short opt;\n    unsigned char used;\n};\n\nvector<int> beamSearch(const vector<int>& order, int perWidth, long long finalWeight) {\n    vector<vector<int>> finalCells = computeFinalCells(order);\n\n    vector<vector<BeamState>> layers;\n    layers.reserve(50);\n\n    BeamState init{};\n    init.cell = initBoard;\n    init.fin = 0;\n    init.total = initScore;\n    init.key = initScore;\n    init.parent = -1;\n    init.opt = -1;\n    init.used = 0;\n\n    layers.push_back(vector<BeamState>{init});\n\n    vector<vector<BeamState>> buckets(K + 1);\n    int reserveEach = perWidth * (int)options.size() + 8;\n    for (auto& b : buckets) b.reserve(reserveEach);\n\n    auto cmpState = [](const BeamState& a, const BeamState& b) {\n        if (a.key != b.key) return a.key > b.key;\n        if (a.fin != b.fin) return a.fin > b.fin;\n        return a.total > b.total;\n    };\n\n    for (int step = 0; step < 49; step++) {\n        for (auto& b : buckets) b.clear();\n\n        const vector<BeamState>& cur = layers.back();\n        int anc = order[step];\n        const auto& cells = anchorCells[anc];\n        const vector<int>& fins = finalCells[step];\n\n        for (int si = 0; si < (int)cur.size(); si++) {\n            const BeamState& st = cur[si];\n\n            for (int oid = 0; oid < (int)options.size(); oid++) {\n                const Option& op = options[oid];\n                int nu = (int)st.used + (int)op.cnt;\n                if (nu > K) continue;\n\n                BeamState ns;\n                ns.cell = st.cell;\n                ns.fin = st.fin;\n                ns.total = st.total;\n                ns.parent = si;\n                ns.opt = (short)oid;\n                ns.used = (unsigned char)nu;\n\n                if (op.cnt) {\n                    for (int k = 0; k < 9; k++) {\n                        int idx = cells[k];\n                        int old = ns.cell[idx];\n                        int nv = old + op.val[k];\n                        if (nv >= MOD) nv -= MOD;\n                        ns.cell[idx] = nv;\n                        ns.total += (long long)nv - old;\n                    }\n                }\n\n                for (int idx : fins) {\n                    ns.fin += ns.cell[idx];\n                }\n\n                ns.key = ns.fin * finalWeight + (ns.total - ns.fin);\n                buckets[nu].push_back(std::move(ns));\n            }\n        }\n\n        vector<BeamState> next;\n        next.reserve((K + 1) * perWidth);\n\n        for (int u = 0; u <= K; u++) {\n            auto& v = buckets[u];\n            if ((int)v.size() > perWidth) {\n                nth_element(v.begin(), v.begin() + perWidth, v.end(), cmpState);\n                v.resize(perWidth);\n            }\n            for (auto& s : v) next.push_back(std::move(s));\n        }\n\n        layers.push_back(std::move(next));\n    }\n\n    const vector<BeamState>& last = layers.back();\n    int bestIdx = 0;\n    for (int i = 1; i < (int)last.size(); i++) {\n        if (last[i].fin > last[bestIdx].fin) bestIdx = i;\n    }\n\n    vector<int> optAt(49);\n    int idx = bestIdx;\n\n    for (int step = 48; step >= 0; step--) {\n        const BeamState& st = layers[step + 1][idx];\n        optAt[step] = st.opt;\n        idx = st.parent;\n    }\n\n    vector<int> ops;\n    ops.reserve(K);\n\n    for (int step = 0; step < 49; step++) {\n        int anc = order[step];\n        const Option& op = options[optAt[step]];\n\n        if (op.cnt >= 1) ops.push_back(anc * M + (int)op.s1);\n        if (op.cnt >= 2) ops.push_back(anc * M + (int)op.s2);\n    }\n\n    if ((int)ops.size() > K) ops.resize(K);\n    return ops;\n}\n\nbool optimizePairApprox(Solution& sol, int i, int j, int topC) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    long long base = sol.score;\n\n    vector<pair<long long, int>> all;\n    all.reserve(actions.size());\n\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        all.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    auto cmpPair = [](const pair<long long, int>& a, const pair<long long, int>& b) {\n        return a.first > b.first;\n    };\n\n    if ((int)all.size() > topC) {\n        nth_element(all.begin(), all.begin() + topC, all.end(), cmpPair);\n        all.resize(topC);\n    }\n\n    vector<pair<long long, int>> firsts = all;\n    firsts.push_back({base, -1});\n\n    for (int t = 0; t < 5; t++) {\n        int aid = rng.nextInt((int)actions.size());\n        firsts.push_back({base + evalAdd(sol.board, aid), aid});\n    }\n\n    long long bestScore = oldScore;\n    int best1 = old1;\n    int best2 = old2;\n\n    for (auto [dummyScore, f] : firsts) {\n        long long d1 = 0;\n        if (f >= 0) d1 = applyAdd(sol.board, f);\n        long long sc1 = base + d1;\n\n        long long localBest = sc1;\n        int gbest = -1;\n\n        for (int aid = 0; aid < (int)actions.size(); aid++) {\n            long long cand = sc1 + evalAdd(sol.board, aid);\n            if (cand > localBest) {\n                localBest = cand;\n                gbest = aid;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best1 = f;\n            best2 = gbest;\n        }\n\n        if (f >= 0) applySub(sol.board, f);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        sol.slot[i] = best1;\n        sol.slot[j] = best2;\n\n        if (best1 >= 0) sol.score += applyAdd(sol.board, best1);\n        if (best2 >= 0) sol.score += applyAdd(sol.board, best2);\n\n        return true;\n    } else {\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n\n        return false;\n    }\n}\n\nvoid pairSearchApproxAdaptive(Solution& sol, double timeLimit) {\n    int attempts = 0;\n    int fail = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        int i, j;\n\n        if ((attempts & 7) == 0) {\n            vector<int> none;\n            for (int t = 0; t < K; t++) {\n                if (sol.slot[t] == -1) none.push_back(t);\n            }\n\n            if ((int)none.size() >= 2) {\n                int a = rng.nextInt((int)none.size());\n                int b = rng.nextInt((int)none.size() - 1);\n                if (b >= a) b++;\n                i = none[a];\n                j = none[b];\n            } else {\n                i = rng.nextInt(K);\n                do {\n                    j = rng.nextInt(K);\n                } while (j == i);\n            }\n        } else {\n            i = rng.nextInt(K);\n            do {\n                j = rng.nextInt(K);\n            } while (j == i);\n        }\n\n        attempts++;\n\n        if (optimizePairApprox(sol, i, j, 22)) {\n            coordinateDescent(sol, 4, timeLimit);\n            fail = 0;\n        } else {\n            fail++;\n        }\n\n        if (timer.elapsed() > 1.82 && fail > 70) break;\n    }\n}\n\nbool optimizePairExact(Solution& sol, int i, int j) {\n    if (i == j) return false;\n\n    int old1 = sol.slot[i];\n    int old2 = sol.slot[j];\n    long long oldScore = sol.score;\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    sol.slot[i] = sol.slot[j] = -1;\n\n    long long base = sol.score;\n    long long oldDelta = oldScore - base;\n    long long bestDelta = oldDelta;\n    int bestA = old1;\n    int bestB = old2;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n\n        if (d[a] > bestDelta) {\n            bestDelta = d[a];\n            bestA = a;\n            bestB = -1;\n        }\n    }\n\n    if (0 > bestDelta) {\n        bestDelta = 0;\n        bestA = bestB = -1;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    for (int ia = 0; ia < A; ia++) {\n        int a = ord[ia];\n        if (d[a] + d[ord[0]] <= bestDelta) break;\n\n        for (int ib = 0; ib < A; ib++) {\n            int b = ord[ib];\n            long long ub = d[a] + d[b];\n            if (ub <= bestDelta) break;\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                bestDelta = ub;\n                bestA = a;\n                bestB = b;\n                break;\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        if (delta > bestDelta) {\n            bestDelta = delta;\n            bestA = pi.a;\n            bestB = pi.b;\n        }\n    }\n\n    sol.score = base;\n\n    if (bestDelta > oldDelta) {\n        sol.slot[i] = bestA;\n        sol.slot[j] = bestB;\n\n        if (bestA >= 0) sol.score += applyAdd(sol.board, bestA);\n        if (bestB >= 0) sol.score += applyAdd(sol.board, bestB);\n\n        return true;\n    } else {\n        sol.slot[i] = old1;\n        sol.slot[j] = old2;\n\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n\n        return false;\n    }\n}\n\nvoid exactPairSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 18);\n        vector<pair<int, int>> pairs;\n        pairs.reserve(R * R);\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                pairs.push_back({loss[a].second, loss[b].second});\n            }\n        }\n\n        for (int i = (int)pairs.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(pairs[i], pairs[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n        int maxTries = stagnant == 0 ? 38 : 26;\n\n        for (auto [a, b] : pairs) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizePairExact(sol, a, b)) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= maxTries) break;\n        }\n\n        if (!improved) {\n            int randomTries = 14;\n\n            for (int t = 0; t < randomTries && timer.elapsed() < timeLimit; t++) {\n                int a, b;\n\n                if (rng.nextInt(100) < 75) {\n                    a = loss[rng.nextInt(R)].second;\n                } else {\n                    a = rng.nextInt(K);\n                }\n\n                do {\n                    if (rng.nextInt(100) < 75) {\n                        b = loss[rng.nextInt(R)].second;\n                    } else {\n                        b = rng.nextInt(K);\n                    }\n                } while (a == b);\n\n                if (optimizePairExact(sol, a, b)) {\n                    coordinateDescent(sol, 3, timeLimit);\n                    anchorGroupOptimize(sol, 1, timeLimit);\n                    improved = true;\n                    break;\n                }\n            }\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 3) break;\n        }\n    }\n}\n\nstruct PairCand {\n    long long delta;\n    int a, b;\n};\n\nstruct PairCandMinCmp {\n    bool operator()(const PairCand& x, const PairCand& y) const {\n        return x.delta > y.delta;\n    }\n};\n\nbool optimizeTripleApprox(Solution& sol, int i, int j, int k) {\n    if (i == j || i == k || j == k) return false;\n\n    int old[3] = {sol.slot[i], sol.slot[j], sol.slot[k]};\n    int pos[3] = {i, j, k};\n    long long oldScore = sol.score;\n\n    for (int t = 0; t < 3; t++) {\n        if (old[t] >= 0) sol.score += applySub(sol.board, old[t]);\n        sol.slot[pos[t]] = -1;\n    }\n\n    long long base = sol.score;\n\n    const int A = (int)actions.size();\n    long long d[1000];\n    array<int, 1000> ord;\n\n    for (int a = 0; a < A; a++) {\n        d[a] = evalAdd(sol.board, a);\n        ord[a] = a;\n    }\n\n    sort(ord.begin(), ord.begin() + A, [&](int x, int y) {\n        return d[x] > d[y];\n    });\n\n    const int CAND = 80;\n    priority_queue<PairCand, vector<PairCand>, PairCandMinCmp> pq;\n\n    auto pushCand = [&](long long delta, int a, int b) {\n        PairCand pc{delta, a, b};\n\n        if ((int)pq.size() < CAND) {\n            pq.push(pc);\n        } else if (delta > pq.top().delta) {\n            pq.pop();\n            pq.push(pc);\n        }\n    };\n\n    pushCand(0, -1, -1);\n\n    int singleT = min(A, 120);\n    for (int t = 0; t < singleT; t++) {\n        int a = ord[t];\n        pushCand(d[a], a, -1);\n    }\n\n    int topT = min(A, 80);\n    for (int x = 0; x < topT; x++) {\n        int a = ord[x];\n        for (int y = x + 1; y < topT; y++) {\n            int b = ord[y];\n\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                pushCand(d[a] + d[b], a, b);\n            }\n        }\n    }\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long delta = evalPairInfo(sol.board, pi);\n        pushCand(delta, pi.a, pi.b);\n    }\n\n    vector<PairCand> cands;\n    while (!pq.empty()) {\n        cands.push_back(pq.top());\n        pq.pop();\n    }\n\n    long long bestScore = oldScore;\n    int best[3] = {old[0], old[1], old[2]};\n\n    for (const PairCand& pc : cands) {\n        long long curScore = base;\n\n        if (pc.a >= 0) curScore += applyAdd(sol.board, pc.a);\n        if (pc.b >= 0) curScore += applyAdd(sol.board, pc.b);\n\n        int third = -1;\n        long long localBest = curScore;\n\n        for (int a = 0; a < A; a++) {\n            long long cand = curScore + evalAdd(sol.board, a);\n            if (cand > localBest) {\n                localBest = cand;\n                third = a;\n            }\n        }\n\n        if (localBest > bestScore) {\n            bestScore = localBest;\n            best[0] = pc.a;\n            best[1] = pc.b;\n            best[2] = third;\n        }\n\n        if (pc.b >= 0) applySub(sol.board, pc.b);\n        if (pc.a >= 0) applySub(sol.board, pc.a);\n    }\n\n    sol.score = base;\n\n    if (bestScore > oldScore) {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = best[t];\n            if (best[t] >= 0) sol.score += applyAdd(sol.board, best[t]);\n        }\n        return true;\n    } else {\n        for (int t = 0; t < 3; t++) {\n            sol.slot[pos[t]] = old[t];\n            if (old[t] >= 0) sol.score += applyAdd(sol.board, old[t]);\n        }\n        return false;\n    }\n}\n\nvoid tripleSearch(Solution& sol, double timeLimit) {\n    int stagnant = 0;\n\n    while (timer.elapsed() < timeLimit) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        int R = min(K, 12);\n        vector<array<int, 3>> triples;\n\n        for (int a = 0; a < R; a++) {\n            for (int b = a + 1; b < R; b++) {\n                for (int c = b + 1; c < R; c++) {\n                    triples.push_back({loss[a].second, loss[b].second, loss[c].second});\n                }\n            }\n        }\n\n        for (int i = (int)triples.size() - 1; i > 0; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(triples[i], triples[j]);\n        }\n\n        bool improved = false;\n        int tries = 0;\n\n        for (auto tr : triples) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizeTripleApprox(sol, tr[0], tr[1], tr[2])) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= 7) break;\n        }\n\n        if (improved) {\n            stagnant = 0;\n        } else {\n            stagnant++;\n            if (stagnant >= 2) break;\n        }\n    }\n}\n\nvoid targetedCellExactSearch(Solution& sol, double timeLimit) {\n    int rounds = 0;\n\n    while (timer.elapsed() < timeLimit && rounds < 2) {\n        vector<pair<long long, int>> loss;\n        loss.reserve(K);\n        long long lossSlot[KMAX];\n\n        for (int i = 0; i < K; i++) {\n            long long ls = 0;\n            if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n            lossSlot[i] = ls;\n            loss.push_back({ls, i});\n        }\n\n        sort(loss.begin(), loss.end());\n\n        vector<int> cells(81);\n        iota(cells.begin(), cells.end(), 0);\n        sort(cells.begin(), cells.end(), [&](int x, int y) {\n            return sol.board[x] < sol.board[y];\n        });\n\n        bool seen[KMAX][KMAX] = {};\n        vector<pair<int, int>> pairs;\n\n        auto addPair = [&](int a, int b) {\n            if (a == b) return;\n            if (a > b) swap(a, b);\n            if (!seen[a][b]) {\n                seen[a][b] = true;\n                pairs.push_back({a, b});\n            }\n        };\n\n        int weakR = min(K, 10);\n        for (int a = 0; a < weakR; a++) {\n            for (int b = a + 1; b < weakR; b++) {\n                addPair(loss[a].second, loss[b].second);\n            }\n        }\n\n        int cellLim = 14;\n        for (int ci = 0; ci < cellLim; ci++) {\n            int cell = cells[ci];\n\n            vector<int> coverSlots;\n            for (int s = 0; s < K; s++) {\n                int aid = sol.slot[s];\n                if (aid >= 0 && actionCoversCell(aid, cell)) {\n                    coverSlots.push_back(s);\n                }\n            }\n\n            sort(coverSlots.begin(), coverSlots.end(), [&](int x, int y) {\n                return lossSlot[x] < lossSlot[y];\n            });\n\n            if ((int)coverSlots.size() > 18) coverSlots.resize(18);\n\n            for (int u : coverSlots) {\n                int lim = min(K, 14);\n                for (int t = 0; t < lim; t++) {\n                    addPair(u, loss[t].second);\n                }\n            }\n\n            for (int a = 0; a < (int)coverSlots.size(); a++) {\n                for (int b = a + 1; b < (int)coverSlots.size(); b++) {\n                    addPair(coverSlots[a], coverSlots[b]);\n                }\n            }\n        }\n\n        sort(pairs.begin(), pairs.end(), [&](const auto& x, const auto& y) {\n            long long sx = lossSlot[x.first] + lossSlot[x.second];\n            long long sy = lossSlot[y.first] + lossSlot[y.second];\n            return sx < sy;\n        });\n\n        bool improved = false;\n        int tries = 0;\n        int maxTries = 10;\n\n        for (auto [a, b] : pairs) {\n            if (timer.elapsed() > timeLimit) break;\n\n            if (optimizePairExact(sol, a, b)) {\n                coordinateDescent(sol, 3, timeLimit);\n                anchorGroupOptimize(sol, 1, timeLimit);\n                improved = true;\n                break;\n            }\n\n            if (++tries >= maxTries) break;\n        }\n\n        if (!improved) break;\n        rounds++;\n    }\n}\n\nstruct AddSeed {\n    long long key;\n    int a, b;\n};\n\nstruct AddSeedMinCmp {\n    bool operator()(const AddSeed& x, const AddSeed& y) const {\n        return x.key > y.key;\n    }\n};\n\nvector<pair<int, int>> buildGlobalAddPairs(const array<int, KMAX>& board, int cap, double timeLimit) {\n    const int A = (int)actions.size();\n    long long d[1000];\n\n    for (int a = 0; a < A; a++) d[a] = evalAdd(board, a);\n\n    priority_queue<AddSeed, vector<AddSeed>, AddSeedMinCmp> pq;\n\n    auto pushSeed = [&](long long key, int a, int b) {\n        if ((int)pq.size() < cap) {\n            pq.push({key, a, b});\n        } else if (key > pq.top().key) {\n            pq.pop();\n            pq.push({key, a, b});\n        }\n    };\n\n    for (const PairInfo& pi : overlapPairs) {\n        long long v = evalPairInfo(board, pi);\n        pushSeed(v, pi.a, pi.b);\n    }\n\n    for (int a = 0; a < A; a++) {\n        if ((a & 15) == 0 && timer.elapsed() > timeLimit) break;\n\n        for (int b = a + 1; b < A; b++) {\n            if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                pushSeed(d[a] + d[b], a, b);\n            }\n        }\n    }\n\n    vector<pair<int, int>> res;\n    res.reserve(pq.size());\n\n    while (!pq.empty()) {\n        res.push_back({pq.top().a, pq.top().b});\n        pq.pop();\n    }\n\n    return res;\n}\n\nint selectTopActionsD(const array<int, KMAX>& board, int topC, int ids[], long long ds[]) {\n    int sz = 0;\n\n    for (int aid = 0; aid < (int)actions.size(); aid++) {\n        long long d = evalAdd(board, aid);\n\n        if (sz < topC) {\n            int pos = sz++;\n            while (pos > 0 && d > ds[pos - 1]) {\n                ds[pos] = ds[pos - 1];\n                ids[pos] = ids[pos - 1];\n                pos--;\n            }\n            ds[pos] = d;\n            ids[pos] = aid;\n        } else if (d > ds[topC - 1]) {\n            int pos = topC - 1;\n            while (pos > 0 && d > ds[pos - 1]) {\n                ds[pos] = ds[pos - 1];\n                ids[pos] = ids[pos - 1];\n                pos--;\n            }\n            ds[pos] = d;\n            ids[pos] = aid;\n        }\n    }\n\n    return sz;\n}\n\nvector<pair<int, int>> buildRemovalPairsForBroad(const Solution& sol, int maxPairs) {\n    vector<pair<long long, int>> loss;\n    loss.reserve(K);\n    long long lossSlot[KMAX];\n\n    for (int i = 0; i < K; i++) {\n        long long ls = 0;\n        if (sol.slot[i] >= 0) ls = -evalSub(sol.board, sol.slot[i]);\n        lossSlot[i] = ls;\n        loss.push_back({ls, i});\n    }\n\n    sort(loss.begin(), loss.end());\n\n    bool seen[KMAX][KMAX] = {};\n    vector<pair<int, int>> pairs;\n    pairs.reserve(maxPairs + 2048);\n\n    auto addPair = [&](int a, int b) {\n        if (a == b) return;\n        if (a > b) swap(a, b);\n        if (!seen[a][b]) {\n            seen[a][b] = true;\n            pairs.push_back({a, b});\n        }\n    };\n\n    int R = min(K, 24);\n    for (int a = 0; a < R; a++) {\n        for (int b = a + 1; b < R; b++) {\n            addPair(loss[a].second, loss[b].second);\n        }\n    }\n\n    vector<int> cells(81);\n    iota(cells.begin(), cells.end(), 0);\n    sort(cells.begin(), cells.end(), [&](int x, int y) {\n        return sol.board[x] < sol.board[y];\n    });\n\n    for (int ci = 0; ci < 12; ci++) {\n        int cell = cells[ci];\n\n        vector<int> cover;\n        for (int s = 0; s < K; s++) {\n            int aid = sol.slot[s];\n            if (aid >= 0 && actionCoversCell(aid, cell)) cover.push_back(s);\n        }\n\n        sort(cover.begin(), cover.end(), [&](int x, int y) {\n            return lossSlot[x] < lossSlot[y];\n        });\n\n        if ((int)cover.size() > 16) cover.resize(16);\n\n        for (int u : cover) {\n            for (int t = 0; t < min(K, 10); t++) {\n                addPair(u, loss[t].second);\n            }\n        }\n\n        for (int a = 0; a < (int)cover.size(); a++) {\n            for (int b = a + 1; b < (int)cover.size(); b++) {\n                addPair(cover[a], cover[b]);\n            }\n        }\n    }\n\n    // Add extra random diversity after the deterministic prefix.\n    // The first 620 pairs remain identical to the previous broad search.\n    for (int guard = 0; guard < 2500; guard++) {\n        addPair(rng.nextInt(K), rng.nextInt(K));\n    }\n\n    if ((int)pairs.size() > maxPairs) {\n        int keep = min({(int)pairs.size(), maxPairs, 620});\n        vector<pair<int, int>> res;\n        res.reserve(maxPairs);\n\n        for (int i = 0; i < keep; i++) res.push_back(pairs[i]);\n\n        int need = maxPairs - keep;\n        int rest = (int)pairs.size() - keep;\n\n        for (int t = 0; t < need && t < rest; t++) {\n            int j = keep + t + rng.nextInt(rest - t);\n            swap(pairs[keep + t], pairs[j]);\n            res.push_back(pairs[keep + t]);\n        }\n\n        pairs.swap(res);\n    }\n\n    return pairs;\n}\n\nbool broadPairApproxPass(Solution& sol, double timeLimit) {\n    if (timer.elapsed() > timeLimit) return false;\n\n    const int TOP_SINGLE = 26;\n    const int GLOBAL_PAIR = 180;\n    const int MAX_REM = 1200;\n\n    vector<pair<int, int>> globalPairs = buildGlobalAddPairs(sol.board, GLOBAL_PAIR, timeLimit);\n    vector<pair<int, int>> remPairs = buildRemovalPairsForBroad(sol, MAX_REM);\n\n    long long origScore = sol.score;\n    long long bestScore = origScore;\n    int bestI = -1, bestJ = -1;\n    int bestA = -1, bestB = -1;\n\n    int ids[40];\n    long long ds[40];\n\n    auto updateBest = [&](long long cand, int i, int j, int a, int b) {\n        if (cand > bestScore) {\n            bestScore = cand;\n            bestI = i;\n            bestJ = j;\n            bestA = a;\n            bestB = b;\n        }\n    };\n\n    for (int ri = 0; ri < (int)remPairs.size(); ri++) {\n        if ((ri & 7) == 0) {\n            double now = timer.elapsed();\n            if (now > timeLimit) break;\n            if (bestScore > origScore && now + 0.008 > timeLimit) break;\n        }\n\n        int i = remPairs[ri].first;\n        int j = remPairs[ri].second;\n        int old1 = sol.slot[i];\n        int old2 = sol.slot[j];\n\n        long long savedScore = sol.score;\n\n        if (old1 >= 0) sol.score += applySub(sol.board, old1);\n        if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n        long long base = sol.score;\n\n        updateBest(base, i, j, -1, -1);\n\n        int sz = selectTopActionsD(sol.board, TOP_SINGLE, ids, ds);\n\n        for (int x = 0; x < sz; x++) {\n            updateBest(base + ds[x], i, j, ids[x], -1);\n        }\n\n        for (int x = 0; x < sz; x++) {\n            int a = ids[x];\n            for (int y = x; y < sz; y++) {\n                int b = ids[y];\n                long long add;\n                if (!anchorOverlap[actions[a].anchor][actions[b].anchor]) {\n                    add = ds[x] + ds[y];\n                } else {\n                    add = evalAdd2(sol.board, a, b);\n                }\n                updateBest(base + add, i, j, a, b);\n            }\n        }\n\n        for (auto [a, b] : globalPairs) {\n            long long add = evalAdd2(sol.board, a, b);\n            updateBest(base + add, i, j, a, b);\n        }\n\n        if (old1 >= 0) sol.score += applyAdd(sol.board, old1);\n        if (old2 >= 0) sol.score += applyAdd(sol.board, old2);\n        sol.score = savedScore;\n    }\n\n    if (bestScore <= origScore || bestI < 0) return false;\n\n    // New: polish the best broad candidate with the exact 2-slot optimizer.\n    if (timer.elapsed() + 0.006 < timeLimit) {\n        if (optimizePairExact(sol, bestI, bestJ)) return true;\n    }\n\n    // Fallback: apply the approximate best move found.\n    int old1 = sol.slot[bestI];\n    int old2 = sol.slot[bestJ];\n\n    if (old1 >= 0) sol.score += applySub(sol.board, old1);\n    if (old2 >= 0) sol.score += applySub(sol.board, old2);\n\n    sol.slot[bestI] = bestA;\n    sol.slot[bestJ] = bestB;\n\n    if (bestA >= 0) sol.score += applyAdd(sol.board, bestA);\n    if (bestB >= 0) sol.score += applyAdd(sol.board, bestB);\n\n    return true;\n}\n\nvoid broadPairApproxSearch(Solution& sol, double timeLimit) {\n    int pass = 0;\n\n    while (timer.elapsed() < timeLimit && pass < 4) {\n        bool improved = broadPairApproxPass(sol, timeLimit);\n        if (!improved) break;\n\n        coordinateDescent(sol, 3, timeLimit);\n        anchorGroupOptimize(sol, 1, timeLimit);\n\n        pass++;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> K;\n\n    for (int i = 0; i < BN; i++) {\n        for (int j = 0; j < BN; j++) {\n            int x;\n            cin >> x;\n            initBoard[i * BN + j] = x;\n            initScore += x;\n        }\n    }\n\n    for (int m = 0; m < M; m++) {\n        for (int i = 0; i < 3; i++) {\n            for (int j = 0; j < 3; j++) {\n                cin >> stampVal[m][i * 3 + j];\n            }\n        }\n    }\n\n    timer.reset();\n\n    precompute();\n\n    Solution best = greedySolution();\n\n    coordinateDescent(best, 25, 1.86);\n\n    vector<int> order = findBalancedOrder();\n\n    if (timer.elapsed() < 1.20) {\n        vector<int> ops = beamSearch(order, 6, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 18, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    vector<int> revOrder = order;\n    reverse(revOrder.begin(), revOrder.end());\n\n    if (timer.elapsed() < 1.45) {\n        vector<int> ops = beamSearch(revOrder, 4, 10);\n        Solution sol = makeSolutionFromOps(ops);\n        coordinateDescent(sol, 14, 1.86);\n        if (sol.score > best.score) best = sol;\n    }\n\n    pairSearchApproxAdaptive(best, 1.86);\n\n    anchorGroupOptimize(best, 2, 1.875);\n    coordinateDescent(best, 5, 1.885);\n\n    exactPairSearch(best, 1.910);\n    tripleSearch(best, 1.925);\n\n    targetedCellExactSearch(best, 1.945);\n\n    // More time and broader/removal-diverse pair search.\n    broadPairApproxSearch(best, 1.985);\n\n    anchorGroupOptimize(best, 1, 1.990);\n    coordinateDescent(best, 2, 1.990);\n\n    vector<int> out;\n    for (int i = 0; i < K; i++) {\n        if (best.slot[i] >= 0) out.push_back(best.slot[i]);\n    }\n\n    cout << out.size() << '\\n';\n\n    for (int id : out) {\n        const Action& a = actions[id];\n        cout << a.m << ' ' << a.p << ' ' << a.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 TOT = 25;\nstatic constexpr int BASE = 6;\nstatic constexpr int PBASE = 7776;\nstatic constexpr int TOTAL_STATES = PBASE * PBASE;\nstatic constexpr int INF = 1e9;\n\nint A[N][N];\nint srcOf[TOT], idxOf[TOT];\nint pow6_[N + 1];\n\nuint8_t dig[PBASE][N];\nuint8_t sumCode[PBASE];\nuint8_t exhCode[PBASE];\n\nvector<signed char> memoBlock;\nvector<signed char> memoHBlock;\n\ninline int manhattan(int r1, int c1, int r2, int c2) {\n    return abs(r1 - r2) + abs(c1 - c2);\n}\n\nstruct TransCode {\n    int npcode, nqcode, code, k;\n};\n\nbool makeTransCodesLimited(int pcode, int qcode, int d, int capBase, TransCode &tr) {\n    int qd = dig[qcode][d];\n    if (qd >= N) return false;\n\n    int x = N * d + qd;\n    int s = srcOf[x];\n    int idx = idxOf[x];\n    int ps = dig[pcode][s];\n\n    int nq = qcode + pow6_[d];\n    int np = pcode;\n    int k = 0;\n\n    if (idx < ps) {\n        k = 0;\n    } else {\n        k = idx - ps;\n        int buffer = (int)sumCode[pcode] - (int)sumCode[qcode];\n        int capacity = capBase + (int)exhCode[pcode];\n        if (buffer + k > capacity) return false;\n        np = pcode + (idx + 1 - ps) * pow6_[s];\n    }\n\n    tr = {np, nq, np * PBASE + nq, k};\n    return true;\n}\n\nbool makeTransCodes(int pcode, int qcode, int d, TransCode &tr) {\n    return makeTransCodesLimited(pcode, qcode, d, 15, tr);\n}\n\nbool makeHTransCodes(int pcode, int qcode, int d, TransCode &tr) {\n    return makeTransCodesLimited(pcode, qcode, d, 11, tr);\n}\n\nint dfsBlock(int code) {\n    signed char m = memoBlock[code];\n    if (m != -1) {\n        if (m >= 100) return INF;\n        return (int)m;\n    }\n\n    int pcode = code / PBASE;\n    int qcode = code % PBASE;\n\n    if (sumCode[qcode] == TOT) {\n        memoBlock[code] = 0;\n        return 0;\n    }\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(pcode, qcode, d, tr)) continue;\n        int sub = dfsBlock(tr.code);\n        if (sub >= INF) continue;\n        best = min(best, tr.k + sub);\n    }\n\n    memoBlock[code] = (best >= INF ? 100 : (signed char)best);\n    return best;\n}\n\nint dfsHBlock(int code) {\n    signed char m = memoHBlock[code];\n    if (m != -1) {\n        if (m >= 100) return INF;\n        return (int)m;\n    }\n\n    int pcode = code / PBASE;\n    int qcode = code % PBASE;\n\n    if (sumCode[qcode] == TOT) {\n        memoHBlock[code] = 0;\n        return 0;\n    }\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeHTransCodes(pcode, qcode, d, tr)) continue;\n        int sub = dfsHBlock(tr.code);\n        if (sub >= INF) continue;\n        best = min(best, tr.k + sub);\n    }\n\n    memoHBlock[code] = (best >= INF ? 100 : (signed char)best);\n    return best;\n}\n\nstruct RowOption {\n    vector<int> cols;\n    string act;\n    int len = 0;\n    int finalCol = 0;\n};\n\nvector<RowOption> smallOpts, bigOpts, hSmallOpts;\n\nRowOption makeRowOption(const vector<int> &cols) {\n    RowOption ro;\n    ro.cols = cols;\n\n    int pos = 0;\n    for (int t = 0; t < (int)cols.size(); t++) {\n        if (t > 0) {\n            while (pos > 0) {\n                ro.act.push_back('L');\n                pos--;\n            }\n        }\n\n        ro.act.push_back('P');\n\n        while (pos < cols[t]) {\n            ro.act.push_back('R');\n            pos++;\n        }\n\n        ro.act.push_back('Q');\n    }\n\n    ro.len = (int)ro.act.size();\n    ro.finalCol = cols.empty() ? 0 : cols.back();\n    return ro;\n}\n\nvoid initRowOptions() {\n    vector<vector<int>> smallDefs = {\n        {},\n        {1},\n        {2},\n        {3},\n        {2, 1},\n        {3, 1},\n        {3, 2},\n        {3, 2, 1},\n    };\n    for (auto &v : smallDefs) smallOpts.push_back(makeRowOption(v));\n\n    bigOpts.push_back(makeRowOption({}));\n\n    vector<int> cur;\n    bool used[4] = {};\n    function<void(int, int)> dfs = [&](int dep, int len) {\n        if (dep == len) {\n            bigOpts.push_back(makeRowOption(cur));\n            return;\n        }\n        for (int c = 1; c <= 3; c++) {\n            if (used[c]) continue;\n            used[c] = true;\n            cur.push_back(c);\n            dfs(dep + 1, len);\n            cur.pop_back();\n            used[c] = false;\n        }\n    };\n\n    for (int len = 1; len <= 3; len++) {\n        memset(used, 0, sizeof(used));\n        cur.clear();\n        dfs(0, len);\n    }\n\n    vector<vector<int>> hDefs = {\n        {},\n        {1},\n        {2},\n        {2, 1},\n    };\n    for (auto &v : hDefs) hSmallOpts.push_back(makeRowOption(v));\n}\n\nstring directScript(int row, int d) {\n    string s;\n    s.push_back('P');\n    s.append(4, 'R');\n    if (row < d) s.append(d - row, 'D');\n    else s.append(row - d, 'U');\n    s.push_back('Q');\n    return s;\n}\n\nstring returnScript(int d, int row) {\n    string s;\n    if (d < row) s.append(row - d, 'D');\n    else s.append(d - row, 'U');\n    s.append(4, 'L');\n    return s;\n}\n\n/*** standard mode ***/\n\nstruct Pattern {\n    array<int, N> opt{};\n    int directRow = -1;\n    int directD = -1;\n    int directAfter = -1;\n    int T = 0;\n    int repR = -1, repC = -1;\n};\n\nint initialLenRow(const Pattern &p, int row) {\n    if (p.directRow == row) {\n        int len = 6 + abs(row - p.directD);\n        if (p.directAfter >= 0) {\n            len += abs(row - p.directD) + 4;\n            len += (row == 0 ? bigOpts[p.directAfter].len : smallOpts[p.directAfter].len);\n        }\n        return len;\n    }\n    return row == 0 ? bigOpts[p.opt[0]].len : smallOpts[p.opt[row]].len;\n}\n\nvoid computeT(Pattern &p) {\n    p.T = 0;\n    for (int i = 0; i < N; i++) p.T = max(p.T, initialLenRow(p, i));\n}\n\npair<int, int> baseBigFinal(const Pattern &p) {\n    if (p.directRow == 0) {\n        if (p.directAfter >= 0) return {0, bigOpts[p.directAfter].finalCol};\n        return {p.directD, 4};\n    }\n    return {0, bigOpts[p.opt[0]].finalCol};\n}\n\npair<int, int> finalBigPos(const Pattern &p) {\n    if (p.repR >= 0) return {p.repR, p.repC};\n    return baseBigFinal(p);\n}\n\nstring baseBigScript(const Pattern &p) {\n    if (p.directRow == 0) {\n        string s = directScript(0, p.directD);\n        if (p.directAfter >= 0) {\n            s += returnScript(p.directD, 0);\n            s += bigOpts[p.directAfter].act;\n        }\n        return s;\n    }\n    return bigOpts[p.opt[0]].act;\n}\n\nint safeDist(pair<int, int> a, pair<int, int> b) {\n    auto [r, c] = a;\n    auto [tr, tc] = b;\n\n    if (c == 4) {\n        if (tc == 4) return abs(r - tr);\n        if (tr == 0) return r + abs(4 - tc);\n        return INF;\n    } else {\n        if (r != 0) return INF;\n        if (tr == 0) return abs(c - tc);\n        if (tc == 4) return abs(4 - c) + tr;\n        return INF;\n    }\n}\n\nstring repositionScript(pair<int, int> a, pair<int, int> b) {\n    auto [r, c] = a;\n    auto [tr, tc] = b;\n    string s;\n\n    auto moveV = [&](int from, int to) {\n        if (from < to) s.append(to - from, 'D');\n        else s.append(from - to, 'U');\n    };\n    auto moveH = [&](int from, int to) {\n        if (from < to) s.append(to - from, 'R');\n        else s.append(from - to, 'L');\n    };\n\n    if (c == 4) {\n        if (tc == 4) {\n            moveV(r, tr);\n        } else {\n            moveV(r, 0);\n            moveH(4, tc);\n        }\n    } else {\n        if (tr == 0) {\n            moveH(c, tc);\n        } else {\n            moveH(c, 4);\n            moveV(0, tr);\n        }\n    }\n\n    return s;\n}\n\nstring bigInitScript(const Pattern &p) {\n    string s = baseBigScript(p);\n    if (p.repR >= 0) s += repositionScript(baseBigFinal(p), {p.repR, p.repC});\n    return s;\n}\n\nstring smallInitScript(const Pattern &p, int row) {\n    string s;\n    if (p.directRow == row) {\n        s = directScript(row, p.directD);\n        if (p.directAfter >= 0) {\n            s += returnScript(p.directD, row);\n            s += smallOpts[p.directAfter].act;\n        }\n        s.push_back('B');\n    } else {\n        s = smallOpts[p.opt[row]].act;\n        s.push_back('B');\n    }\n    return s;\n}\n\nbool samePattern(const Pattern &a, const Pattern &b) {\n    return a.opt == b.opt\n        && a.directRow == b.directRow\n        && a.directD == b.directD\n        && a.directAfter == b.directAfter\n        && a.T == b.T\n        && a.repR == b.repR\n        && a.repC == b.repC;\n}\n\nvector<Pattern> reachableVariants(const Pattern &p) {\n    vector<Pattern> res;\n    res.push_back(p);\n\n    if (p.directRow > 0) return res;\n\n    int bigLen = initialLenRow(p, 0);\n    int slack = p.T - bigLen;\n    if (slack <= 0) return res;\n\n    pair<int, int> base = baseBigFinal(p);\n    vector<pair<int, int>> targets;\n    for (int c = 0; c < N; c++) targets.push_back({0, c});\n    for (int r = 1; r < N; r++) targets.push_back({r, 4});\n\n    for (auto tg : targets) {\n        if (tg == base) continue;\n        int d = safeDist(base, tg);\n        if (d <= slack) {\n            Pattern q = p;\n            q.repR = tg.first;\n            q.repC = tg.second;\n            res.push_back(q);\n        }\n    }\n\n    return res;\n}\n\nstruct State {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = 0;\n        act.clear();\n        eval = 0;\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) { p[s]++; pcode += pow6_[s]; }\n    void incQ(int d) { q[d]++; qcode += pow6_[d]; }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveTo(int tr, int tc) {\n        while (r < tr) add('D');\n        while (r > tr) add('U');\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    vector<pair<int, int>> storageOptions(int b, int srcRow, double storageW, int maxOpt) const {\n        vector<tuple<double, int, int, int>> cand;\n        int bd = b / N;\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n                cand.emplace_back(sc, tie, rr, cc);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        vector<pair<int, int>> res;\n        for (int i = 0; i < (int)cand.size() && i < maxOpt; i++) {\n            res.push_back({get<2>(cand[i]), get<3>(cand[i])});\n        }\n        return res;\n    }\n};\n\ntemplate<class S>\nvoid setupInitial(S &st, const Pattern &pat) {\n    st.clear();\n\n    if (pat.directRow >= 0) {\n        st.q[pat.directD] = 1;\n        st.qcode += pow6_[pat.directD];\n    }\n\n    for (int i = 0; i < N; i++) {\n        const vector<int> *cols = nullptr;\n        int offset = 0;\n        int cnt = 0;\n\n        if (pat.directRow == i) {\n            offset = 1;\n            cnt = 1;\n            if (pat.directAfter >= 0) {\n                const RowOption &ro = (i == 0 ? bigOpts[pat.directAfter] : smallOpts[pat.directAfter]);\n                cols = &ro.cols;\n                cnt += (int)ro.cols.size();\n            }\n        } else {\n            const RowOption &ro = (i == 0 ? bigOpts[pat.opt[0]] : smallOpts[pat.opt[i]]);\n            cols = &ro.cols;\n            offset = 0;\n            cnt = (int)ro.cols.size();\n        }\n\n        st.p[i] = cnt;\n        st.pcode += cnt * pow6_[i];\n\n        if (cols != nullptr) {\n            for (int t = 0; t < (int)cols->size(); t++) {\n                int b = A[i][offset + t];\n                int cc = (*cols)[t];\n                st.occ[i][cc] = b;\n                st.lr[b] = i;\n                st.lc[b] = cc;\n            }\n        }\n\n        if (cnt < N) st.occ[i][0] = A[i][cnt];\n    }\n\n    auto pos = finalBigPos(pat);\n    st.r = pos.first;\n    st.c = pos.second;\n}\n\nState makeInitialState(const Pattern &pat) {\n    State st;\n    setupInitial(st, pat);\n    st.act.reserve(512);\n    return st;\n}\n\nbool doDispatchBuffered(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int rr = ns.lr[x], cc = ns.lc[x];\n    if (rr < 0 || ns.occ[rr][cc] != x) return false;\n\n    ns.moveTo(rr, cc);\n    ns.add('P');\n    ns.occ[rr][cc] = -1;\n    ns.lr[x] = ns.lc[x] = -1;\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nbool doDispatchSource(State &ns, int d) {\n    int x = N * d + ns.q[d];\n    int s = srcOf[x];\n\n    if (ns.p[s] >= N) return false;\n    if (A[s][ns.p[s]] != x) return false;\n    if (ns.occ[s][0] != x) return false;\n\n    ns.moveTo(s, 0);\n    ns.add('P');\n    ns.occ[s][0] = -1;\n    ns.incP(s);\n    if (ns.p[s] < N) ns.occ[s][0] = A[s][ns.p[s]];\n\n    if (ns.occ[d][N - 1] != -1) return false;\n    ns.moveTo(d, N - 1);\n    ns.add('Q');\n    ns.incQ(d);\n    return true;\n}\n\nvoid expandBlockers(\n    const State &cur,\n    int s,\n    int idx,\n    int d,\n    double storageW,\n    int optLimit,\n    vector<State> &out\n) {\n    if (cur.p[s] == idx) {\n        State ns = cur;\n        if (doDispatchSource(ns, d)) out.push_back(std::move(ns));\n        return;\n    }\n\n    if (cur.p[s] > idx) return;\n\n    int b = A[s][cur.p[s]];\n    if (cur.occ[s][0] != b) return;\n\n    State base = cur;\n    base.moveTo(s, 0);\n    base.add('P');\n    base.occ[s][0] = -1;\n    base.incP(s);\n    if (base.p[s] < N) base.occ[s][0] = A[s][base.p[s]];\n\n    auto opts = base.storageOptions(b, s, storageW, optLimit);\n    for (auto [rr, cc] : opts) {\n        if (base.occ[rr][cc] != -1) continue;\n\n        State ns = base;\n        ns.moveTo(rr, cc);\n        ns.add('Q');\n        ns.occ[rr][cc] = b;\n        ns.lr[b] = rr;\n        ns.lc[b] = cc;\n\n        expandBlockers(ns, s, idx, d, storageW, optLimit, out);\n    }\n}\n\nvector<State> expandExecuteTarget(\n    const State &st,\n    int d,\n    double storageW,\n    int optLimit,\n    int perTransLimit\n) {\n    vector<State> res;\n\n    int x = N * d + st.q[d];\n    int s = srcOf[x];\n    int idx = idxOf[x];\n\n    if (idx < st.p[s]) {\n        State ns = st;\n        if (doDispatchBuffered(ns, d)) res.push_back(std::move(ns));\n    } else {\n        expandBlockers(st, s, idx, d, storageW, optLimit, res);\n    }\n\n    if ((int)res.size() > perTransLimit) {\n        sort(res.begin(), res.end(), [](const State &a, const State &b) {\n            return a.act.size() < b.act.size();\n        });\n        res.resize(perTransLimit);\n    }\n\n    return res;\n}\n\nint nearestHeuristic(const State &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct PlanResult {\n    bool ok = false;\n    string act;\n};\n\nPlanResult buildBeam(const State &init, double storageW, int width, int hcoef, int optLimit) {\n    if (dfsBlock(init.code()) >= INF) return {false, \"\"};\n\n    vector<State> beam;\n    beam.push_back(init);\n\n    auto comp = [](const State &a, const State &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return a.act.size() < b.act.size();\n    };\n\n    int perTransLimit = (optLimit <= 1 ? 1 : (optLimit == 2 ? 8 : 12));\n\n    for (int step = init.delivered(); step < TOT; step++) {\n        vector<State> cand;\n        cand.reserve((size_t)width * N * perTransLimit);\n\n        for (const State &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                vector<State> nsList = expandExecuteTarget(st, d, storageW, optLimit, perTransLimit);\n                for (State &ns : nsList) {\n                    if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n                    int near = nearestHeuristic(ns);\n                    ns.eval = (int)ns.act.size() + hcoef * remAfter + near;\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return {false, \"\"};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    string best;\n    int bestLen = INF;\n    for (const State &st : beam) {\n        if (st.delivered() == TOT && (int)st.act.size() < bestLen) {\n            bestLen = (int)st.act.size();\n            best = st.act;\n        }\n    }\n\n    if (best.empty()) return {false, \"\"};\n    return {true, best};\n}\n\nstruct LiteState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n    int r = 0, c = 0, len = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = len = 0;\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) { p[s]++; pcode += pow6_[s]; }\n    void incQ(int d) { q[d]++; qcode += pow6_[d]; }\n\n    void moveTo(int tr, int tc) {\n        len += abs(r - tr) + abs(c - tc);\n        r = tr;\n        c = tc;\n    }\n\n    pair<int, int> chooseStorage(int b, int srcRow, double storageW) const {\n        int bd = b / N;\n        double best = 1e100;\n        int bestTie = INF;\n        pair<int, int> res = {-1, -1};\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + (N - 1 - cc);\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n\n                if (sc + 1e-9 < best || (fabs(sc - best) <= 1e-9 && tie < bestTie)) {\n                    best = sc;\n                    bestTie = tie;\n                    res = {rr, cc};\n                }\n            }\n        }\n\n        return res;\n    }\n\n    bool dispatchBuffered(int d) {\n        int x = N * d + q[d];\n        int rr = lr[x], cc = lc[x];\n        if (rr < 0 || occ[rr][cc] != x) return false;\n\n        moveTo(rr, cc);\n        len++;\n        occ[rr][cc] = -1;\n        lr[x] = lc[x] = -1;\n\n        moveTo(d, N - 1);\n        len++;\n        incQ(d);\n        return true;\n    }\n\n    bool dispatchSource(int d) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n\n        if (p[s] >= N) return false;\n        if (A[s][p[s]] != x) return false;\n        if (occ[s][0] != x) return false;\n\n        moveTo(s, 0);\n        len++;\n        occ[s][0] = -1;\n        incP(s);\n        if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n        moveTo(d, N - 1);\n        len++;\n        incQ(d);\n        return true;\n    }\n\n    bool executeTarget(int d, double storageW) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        if (idx < p[s]) return dispatchBuffered(d);\n\n        while (p[s] < idx) {\n            int b = A[s][p[s]];\n            if (occ[s][0] != b) return false;\n\n            moveTo(s, 0);\n            len++;\n            occ[s][0] = -1;\n            incP(s);\n            if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n            auto cell = chooseStorage(b, s, storageW);\n            if (cell.first < 0) return false;\n\n            moveTo(cell.first, cell.second);\n            len++;\n            occ[cell.first][cell.second] = b;\n            lr[b] = cell.first;\n            lc[b] = cell.second;\n        }\n\n        return dispatchSource(d);\n    }\n};\n\nLiteState makeLiteInitialState(const Pattern &pat) {\n    LiteState st;\n    setupInitial(st, pat);\n    return st;\n}\n\nint nearestLite(const LiteState &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, N - 1) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, N - 1) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nint greedyLength(const Pattern &pat, double storageW, int hcoef) {\n    string bs = bigInitScript(pat);\n    if ((int)bs.size() > pat.T) return INF;\n\n    LiteState st = makeLiteInitialState(pat);\n    if (dfsBlock(st.code()) >= INF) return INF;\n\n    for (int step = st.delivered(); step < TOT; step++) {\n        int bestEval = INF;\n        int bestLen = INF;\n        bool found = false;\n        LiteState bestSt;\n\n        for (int d = 0; d < N; d++) {\n            TransCode tr;\n            if (!makeTransCodes(st.pcode, st.qcode, d, tr)) continue;\n            int remAfter = dfsBlock(tr.code);\n            if (remAfter >= INF) continue;\n\n            LiteState ns = st;\n            if (!ns.executeTarget(d, storageW)) continue;\n            if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n\n            int eval = ns.len + hcoef * remAfter + nearestLite(ns);\n            if (eval < bestEval || (eval == bestEval && ns.len < bestLen)) {\n                bestEval = eval;\n                bestLen = ns.len;\n                bestSt = ns;\n                found = true;\n            }\n        }\n\n        if (!found) return INF;\n        st = bestSt;\n    }\n\n    return pat.T + st.len;\n}\n\nvector<Pattern> generateCandidates() {\n    vector<Pattern> res;\n    int B = (int)bigOpts.size();\n    int S = (int)smallOpts.size();\n    int smallCodeMax = 1;\n    for (int i = 1; i < N; i++) smallCodeMax *= S;\n\n    for (int b = 0; b < B; b++) {\n        for (int code = 0; code < smallCodeMax; code++) {\n            Pattern p;\n            p.opt.fill(0);\n            p.opt[0] = b;\n            int tmp = code;\n            for (int i = 1; i < N; i++) {\n                p.opt[i] = tmp % S;\n                tmp /= S;\n            }\n            computeT(p);\n            res.push_back(p);\n        }\n    }\n\n    vector<int> oneSmall;\n    for (int i = 0; i < S; i++) {\n        if (smallOpts[i].cols.size() == 1) oneSmall.push_back(i);\n    }\n\n    for (int dr = 0; dr < N; dr++) {\n        if (A[dr][0] % N != 0) continue;\n        int d = A[dr][0] / N;\n\n        if (dr == 0) {\n            for (int after = -1; after < B; after++) {\n                for (int code = 0; code < smallCodeMax; code++) {\n                    Pattern p;\n                    p.opt.fill(0);\n                    p.opt[0] = -1;\n                    int tmp = code;\n                    for (int i = 1; i < N; i++) {\n                        p.opt[i] = tmp % S;\n                        tmp /= S;\n                    }\n                    p.directRow = 0;\n                    p.directD = d;\n                    p.directAfter = after;\n                    computeT(p);\n                    res.push_back(p);\n                }\n            }\n        } else {\n            vector<int> afters;\n            afters.push_back(-1);\n            for (int x : oneSmall) afters.push_back(x);\n\n            int codeMax = 1;\n            for (int i = 1; i < N; i++) if (i != dr) codeMax *= S;\n\n            for (int after : afters) {\n                for (int b = 0; b < B; b++) {\n                    for (int code = 0; code < codeMax; code++) {\n                        Pattern p;\n                        p.opt.fill(0);\n                        p.opt[0] = b;\n                        int tmp = code;\n                        for (int i = 1; i < N; i++) {\n                            if (i == dr) {\n                                p.opt[i] = -1;\n                            } else {\n                                p.opt[i] = tmp % S;\n                                tmp /= S;\n                            }\n                        }\n                        p.directRow = dr;\n                        p.directD = d;\n                        p.directAfter = after;\n                        computeT(p);\n                        res.push_back(p);\n                    }\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\narray<string, N> makeSortedOutput(const Pattern &pat, const string &cont) {\n    array<string, N> out;\n\n    string big = bigInitScript(pat);\n    if ((int)big.size() < pat.T) big += string(pat.T - (int)big.size(), '.');\n    big += cont;\n    out[0] = big;\n\n    for (int i = 1; i < N; i++) out[i] = smallInitScript(pat, i);\n\n    return out;\n}\n\n/*** handoff mode ***/\n\nint hDirectCode() {\n    return (int)hSmallOpts.size();\n}\n\nint hDirectAfterBase() {\n    return (int)hSmallOpts.size() + 1;\n}\n\nint hDirectAfterOpt(int opt) {\n    int base = hDirectAfterBase();\n    if (base <= opt && opt < base + (int)hSmallOpts.size()) return opt - base;\n    return -1;\n}\n\nbool isHDirectSmall(int row, int opt) {\n    if (A[row][0] != row * N) return false;\n    if (opt == hDirectCode()) return true;\n    return hDirectAfterOpt(opt) >= 0;\n}\n\nint hSmallInitLen(int opt) {\n    const RowOption &ro = hSmallOpts[opt];\n    return ro.len + (4 - ro.finalCol);\n}\n\nstring hSmallInitScript(int opt) {\n    const RowOption &ro = hSmallOpts[opt];\n    string s = ro.act;\n    s.append(4 - ro.finalCol, 'R');\n    return s;\n}\n\nint hSmallInitLenRow(int row, int opt) {\n    if (isHDirectSmall(row, opt)) {\n        int len = 6;\n        int after = hDirectAfterOpt(opt);\n        if (after >= 0) {\n            const RowOption &ro = hSmallOpts[after];\n            len += 4;\n            len += ro.len;\n            len += 4 - ro.finalCol;\n        }\n        return len;\n    }\n    return hSmallInitLen(opt);\n}\n\nstring hSmallInitScriptRow(int row, int opt) {\n    if (isHDirectSmall(row, opt)) {\n        string s = \"PRRRRQ\";\n        int after = hDirectAfterOpt(opt);\n        if (after >= 0) {\n            const RowOption &ro = hSmallOpts[after];\n            s.append(4, 'L');\n            s += ro.act;\n            s.append(4 - ro.finalCol, 'R');\n        }\n        return s;\n    }\n    return hSmallInitScript(opt);\n}\n\nstruct HPattern {\n    int bopt = 0;\n    int bdirectAfter = -2;\n    array<int, N> sopt{};\n    int T = 0;\n    int repC = 0;\n};\n\nstring hPatternKey(const HPattern &p) {\n    string s;\n    s.reserve(40);\n    s += to_string(p.bopt);\n    s.push_back(',');\n    s += to_string(p.bdirectAfter);\n    s.push_back(',');\n    s += to_string(p.repC);\n    for (int i = 1; i < N; i++) {\n        s.push_back(',');\n        s += to_string(p.sopt[i]);\n    }\n    return s;\n}\n\nstruct Row0ExtraPlan {\n    bool ok = false;\n    string script;\n    int p0 = 0;\n    int q0 = 0;\n    int finalC = 0;\n    array<int, N> occ{};\n};\n\nRow0ExtraPlan buildRow0ExtraPlan(int mode, int bopt) {\n    Row0ExtraPlan pl;\n    pl.occ.fill(-1);\n\n    int c = 0;\n    int p0 = 0;\n    int q0 = 0;\n    string s;\n\n    auto moveC = [&](int tc) {\n        while (c < tc) {\n            s.push_back('R');\n            c++;\n        }\n        while (c > tc) {\n            s.push_back('L');\n            c--;\n        }\n    };\n\n    if (mode == -4) {\n        if (A[0][0] != 0) return pl;\n        s = \"PRRRRQ\";\n        c = 4;\n        p0 = 1;\n        q0 = 1;\n        if (p0 < N) pl.occ[0] = A[0][p0];\n    } else if (mode == -5) {\n        if (srcOf[0] != 0) return pl;\n        int pos0 = idxOf[0];\n        if (pos0 < 1 || pos0 > 3) return pl;\n        if (bopt < 0 || bopt >= (int)bigOpts.size()) return pl;\n\n        const RowOption &ro = bigOpts[bopt];\n        if ((int)ro.cols.size() != pos0) return pl;\n\n        s = ro.act;\n        c = ro.finalCol;\n\n        for (int t = 0; t < pos0; t++) {\n            int b = A[0][t];\n            int cc = ro.cols[t];\n            pl.occ[cc] = b;\n        }\n\n        moveC(0);\n        s.push_back('P');\n        p0 = pos0 + 1;\n        if (p0 < N) pl.occ[0] = A[0][p0];\n\n        moveC(4);\n        s.push_back('Q');\n        q0 = 1;\n    } else {\n        return pl;\n    }\n\n    while (q0 < N && srcOf[q0] == 0) {\n        int idx = idxOf[q0];\n\n        if (idx < p0) {\n            int cc = -1;\n            for (int j = 1; j <= 3; j++) {\n                if (pl.occ[j] == q0) {\n                    cc = j;\n                    break;\n                }\n            }\n            if (cc < 0) break;\n\n            moveC(cc);\n            s.push_back('P');\n            pl.occ[cc] = -1;\n\n            moveC(4);\n            s.push_back('Q');\n            q0++;\n        } else if (idx == p0) {\n            if (pl.occ[0] != q0) break;\n\n            moveC(0);\n            s.push_back('P');\n            pl.occ[0] = -1;\n\n            p0++;\n            if (p0 < N) pl.occ[0] = A[0][p0];\n\n            moveC(4);\n            s.push_back('Q');\n            q0++;\n        } else {\n            break;\n        }\n    }\n\n    pl.ok = true;\n    pl.script = s;\n    pl.p0 = p0;\n    pl.q0 = q0;\n    pl.finalC = c;\n    return pl;\n}\n\nint hBigBaseLen(const HPattern &p) {\n    if (p.bdirectAfter == -5 || p.bdirectAfter == -4) {\n        auto pl = buildRow0ExtraPlan(p.bdirectAfter, p.bopt);\n        return pl.ok ? (int)pl.script.size() : INF;\n    }\n    if (p.bdirectAfter == -3) {\n        return bigOpts[p.bopt].len + bigOpts[p.bopt].finalCol + 6;\n    }\n    if (p.bdirectAfter == -2) return bigOpts[p.bopt].len;\n\n    int len = 6;\n    if (p.bdirectAfter >= 0) len += 4 + bigOpts[p.bdirectAfter].len;\n    return len;\n}\n\nint hBigBaseFinalC(const HPattern &p) {\n    if (p.bdirectAfter == -5 || p.bdirectAfter == -4) {\n        auto pl = buildRow0ExtraPlan(p.bdirectAfter, p.bopt);\n        return pl.ok ? pl.finalC : 0;\n    }\n    if (p.bdirectAfter == -3) return 4;\n    if (p.bdirectAfter == -2) return bigOpts[p.bopt].finalCol;\n    if (p.bdirectAfter >= 0) return bigOpts[p.bdirectAfter].finalCol;\n    return 4;\n}\n\nstring hBigBaseScript(const HPattern &p) {\n    if (p.bdirectAfter == -5 || p.bdirectAfter == -4) {\n        auto pl = buildRow0ExtraPlan(p.bdirectAfter, p.bopt);\n        return pl.ok ? pl.script : string();\n    }\n\n    if (p.bdirectAfter == -3) {\n        string s = bigOpts[p.bopt].act;\n        int c = bigOpts[p.bopt].finalCol;\n        s.append(c, 'L');\n        s += \"PRRRRQ\";\n        return s;\n    }\n\n    if (p.bdirectAfter == -2) return bigOpts[p.bopt].act;\n\n    string s = \"PRRRRQ\";\n    if (p.bdirectAfter >= 0) {\n        s.append(4, 'L');\n        s += bigOpts[p.bdirectAfter].act;\n    }\n    return s;\n}\n\nstring hBigInitScript(const HPattern &p) {\n    string s = hBigBaseScript(p);\n    int c = hBigBaseFinalC(p);\n\n    while (c < p.repC) {\n        s.push_back('R');\n        c++;\n    }\n    while (c > p.repC) {\n        s.push_back('L');\n        c--;\n    }\n    return s;\n}\n\nvoid computeHT(HPattern &p) {\n    p.T = hBigBaseLen(p);\n    for (int i = 1; i < N; i++) p.T = max(p.T, hSmallInitLenRow(i, p.sopt[i]));\n}\n\nstruct HState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n\n    int r = 0, c = 0;\n    string act;\n    int eval = 0;\n\n    int nextFree[N];\n    int smallLenRel = 0;\n    uint8_t hcnt[N];\n    short htime[N][N];\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = 0;\n        act.clear();\n        eval = 0;\n        smallLenRel = 0;\n        for (int i = 0; i < N; i++) {\n            nextFree[i] = 0;\n            hcnt[i] = 0;\n            for (int j = 0; j < N; j++) htime[i][j] = 0;\n        }\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) { p[s]++; pcode += pow6_[s]; }\n    void incQ(int d) { q[d]++; qcode += pow6_[d]; }\n\n    void add(char ch) {\n        act.push_back(ch);\n        if (ch == 'U') r--;\n        else if (ch == 'D') r++;\n        else if (ch == 'L') c--;\n        else if (ch == 'R') c++;\n    }\n\n    void moveSafe(int tr, int tc) {\n        if (r > 0 && c == 3 && !(r == tr && c == tc)) add('L');\n\n        if (r != tr) {\n            while (c > 2) add('L');\n            while (r < tr) add('D');\n            while (r > tr) add('U');\n        }\n\n        while (c < tc) add('R');\n        while (c > tc) add('L');\n    }\n\n    void placeHandoff(int d) {\n        moveSafe(d, 2);\n        while ((int)act.size() + 1 < nextFree[d]) add('.');\n        add('R');\n\n        int qtime = (int)act.size();\n        add('Q');\n\n        htime[d][hcnt[d]++] = (short)qtime;\n        smallLenRel = max(smallLenRel, qtime + 5);\n        nextFree[d] = qtime + 4;\n        incQ(d);\n    }\n\n    vector<pair<int, int>> storageOptions(int b, int srcRow, double storageW, int maxOpt) const {\n        vector<tuple<double, int, int, int>> cand;\n        int bd = b / N;\n        int endC = (bd == 0 ? 4 : 3);\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (rr > 0 && cc == 3) continue;\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + abs(endC - cc);\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n                cand.emplace_back(sc, tie, rr, cc);\n            }\n        }\n\n        sort(cand.begin(), cand.end());\n\n        vector<pair<int, int>> res;\n        for (int i = 0; i < (int)cand.size() && i < maxOpt; i++) {\n            res.push_back({get<2>(cand[i]), get<3>(cand[i])});\n        }\n        return res;\n    }\n};\n\ntemplate<class S>\nvoid setupHInitial(S &st, const HPattern &pat) {\n    st.clear();\n\n    if (pat.bdirectAfter == -5 || pat.bdirectAfter == -4) {\n        auto pl = buildRow0ExtraPlan(pat.bdirectAfter, pat.bopt);\n\n        st.q[0] = pl.q0;\n        st.qcode += pl.q0 * pow6_[0];\n\n        st.p[0] = pl.p0;\n        st.pcode += pl.p0 * pow6_[0];\n\n        for (int cc = 0; cc <= 3; cc++) {\n            int b = pl.occ[cc];\n            if (b != -1) {\n                st.occ[0][cc] = b;\n                st.lr[b] = 0;\n                st.lc[b] = cc;\n            }\n        }\n    } else if (pat.bdirectAfter == -3) {\n        int idx0 = idxOf[0];\n        const RowOption &ro = bigOpts[pat.bopt];\n\n        st.q[0] = 1;\n        st.qcode += pow6_[0];\n\n        int cnt = idx0 + 1;\n        st.p[0] = cnt;\n        st.pcode += cnt * pow6_[0];\n\n        for (int t = 0; t < idx0; t++) {\n            int b = A[0][t];\n            int cc = ro.cols[t];\n            st.occ[0][cc] = b;\n            st.lr[b] = 0;\n            st.lc[b] = cc;\n        }\n\n        if (cnt < N) st.occ[0][0] = A[0][cnt];\n    } else if (pat.bdirectAfter == -2) {\n        const RowOption &ro = bigOpts[pat.bopt];\n        int cnt = (int)ro.cols.size();\n        st.p[0] = cnt;\n        st.pcode += cnt * pow6_[0];\n\n        for (int t = 0; t < cnt; t++) {\n            int b = A[0][t];\n            int cc = ro.cols[t];\n            st.occ[0][cc] = b;\n            st.lr[b] = 0;\n            st.lc[b] = cc;\n        }\n        if (cnt < N) st.occ[0][0] = A[0][cnt];\n    } else {\n        st.q[0] = 1;\n        st.qcode += pow6_[0];\n\n        int cnt = 1;\n        if (pat.bdirectAfter >= 0) {\n            const RowOption &ro = bigOpts[pat.bdirectAfter];\n            for (int t = 0; t < (int)ro.cols.size(); t++) {\n                int b = A[0][1 + t];\n                int cc = ro.cols[t];\n                st.occ[0][cc] = b;\n                st.lr[b] = 0;\n                st.lc[b] = cc;\n            }\n            cnt += (int)ro.cols.size();\n        }\n\n        st.p[0] = cnt;\n        st.pcode += cnt * pow6_[0];\n        if (cnt < N) st.occ[0][0] = A[0][cnt];\n    }\n\n    for (int i = 1; i < N; i++) {\n        int opt = pat.sopt[i];\n\n        if (isHDirectSmall(i, opt)) {\n            st.q[i] = 1;\n            st.qcode += pow6_[i];\n\n            int cnt = 1;\n            int after = hDirectAfterOpt(opt);\n            if (after >= 0) {\n                const RowOption &ro = hSmallOpts[after];\n                for (int t = 0; t < (int)ro.cols.size(); t++) {\n                    int b = A[i][1 + t];\n                    int cc = ro.cols[t];\n                    st.occ[i][cc] = b;\n                    st.lr[b] = i;\n                    st.lc[b] = cc;\n                }\n                cnt += (int)ro.cols.size();\n            }\n\n            st.p[i] = cnt;\n            st.pcode += cnt * pow6_[i];\n            if (cnt < N) st.occ[i][0] = A[i][cnt];\n            continue;\n        }\n\n        const RowOption &ro = hSmallOpts[opt];\n        int cnt = (int)ro.cols.size();\n        st.p[i] = cnt;\n        st.pcode += cnt * pow6_[i];\n\n        for (int t = 0; t < cnt; t++) {\n            int b = A[i][t];\n            int cc = ro.cols[t];\n            st.occ[i][cc] = b;\n            st.lr[b] = i;\n            st.lc[b] = cc;\n        }\n        if (cnt < N) st.occ[i][0] = A[i][cnt];\n    }\n\n    st.r = 0;\n    st.c = pat.repC;\n}\n\nHState makeHInitialState(const HPattern &pat) {\n    HState st;\n    setupHInitial(st, pat);\n    st.act.reserve(512);\n    return st;\n}\n\nbool hPlaceOutput(HState &ns, int d) {\n    if (d == 0) {\n        ns.moveSafe(0, 4);\n        ns.add('Q');\n        ns.incQ(0);\n    } else {\n        ns.placeHandoff(d);\n    }\n    return true;\n}\n\nbool doHDispatchBuffered(HState &ns, int d) {\n    int x = N * d + ns.q[d];\n    int rr = ns.lr[x], cc = ns.lc[x];\n    if (rr < 0 || ns.occ[rr][cc] != x) return false;\n\n    ns.moveSafe(rr, cc);\n    ns.add('P');\n    ns.occ[rr][cc] = -1;\n    ns.lr[x] = ns.lc[x] = -1;\n\n    return hPlaceOutput(ns, d);\n}\n\nbool doHDispatchSource(HState &ns, int d) {\n    int x = N * d + ns.q[d];\n    int s = srcOf[x];\n\n    if (ns.p[s] >= N) return false;\n    if (A[s][ns.p[s]] != x) return false;\n    if (ns.occ[s][0] != x) return false;\n\n    ns.moveSafe(s, 0);\n    ns.add('P');\n    ns.occ[s][0] = -1;\n    ns.incP(s);\n    if (ns.p[s] < N) ns.occ[s][0] = A[s][ns.p[s]];\n\n    return hPlaceOutput(ns, d);\n}\n\nvoid expandHBlockers(\n    const HState &cur,\n    int s,\n    int idx,\n    int d,\n    double storageW,\n    int optLimit,\n    vector<HState> &out\n) {\n    if (cur.p[s] == idx) {\n        HState ns = cur;\n        if (doHDispatchSource(ns, d)) out.push_back(std::move(ns));\n        return;\n    }\n\n    if (cur.p[s] > idx) return;\n\n    int b = A[s][cur.p[s]];\n    if (cur.occ[s][0] != b) return;\n\n    HState base = cur;\n    base.moveSafe(s, 0);\n    base.add('P');\n    base.occ[s][0] = -1;\n    base.incP(s);\n    if (base.p[s] < N) base.occ[s][0] = A[s][base.p[s]];\n\n    auto opts = base.storageOptions(b, s, storageW, optLimit);\n    for (auto [rr, cc] : opts) {\n        if (base.occ[rr][cc] != -1) continue;\n\n        HState ns = base;\n        ns.moveSafe(rr, cc);\n        ns.add('Q');\n        ns.occ[rr][cc] = b;\n        ns.lr[b] = rr;\n        ns.lc[b] = cc;\n\n        expandHBlockers(ns, s, idx, d, storageW, optLimit, out);\n    }\n}\n\nvector<HState> expandHExecuteTarget(\n    const HState &st,\n    int d,\n    double storageW,\n    int optLimit,\n    int perTransLimit\n) {\n    vector<HState> res;\n\n    int x = N * d + st.q[d];\n    int s = srcOf[x];\n    int idx = idxOf[x];\n\n    if (idx < st.p[s]) {\n        HState ns = st;\n        if (doHDispatchBuffered(ns, d)) res.push_back(std::move(ns));\n    } else {\n        expandHBlockers(st, s, idx, d, storageW, optLimit, res);\n    }\n\n    if ((int)res.size() > perTransLimit) {\n        sort(res.begin(), res.end(), [](const HState &a, const HState &b) {\n            return max((int)a.act.size(), a.smallLenRel) < max((int)b.act.size(), b.smallLenRel);\n        });\n        res.resize(perTransLimit);\n    }\n\n    return res;\n}\n\ntemplate<class S>\nint nearestHGeneric(const S &st) {\n    if (st.delivered() >= TOT) return 0;\n\n    int best = INF;\n    for (int d = 0; d < N; d++) {\n        TransCode tr;\n        if (!makeHTransCodes(st.pcode, st.qcode, d, tr)) continue;\n        if (dfsHBlock(tr.code) >= INF) continue;\n\n        int x = N * d + st.q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n        int endC = (d == 0 ? 4 : 3);\n\n        int val = INF;\n        if (idx < st.p[s]) {\n            int rr = st.lr[x], cc = st.lc[x];\n            if (rr < 0) continue;\n            val = manhattan(st.r, st.c, rr, cc) + 1\n                + manhattan(rr, cc, d, endC) + 1;\n        } else {\n            val = manhattan(st.r, st.c, s, 0) + 1\n                + manhattan(s, 0, d, endC) + 1;\n        }\n        best = min(best, val);\n    }\n\n    if (best >= INF) return 0;\n    return best / 2;\n}\n\nstruct HPlanResult {\n    bool ok = false;\n    string act;\n    int smallLenRel = 0;\n    array<uint8_t, N> hcnt{};\n    array<array<short, N>, N> htime{};\n};\n\nHPlanResult buildHBeam(const HState &init, double storageW, int width, int hcoef, int optLimit) {\n    if (dfsHBlock(init.code()) >= INF) return {false, \"\", 0, {}, {}};\n\n    vector<HState> beam;\n    beam.push_back(init);\n\n    auto comp = [](const HState &a, const HState &b) {\n        if (a.eval != b.eval) return a.eval < b.eval;\n        return max((int)a.act.size(), a.smallLenRel) < max((int)b.act.size(), b.smallLenRel);\n    };\n\n    int perTransLimit = (optLimit <= 1 ? 1 : 8);\n\n    for (int step = init.delivered(); step < TOT; step++) {\n        vector<HState> cand;\n        cand.reserve((size_t)width * N * perTransLimit);\n\n        for (const HState &st : beam) {\n            if (st.delivered() != step) continue;\n\n            for (int d = 0; d < N; d++) {\n                TransCode tr;\n                if (!makeHTransCodes(st.pcode, st.qcode, d, tr)) continue;\n\n                int remAfter = dfsHBlock(tr.code);\n                if (remAfter >= INF) continue;\n\n                vector<HState> nsList = expandHExecuteTarget(st, d, storageW, optLimit, perTransLimit);\n                for (HState &ns : nsList) {\n                    if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n                    int near = nearestHGeneric(ns);\n                    ns.eval = max((int)ns.act.size(), ns.smallLenRel) + hcoef * remAfter + near;\n                    cand.push_back(std::move(ns));\n                }\n            }\n        }\n\n        if (cand.empty()) return {false, \"\", 0, {}, {}};\n\n        if ((int)cand.size() > width) {\n            nth_element(cand.begin(), cand.begin() + width, cand.end(), comp);\n            cand.resize(width);\n        }\n        sort(cand.begin(), cand.end(), comp);\n        beam.swap(cand);\n    }\n\n    int bestLen = INF;\n    HState bestState;\n    bool found = false;\n\n    for (const HState &st0 : beam) {\n        HState st = st0;\n        if (st.r > 0 && st.c == 3) st.add('L');\n        int len = max((int)st.act.size(), st.smallLenRel);\n        if (len < bestLen) {\n            bestLen = len;\n            bestState = std::move(st);\n            found = true;\n        }\n    }\n\n    if (!found) return {false, \"\", 0, {}, {}};\n\n    HPlanResult res;\n    res.ok = true;\n    res.act = bestState.act;\n    res.smallLenRel = bestState.smallLenRel;\n    for (int i = 0; i < N; i++) {\n        res.hcnt[i] = bestState.hcnt[i];\n        for (int j = 0; j < N; j++) res.htime[i][j] = bestState.htime[i][j];\n    }\n    return res;\n}\n\nstruct HLiteState {\n    array<int, N> p{}, q{};\n    int pcode = 0, qcode = 0;\n    array<int, TOT> lr{}, lc{};\n    int occ[N][N];\n    int r = 0, c = 0, len = 0;\n    int nextFree[N];\n    int smallLenRel = 0;\n\n    void clear() {\n        p.fill(0);\n        q.fill(0);\n        pcode = qcode = 0;\n        lr.fill(-1);\n        lc.fill(-1);\n        for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) occ[i][j] = -1;\n        r = c = len = 0;\n        smallLenRel = 0;\n        for (int i = 0; i < N; i++) nextFree[i] = 0;\n    }\n\n    int code() const { return pcode * PBASE + qcode; }\n    int delivered() const { return sumCode[qcode]; }\n\n    void incP(int s) { p[s]++; pcode += pow6_[s]; }\n    void incQ(int d) { q[d]++; qcode += pow6_[d]; }\n\n    void moveSafe(int tr, int tc) {\n        if (r > 0 && c == 3 && !(r == tr && c == tc)) {\n            len++;\n            c = 2;\n        }\n\n        if (r != tr) {\n            if (c > 2) {\n                len += c - 2;\n                c = 2;\n            }\n            len += abs(r - tr);\n            r = tr;\n        }\n\n        len += abs(c - tc);\n        c = tc;\n    }\n\n    void placeHandoff(int d) {\n        moveSafe(d, 2);\n        while (len + 1 < nextFree[d]) len++;\n        len++;\n        c = 3;\n\n        int qtime = len;\n        len++;\n        smallLenRel = max(smallLenRel, qtime + 5);\n        nextFree[d] = qtime + 4;\n        incQ(d);\n    }\n\n    pair<int, int> chooseStorage(int b, int srcRow, double storageW) const {\n        int bd = b / N;\n        int endC = (bd == 0 ? 4 : 3);\n        double best = 1e100;\n        int bestTie = INF;\n        pair<int, int> res = {-1, -1};\n\n        for (int rr = 0; rr < N; rr++) {\n            for (int cc = 0; cc < N - 1; cc++) {\n                if (rr > 0 && cc == 3) continue;\n                if (occ[rr][cc] != -1) continue;\n                if (cc == 0 && p[rr] < N) continue;\n\n                int ds = abs(srcRow - rr) + cc;\n                int dg = abs(bd - rr) + abs(endC - cc);\n                double sc = 2.0 * ds + storageW * dg;\n                int tie = dg * 100 + ds * 10 - cc;\n\n                if (sc + 1e-9 < best || (fabs(sc - best) <= 1e-9 && tie < bestTie)) {\n                    best = sc;\n                    bestTie = tie;\n                    res = {rr, cc};\n                }\n            }\n        }\n\n        return res;\n    }\n\n    bool placeOutput(int d) {\n        if (d == 0) {\n            moveSafe(0, 4);\n            len++;\n            incQ(0);\n        } else {\n            placeHandoff(d);\n        }\n        return true;\n    }\n\n    bool dispatchBuffered(int d) {\n        int x = N * d + q[d];\n        int rr = lr[x], cc = lc[x];\n        if (rr < 0 || occ[rr][cc] != x) return false;\n\n        moveSafe(rr, cc);\n        len++;\n        occ[rr][cc] = -1;\n        lr[x] = lc[x] = -1;\n\n        return placeOutput(d);\n    }\n\n    bool dispatchSource(int d) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n\n        if (p[s] >= N) return false;\n        if (A[s][p[s]] != x) return false;\n        if (occ[s][0] != x) return false;\n\n        moveSafe(s, 0);\n        len++;\n        occ[s][0] = -1;\n        incP(s);\n        if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n        return placeOutput(d);\n    }\n\n    bool executeTarget(int d, double storageW) {\n        int x = N * d + q[d];\n        int s = srcOf[x];\n        int idx = idxOf[x];\n\n        if (idx < p[s]) return dispatchBuffered(d);\n\n        while (p[s] < idx) {\n            int b = A[s][p[s]];\n            if (occ[s][0] != b) return false;\n\n            moveSafe(s, 0);\n            len++;\n            occ[s][0] = -1;\n            incP(s);\n            if (p[s] < N) occ[s][0] = A[s][p[s]];\n\n            auto cell = chooseStorage(b, s, storageW);\n            if (cell.first < 0) return false;\n\n            moveSafe(cell.first, cell.second);\n            len++;\n            occ[cell.first][cell.second] = b;\n            lr[b] = cell.first;\n            lc[b] = cell.second;\n        }\n\n        return dispatchSource(d);\n    }\n};\n\nHLiteState makeHLiteInitialState(const HPattern &pat) {\n    HLiteState st;\n    setupHInitial(st, pat);\n    return st;\n}\n\nint hGreedyLength(const HPattern &pat, double storageW, int hcoef) {\n    string bs = hBigInitScript(pat);\n    if ((int)bs.size() > pat.T) return INF;\n\n    HLiteState st = makeHLiteInitialState(pat);\n    if (dfsHBlock(st.code()) >= INF) return INF;\n\n    for (int step = st.delivered(); step < TOT; step++) {\n        int bestEval = INF;\n        int bestLen = INF;\n        bool found = false;\n        HLiteState bestSt;\n\n        for (int d = 0; d < N; d++) {\n            TransCode tr;\n            if (!makeHTransCodes(st.pcode, st.qcode, d, tr)) continue;\n            int remAfter = dfsHBlock(tr.code);\n            if (remAfter >= INF) continue;\n\n            HLiteState ns = st;\n            if (!ns.executeTarget(d, storageW)) continue;\n            if (ns.pcode != tr.npcode || ns.qcode != tr.nqcode) continue;\n\n            int curLen = max(ns.len, ns.smallLenRel);\n            int eval = curLen + hcoef * remAfter + nearestHGeneric(ns);\n            if (eval < bestEval || (eval == bestEval && curLen < bestLen)) {\n                bestEval = eval;\n                bestLen = curLen;\n                bestSt = ns;\n                found = true;\n            }\n        }\n\n        if (!found) return INF;\n        st = bestSt;\n    }\n\n    if (st.r > 0 && st.c == 3) st.len++;\n    return pat.T + max(st.len, st.smallLenRel);\n}\n\nvector<HPattern> generateHPatterns() {\n    vector<HPattern> res;\n\n    int B = (int)bigOpts.size();\n    int S = (int)hSmallOpts.size();\n\n    vector<pair<int, int>> bigVars;\n\n    if (A[0][0] == 0) {\n        bigVars.push_back({-1, 0});\n        bigVars.push_back({-4, 0});\n        for (int after = 0; after < B; after++) bigVars.push_back({after, 0});\n    }\n\n    if (srcOf[0] == 0) {\n        int pos0 = idxOf[0];\n        if (1 <= pos0 && pos0 <= 3) {\n            for (int b = 0; b < B; b++) {\n                if ((int)bigOpts[b].cols.size() == pos0) {\n                    bigVars.push_back({-3, b});\n                    bigVars.push_back({-5, b});\n                }\n            }\n        }\n    }\n\n    for (int b = 0; b < B; b++) bigVars.push_back({-2, b});\n\n    vector<int> optList[N];\n    for (int i = 1; i < N; i++) {\n        if (A[i][0] == i * N) optList[i].push_back(hDirectCode());\n        for (int o = 0; o < S; o++) optList[i].push_back(o);\n    }\n\n    for (auto [bdirectAfter, bopt] : bigVars) {\n        int sizes[5] = {};\n        int total = 1;\n        for (int i = 1; i < N; i++) {\n            sizes[i] = (int)optList[i].size();\n            total *= sizes[i];\n        }\n\n        for (int code = 0; code < total; code++) {\n            HPattern base;\n            base.bopt = bopt;\n            base.bdirectAfter = bdirectAfter;\n            base.sopt.fill(0);\n\n            int tmp = code;\n            for (int i = 1; i < N; i++) {\n                int id = tmp % sizes[i];\n                tmp /= sizes[i];\n                base.sopt[i] = optList[i][id];\n            }\n\n            computeHT(base);\n            if (base.T >= INF) continue;\n\n            int finalC = hBigBaseFinalC(base);\n            int slack = base.T - hBigBaseLen(base);\n\n            for (int c = 0; c < N; c++) {\n                if (abs(c - finalC) <= slack) {\n                    HPattern p = base;\n                    p.repC = c;\n                    res.push_back(p);\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\narray<string, N> makeHOutput(const HPattern &pat, const HPlanResult &pr) {\n    array<string, N> out;\n\n    string big = hBigInitScript(pat);\n    if ((int)big.size() < pat.T) big += string(pat.T - (int)big.size(), '.');\n    big += pr.act;\n    out[0] = big;\n\n    for (int i = 1; i < N; i++) {\n        string s = hSmallInitScriptRow(i, pat.sopt[i]);\n        int need = pat.T + pr.smallLenRel;\n        if ((int)s.size() < need) s.resize(need, '.');\n\n        for (int k = 0; k < pr.hcnt[i]; k++) {\n            int t = pat.T + pr.htime[i][k];\n            if ((int)s.size() <= t + 4) s.resize(t + 5, '.');\n            s[t + 1] = 'L';\n            s[t + 2] = 'P';\n            s[t + 3] = 'R';\n            s[t + 4] = 'Q';\n        }\n        out[i] = s;\n    }\n\n    return out;\n}\n\n/*** fallback direct ***/\n\nstring buildDirectPlan() {\n    State st;\n    st.clear();\n    for (int i = 0; i < N; i++) st.occ[i][0] = A[i][0];\n\n    for (int s = 0; s < N; s++) {\n        while (st.p[s] < N) {\n            int x = A[s][st.p[s]];\n            int d = x / N;\n\n            st.moveTo(s, 0);\n            st.add('P');\n            st.occ[s][0] = -1;\n            st.incP(s);\n            if (st.p[s] < N) st.occ[s][0] = A[s][st.p[s]];\n\n            st.moveTo(d, N - 1);\n            st.add('Q');\n        }\n    }\n\n    return st.act;\n}\n\nint directInversions() {\n    vector<int> seq[N];\n    int inv = 0;\n\n    for (int s = 0; s < N; s++) {\n        for (int k = 0; k < N; k++) {\n            int x = A[s][k];\n            int d = x / N;\n            for (int y : seq[d]) {\n                if (y > x) inv++;\n            }\n            seq[d].push_back(x);\n        }\n    }\n\n    return inv;\n}\n\nvoid initTables() {\n    pow6_[0] = 1;\n    for (int i = 0; i < N; i++) pow6_[i + 1] = pow6_[i] * BASE;\n\n    for (int code = 0; code < PBASE; code++) {\n        int tmp = code;\n        int sm = 0, ex = 0;\n        for (int i = 0; i < N; i++) {\n            int v = tmp % BASE;\n            tmp /= BASE;\n            dig[code][i] = (uint8_t)v;\n            sm += v;\n            if (v == N) ex++;\n        }\n        sumCode[code] = (uint8_t)sm;\n        exhCode[code] = (uint8_t)ex;\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    initTables();\n    initRowOptions();\n\n    int Nin;\n    cin >> Nin;\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            cin >> A[i][j];\n            srcOf[A[i][j]] = i;\n            idxOf[A[i][j]] = j;\n        }\n    }\n\n    auto startTime = chrono::steady_clock::now();\n    auto elapsedMs = [&]() -> long long {\n        return chrono::duration_cast<chrono::milliseconds>(\n            chrono::steady_clock::now() - startTime\n        ).count();\n    };\n\n    memoBlock.assign(TOTAL_STATES, -1);\n    memoHBlock.assign(TOTAL_STATES, -1);\n\n    array<string, N> bestOut;\n    long long bestScore = (long long)4e18;\n\n    {\n        string directAct = buildDirectPlan();\n        int inv = directInversions();\n        long long directScore = (long long)directAct.size() + 100LL * inv;\n\n        bestOut[0] = directAct.empty() ? \".\" : directAct;\n        for (int i = 1; i < N; i++) bestOut[i] = \"B\";\n        bestScore = directScore;\n    }\n\n    auto tryUpdateSorted = [&](const Pattern &pat, const string &cont) {\n        if (cont.empty()) return;\n\n        string bs = bigInitScript(pat);\n        if ((int)bs.size() > pat.T) return;\n\n        auto out = makeSortedOutput(pat, cont);\n        int m0 = 0;\n        for (int i = 0; i < N; i++) m0 = max(m0, (int)out[i].size());\n        if (m0 <= 0 || m0 > 10000) return;\n\n        if ((long long)m0 < bestScore) {\n            bestScore = m0;\n            bestOut = out;\n        }\n    };\n\n    auto tryUpdateH = [&](const HPattern &pat, const HPlanResult &pr) {\n        if (!pr.ok) return;\n\n        string bs = hBigInitScript(pat);\n        if ((int)bs.size() > pat.T) return;\n\n        int m0 = max(pat.T + (int)pr.act.size(), pat.T + pr.smallLenRel);\n        if (m0 <= 0 || m0 > 10000) return;\n\n        if ((long long)m0 < bestScore) {\n            bestScore = m0;\n            bestOut = makeHOutput(pat, pr);\n        }\n    };\n\n    vector<Pattern> candidates = generateCandidates();\n\n    vector<pair<int, int>> estimates;\n    estimates.reserve(candidates.size());\n\n    for (int idx = 0; idx < (int)candidates.size(); idx++) {\n        if ((idx & 255) == 0 && elapsedMs() > 1450 && (int)estimates.size() > 80) break;\n\n        int gl = greedyLength(candidates[idx], 1.0, 8);\n        if (gl < INF) estimates.push_back({gl, idx});\n    }\n\n    sort(estimates.begin(), estimates.end());\n\n    vector<Pattern> baseSelected;\n\n    auto addUnique = [&](vector<Pattern> &v, const Pattern &p) {\n        for (const Pattern &q : v) {\n            if (samePattern(p, q)) return;\n        }\n        v.push_back(p);\n    };\n\n    for (int i = 0; i < (int)estimates.size() && i < 60; i++) {\n        addUnique(baseSelected, candidates[estimates[i].second]);\n    }\n\n    for (int so = 0; so < (int)smallOpts.size(); so++) {\n        int bo = -1;\n        for (int b = 0; b < (int)bigOpts.size(); b++) {\n            if (bigOpts[b].cols == smallOpts[so].cols) {\n                bo = b;\n                break;\n            }\n        }\n        if (bo < 0) continue;\n\n        Pattern p;\n        p.opt.fill(so);\n        p.opt[0] = bo;\n        computeT(p);\n        addUnique(baseSelected, p);\n    }\n\n    vector<Pattern> variants;\n    for (const Pattern &p : baseSelected) {\n        for (const Pattern &v : reachableVariants(p)) {\n            addUnique(variants, v);\n        }\n    }\n\n    vector<pair<int, int>> variantEst;\n    for (int i = 0; i < (int)variants.size(); i++) {\n        if ((i & 63) == 0 && elapsedMs() > 1800 && (int)variantEst.size() > 30) break;\n        int gl = greedyLength(variants[i], 1.0, 8);\n        if (gl < INF) variantEst.push_back({gl, i});\n    }\n\n    sort(variantEst.begin(), variantEst.end());\n\n    vector<Pattern> finalPatterns;\n    for (int i = 0; i < (int)variantEst.size() && i < 42; i++) {\n        addUnique(finalPatterns, variants[variantEst[i].second]);\n    }\n    for (int i = 0; i < (int)baseSelected.size() && i < 10; i++) {\n        addUnique(finalPatterns, baseSelected[i]);\n    }\n\n    if (finalPatterns.empty()) {\n        Pattern p;\n        p.opt.fill(0);\n        p.opt[0] = 0;\n        computeT(p);\n        finalPatterns.push_back(p);\n    }\n\n    for (int rank = 0; rank < (int)finalPatterns.size(); rank++) {\n        if (elapsedMs() > 2480) break;\n\n        const Pattern &pat = finalPatterns[rank];\n        State init = makeInitialState(pat);\n\n        if (dfsBlock(init.code()) >= INF) continue;\n\n        {\n            PlanResult pr = buildBeam(init, 1.0, 1, 8, 1);\n            if (pr.ok) tryUpdateSorted(pat, pr.act);\n        }\n\n        vector<double> weights;\n        vector<int> hs;\n        int width;\n\n        if (rank < 6) {\n            weights = {0.0, 0.4, 0.9, 1.8, 4.0};\n            hs = {0, 8};\n            width = 240;\n        } else if (rank < 20) {\n            weights = {0.4, 0.9, 1.8, 3.5};\n            hs = {8};\n            width = 145;\n        } else {\n            weights = {0.9, 2.5};\n            hs = {8};\n            width = 80;\n        }\n\n        for (int h : hs) {\n            for (double w : weights) {\n                if (elapsedMs() > 2520) break;\n\n                PlanResult pr = buildBeam(init, w, width, h, 1);\n                if (pr.ok) tryUpdateSorted(pat, pr.act);\n            }\n        }\n    }\n\n    if (elapsedMs() < 2820) {\n        vector<HPattern> rawHpats = generateHPatterns();\n\n        vector<HPattern> hpats;\n        hpats.reserve(rawHpats.size());\n        unordered_set<string> seenH;\n        seenH.reserve(rawHpats.size() * 2 + 1000);\n\n        for (const HPattern &p : rawHpats) {\n            string key = hPatternKey(p);\n            if (seenH.insert(key).second) hpats.push_back(p);\n        }\n\n        vector<pair<int, int>> hEst;\n        hEst.reserve(hpats.size() + 1000);\n\n        for (int idx = 0; idx < (int)hpats.size(); idx++) {\n            if ((idx & 127) == 0 && elapsedMs() > 2630 && (int)hEst.size() > 30) break;\n            int gl = hGreedyLength(hpats[idx], 1.0, 8);\n            if (gl < INF) hEst.push_back({gl, idx});\n        }\n\n        sort(hEst.begin(), hEst.end());\n\n        if (elapsedMs() < 2680 && !hEst.empty()) {\n            int baseCnt = min(24, (int)hEst.size());\n            int originalHCount = (int)hpats.size();\n\n            auto addVariant = [&](HPattern q) {\n                if (elapsedMs() > 2760) return;\n\n                computeHT(q);\n                if (q.T >= INF) return;\n\n                int baseLen = hBigBaseLen(q);\n                if (baseLen >= INF) return;\n\n                int finalC = hBigBaseFinalC(q);\n                int slack = q.T - baseLen;\n\n                for (int c = 0; c < N; c++) {\n                    if (abs(c - finalC) > slack) continue;\n\n                    HPattern qq = q;\n                    qq.repC = c;\n\n                    string key = hPatternKey(qq);\n                    if (!seenH.insert(key).second) continue;\n\n                    int gl = hGreedyLength(qq, 1.0, 8);\n                    if (gl < INF) {\n                        hpats.push_back(qq);\n                        hEst.push_back({gl, (int)hpats.size() - 1});\n                    }\n                }\n            };\n\n            for (int bi = 0; bi < baseCnt; bi++) {\n                if (elapsedMs() > 2740) break;\n\n                const HPattern base = hpats[hEst[bi].second];\n\n                vector<int> rows;\n                for (int row = 1; row < N; row++) {\n                    if (A[row][0] == row * N) rows.push_back(row);\n                }\n\n                for (int row : rows) {\n                    for (int after = 1; after < (int)hSmallOpts.size(); after++) {\n                        if (elapsedMs() > 2750) break;\n\n                        HPattern q = base;\n                        q.sopt[row] = hDirectAfterBase() + after;\n                        addVariant(q);\n                    }\n                }\n\n                if ((int)rows.size() >= 2 && elapsedMs() < 2740) {\n                    for (int a = 0; a < (int)rows.size(); a++) {\n                        for (int b = a + 1; b < (int)rows.size(); b++) {\n                            for (int afterA = 1; afterA < (int)hSmallOpts.size(); afterA++) {\n                                for (int afterB = 1; afterB < (int)hSmallOpts.size(); afterB++) {\n                                    if (elapsedMs() > 2760) break;\n\n                                    HPattern q = base;\n                                    q.sopt[rows[a]] = hDirectAfterBase() + afterA;\n                                    q.sopt[rows[b]] = hDirectAfterBase() + afterB;\n                                    addVariant(q);\n                                }\n                            }\n                        }\n                    }\n                }\n            }\n\n            if ((int)hpats.size() > originalHCount) {\n                sort(hEst.begin(), hEst.end());\n            }\n        }\n\n        vector<int> hSel;\n        vector<char> used(hpats.size(), 0);\n        auto addHSel = [&](int idx) {\n            if (0 <= idx && idx < (int)hpats.size() && !used[idx]) {\n                used[idx] = 1;\n                hSel.push_back(idx);\n            }\n        };\n\n        for (int i = 0; i < (int)hEst.size() && (int)hSel.size() < 34; i++) {\n            addHSel(hEst[i].second);\n        }\n\n        for (int rank = 0; rank < (int)hSel.size(); rank++) {\n            if (elapsedMs() > 2860) break;\n\n            const HPattern &pat = hpats[hSel[rank]];\n            HState init = makeHInitialState(pat);\n\n            if (dfsHBlock(init.code()) >= INF) continue;\n\n            {\n                HPlanResult pr = buildHBeam(init, 1.0, 1, 8, 1);\n                tryUpdateH(pat, pr);\n            }\n\n            vector<double> weights;\n            int width;\n\n            if (rank < 5) {\n                weights = {0.4, 0.9, 1.8, 3.5};\n                width = 150;\n            } else if (rank < 14) {\n                weights = {0.8, 1.8, 3.0};\n                width = 90;\n            } else {\n                weights = {1.2};\n                width = 55;\n            }\n\n            for (double w : weights) {\n                if (elapsedMs() > 2870) break;\n                HPlanResult pr = buildHBeam(init, w, width, 8, 1);\n                tryUpdateH(pat, pr);\n            }\n\n            if (rank < 3 && elapsedMs() < 2800) {\n                for (double w : {0.8, 2.0}) {\n                    if (elapsedMs() > 2840) break;\n                    HPlanResult pr = buildHBeam(init, w, 65, 8, 2);\n                    tryUpdateH(pat, pr);\n                }\n            }\n        }\n    }\n\n    for (int rank = 0; rank < (int)finalPatterns.size() && rank < 4; rank++) {\n        if (elapsedMs() > 2820) break;\n\n        const Pattern &pat = finalPatterns[rank];\n        State init = makeInitialState(pat);\n\n        for (double w : {0.7, 1.5, 3.0}) {\n            if (elapsedMs() > 2910) break;\n            PlanResult pr = buildBeam(init, w, 65, 8, 2);\n            if (pr.ok) tryUpdateSorted(pat, pr.act);\n        }\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (bestOut[i].empty()) bestOut[i] = \".\";\n        cout << bestOut[i] << '\\n';\n    }\n\n    return 0;\n}","ahc034":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int N = 20;\nstatic const int V = N * N;\nstatic const long long INFLL = (1LL << 60);\nstatic const int INF = 1e9;\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    bool ok(double lim) const { return elapsed() < lim; }\n};\n\nTimer TIMER;\n\nint H[V];\nint DIST[V][V];\nlong long BASE_COST = 0;\n\nint cell_id(int r, int c) { return r * N + c; }\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 Op {\n    char c;\n    int d;\n};\n\nstruct Solution {\n    vector<Op> ops;\n    long long cost = 0;\n    long long load = 0;\n    int pos = 0;\n    bool valid = true;\n\n    Solution() { ops.reserve(4096); }\n\n    void moveOne(char ch) {\n        ops.push_back({ch, 0});\n        cost += 100 + load;\n\n        int r = pos / N;\n        int c = pos % N;\n        if (ch == 'U') --r;\n        if (ch == 'D') ++r;\n        if (ch == 'L') --c;\n        if (ch == 'R') ++c;\n\n        if (r < 0 || r >= N || c < 0 || c >= N) valid = false;\n        pos = cell_id(r, c);\n    }\n\n    void moveTo(int target) {\n        int tr = target / N;\n        int tc = target % N;\n        while (pos / N < tr) moveOne('D');\n        while (pos / N > tr) moveOne('U');\n        while (pos % N < tc) moveOne('R');\n        while (pos % N > tc) moveOne('L');\n    }\n\n    void addLoad(long long d) {\n        while (d > 0) {\n            int x = (int)min<long long>(d, 1000000);\n            ops.push_back({'+', x});\n            cost += x;\n            load += x;\n            d -= x;\n        }\n    }\n\n    void addUnload(long long d) {\n        while (d > 0) {\n            int x = (int)min<long long>(d, 1000000);\n            if (load < x) valid = false;\n            ops.push_back({'-', x});\n            cost += x;\n            load -= x;\n            d -= x;\n        }\n    }\n};\n\narray<int, V> nearestDist(const vector<int>& rem, bool positive, bool& has) {\n    array<int, V> dist;\n    dist.fill(INF);\n    queue<int> q;\n    has = false;\n\n    for (int i = 0; i < V; ++i) {\n        if ((positive && rem[i] > 0) || (!positive && rem[i] < 0)) {\n            dist[i] = 0;\n            q.push(i);\n            has = true;\n        }\n    }\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        int r = v / N;\n        int c = v % N;\n        const int dr[4] = {-1, 1, 0, 0};\n        const int dc[4] = {0, 0, -1, 1};\n\n        for (int k = 0; k < 4; ++k) {\n            int nr = r + dr[k];\n            int nc = c + dc[k];\n            if (nr < 0 || nr >= N || nc < 0 || nc >= N) continue;\n\n            int to = cell_id(nr, nc);\n            if (dist[to] > dist[v] + 1) {\n                dist[to] = dist[v] + 1;\n                q.push(to);\n            }\n        }\n    }\n\n    return dist;\n}\n\nint selectSource(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearNeg,\n    int mode,\n    int maxAmount\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] <= 0) continue;\n        if (maxAmount >= 0 && rem[i] > maxAmount) continue;\n\n        int d = DIST[cur][i];\n        int nd = nearNeg[i] >= INF ? 0 : nearNeg[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * rem[i];\n        } else if (mode == 1) {\n            score = 10000LL * d - 200LL * rem[i];\n        } else {\n            score = 8000LL * d + 3000LL * nd - 50LL * rem[i];\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nint selectDemand(\n    int cur,\n    const vector<int>& rem,\n    const array<int, V>& nearPos,\n    bool hasPos,\n    long long load,\n    int mode\n) {\n    long long bestScore = INFLL;\n    int best = -1;\n\n    for (int i = 0; i < V; ++i) {\n        if (rem[i] >= 0) continue;\n\n        int demand = -rem[i];\n        int del = (int)min<long long>(load, demand);\n        if (del <= 0) continue;\n\n        int d = DIST[cur][i];\n        int future = 0;\n        if (load == del && hasPos && nearPos[i] < INF) future = nearPos[i];\n\n        long long score;\n        if (mode == 0) {\n            score = 10000LL * d - 10LL * del + 1000LL * future;\n        } else if (mode == 1) {\n            score = 1000LL * d * (100 + load) / (del + 10) + 500LL * future;\n        } else {\n            score = 10000LL * d - 200LL * del + 1000LL * future;\n        }\n\n        if (score < bestScore) {\n            bestScore = score;\n            best = i;\n        }\n    }\n\n    return best;\n}\n\nSolution makeGreedySolution(int maxLoad, int ratioNum, int ratioDen, int sourceMode, int demandMode) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 10000; ++iter) {\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            sol.moveTo(p);\n            int a = rem[p];\n            sol.addLoad(a);\n            rem[p] = 0;\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (maxLoad > 0 && hasPos) {\n                int maxAmount = maxLoad - (int)sol.load;\n                if (maxAmount > 0) {\n                    p = selectSource(sol.pos, rem, nearNeg, sourceMode, maxAmount);\n                    if (p >= 0) {\n                        int nearestDemand = nearNeg[sol.pos];\n                        int dp = DIST[sol.pos][p];\n\n                        if (nearestDemand > 0 &&\n                            1LL * dp * ratioDen <= 1LL * nearestDemand * ratioNum) {\n                            takePos = true;\n                        }\n                    }\n                }\n            }\n\n            if (takePos) {\n                sol.moveTo(p);\n                int a = rem[p];\n                sol.addLoad(a);\n                rem[p] = 0;\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                sol.moveTo(q);\n                int x = (int)min<long long>(sol.load, -rem[q]);\n                sol.addUnload(x);\n                rem[q] += x;\n            }\n        }\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nvoid serviceCell(Solution& sol, vector<int>& rem, int cap) {\n    int v = sol.pos;\n\n    if (rem[v] < 0 && sol.load > 0) {\n        long long x = min<long long>(sol.load, -rem[v]);\n        sol.addUnload(x);\n        rem[v] += (int)x;\n    }\n\n    if (rem[v] > 0 && sol.load < cap) {\n        long long x = min<long long>(rem[v], (long long)cap - sol.load);\n        sol.addLoad(x);\n        rem[v] -= (int)x;\n    }\n}\n\nlong long stepScoreForService(int nxt, int target, const vector<int>& rem, long long load, int cap) {\n    long long score = 0;\n\n    if (rem[nxt] < 0 && load > 0) {\n        long long x = min<long long>(load, -rem[nxt]);\n        score -= 100000LL * x;\n        score -= 3000LL * x * DIST[nxt][target];\n    }\n\n    if (rem[nxt] > 0 && load < cap) {\n        long long x = min<long long>(rem[nxt], (long long)cap - load);\n        score -= 20000LL * x;\n        score += 700LL * x * DIST[nxt][target];\n    }\n\n    return score;\n}\n\nvoid moveToService(Solution& sol, int target, vector<int>& rem, int cap, int pathMode) {\n    serviceCell(sol, rem, cap);\n\n    while (sol.pos != target) {\n        int r = sol.pos / N;\n        int c = sol.pos % N;\n        int tr = target / N;\n        int tc = target % N;\n\n        char chosen = 0;\n\n        if (pathMode == 0) {\n            if (r < tr) chosen = 'D';\n            else if (r > tr) chosen = 'U';\n            else if (c < tc) chosen = 'R';\n            else chosen = 'L';\n        } else if (pathMode == 1) {\n            if (c < tc) chosen = 'R';\n            else if (c > tc) chosen = 'L';\n            else if (r < tr) chosen = 'D';\n            else chosen = 'U';\n        } else {\n            vector<pair<char, int>> cand;\n            if (r < tr) cand.push_back({'D', cell_id(r + 1, c)});\n            if (r > tr) cand.push_back({'U', cell_id(r - 1, c)});\n            if (c < tc) cand.push_back({'R', cell_id(r, c + 1)});\n            if (c > tc) cand.push_back({'L', cell_id(r, c - 1)});\n\n            long long best = INFLL;\n            for (auto [ch, id] : cand) {\n                long long sc = stepScoreForService(id, target, rem, sol.load, cap);\n                if (sc < best) {\n                    best = sc;\n                    chosen = ch;\n                }\n            }\n        }\n\n        sol.moveOne(chosen);\n        serviceCell(sol, rem, cap);\n    }\n}\n\nSolution makeGreedyServiceSolution(\n    int cap,\n    int ratioNum,\n    int ratioDen,\n    int sourceMode,\n    int demandMode,\n    int pathMode\n) {\n    Solution sol;\n    vector<int> rem(V);\n    for (int i = 0; i < V; ++i) rem[i] = H[i];\n\n    for (int iter = 0; iter < 20000; ++iter) {\n        serviceCell(sol, rem, cap);\n\n        bool hasPos = false, hasNeg = false;\n        auto nearPos = nearestDist(rem, true, hasPos);\n        auto nearNeg = nearestDist(rem, false, hasNeg);\n\n        if (sol.load == 0) {\n            if (!hasPos) break;\n\n            int p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n            if (p < 0) {\n                sol.valid = false;\n                break;\n            }\n\n            moveToService(sol, p, rem, cap, pathMode);\n        } else {\n            if (!hasNeg) {\n                sol.valid = false;\n                break;\n            }\n\n            bool takePos = false;\n            int p = -1;\n\n            if (sol.load < cap && hasPos) {\n                p = selectSource(sol.pos, rem, nearNeg, sourceMode, -1);\n                if (p >= 0) {\n                    int direct = nearNeg[sol.pos];\n                    int via = DIST[sol.pos][p] + nearNeg[p];\n\n                    if (direct >= INF) direct = 1000;\n                    if (via * ratioDen <= direct * ratioNum + 2 * ratioDen) {\n                        takePos = true;\n                    }\n\n                    if (DIST[sol.pos][p] <= 2 && sol.load < cap * 3LL / 4) {\n                        takePos = true;\n                    }\n                }\n            }\n\n            if (takePos) {\n                moveToService(sol, p, rem, cap, pathMode);\n            } else {\n                int q = selectDemand(sol.pos, rem, nearPos, hasPos, sol.load, demandMode);\n                if (q < 0) {\n                    sol.valid = false;\n                    break;\n                }\n\n                moveToService(sol, q, rem, cap, pathMode);\n            }\n        }\n    }\n\n    serviceCell(sol, rem, cap);\n\n    if (sol.load != 0) sol.valid = false;\n    for (int x : rem) {\n        if (x != 0) sol.valid = false;\n    }\n\n    return sol;\n}\n\nstruct MinCostFlow {\n    struct Edge {\n        int to, rev;\n        long long cap, cost;\n    };\n\n    int n;\n    vector<vector<Edge>> g;\n\n    MinCostFlow(int n_) : n(n_), g(n_) {}\n\n    int addEdge(int fr, int to, long long cap, long long cost) {\n        Edge f{to, (int)g[to].size(), cap, cost};\n        Edge r{fr, (int)g[fr].size(), 0, -cost};\n        g[fr].push_back(f);\n        g[to].push_back(r);\n        return (int)g[fr].size() - 1;\n    }\n\n    pair<long long, long long> minCostFlow(int s, int t, long long maxf) {\n        long long flow = 0;\n        long long cost = 0;\n\n        vector<long long> pot(n, 0), dist(n);\n        vector<int> pv(n), pe(n);\n\n        while (flow < maxf) {\n            fill(dist.begin(), dist.end(), INFLL);\n            dist[s] = 0;\n\n            priority_queue<pair<long long, int>, vector<pair<long long, int>>, greater<pair<long long, int>>> pq;\n            pq.push({0, s});\n\n            while (!pq.empty()) {\n                auto [d, v] = pq.top();\n                pq.pop();\n\n                if (dist[v] != d) continue;\n\n                for (int i = 0; i < (int)g[v].size(); ++i) {\n                    Edge& e = g[v][i];\n                    if (e.cap <= 0) continue;\n\n                    long long nd = d + e.cost + pot[v] - pot[e.to];\n                    if (nd < dist[e.to]) {\n                        dist[e.to] = nd;\n                        pv[e.to] = v;\n                        pe[e.to] = i;\n                        pq.push({nd, e.to});\n                    }\n                }\n            }\n\n            if (dist[t] == INFLL) break;\n\n            for (int v = 0; v < n; ++v) {\n                if (dist[v] < INFLL) pot[v] += dist[v];\n            }\n\n            long long add = maxf - flow;\n            for (int v = t; v != s; v = pv[v]) {\n                add = min(add, g[pv[v]][pe[v]].cap);\n            }\n\n            for (int v = t; v != s; v = pv[v]) {\n                Edge& e = g[pv[v]][pe[v]];\n                e.cap -= add;\n                g[v][e.rev].cap += add;\n                cost += add * e.cost;\n            }\n\n            flow += add;\n        }\n\n        return {flow, cost};\n    }\n};\n\nstruct Flow {\n    int s, t, amount;\n};\n\nvector<Flow> computeMinCostFlows(int variant) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n            total += H[i];\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n    if (total == 0) return {};\n\n    int SRC = 0;\n    int posBase = 1;\n    int negBase = 1 + P;\n    int SNK = 1 + P + Q;\n    int nodes = SNK + 1;\n\n    MinCostFlow mf(nodes);\n\n    for (int i = 0; i < P; ++i) {\n        mf.addEdge(SRC, posBase + i, posAmt[i], 0);\n    }\n\n    for (int j = 0; j < Q; ++j) {\n        mf.addEdge(negBase + j, SNK, negAmt[j], 0);\n    }\n\n    struct Ref {\n        int node, edgeIndex, pi, qi;\n    };\n    vector<Ref> refs;\n\n    const long long CAP = 1e9;\n    const long long W = 100000000LL;\n\n    for (int i = 0; i < P; ++i) {\n        for (int j = 0; j < Q; ++j) {\n            long long tie = 0;\n\n            if (variant != 0) {\n                uint64_t seed = ((uint64_t)variant << 48) ^ ((uint64_t)posCells[i] << 24) ^ (uint64_t)negCells[j];\n                tie = splitmix64(seed) % 1000;\n            }\n\n            long long c = 1LL * DIST[posCells[i]][negCells[j]] * W + tie;\n            int idx = mf.addEdge(posBase + i, negBase + j, CAP, c);\n            refs.push_back({posBase + i, idx, i, j});\n        }\n    }\n\n    mf.minCostFlow(SRC, SNK, total);\n\n    vector<Flow> flows;\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            flows.push_back({posCells[ref.pi], negCells[ref.qi], (int)used});\n        }\n    }\n\n    return flows;\n}\n\nvector<Flow> computeGreedyFlows(int mode) {\n    vector<int> posCells, posAmt, negCells, negAmt;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) {\n            posCells.push_back(i);\n            posAmt.push_back(H[i]);\n        } else if (H[i] < 0) {\n            negCells.push_back(i);\n            negAmt.push_back(-H[i]);\n        }\n    }\n\n    int P = (int)posCells.size();\n    int Q = (int)negCells.size();\n\n    vector<Flow> flows;\n\n    for (int step = 0; step < P + Q + 5; ++step) {\n        long long bestScore = INFLL;\n        int bi = -1, bj = -1;\n\n        for (int i = 0; i < P; ++i) {\n            if (posAmt[i] <= 0) continue;\n\n            for (int j = 0; j < Q; ++j) {\n                if (negAmt[j] <= 0) continue;\n\n                int a = min(posAmt[i], negAmt[j]);\n                int d = DIST[posCells[i]][negCells[j]];\n\n                long long score;\n                if (mode == 0) {\n                    score = 100000LL * d - 700LL * a;\n                } else if (mode == 1) {\n                    score = 100000LL * d\n                          + 150LL * (DIST[0][posCells[i]] + DIST[0][negCells[j]])\n                          - 500LL * a;\n                } else {\n                    score = 100000LL * d\n                          - 1200LL * a\n                          + 20LL * abs(posAmt[i] - negAmt[j]);\n                }\n\n                if (score < bestScore) {\n                    bestScore = score;\n                    bi = i;\n                    bj = j;\n                }\n            }\n        }\n\n        if (bi < 0) break;\n\n        int a = min(posAmt[bi], negAmt[bj]);\n        flows.push_back({posCells[bi], negCells[bj], a});\n        posAmt[bi] -= a;\n        negAmt[bj] -= a;\n    }\n\n    return flows;\n}\n\nvector<int> optimizeOrder(const vector<int>& starts, const vector<int>& ends) {\n    int m = (int)starts.size();\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    vector<int> startLink(m);\n    vector<vector<int>> link(m, vector<int>(m));\n\n    for (int i = 0; i < m; ++i) {\n        startLink[i] = DIST[0][starts[i]];\n    }\n\n    for (int i = 0; i < m; ++i) {\n        for (int j = 0; j < m; ++j) {\n            link[i][j] = DIST[ends[i]][starts[j]];\n        }\n    }\n\n    auto L = [&](int prev, int cur) -> int {\n        if (prev < 0) return startLink[cur];\n        return link[prev][cur];\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n\n    for (int cnt = 0; cnt < m; ++cnt) {\n        int bestG = -1, bestPos = 0;\n        int bestInc = INF;\n\n        for (int g = 0; g < m; ++g) {\n            if (used[g]) continue;\n\n            for (int p = 0; p <= (int)order.size(); ++p) {\n                int prev = (p == 0 ? -1 : order[p - 1]);\n                int nxt = (p == (int)order.size() ? -2 : order[p]);\n\n                int inc = L(prev, g);\n                if (nxt != -2) inc += L(g, nxt) - L(prev, nxt);\n\n                if (inc < bestInc) {\n                    bestInc = inc;\n                    bestG = g;\n                    bestPos = p;\n                }\n            }\n        }\n\n        order.insert(order.begin() + bestPos, bestG);\n        used[bestG] = true;\n    }\n\n    for (int pass = 0; pass < 30; ++pass) {\n        int bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prev = (i == 0 ? -1 : order[i - 1]);\n            int nxt = (i + 1 == m ? -2 : order[i + 1]);\n\n            int oldRemove = L(prev, x);\n            if (nxt != -2) oldRemove += L(x, nxt);\n\n            int newRemove = 0;\n            if (nxt != -2) newRemove += L(prev, nxt);\n\n            int removeDelta = newRemove - oldRemove;\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int oldInsert = 0;\n                if (after != -2) oldInsert += L(before, after);\n\n                int newInsert = L(before, x);\n                if (after != -2) newInsert += L(x, after);\n\n                int delta = removeDelta + newInsert - oldInsert;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            int oldInternal = 0;\n            int newInternal = 0;\n            int prev = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += L(order[r - 1], order[r]);\n                newInternal += L(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                int oldCost = L(prev, order[l]) + oldInternal;\n                if (after != -2) oldCost += L(order[r], after);\n\n                int newCost = L(prev, order[r]) + newInternal;\n                if (after != -2) newCost += L(order[l], after);\n\n                int delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else if (bestType == 2) {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nstruct SourceGroup {\n    int source = -1;\n    int total = 0;\n    int end = -1;\n    vector<int> dest, amt, order;\n};\n\nvoid computeSourceOrder(SourceGroup& g, int target) {\n    int k = (int)g.dest.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            dp[idx(mask, j)] = 1LL * DIST[g.source][g.dest[j]] * (100 + total);\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = total - sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.dest[last]][g.dest[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)];\n            if (target >= 0) c += 100LL * DIST[g.dest[last]][target];\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = g.source;\n        int load = total;\n\n        for (int left = k; left > 0; --left) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score = 1LL * DIST[cur][g.dest[j]] * (100 + load);\n                if (left == 1 && target >= 0) {\n                    score += 100LL * DIST[g.dest[j]][target];\n                }\n\n                score -= 5LL * g.amt[j];\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.dest[bj];\n            load -= g.amt[bj];\n        }\n    }\n\n    g.end = g.dest[g.order.back()];\n}\n\nvector<SourceGroup> buildSourceGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.s].push_back({f.t, f.amount});\n    }\n\n    vector<SourceGroup> groups;\n\n    for (int s = 0; s < V; ++s) {\n        if (mp[s].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [t, a] : mp[s]) comb[t] += a;\n\n        SourceGroup g;\n        g.source = s;\n\n        for (auto [t, a] : comb) {\n            g.dest.push_back(t);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeSourceOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeSourceGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildSourceGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].source;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n            computeSourceOrder(groups[gi], target);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].source;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int target = (p + 1 < m ? groups[order[p + 1]].source : -1);\n        computeSourceOrder(groups[gi], target);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        sol.moveTo(g.source);\n        sol.addLoad(g.total);\n\n        for (int idx : g.order) {\n            sol.moveTo(g.dest[idx]);\n            sol.addUnload(g.amt[idx]);\n        }\n    }\n\n    return sol;\n}\n\nSolution makePairSolution(const vector<Flow>& flows) {\n    Solution sol;\n    int m = (int)flows.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = flows[i].s;\n        ends[i] = flows[i].t;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int idx : order) {\n        const auto& f = flows[idx];\n\n        sol.moveTo(f.s);\n        sol.addLoad(f.amount);\n        sol.moveTo(f.t);\n        sol.addUnload(f.amount);\n    }\n\n    return sol;\n}\n\nstruct DemandGroup {\n    int demand = -1;\n    int total = 0;\n    int start = -1;\n    int end = -1;\n    vector<int> src, amt, order;\n};\n\nvoid computeDemandOrder(DemandGroup& g, int prevCell) {\n    int k = (int)g.src.size();\n    g.order.clear();\n\n    if (k == 0) return;\n\n    const int DP_LIMIT = 14;\n    int total = g.total;\n\n    if (k <= DP_LIMIT) {\n        int SZ = 1 << k;\n        vector<int> sumAmt(SZ, 0);\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int b = __builtin_ctz(mask);\n            sumAmt[mask] = sumAmt[mask ^ (1 << b)] + g.amt[b];\n        }\n\n        vector<long long> dp(SZ * k, INFLL);\n        vector<int> par(SZ * k, -2);\n\n        auto idx = [&](int mask, int last) {\n            return mask * k + last;\n        };\n\n        for (int j = 0; j < k; ++j) {\n            int mask = 1 << j;\n            long long entry = 0;\n            if (prevCell >= 0) entry = 100LL * DIST[prevCell][g.src[j]];\n\n            dp[idx(mask, j)] = entry;\n            par[idx(mask, j)] = -1;\n        }\n\n        for (int mask = 1; mask < SZ; ++mask) {\n            int curLoad = sumAmt[mask];\n\n            for (int last = 0; last < k; ++last) {\n                if (!(mask & (1 << last))) continue;\n\n                long long cur = dp[idx(mask, last)];\n                if (cur >= INFLL / 2) continue;\n\n                for (int nxt = 0; nxt < k; ++nxt) {\n                    if (mask & (1 << nxt)) continue;\n\n                    int nmask = mask | (1 << nxt);\n                    long long nc = cur + 1LL * DIST[g.src[last]][g.src[nxt]] * (100 + curLoad);\n                    int id = idx(nmask, nxt);\n\n                    if (nc < dp[id]) {\n                        dp[id] = nc;\n                        par[id] = last;\n                    }\n                }\n            }\n        }\n\n        int full = SZ - 1;\n        long long best = INFLL;\n        int bestLast = -1;\n\n        for (int last = 0; last < k; ++last) {\n            long long c = dp[idx(full, last)] + 1LL * DIST[g.src[last]][g.demand] * (100 + total);\n\n            if (c < best) {\n                best = c;\n                bestLast = last;\n            }\n        }\n\n        vector<int> rev;\n        int mask = full;\n        int last = bestLast;\n\n        while (last != -1) {\n            rev.push_back(last);\n            int p = par[idx(mask, last)];\n            mask ^= 1 << last;\n            last = p;\n        }\n\n        reverse(rev.begin(), rev.end());\n        g.order = rev;\n    } else {\n        vector<char> used(k, false);\n        int cur = -1;\n        int load = 0;\n\n        for (int step = 0; step < k; ++step) {\n            long long best = INFLL;\n            int bj = -1;\n\n            for (int j = 0; j < k; ++j) {\n                if (used[j]) continue;\n\n                long long score;\n\n                if (step == 0) {\n                    score = 0;\n                    if (prevCell >= 0) score += 100LL * DIST[prevCell][g.src[j]];\n                    score -= 50LL * DIST[g.src[j]][g.demand];\n                } else {\n                    score = 1LL * DIST[cur][g.src[j]] * (100 + load)\n                          + 10LL * DIST[g.src[j]][g.demand];\n                }\n\n                if (score < best) {\n                    best = score;\n                    bj = j;\n                }\n            }\n\n            used[bj] = true;\n            g.order.push_back(bj);\n            cur = g.src[bj];\n            load += g.amt[bj];\n        }\n    }\n\n    g.start = g.src[g.order.front()];\n    g.end = g.demand;\n}\n\nvector<DemandGroup> buildDemandGroups(const vector<Flow>& flows) {\n    vector<vector<pair<int, int>>> mp(V);\n\n    for (auto& f : flows) {\n        mp[f.t].push_back({f.s, f.amount});\n    }\n\n    vector<DemandGroup> groups;\n\n    for (int t = 0; t < V; ++t) {\n        if (mp[t].empty()) continue;\n\n        map<int, int> comb;\n        for (auto [s, a] : mp[t]) comb[s] += a;\n\n        DemandGroup g;\n        g.demand = t;\n\n        for (auto [s, a] : comb) {\n            g.src.push_back(s);\n            g.amt.push_back(a);\n            g.total += a;\n        }\n\n        computeDemandOrder(g, -1);\n        groups.push_back(g);\n    }\n\n    return groups;\n}\n\nSolution makeDemandGroupSolution(const vector<Flow>& flows) {\n    Solution sol;\n    auto groups = buildDemandGroups(flows);\n    int m = (int)groups.size();\n\n    if (m == 0) return sol;\n\n    vector<int> starts(m), ends(m);\n\n    for (int i = 0; i < m; ++i) {\n        starts[i] = groups[i].start;\n        ends[i] = groups[i].end;\n    }\n\n    vector<int> order = optimizeOrder(starts, ends);\n\n    for (int round = 0; round < 1; ++round) {\n        for (int p = 0; p < m; ++p) {\n            int gi = order[p];\n            int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n            computeDemandOrder(groups[gi], prev);\n        }\n\n        for (int i = 0; i < m; ++i) {\n            starts[i] = groups[i].start;\n            ends[i] = groups[i].end;\n        }\n\n        order = optimizeOrder(starts, ends);\n    }\n\n    for (int p = 0; p < m; ++p) {\n        int gi = order[p];\n        int prev = (p == 0 ? 0 : groups[order[p - 1]].demand);\n        computeDemandOrder(groups[gi], prev);\n    }\n\n    for (int gi : order) {\n        auto& g = groups[gi];\n\n        for (int idx : g.order) {\n            sol.moveTo(g.src[idx]);\n            sol.addLoad(g.amt[idx]);\n        }\n\n        sol.moveTo(g.demand);\n        sol.addUnload(g.total);\n    }\n\n    return sol;\n}\n\nstruct EdgeJob {\n    int s, t, amount;\n};\n\nlong long edgeTieCost(int variant, int u, int v) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    int ar2 = r1 + r2;\n    int ac2 = c1 + c2;\n\n    if (variant == 0) return 0;\n    if (variant == 1) return ar2 + ac2;\n    if (variant == 2) return (2 * (N - 1) - ar2) + (2 * (N - 1) - ac2);\n    if (variant == 3) return abs(ar2 - (N - 1)) + abs(ac2 - (N - 1));\n\n    uint64_t seed = ((uint64_t)variant << 40) ^ ((uint64_t)u << 20) ^ (uint64_t)v;\n    return splitmix64(seed) % 50;\n}\n\nvoid addSignedEdgeFlow(vector<long long>& right, vector<long long>& down, int u, int v, long long a) {\n    int r1 = u / N, c1 = u % N;\n    int r2 = v / N, c2 = v % N;\n\n    if (r1 == r2) {\n        if (c2 == c1 + 1) {\n            right[r1 * (N - 1) + c1] += a;\n        } else if (c2 == c1 - 1) {\n            right[r1 * (N - 1) + c2] -= a;\n        }\n    } else if (c1 == c2) {\n        if (r2 == r1 + 1) {\n            down[r1 * N + c1] += a;\n        } else if (r2 == r1 - 1) {\n            down[r2 * N + c1] -= a;\n        }\n    }\n}\n\nvector<EdgeJob> signedToEdgeJobs(const vector<long long>& right, const vector<long long>& down) {\n    vector<EdgeJob> jobs;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c + 1 < N; ++c) {\n            long long f = right[r * (N - 1) + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r, c + 1), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r, c + 1), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    for (int r = 0; r + 1 < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            long long f = down[r * N + c];\n\n            if (f > 0) {\n                jobs.push_back({cell_id(r, c), cell_id(r + 1, c), (int)f});\n            } else if (f < 0) {\n                jobs.push_back({cell_id(r + 1, c), cell_id(r, c), (int)(-f)});\n            }\n        }\n    }\n\n    return jobs;\n}\n\nvector<EdgeJob> computeGridEdgeJobs(int variant) {\n    long long total = 0;\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) total += H[i];\n    }\n\n    if (total == 0) return {};\n\n    int SRC = V;\n    int SNK = V + 1;\n    MinCostFlow mf(V + 2);\n\n    for (int i = 0; i < V; ++i) {\n        if (H[i] > 0) mf.addEdge(SRC, i, H[i], 0);\n        if (H[i] < 0) mf.addEdge(i, SNK, -H[i], 0);\n    }\n\n    struct Ref {\n        int u, v, node, edgeIndex;\n    };\n\n    vector<Ref> refs;\n\n    const long long CAP = 1000000000LL;\n    const long long W = 100000LL;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int u = cell_id(r, c);\n\n            if (r + 1 < N) {\n                int v = cell_id(r + 1, c);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n\n            if (c + 1 < N) {\n                int v = cell_id(r, c + 1);\n\n                int idx1 = mf.addEdge(u, v, CAP, W + edgeTieCost(variant, u, v));\n                refs.push_back({u, v, u, idx1});\n\n                int idx2 = mf.addEdge(v, u, CAP, W + edgeTieCost(variant, v, u));\n                refs.push_back({v, u, v, idx2});\n            }\n        }\n    }\n\n    auto [flow, cost] = mf.minCostFlow(SRC, SNK, total);\n    if (flow != total) return {};\n\n    vector<long long> right(N * (N - 1), 0), down((N - 1) * N, 0);\n\n    for (auto& ref : refs) {\n        long long used = CAP - mf.g[ref.node][ref.edgeIndex].cap;\n        if (used > 0) {\n            addSignedEdgeFlow(right, down, ref.u, ref.v, used);\n        }\n    }\n\n    return signedToEdgeJobs(right, down);\n}\n\nvector<int> optimizeEdgeOrder(const vector<EdgeJob>& jobs) {\n    int m = (int)jobs.size();\n\n    if (m == 0) return {};\n    if (m == 1) return {0};\n\n    auto link = [&](int a, int b) -> long long {\n        if (b == -2) {\n            if (a == -1) return 0;\n            return jobs[a].amount;\n        }\n\n        if (a == -1) {\n            return 100LL * DIST[0][jobs[b].s] + jobs[b].amount;\n        }\n\n        if (jobs[a].t == jobs[b].s) {\n            return llabs((long long)jobs[a].amount - jobs[b].amount);\n        }\n\n        return jobs[a].amount\n             + 100LL * DIST[jobs[a].t][jobs[b].s]\n             + jobs[b].amount;\n    };\n\n    vector<int> order;\n    vector<char> used(m, false);\n    int prev = -1;\n\n    for (int k = 0; k < m; ++k) {\n        long long best = INFLL;\n        int bj = -1;\n\n        for (int j = 0; j < m; ++j) {\n            if (used[j]) continue;\n\n            long long sc = link(prev, j);\n            if (sc < best) {\n                best = sc;\n                bj = j;\n            }\n        }\n\n        used[bj] = true;\n        order.push_back(bj);\n        prev = bj;\n    }\n\n    int maxPass = (m > 500 ? 5 : 10);\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        long long bestDelta = 0;\n        int bestType = 0;\n        int bestI = -1, bestP = -1;\n        int bestL = -1, bestR = -1;\n\n        for (int i = 0; i < m; ++i) {\n            int x = order[i];\n            int prevNode = (i == 0 ? -1 : order[i - 1]);\n            int nextNode = (i + 1 == m ? -2 : order[i + 1]);\n\n            long long removeDelta = link(prevNode, nextNode) - link(prevNode, x) - link(x, nextNode);\n\n            for (int p = 0; p <= m - 1; ++p) {\n                int before;\n\n                if (p == 0) {\n                    before = -1;\n                } else {\n                    int idx = p - 1;\n                    before = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                int after;\n\n                if (p == m - 1) {\n                    after = -2;\n                } else {\n                    int idx = p;\n                    after = (idx < i ? order[idx] : order[idx + 1]);\n                }\n\n                long long delta = removeDelta\n                                + link(before, x)\n                                + link(x, after)\n                                - link(before, after);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 1;\n                    bestI = i;\n                    bestP = p;\n                }\n            }\n        }\n\n        for (int l = 0; l + 1 < m; ++l) {\n            long long oldInternal = 0;\n            long long newInternal = 0;\n            int before = (l == 0 ? -1 : order[l - 1]);\n\n            for (int r = l + 1; r < m; ++r) {\n                oldInternal += link(order[r - 1], order[r]);\n                newInternal += link(order[r], order[r - 1]);\n\n                int after = (r + 1 == m ? -2 : order[r + 1]);\n\n                long long oldCost = link(before, order[l]) + oldInternal + link(order[r], after);\n                long long newCost = link(before, order[r]) + newInternal + link(order[l], after);\n\n                long long delta = newCost - oldCost;\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestType = 2;\n                    bestL = l;\n                    bestR = r;\n                }\n            }\n        }\n\n        if (bestDelta >= 0) break;\n\n        if (bestType == 1) {\n            int x = order[bestI];\n            order.erase(order.begin() + bestI);\n            order.insert(order.begin() + bestP, x);\n        } else {\n            reverse(order.begin() + bestL, order.begin() + bestR + 1);\n        }\n    }\n\n    return order;\n}\n\nSolution makeEdgeRelaySolution(const vector<EdgeJob>& jobs) {\n    Solution sol;\n\n    vector<long long> delta(V, 0);\n\n    for (auto& e : jobs) {\n        if (DIST[e.s][e.t] != 1 || e.amount <= 0) {\n            sol.valid = false;\n            return sol;\n        }\n\n        delta[e.s] -= e.amount;\n        delta[e.t] += e.amount;\n    }\n\n    for (int i = 0; i < V; ++i) {\n        if (delta[i] != -H[i]) {\n            sol.valid = false;\n            return sol;\n        }\n    }\n\n    if (jobs.empty()) return sol;\n\n    vector<int> order = optimizeEdgeOrder(jobs);\n\n    for (int idx : order) {\n        const auto& e = jobs[idx];\n\n        if (sol.pos != e.s) {\n            if (sol.load > 0) sol.addUnload(sol.load);\n            sol.moveTo(e.s);\n        }\n\n        if (sol.load < e.amount) {\n            sol.addLoad(e.amount - sol.load);\n        } else if (sol.load > e.amount) {\n            sol.addUnload(sol.load - e.amount);\n        }\n\n        sol.moveTo(e.t);\n    }\n\n    if (sol.load > 0) sol.addUnload(sol.load);\n\n    return sol;\n}\n\nSolution makeGridRelaySolution(int variant) {\n    vector<EdgeJob> jobs = computeGridEdgeJobs(variant);\n    return makeEdgeRelaySolution(jobs);\n}\n\npair<int, int> transformCoord(int r, int c, int type) {\n    if (type == 0) return {r, c};\n    if (type == 1) return {c, N - 1 - r};\n    if (type == 2) return {N - 1 - r, N - 1 - c};\n    if (type == 3) return {N - 1 - c, r};\n    if (type == 4) return {r, N - 1 - c};\n    if (type == 5) return {N - 1 - r, c};\n    if (type == 6) return {c, r};\n    return {N - 1 - c, N - 1 - r};\n}\n\nSolution makeCycleSolution() {\n    vector<pair<int, int>> base;\n\n    for (int i = 0; i < N; ++i) base.push_back({i, 0});\n\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) base.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) base.push_back({i, j});\n        }\n    }\n\n    for (int j = N - 1; j >= 1; --j) base.push_back({0, j});\n\n    long long bestCost = INFLL;\n    vector<int> bestCycle;\n    int bestStart = -1;\n\n    for (int type = 0; type < 8; ++type) {\n        vector<int> cyc;\n        cyc.reserve(V);\n\n        for (auto [r, c] : base) {\n            auto [nr, nc] = transformCoord(r, c, type);\n            cyc.push_back(cell_id(nr, nc));\n        }\n\n        for (int rev = 0; rev < 2; ++rev) {\n            if (rev) reverse(cyc.begin(), cyc.end());\n\n            for (int s = 0; s < V; ++s) {\n                long long load = 0;\n                long long cost = BASE_COST + 100LL * DIST[0][cyc[s]];\n                bool ok = true;\n\n                for (int k = 0; k < V; ++k) {\n                    int id = cyc[(s + k) % V];\n                    load += H[id];\n\n                    if (load < 0) {\n                        ok = false;\n                        break;\n                    }\n\n                    if (k + 1 < V) {\n                        int nxt = cyc[(s + k + 1) % V];\n                        cost += 1LL * DIST[id][nxt] * (100 + load);\n                    }\n                }\n\n                if (ok && cost < bestCost) {\n                    bestCost = cost;\n                    bestCycle = cyc;\n                    bestStart = s;\n                }\n            }\n\n            if (rev) reverse(cyc.begin(), cyc.end());\n        }\n    }\n\n    Solution sol;\n\n    if (bestStart < 0) {\n        sol.valid = false;\n        return sol;\n    }\n\n    sol.moveTo(bestCycle[bestStart]);\n\n    for (int k = 0; k < V; ++k) {\n        int id = bestCycle[(bestStart + k) % V];\n\n        if (H[id] > 0) sol.addLoad(H[id]);\n        else if (H[id] < 0) sol.addUnload(-H[id]);\n\n        if (k + 1 < V) {\n            int nxt = bestCycle[(bestStart + k + 1) % V];\n            sol.moveTo(nxt);\n        }\n    }\n\n    return sol;\n}\n\nstruct Event {\n    int cell;\n    int delta;\n};\n\nstruct EventEval {\n    long long cost;\n    int rot;\n};\n\nEventEval evalEventOrder(const vector<Event>& ev) {\n    int m = (int)ev.size();\n    if (m == 0) return {BASE_COST == 0 ? 0 : INFLL, -1};\n\n    vector<long long> cum(m + 1, 0);\n    long long handling = 0;\n\n    for (int i = 0; i < m; ++i) {\n        cum[i + 1] = cum[i] + ev[i].delta;\n        handling += llabs((long long)ev[i].delta);\n    }\n\n    if (cum[m] != 0) return {INFLL, -1};\n\n    long long mn = cum[0];\n    for (int i = 1; i < m; ++i) mn = min(mn, cum[i]);\n\n    long long cyclicMove = 0;\n    for (int i = 0; i < m; ++i) {\n        int j = (i + 1) % m;\n        long long loadAfter = cum[i + 1] - mn;\n        if (loadAfter < 0) return {INFLL, -1};\n        cyclicMove += 1LL * DIST[ev[i].cell][ev[j].cell] * (100 + loadAfter);\n    }\n\n    long long best = INFLL;\n    int bestRot = -1;\n\n    for (int r = 0; r < m; ++r) {\n        if (cum[r] != mn) continue;\n\n        int pred = (r + m - 1) % m;\n        long long omitted = 100LL * DIST[ev[pred].cell][ev[r].cell];\n        long long c = handling + cyclicMove - omitted + 100LL * DIST[0][ev[r].cell];\n\n        if (c < best) {\n            best = c;\n            bestRot = r;\n        }\n    }\n\n    return {best, bestRot};\n}\n\nSolution makeEventSequenceSolution(const vector<Event>& ev) {\n    Solution sol;\n\n    if (ev.empty()) {\n        if (BASE_COST != 0) sol.valid = false;\n        return sol;\n    }\n\n    vector<long long> sum(V, 0);\n    for (auto& e : ev) sum[e.cell] += e.delta;\n\n    for (int i = 0; i < V; ++i) {\n        if (sum[i] != H[i]) {\n            sol.valid = false;\n            return sol;\n        }\n    }\n\n    EventEval ee = evalEventOrder(ev);\n    if (ee.rot < 0 || ee.cost >= INFLL / 2) {\n        sol.valid = false;\n        return sol;\n    }\n\n    int m = (int)ev.size();\n    int step = 0;\n\n    while (step < m) {\n        int idx = (ee.rot + step) % m;\n        int cell = ev[idx].cell;\n        long long d = ev[idx].delta;\n        ++step;\n\n        while (step < m) {\n            int idx2 = (ee.rot + step) % m;\n            if (ev[idx2].cell != cell) break;\n\n            if ((d > 0 && ev[idx2].delta > 0) || (d < 0 && ev[idx2].delta < 0)) {\n                d += ev[idx2].delta;\n                ++step;\n            } else {\n                break;\n            }\n        }\n\n        sol.moveTo(cell);\n        if (d > 0) sol.addLoad(d);\n        else sol.addUnload(-d);\n    }\n\n    if (sol.load != 0) sol.valid = false;\n    return sol;\n}\n\nuint64_t hashEvents(const vector<Event>& ev) {\n    uint64_t h = ev.size() + 1234567;\n    for (auto& e : ev) {\n        uint64_t key = ((uint64_t)e.cell << 32) ^ (uint32_t)(e.delta + 1000007);\n        h = splitmix64(h ^ key);\n    }\n    return h;\n}\n\nvector<Event> eventsFromCellOrder(const vector<int>& cells) {\n    vector<Event> ev;\n\n    for (int id : cells) {\n        int x = H[id];\n        if (x == 0) continue;\n        ev.push_back({id, x});\n    }\n\n    return ev;\n}\n\nint hilbertIndex(int x, int y) {\n    int n = 32;\n    int d = 0;\n\n    for (int s = n / 2; s > 0; s >>= 1) {\n        int rx = (x & s) ? 1 : 0;\n        int ry = (y & s) ? 1 : 0;\n\n        d += s * s * ((3 * rx) ^ ry);\n\n        if (ry == 0) {\n            if (rx == 1) {\n                x = s - 1 - x;\n                y = s - 1 - y;\n            }\n            swap(x, y);\n        }\n    }\n\n    return d;\n}\n\nint mortonIndex(int x, int y) {\n    int d = 0;\n    for (int b = 0; b < 5; ++b) {\n        d |= ((y >> b) & 1) << (2 * b);\n        d |= ((x >> b) & 1) << (2 * b + 1);\n    }\n    return d;\n}\n\nvector<int> makeGreedyCellOrder(int mode) {\n    vector<char> used(V, false);\n    int remCnt = 0;\n    for (int i = 0; i < V; ++i) if (H[i] != 0) ++remCnt;\n\n    vector<int> order;\n    order.reserve(remCnt);\n\n    long long load = 0;\n    int cur = 0;\n\n    for (int step = 0; step < remCnt; ++step) {\n        long long bestScore = INFLL;\n        int best = -1;\n\n        for (int i = 0; i < V; ++i) {\n            if (H[i] == 0 || used[i]) continue;\n            if (H[i] < 0 && load < -H[i]) continue;\n\n            long long d = DIST[cur][i];\n            long long a = abs(H[i]);\n            long long nh = load + H[i];\n\n            long long score;\n            if (mode == 0) {\n                score = d * (100 + load) + (H[i] > 0 ? 2000 + 50 * a : -1000 * a);\n            } else if (mode == 1) {\n                long long target = 150;\n                score = d * (100 + load) + llabs(nh - target) * 80 + (H[i] > 0 ? 500 : 0);\n            } else if (mode == 2) {\n                long long target = 350;\n                score = d * (100 + load) + llabs(nh - target) * 40 + (H[i] > 0 ? 200 : 0);\n            } else if (mode == 3) {\n                score = 10000LL * d - (H[i] < 0 ? 500LL * a : 100LL * a) + 20LL * nh;\n            } else if (mode == 4) {\n                if (load < 200) {\n                    score = d * (100 + load) + (H[i] > 0 ? -200LL * a : 5000LL - 100LL * a);\n                } else {\n                    score = d * (100 + load) + (H[i] > 0 ? 1500LL : -800LL * a);\n                }\n            } else {\n                score = d * (100 + load) / (a + 5) + (H[i] > 0 ? 200 : -300);\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best = i;\n            }\n        }\n\n        if (best < 0) {\n            for (int i = 0; i < V; ++i) {\n                if (H[i] > 0 && !used[i]) {\n                    int d = DIST[cur][i];\n                    if (d < bestScore) {\n                        bestScore = d;\n                        best = i;\n                    }\n                }\n            }\n        }\n\n        if (best < 0) break;\n\n        used[best] = true;\n        order.push_back(best);\n        load += H[best];\n        cur = best;\n\n        if (load < 0) break;\n    }\n\n    return order;\n}\n\nvector<int> makeNearestCellOrder(int mode) {\n    vector<char> used(V, false);\n    int cnt = 0;\n    for (int i = 0; i < V; ++i) if (H[i] != 0) ++cnt;\n\n    vector<int> order;\n    order.reserve(cnt);\n\n    int cur = 0;\n    int lastSign = 0;\n\n    for (int step = 0; step < cnt; ++step) {\n        long long bestScore = INFLL;\n        int best = -1;\n\n        for (int i = 0; i < V; ++i) {\n            if (H[i] == 0 || used[i]) continue;\n\n            int sg = H[i] > 0 ? 1 : -1;\n            int a = abs(H[i]);\n            long long d = DIST[cur][i];\n\n            long long score = 100000LL * d;\n\n            if (mode == 0) {\n                score -= 100LL * a;\n            } else if (mode == 1) {\n                score -= 800LL * a;\n            } else if (mode == 2) {\n                if (lastSign != 0 && sg == lastSign) score += 8000;\n                score -= 300LL * a;\n            } else {\n                int r = i / N;\n                int c = i % N;\n                score += 200LL * abs(r - N / 2) + 200LL * abs(c - N / 2);\n                score -= 400LL * a;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                best = i;\n            }\n        }\n\n        if (best < 0) break;\n\n        used[best] = true;\n        order.push_back(best);\n        cur = best;\n        lastSign = H[best] > 0 ? 1 : -1;\n    }\n\n    return order;\n}\n\nvector<pair<int, int>> makeBlockSnakeBase(int B) {\n    vector<pair<int, int>> res;\n\n    for (int br = 0; br < N; br += B) {\n        vector<int> bcs;\n        for (int bc = 0; bc < N; bc += B) bcs.push_back(bc);\n        if ((br / B) % 2 == 1) reverse(bcs.begin(), bcs.end());\n\n        for (int bc : bcs) {\n            for (int rr = 0; rr < B; ++rr) {\n                if (rr % 2 == 0) {\n                    for (int cc = 0; cc < B; ++cc) {\n                        res.push_back({br + rr, bc + cc});\n                    }\n                } else {\n                    for (int cc = B - 1; cc >= 0; --cc) {\n                        res.push_back({br + rr, bc + cc});\n                    }\n                }\n            }\n        }\n    }\n\n    return res;\n}\n\nvector<pair<int, int>> makeProjectionSnakeBase(int a, int b) {\n    map<int, vector<pair<int, pair<int, int>>>> mp;\n\n    for (int r = 0; r < N; ++r) {\n        for (int c = 0; c < N; ++c) {\n            int key = a * r + b * c;\n            int sec = -b * r + a * c;\n            mp[key].push_back({sec, {r, c}});\n        }\n    }\n\n    vector<pair<int, int>> res;\n    bool rev = false;\n\n    for (auto& [key, vec] : mp) {\n        sort(vec.begin(), vec.end());\n        if (rev) reverse(vec.begin(), vec.end());\n\n        for (auto& x : vec) {\n            res.push_back(x.second);\n        }\n\n        rev = !rev;\n    }\n\n    return res;\n}\n\ntemplate<class F>\nvoid generateEventCandidates(F&& considerEvent) {\n    unordered_set<uint64_t> seen;\n\n    auto addEventOrder = [&](const vector<Event>& ev) {\n        if (ev.empty()) return;\n\n        vector<long long> sum(V, 0);\n        long long total = 0;\n\n        for (auto& e : ev) {\n            if (e.delta == 0) return;\n            if (e.cell < 0 || e.cell >= V) return;\n            sum[e.cell] += e.delta;\n            total += e.delta;\n        }\n\n        if (total != 0) return;\n\n        for (int i = 0; i < V; ++i) {\n            if (sum[i] != H[i]) return;\n        }\n\n        uint64_t h = hashEvents(ev);\n        if (seen.insert(h).second) {\n            considerEvent(ev);\n        }\n    };\n\n    auto addCells = [&](const vector<int>& cells) {\n        addEventOrder(eventsFromCellOrder(cells));\n    };\n\n    vector<vector<pair<int, int>>> bases;\n\n    vector<pair<int, int>> rowSnake;\n    for (int r = 0; r < N; ++r) {\n        if (r % 2 == 0) {\n            for (int c = 0; c < N; ++c) rowSnake.push_back({r, c});\n        } else {\n            for (int c = N - 1; c >= 0; --c) rowSnake.push_back({r, c});\n        }\n    }\n    bases.push_back(rowSnake);\n\n    vector<pair<int, int>> colSnake;\n    for (int c = 0; c < N; ++c) {\n        if (c % 2 == 0) {\n            for (int r = 0; r < N; ++r) colSnake.push_back({r, c});\n        } else {\n            for (int r = N - 1; r >= 0; --r) colSnake.push_back({r, c});\n        }\n    }\n    bases.push_back(colSnake);\n\n    vector<pair<int, int>> diagSnake;\n    for (int s = 0; s <= 2 * (N - 1); ++s) {\n        vector<pair<int, int>> tmp;\n        for (int r = max(0, s - (N - 1)); r <= min(N - 1, s); ++r) {\n            int c = s - r;\n            tmp.push_back({r, c});\n        }\n        if (s % 2 == 1) reverse(tmp.begin(), tmp.end());\n        for (auto p : tmp) diagSnake.push_back(p);\n    }\n    bases.push_back(diagSnake);\n\n    vector<pair<int, int>> cycleBase;\n    for (int i = 0; i < N; ++i) cycleBase.push_back({i, 0});\n    for (int j = 1; j < N; ++j) {\n        if (j % 2 == 1) {\n            for (int i = N - 1; i >= 1; --i) cycleBase.push_back({i, j});\n        } else {\n            for (int i = 1; i < N; ++i) cycleBase.push_back({i, j});\n        }\n    }\n    for (int j = N - 1; j >= 1; --j) cycleBase.push_back({0, j});\n    bases.push_back(cycleBase);\n\n    vector<pair<int, int>> spiral;\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) spiral.push_back({top, c});\n        ++top;\n        for (int r = top; r <= bottom; ++r) spiral.push_back({r, right});\n        --right;\n        if (top <= bottom) {\n            for (int c = right; c >= left; --c) spiral.push_back({bottom, c});\n            --bottom;\n        }\n        if (left <= right) {\n            for (int r = bottom; r >= top; --r) spiral.push_back({r, left});\n            ++left;\n        }\n    }\n    bases.push_back(spiral);\n\n    bases.push_back(makeProjectionSnakeBase(1, 2));\n    bases.push_back(makeProjectionSnakeBase(2, 1));\n    bases.push_back(makeBlockSnakeBase(4));\n    bases.push_back(makeBlockSnakeBase(5));\n\n    for (auto& base : bases) {\n        for (int type = 0; type < 8; ++type) {\n            vector<int> cells;\n            cells.reserve(V);\n\n            for (auto [r, c] : base) {\n                auto [nr, nc] = transformCoord(r, c, type);\n                cells.push_back(cell_id(nr, nc));\n            }\n\n            addCells(cells);\n            reverse(cells.begin(), cells.end());\n            addCells(cells);\n        }\n    }\n\n    for (int curve = 0; curve < 2; ++curve) {\n        for (int type = 0; type < 8; ++type) {\n            vector<pair<int, int>> arr;\n            arr.reserve(V);\n\n            for (int id = 0; id < V; ++id) {\n                int r = id / N;\n                int c = id % N;\n                auto [tr, tc] = transformCoord(r, c, type);\n\n                int key = (curve == 0 ? hilbertIndex(tr, tc) : mortonIndex(tr, tc));\n                arr.push_back({key, id});\n            }\n\n            sort(arr.begin(), arr.end());\n\n            vector<int> cells;\n            cells.reserve(V);\n            for (auto [key, id] : arr) cells.push_back(id);\n\n            addCells(cells);\n            reverse(cells.begin(), cells.end());\n            addCells(cells);\n        }\n    }\n\n    int nonzero = 0;\n    for (int i = 0; i < V; ++i) if (H[i] != 0) ++nonzero;\n\n    for (int mode = 0; mode < 6; ++mode) {\n        vector<int> cells = makeGreedyCellOrder(mode);\n        if ((int)cells.size() == nonzero) {\n            addCells(cells);\n        }\n    }\n\n    for (int mode = 0; mode < 4; ++mode) {\n        vector<int> cells = makeNearestCellOrder(mode);\n        if ((int)cells.size() == nonzero) {\n            addCells(cells);\n            reverse(cells.begin(), cells.end());\n            addCells(cells);\n        }\n    }\n}\n\nvector<Event> improveEventOrder(vector<Event> cur, uint64_t seed, double deadline) {\n    int m = (int)cur.size();\n    if (m < 4 || m > 500) return cur;\n\n    auto rng = [&]() -> uint64_t {\n        seed += 0x9e3779b97f4a7c15ULL;\n        return splitmix64(seed);\n    };\n\n    EventEval ce = evalEventOrder(cur);\n    if (ce.cost >= INFLL / 2) return cur;\n\n    long long curCost = ce.cost;\n    vector<Event> best = cur;\n    long long bestCost = curCost;\n\n    auto tryImprove = [&](vector<Event>& cand) {\n        EventEval ne = evalEventOrder(cand);\n        if (ne.cost < curCost) {\n            cur.swap(cand);\n            curCost = ne.cost;\n            if (curCost < bestCost) {\n                bestCost = curCost;\n                best = cur;\n            }\n            return true;\n        }\n        return false;\n    };\n\n    // Cheap deterministic adjacent-swap hill climbing.\n    for (int pass = 0; pass < 2 && TIMER.ok(deadline); ++pass) {\n        bool any = false;\n        for (int i = 0; i + 1 < m && TIMER.ok(deadline); ++i) {\n            vector<Event> cand = cur;\n            swap(cand[i], cand[i + 1]);\n            if (tryImprove(cand)) any = true;\n        }\n        if (!any) break;\n    }\n\n    // Small bounded random local search.\n    for (int it = 0; it < 2500; ++it) {\n        if ((it & 31) == 0 && !TIMER.ok(deadline)) break;\n\n        vector<Event> cand = cur;\n        int op = (int)(rng() % 100);\n\n        if (op < 40) {\n            int a = (int)(rng() % m);\n            int b = (int)(rng() % m);\n            if (a != b) swap(cand[a], cand[b]);\n        } else if (op < 75) {\n            int len = 2 + (int)(rng() % min(20, m - 1));\n            int l = (int)(rng() % (m - len + 1));\n            reverse(cand.begin() + l, cand.begin() + l + len);\n        } else {\n            int a = (int)(rng() % m);\n            Event e = cand[a];\n            cand.erase(cand.begin() + a);\n            int p = (int)(rng() % (m - 1 + 1));\n            cand.insert(cand.begin() + p, e);\n        }\n\n        tryImprove(cand);\n    }\n\n    return best;\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int inputN;\n    cin >> inputN;\n\n    uint64_t inputHash = 123456789;\n\n    for (int i = 0; i < N; ++i) {\n        for (int j = 0; j < N; ++j) {\n            int id = cell_id(i, j);\n            cin >> H[id];\n            inputHash = splitmix64(inputHash ^ (uint64_t)(H[id] + 1000 + id * 10007));\n        }\n    }\n\n    for (int a = 0; a < V; ++a) {\n        int ar = a / N;\n        int ac = a % N;\n\n        for (int b = 0; b < V; ++b) {\n            int br = b / N;\n            int bc = b % N;\n            DIST[a][b] = abs(ar - br) + abs(ac - bc);\n        }\n    }\n\n    for (int i = 0; i < V; ++i) BASE_COST += abs(H[i]);\n\n    if (BASE_COST == 0) {\n        return 0;\n    }\n\n    Solution best;\n    best.cost = INFLL;\n    best.valid = false;\n\n    auto consider = [&](Solution&& sol) {\n        if (!sol.valid) return;\n        if (sol.load != 0) return;\n        if (sol.ops.size() > 100000) return;\n\n        if (!best.valid || sol.cost < best.cost) {\n            best = std::move(sol);\n        }\n    };\n\n    consider(makeCycleSolution());\n\n    vector<pair<long long, vector<Event>>> topEvents;\n\n    auto addTopEvent = [&](long long cost, const vector<Event>& ev) {\n        topEvents.push_back({cost, ev});\n        sort(topEvents.begin(), topEvents.end(), [](auto& a, auto& b) {\n            return a.first < b.first;\n        });\n        if ((int)topEvents.size() > 3) topEvents.pop_back();\n    };\n\n    auto considerEvent = [&](const vector<Event>& ev) {\n        EventEval ee = evalEventOrder(ev);\n        if (ee.rot < 0 || ee.cost >= INFLL / 2) return;\n\n        addTopEvent(ee.cost, ev);\n\n        if (best.valid && ee.cost >= best.cost) return;\n        consider(makeEventSequenceSolution(ev));\n    };\n\n    generateEventCandidates(considerEvent);\n\n    vector<int> maxLoads = {0, 120, 250, 500};\n    vector<pair<int, int>> ratios = {{1, 1}, {3, 2}, {2, 1}};\n    vector<int> sourceModes = {0, 2};\n    vector<int> demandModes = {0, 1, 2};\n\n    for (int ml : maxLoads) {\n        for (auto [rn, rd] : ratios) {\n            if (ml == 0 && !(rn == 1 && rd == 1)) continue;\n\n            for (int sm : sourceModes) {\n                for (int dm : demandModes) {\n                    consider(makeGreedySolution(ml, rn, rd, sm, dm));\n                }\n            }\n        }\n    }\n\n    vector<int> caps = {120, 250, 500, 1000000000};\n\n    for (int cap : caps) {\n        for (auto [rn, rd] : ratios) {\n            for (int sm : sourceModes) {\n                for (int dm : {0, 1}) {\n                    consider(makeGreedyServiceSolution(cap, rn, rd, sm, dm, 2));\n                }\n            }\n        }\n    }\n\n    for (int pm : {0, 1}) {\n        consider(makeGreedyServiceSolution(250, 3, 2, 2, 1, pm));\n        consider(makeGreedyServiceSolution(500, 3, 2, 2, 1, pm));\n    }\n\n    for (int variant = 0; variant < 3; ++variant) {\n        vector<Flow> flows = computeMinCostFlows(variant);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    for (int mode = 0; mode < 3; ++mode) {\n        vector<Flow> flows = computeGreedyFlows(mode);\n\n        consider(makePairSolution(flows));\n        consider(makeSourceGroupSolution(flows));\n        consider(makeDemandGroupSolution(flows));\n    }\n\n    for (int variant = 0; variant < 5; ++variant) {\n        consider(makeGridRelaySolution(variant));\n    }\n\n    // Optional lightweight local improvement of the best cyclic event orders.\n    if (TIMER.ok(1.68)) {\n        for (int i = 0; i < (int)topEvents.size(); ++i) {\n            if (!TIMER.ok(1.74)) break;\n\n            vector<Event> improved = improveEventOrder(\n                topEvents[i].second,\n                inputHash ^ (uint64_t)(i + 1) * 0x9e3779b97f4a7c15ULL,\n                1.76\n            );\n\n            EventEval ee = evalEventOrder(improved);\n            if (ee.cost < best.cost) {\n                consider(makeEventSequenceSolution(improved));\n            }\n        }\n    }\n\n    for (int variant = 5; variant < 8; ++variant) {\n        if (!TIMER.ok(1.84)) break;\n        consider(makeGridRelaySolution(variant));\n    }\n\n    for (const Op& op : best.ops) {\n        if (op.c == '+' || op.c == '-') {\n            cout << op.c << op.d << '\\n';\n        } else {\n            cout << op.c << '\\n';\n        }\n    }\n\n    return 0;\n}","ahc035":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct Solver {\n    int N, M, T;\n    int S, G;\n    int SUM_MAXV;\n    int APPROX_MAXV;\n\n    vector<vector<int>> X;\n    vector<int> initMax;\n\n    vector<vector<int>> neigh;\n    vector<int> degSlot;\n    vector<pair<int,int>> gridEdges;\n    vector<unsigned long long> incidentMask;\n    vector<int> posOrder;\n\n    mt19937 rng;\n\n    struct FinalStats {\n        double mean;\n        double sd;\n        int q25;\n        int q50;\n    };\n\n    Solver(int N_, int M_, int T_, const vector<vector<int>>& X_)\n        : N(N_), M(M_), T(T_), X(X_), rng(123456789) {\n        S = 2 * N * (N - 1);\n        G = N * N;\n        APPROX_MAXV = M * 100;\n\n        initMax.assign(M, 1);\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n            initMax[l] = max(1, mx);\n        }\n\n        SUM_MAXV = 0;\n        for (int v : initMax) SUM_MAXV += v;\n        SUM_MAXV = max(1, SUM_MAXV);\n\n        build_grid_info();\n    }\n\n    void build_grid_info() {\n        neigh.assign(S, {});\n        degSlot.assign(S, 0);\n        gridEdges.clear();\n        incidentMask.assign(S, 0ULL);\n\n        auto add_edge = [&](int p, int q) {\n            int eid = (int)gridEdges.size();\n            gridEdges.push_back({p, q});\n            neigh[p].push_back(q);\n            neigh[q].push_back(p);\n            incidentMask[p] |= (1ULL << eid);\n            incidentMask[q] |= (1ULL << eid);\n        };\n\n        auto id = [&](int i, int j) {\n            return i * N + j;\n        };\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                int p = id(i, j);\n                if (j + 1 < N) add_edge(p, id(i, j + 1));\n                if (i + 1 < N) add_edge(p, id(i + 1, j));\n            }\n        }\n\n        for (int p = 0; p < S; p++) degSlot[p] = (int)neigh[p].size();\n\n        posOrder.resize(G);\n        iota(posOrder.begin(), posOrder.end(), 0);\n\n        sort(posOrder.begin(), posOrder.end(), [&](int a, int b) {\n            if (degSlot[a] != degSlot[b]) return degSlot[a] > degSlot[b];\n\n            int ai = a / N, aj = a % N;\n            int bi = b / N, bj = b % N;\n\n            double ca = (ai - (N - 1) / 2.0) * (ai - (N - 1) / 2.0)\n                      + (aj - (N - 1) / 2.0) * (aj - (N - 1) / 2.0);\n            double cb = (bi - (N - 1) / 2.0) * (bi - (N - 1) / 2.0)\n                      + (bj - (N - 1) / 2.0) * (bj - (N - 1) / 2.0);\n\n            return ca < cb;\n        });\n    }\n\n    inline double PW(const vector<double>& pairW, int a, int b) const {\n        return pairW[a * S + b];\n    }\n\n    double objective(\n        const vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        double ret = 0.0;\n\n        for (int p = 0; p < G; p++) {\n            ret += nodeCoef * degSlot[p] * nodeW[slotSeed[p]];\n        }\n\n        for (auto [p, q] : gridEdges) {\n            ret += PW(pairW, slotSeed[p], slotSeed[q]);\n        }\n\n        return ret;\n    }\n\n    double swap_delta(\n        const vector<int>& slotSeed,\n        int p,\n        int q,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef\n    ) const {\n        if (p == q) return 0.0;\n\n        int a = slotSeed[p];\n        int b = slotSeed[q];\n\n        double delta = 0.0;\n\n        delta += nodeCoef * degSlot[p] * (nodeW[b] - nodeW[a]);\n        delta += nodeCoef * degSlot[q] * (nodeW[a] - nodeW[b]);\n\n        for (int r : neigh[p]) {\n            if (r == q) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, b, c) - PW(pairW, a, c);\n        }\n\n        for (int r : neigh[q]) {\n            if (r == p) continue;\n            int c = slotSeed[r];\n            delta += PW(pairW, a, c) - PW(pairW, b, c);\n        }\n\n        return delta;\n    }\n\n    double local_search(\n        vector<int>& slotSeed,\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        int maxIter\n    ) const {\n        double cur = objective(slotSeed, pairW, nodeW, nodeCoef);\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            double bestD = 1e-9;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < S; p++) {\n                for (int q = p + 1; q < S; q++) {\n                    if (degSlot[p] == 0 && degSlot[q] == 0) continue;\n\n                    double d = swap_delta(slotSeed, p, q, pairW, nodeW, nodeCoef);\n                    if (d > bestD) {\n                        bestD = d;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur += bestD;\n        }\n\n        return cur;\n    }\n\n    vector<int> make_sorted_initial(const vector<double>& key, bool shuffleGrid) {\n        vector<int> seeds(S);\n        iota(seeds.begin(), seeds.end(), 0);\n\n        sort(seeds.begin(), seeds.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> slotSeed(S, -1);\n\n        for (int k = 0; k < G; k++) {\n            slotSeed[posOrder[k]] = seeds[k];\n        }\n        for (int k = G; k < S; k++) {\n            slotSeed[k] = seeds[k];\n        }\n\n        if (shuffleGrid) {\n            vector<int> planted;\n            for (int p = 0; p < G; p++) planted.push_back(slotSeed[p]);\n            shuffle(planted.begin(), planted.end(), rng);\n            for (int p = 0; p < G; p++) slotSeed[p] = planted[p];\n        }\n\n        return slotSeed;\n    }\n\n    vector<int> make_greedy_initial(\n        const vector<double>& pairW,\n        const vector<double>& nodeW,\n        double nodeCoef,\n        double noiseAmp\n    ) {\n        vector<int> slotSeed(S, -1);\n        vector<char> used(S, 0);\n\n        uniform_real_distribution<double> dist(-noiseAmp, noiseAmp);\n\n        for (int p : posOrder) {\n            int best = -1;\n            double bestScore = -1e100;\n\n            for (int s = 0; s < S; s++) {\n                if (used[s]) continue;\n\n                double sc = nodeCoef * degSlot[p] * nodeW[s];\n\n                for (int r : neigh[p]) {\n                    if (r < G && slotSeed[r] != -1) {\n                        sc += PW(pairW, s, slotSeed[r]);\n                    }\n                }\n\n                if (noiseAmp > 0) sc += dist(rng);\n\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = s;\n                }\n            }\n\n            slotSeed[p] = best;\n            used[best] = 1;\n        }\n\n        int out = G;\n        for (int s = 0; s < S; s++) {\n            if (!used[s]) slotSeed[out++] = s;\n        }\n\n        return slotSeed;\n    }\n\n    void compute_node_info(\n        int turn,\n        vector<int>& val,\n        vector<double>& nodeW,\n        vector<double>& criticalKey\n    ) const {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n\n        val.assign(S, 0);\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) val[i] += X[i][l];\n        }\n\n        vector<double> rankBonus(S, 0.0);\n\n        static const double rw[10] = {\n            260.0, 160.0, 100.0, 60.0, 36.0,\n            22.0, 14.0, 9.0, 6.0, 4.0\n        };\n\n        double rankScale = 1.15 - 0.25 * prog;\n\n        for (int l = 0; l < M; l++) {\n            vector<int> ids(S);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (X[a][l] != X[b][l]) return X[a][l] > X[b][l];\n                return a < b;\n            });\n\n            int curMax = max(1, X[ids[0]][l]);\n\n            for (int r = 0; r < min(10, S); r++) {\n                int id = ids[r];\n                double frac0 = (double)X[id][l] / initMax[l];\n                double frac1 = (double)X[id][l] / curMax;\n                double frac = 0.6 * frac0 + 0.4 * frac1;\n                rankBonus[id] += rankScale * rw[r] * frac;\n            }\n\n            int second = X[ids[min(1, S - 1)]][l];\n            int gap = X[ids[0]][l] - second;\n            rankBonus[ids[0]] += (1.0 - 0.3 * prog) * 3.0 * gap;\n        }\n\n        nodeW.assign(S, 0.0);\n        criticalKey.assign(S, 0.0);\n\n        double quadCoef = 0.85 - 0.30 * prog;\n\n        for (int i = 0; i < S; i++) {\n            double quad = 0.0;\n            for (int l = 0; l < M; l++) {\n                quad += (double)X[i][l] * X[i][l] / initMax[l];\n            }\n\n            nodeW[i] = val[i] + quadCoef * quad + rankBonus[i];\n            criticalKey[i] = nodeW[i] + 0.75 * rankBonus[i];\n        }\n    }\n\n    vector<double> build_pair_quantile(double beta, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double mean = 0.5 * (ysum[i] + ysum[j]);\n                double var = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double d = a - b;\n                    var += 0.25 * d * d;\n                    pot += max(a, b);\n                }\n\n                double sd = sqrt(max(0.0, var));\n                double w = (1.0 - potCoef) * (mean + beta * sd) + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    vector<double> build_pair_ce(double tau, double potCoef, double qpair) const {\n        vector<double> pairW(S * S, 0.0);\n\n        vector<double> y(S * M, 0.0);\n        vector<double> ysum(S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                double x = X[i][l];\n                double yy = x + qpair * x * x / initMax[l];\n                y[i * M + l] = yy;\n                ysum[i] += yy;\n            }\n        }\n\n        for (int i = 0; i < S; i++) {\n            pairW[i * S + i] = ysum[i];\n\n            for (int j = i + 1; j < S; j++) {\n                double ce = 0.0;\n                double pot = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double a = y[i * M + l];\n                    double b = y[j * M + l];\n                    double mx = max(a, b);\n                    double diff = fabs(a - b);\n\n                    ce += mx + tau * log(0.5 * (1.0 + exp(-diff / tau)));\n                    pot += mx;\n                }\n\n                double w = (1.0 - potCoef) * ce + potCoef * pot;\n\n                pairW[i * S + j] = pairW[j * S + i] = w;\n            }\n        }\n\n        return pairW;\n    }\n\n    void build_raw_pair_stats(\n        const vector<int>& val,\n        vector<double>& mu,\n        vector<double>& sd\n    ) const {\n        mu.assign(S * S, 0.0);\n        sd.assign(S * S, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            mu[i * S + i] = val[i];\n            sd[i * S + i] = 0.0;\n\n            for (int j = i + 1; j < S; j++) {\n                double m = 0.5 * (val[i] + val[j]);\n                double var = 0.0;\n\n                for (int l = 0; l < M; l++) {\n                    double d = X[i][l] - X[j][l];\n                    var += 0.25 * d * d;\n                }\n\n                double s = sqrt(max(0.0, var));\n\n                mu[i * S + j] = mu[j * S + i] = m;\n                sd[i * S + j] = sd[j * S + i] = s;\n            }\n        }\n    }\n\n    static inline double normal_cdf(double z) {\n        if (z < -8.0) return 0.0;\n        if (z > 8.0) return 1.0;\n        return 0.5 * erfc(-z * 0.70710678118654752440);\n    }\n\n    double approx_expected_max_normal(\n        const vector<int>& slotSeed,\n        const vector<double>& mu,\n        const vector<double>& sd\n    ) const {\n        const int STEP = 5;\n        double ret = 0.0;\n\n        for (int s = 0; s < APPROX_MAXV; s += STEP) {\n            double prod = 1.0;\n\n            for (auto [p, q] : gridEdges) {\n                int a = slotSeed[p];\n                int b = slotSeed[q];\n\n                double m = mu[a * S + b];\n                double sig = sd[a * S + b];\n\n                double cdf;\n                if (sig < 1e-9) {\n                    cdf = (m <= s ? 1.0 : 0.0);\n                } else {\n                    cdf = normal_cdf((s + 0.5 - m) / sig);\n                }\n\n                prod *= cdf;\n                if (prod <= 1e-15) {\n                    prod = 0.0;\n                    break;\n                }\n            }\n\n            ret += (1.0 - prod) * STEP;\n        }\n\n        return ret;\n    }\n\n    double coord_max_expectation(const vector<int>& slotSeed) const {\n        double total = 0.0;\n\n        for (int l = 0; l < M; l++) {\n            int mx = 0;\n            for (int i = 0; i < S; i++) mx = max(mx, X[i][l]);\n\n            for (int th = 1; th <= mx; th++) {\n                double prod = 1.0;\n\n                for (auto [p, q] : gridEdges) {\n                    int a = X[slotSeed[p]][l];\n                    int b = X[slotSeed[q]][l];\n\n                    int ge = 0;\n                    if (a >= th) ge++;\n                    if (b >= th) ge++;\n\n                    double pLess = 1.0 - 0.5 * ge;\n\n                    if (pLess <= 0.0) {\n                        prod = 0.0;\n                        break;\n                    }\n\n                    prod *= pLess;\n                    if (prod <= 1e-15) {\n                        prod = 0.0;\n                        break;\n                    }\n                }\n\n                total += 1.0 - prod;\n            }\n        }\n\n        return total;\n    }\n\n    vector<float> build_pair_cdf() const {\n        int L = SUM_MAXV + 1;\n        vector<float> cdf(S * S * L, 0.0f);\n\n        vector<double> dp(L, 0.0), ndp(L, 0.0);\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i; j < S; j++) {\n                fill(dp.begin(), dp.end(), 0.0);\n                dp[0] = 1.0;\n\n                int curMaxSum = 0;\n\n                for (int l = 0; l < M; l++) {\n                    int a = X[i][l];\n                    int b = X[j][l];\n                    int nxtMaxSum = min(SUM_MAXV, curMaxSum + max(a, b));\n\n                    fill(ndp.begin(), ndp.begin() + nxtMaxSum + 1, 0.0);\n\n                    if (a == b) {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            if (s + a <= SUM_MAXV) ndp[s + a] += dp[s];\n                        }\n                    } else {\n                        for (int s = 0; s <= curMaxSum; s++) {\n                            if (dp[s] == 0.0) continue;\n                            double p = 0.5 * dp[s];\n                            if (s + a <= SUM_MAXV) ndp[s + a] += p;\n                            if (s + b <= SUM_MAXV) ndp[s + b] += p;\n                        }\n                    }\n\n                    dp.swap(ndp);\n                    curMaxSum = nxtMaxSum;\n                }\n\n                int idx1 = (i * S + j) * L;\n                int idx2 = (j * S + i) * L;\n\n                double cum = 0.0;\n                for (int s = 0; s <= SUM_MAXV; s++) {\n                    if (s <= curMaxSum) cum += dp[s];\n                    if (cum < 0.0) cum = 0.0;\n                    if (cum > 1.0) cum = 1.0;\n\n                    float v = (float)cum;\n                    cdf[idx1 + s] = v;\n                    cdf[idx2 + s] = v;\n                }\n            }\n        }\n\n        return cdf;\n    }\n\n    vector<float> build_pair_logcdf(const vector<float>& cdf) const {\n        vector<float> logcdf(cdf.size());\n\n        for (size_t i = 0; i < cdf.size(); i++) {\n            float f = cdf[i];\n\n            if (f <= 0.0f) logcdf[i] = -80.0f;\n            else if (f >= 1.0f) logcdf[i] = 0.0f;\n            else logcdf[i] = (float)log((double)f);\n        }\n\n        return logcdf;\n    }\n\n    vector<double> build_pair_tail(\n        const vector<float>& cdf,\n        int threshold,\n        double scale\n    ) const {\n        int L = SUM_MAXV + 1;\n        vector<double> pairW(S * S, 0.0);\n\n        int start = max(0, threshold - 1);\n        if (start >= SUM_MAXV) return pairW;\n\n        for (int i = 0; i < S; i++) {\n            for (int j = i + 1; j < S; j++) {\n                int idx = (i * S + j) * L;\n\n                double tail = 0.0;\n                for (int s = start; s < SUM_MAXV; s++) {\n                    double f = cdf[idx + s];\n                    if (f < 0.0) f = 0.0;\n                    if (f > 1.0) f = 1.0;\n                    tail += 1.0 - f;\n                }\n\n                tail *= scale;\n                pairW[i * S + j] = pairW[j * S + i] = tail;\n            }\n        }\n\n        return pairW;\n    }\n\n    FinalStats exact_final_stats(\n        const vector<int>& slotSeed,\n        const vector<float>& cdf\n    ) const {\n        int L = SUM_MAXV + 1;\n        vector<double> prod(SUM_MAXV, 1.0);\n\n        for (auto [p, q] : gridEdges) {\n            int a = slotSeed[p];\n            int b = slotSeed[q];\n            int idx = (a * S + b) * L;\n\n            for (int s = 0; s < SUM_MAXV; s++) {\n                double f = cdf[idx + s];\n                if (f < 0.0) f = 0.0;\n                if (f > 1.0) f = 1.0;\n                prod[s] *= f;\n            }\n        }\n\n        double mean = 0.0;\n        double second = 0.0;\n        int q25 = SUM_MAXV;\n        int q50 = SUM_MAXV;\n\n        for (int s = 0; s < SUM_MAXV; s++) {\n            double cdfW = prod[s];\n\n            if (q25 == SUM_MAXV && cdfW >= 0.25) q25 = s;\n            if (q50 == SUM_MAXV && cdfW >= 0.50) q50 = s;\n\n            double tail = 1.0 - cdfW;\n            if (tail < 0.0) tail = 0.0;\n            if (tail > 1.0) tail = 1.0;\n\n            mean += tail;\n            second += (2.0 * s + 1.0) * tail;\n        }\n\n        double var = second - mean * mean;\n        if (var < 0.0) var = 0.0;\n\n        return {mean, sqrt(var), q25, q50};\n    }\n\n    double exact_expected_max(\n        const vector<int>& slotSeed,\n        const vector<float>& cdf\n    ) const {\n        return exact_final_stats(slotSeed, cdf).mean;\n    }\n\n    double score_from_logprod(const vector<double>& logProd) const {\n        double ret = 0.0;\n\n        for (int s = 0; s < SUM_MAXV; s++) {\n            double x = logProd[s];\n\n            if (x < -50.0) {\n                ret += 1.0;\n            } else {\n                if (x > 0.0) x = 0.0;\n                ret += 1.0 - exp(x);\n            }\n        }\n\n        return ret;\n    }\n\n    double exact_final_local_search(\n        vector<int>& slotSeed,\n        const vector<float>& logcdf,\n        int maxIter,\n        bool allowDiscardSwap\n    ) const {\n        int L = SUM_MAXV + 1;\n\n        vector<double> logProd(SUM_MAXV, 0.0);\n\n        for (auto [p, q] : gridEdges) {\n            int a = slotSeed[p];\n            int b = slotSeed[q];\n            int base = (a * S + b) * L;\n\n            for (int s = 0; s < SUM_MAXV; s++) {\n                logProd[s] += logcdf[base + s];\n            }\n        }\n\n        double cur = score_from_logprod(logProd);\n\n        int LIM = allowDiscardSwap ? S : G;\n\n        for (int iter = 0; iter < maxIter; iter++) {\n            double bestScore = cur + 1e-8;\n            int bp = -1, bq = -1;\n\n            for (int p = 0; p < LIM; p++) {\n                for (int q = p + 1; q < LIM; q++) {\n                    unsigned long long mask = incidentMask[p] | incidentMask[q];\n                    if (mask == 0ULL) continue;\n\n                    int seedP = slotSeed[p];\n                    int seedQ = slotSeed[q];\n\n                    int oldBase[8], newBase[8], cnt = 0;\n\n                    unsigned long long m = mask;\n                    while (m) {\n                        int eid = __builtin_ctzll(m);\n                        m &= m - 1;\n\n                        auto [u, v] = gridEdges[eid];\n\n                        int oldA = slotSeed[u];\n                        int oldB = slotSeed[v];\n\n                        int newA = oldA;\n                        int newB = oldB;\n\n                        if (u == p) newA = seedQ;\n                        else if (u == q) newA = seedP;\n\n                        if (v == p) newB = seedQ;\n                        else if (v == q) newB = seedP;\n\n                        int ob = (oldA * S + oldB) * L;\n                        int nb = (newA * S + newB) * L;\n\n                        if (ob != nb) {\n                            oldBase[cnt] = ob;\n                            newBase[cnt] = nb;\n                            cnt++;\n                        }\n                    }\n\n                    if (cnt == 0) continue;\n\n                    double sc = 0.0;\n\n                    for (int s = 0; s < SUM_MAXV; s++) {\n                        double nl = logProd[s];\n\n                        for (int k = 0; k < cnt; k++) {\n                            nl += logcdf[newBase[k] + s] - logcdf[oldBase[k] + s];\n                        }\n\n                        if (nl < -50.0) {\n                            sc += 1.0;\n                        } else {\n                            if (nl > 0.0) nl = 0.0;\n                            sc += 1.0 - exp(nl);\n                        }\n                    }\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bp = p;\n                        bq = q;\n                    }\n                }\n            }\n\n            if (bp == -1) break;\n\n            int seedP = slotSeed[bp];\n            int seedQ = slotSeed[bq];\n\n            unsigned long long mask = incidentMask[bp] | incidentMask[bq];\n            unsigned long long m = mask;\n\n            while (m) {\n                int eid = __builtin_ctzll(m);\n                m &= m - 1;\n\n                auto [u, v] = gridEdges[eid];\n\n                int oldA = slotSeed[u];\n                int oldB = slotSeed[v];\n\n                int newA = oldA;\n                int newB = oldB;\n\n                if (u == bp) newA = seedQ;\n                else if (u == bq) newA = seedP;\n\n                if (v == bp) newB = seedQ;\n                else if (v == bq) newB = seedP;\n\n                int ob = (oldA * S + oldB) * L;\n                int nb = (newA * S + newB) * L;\n\n                if (ob != nb) {\n                    for (int s = 0; s < SUM_MAXV; s++) {\n                        logProd[s] += logcdf[nb + s] - logcdf[ob + s];\n                    }\n                }\n            }\n\n            swap(slotSeed[bp], slotSeed[bq]);\n            cur = bestScore;\n        }\n\n        return cur;\n    }\n\n    vector<vector<int>> solve_turn(int turn) {\n        double prog = (T <= 1 ? 1.0 : (double)turn / (T - 1));\n        bool isFinal = (turn == T - 1);\n\n        vector<int> val;\n        vector<double> nodeW, criticalKey;\n        compute_node_info(turn, val, nodeW, criticalKey);\n\n        vector<double> valKey(S);\n        for (int i = 0; i < S; i++) valKey[i] = val[i];\n\n        vector<double> rawMu, rawSd;\n        build_raw_pair_stats(val, rawMu, rawSd);\n\n        double masterNodeCoef = max(0.09, 0.19 - 0.07 * prog);\n        if (isFinal) masterNodeCoef *= 0.55;\n\n        vector<double> masterPairW =\n            build_pair_quantile(\n                1.55 + 0.45 * prog,\n                0.12 + 0.10 * prog,\n                0.16 * (1.0 - prog)\n            );\n\n        vector<float> finalCDF;\n        vector<float> finalLogCDF;\n\n        if (isFinal) {\n            finalCDF = build_pair_cdf();\n            finalLogCDF = build_pair_logcdf(finalCDF);\n        }\n\n        struct Work {\n            vector<double> pairW;\n            double nodeCoef;\n            int iter;\n        };\n\n        vector<Work> works;\n\n        works.push_back(Work{\n            masterPairW,\n            masterNodeCoef,\n            isFinal ? 90 : 105\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                50.0 - 20.0 * prog,\n                0.06 + 0.17 * prog,\n                0.0\n            ),\n            (isFinal ? 0.07 : max(0.11, 0.22 - 0.07 * prog)),\n            isFinal ? 75 : 85\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                2.00 + 0.45 * prog,\n                0.18 + 0.12 * prog,\n                0.10 * (1.0 - prog)\n            ),\n            (isFinal ? 0.055 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 80\n        });\n\n        works.push_back(Work{\n            build_pair_quantile(\n                1.05 + 0.25 * prog,\n                0.38,\n                0.20 * (1.0 - prog)\n            ),\n            (isFinal ? 0.06 : max(0.09, 0.18 - 0.05 * prog)),\n            isFinal ? 70 : 75\n        });\n\n        works.push_back(Work{\n            build_pair_ce(\n                24.0 - 10.0 * prog,\n                0.08 + 0.12 * prog,\n                0.15 * (1.0 - prog)\n            ),\n            (isFinal ? 0.05 : max(0.08, 0.16 - 0.05 * prog)),\n            isFinal ? 75 : 75\n        });\n\n        if (turn >= T - 3) {\n            works.push_back(Work{\n                build_pair_quantile(\n                    2.35 + 0.35 * prog,\n                    0.26,\n                    0.0\n                ),\n                isFinal ? 0.04 : 0.08,\n                isFinal ? 80 : 70\n            });\n        }\n\n        if (isFinal) {\n            works.push_back(Work{\n                build_pair_ce(14.0, 0.18, 0.0),\n                0.04,\n                80\n            });\n            works.push_back(Work{\n                build_pair_ce(9.0, 0.24, 0.0),\n                0.035,\n                80\n            });\n\n            int bestNow = 0;\n            for (int v : val) bestNow = max(bestNow, v);\n\n            vector<pair<int,double>> thresholds = {\n                {bestNow - 80, 5.0},\n                {bestNow - 60, 7.0},\n                {bestNow - 30, 10.0},\n                {bestNow,      10.0},\n                {bestNow + 25, 10.0},\n                {bestNow + 50, 10.0}\n            };\n\n            for (auto [th, scale] : thresholds) {\n                works.push_back(Work{\n                    build_pair_tail(finalCDF, th, scale),\n                    0.02,\n                    85\n                });\n            }\n        }\n\n        double bestScore = -1e100;\n        vector<int> bestSlotSeed;\n\n        vector<pair<double, vector<int>>> finalTop;\n        vector<pair<double, vector<int>>> finalRiskTop;\n\n        auto push_top = [&](auto& vec, double key, const vector<int>& cand, int limit) {\n            vec.push_back({key, cand});\n            sort(vec.begin(), vec.end(), [&](const auto& a, const auto& b) {\n                return a.first > b.first;\n            });\n            if ((int)vec.size() > limit) vec.pop_back();\n        };\n\n        auto eval_candidate = [&](const vector<int>& slotSeed) -> double {\n            double edgeObj = objective(slotSeed, masterPairW, nodeW, masterNodeCoef);\n            double geneObj = coord_max_expectation(slotSeed);\n            double maxObj = approx_expected_max_normal(slotSeed, rawMu, rawSd);\n\n            double geneLambda = 22.0 - 10.0 * prog;\n            double maxLambda = 13.0 + 10.0 * prog;\n\n            return edgeObj + geneLambda * geneObj + maxLambda * maxObj;\n        };\n\n        auto process = [&](vector<int> start, const Work& w) {\n            local_search(start, w.pairW, nodeW, w.nodeCoef, w.iter);\n\n            double sc;\n\n            if (isFinal) {\n                FinalStats st = exact_final_stats(start, finalCDF);\n                sc = st.mean;\n\n                push_top(finalTop, sc, start, 8);\n\n                double riskKey = st.mean - 0.10 * st.sd;\n                push_top(finalRiskTop, riskKey, start, 6);\n            } else {\n                sc = eval_candidate(start);\n            }\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                bestSlotSeed = start;\n            }\n        };\n\n        uniform_real_distribution<double> noise(-1.0, 1.0);\n\n        for (int wi = 0; wi < (int)works.size(); wi++) {\n            const Work& w = works[wi];\n\n            if (wi == 0) {\n                process(make_sorted_initial(nodeW, false), w);\n                process(make_sorted_initial(valKey, false), w);\n                process(make_sorted_initial(criticalKey, false), w);\n                process(make_sorted_initial(criticalKey, true), w);\n            }\n\n            if (wi == 1) {\n                process(make_sorted_initial(nodeW, false), w);\n            }\n\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 0.0), w);\n            process(make_greedy_initial(w.pairW, nodeW, w.nodeCoef, 38.0 + 13.0 * wi), w);\n\n            if (wi < 5) {\n                vector<double> key = criticalKey;\n                double amp = 55.0 + 25.0 * wi;\n                for (int i = 0; i < S; i++) key[i] += amp * noise(rng);\n                process(make_sorted_initial(key, wi % 2), w);\n            }\n        }\n\n        if (isFinal && !finalTop.empty() && !bestSlotSeed.empty()) {\n            sort(finalTop.begin(), finalTop.end(), [&](const auto& a, const auto& b) {\n                return a.first > b.first;\n            });\n            sort(finalRiskTop.begin(), finalRiskTop.end(), [&](const auto& a, const auto& b) {\n                return a.first > b.first;\n            });\n\n            vector<vector<int>> starts;\n\n            auto push_start = [&](const vector<int>& v) {\n                for (auto& u : starts) {\n                    if (u == v) return;\n                }\n                if ((int)starts.size() < 4) starts.push_back(v);\n            };\n\n            push_start(bestSlotSeed);\n\n            for (auto& pr : finalTop) {\n                push_start(pr.second);\n                if ((int)starts.size() >= 3) break;\n            }\n            for (auto& pr : finalRiskTop) {\n                push_start(pr.second);\n                if ((int)starts.size() >= 4) break;\n            }\n\n            vector<pair<FinalStats, vector<int>>> choicePool;\n\n            auto add_choice = [&](const vector<int>& cand) -> FinalStats {\n                for (auto& pr : choicePool) {\n                    if (pr.second == cand) return pr.first;\n                }\n                FinalStats st = exact_final_stats(cand, finalCDF);\n                choicePool.push_back({st, cand});\n                return st;\n            };\n\n            for (auto& stv : starts) add_choice(stv);\n            add_choice(bestSlotSeed);\n\n            FinalStats bestStats = exact_final_stats(bestSlotSeed, finalCDF);\n            bestScore = bestStats.mean;\n\n            auto try_accept_final = [&](const vector<int>& cand) {\n                FinalStats st = add_choice(cand);\n\n                double meanGain = st.mean - bestStats.mean;\n                if (meanGain <= 1e-7) return;\n\n                const double RISK_LAMBDA = 0.04;\n                const double BIG_MEAN_GAIN = 1.0;\n\n                double riskBest = bestStats.mean - RISK_LAMBDA * bestStats.sd;\n                double riskCand = st.mean - RISK_LAMBDA * st.sd;\n\n                if (riskCand > riskBest + 1e-7 || meanGain > BIG_MEAN_GAIN) {\n                    bestStats = st;\n                    bestScore = st.mean;\n                    bestSlotSeed = cand;\n                }\n            };\n\n            for (auto cand0 : starts) {\n                vector<int> candPlanted = cand0;\n                exact_final_local_search(candPlanted, finalLogCDF, 4, false);\n                try_accept_final(candPlanted);\n\n                vector<int> candAll = candPlanted;\n                exact_final_local_search(candAll, finalLogCDF, 4, true);\n                try_accept_final(candAll);\n            }\n\n            // Final robust selector:\n            // keep the exact-mean winner unless another polished candidate has\n            // nearly the same mean and clearly better stability/central quantiles.\n            if (!choicePool.empty()) {\n                int meanBestIdx = 0;\n                for (int i = 1; i < (int)choicePool.size(); i++) {\n                    if (choicePool[i].first.mean > choicePool[meanBestIdx].first.mean) {\n                        meanBestIdx = i;\n                    }\n                }\n\n                FinalStats meanBestStats = choicePool[meanBestIdx].first;\n                vector<int> meanBestSeed = choicePool[meanBestIdx].second;\n\n                auto robust_utility = [&](const FinalStats& st) {\n                    return st.mean - 0.12 * st.sd + 0.020 * st.q50 + 0.008 * st.q25;\n                };\n\n                int chosenIdx = meanBestIdx;\n                double chosenUtil = robust_utility(meanBestStats);\n\n                for (int i = 0; i < (int)choicePool.size(); i++) {\n                    const FinalStats& st = choicePool[i].first;\n\n                    double meanLoss = meanBestStats.mean - st.mean;\n                    if (meanLoss < -1e-9) continue;\n                    if (meanLoss > 3.0) continue;\n\n                    bool close = (meanLoss <= 0.75);\n                    bool safer =\n                        (st.q50 >= meanBestStats.q50 + 3) ||\n                        (st.q25 >= meanBestStats.q25 + 5) ||\n                        (st.sd + 10.0 <= meanBestStats.sd);\n\n                    if (!close && !safer) continue;\n\n                    double u = robust_utility(st);\n                    if (u > chosenUtil + 0.05) {\n                        chosenUtil = u;\n                        chosenIdx = i;\n                    }\n                }\n\n                bestStats = choicePool[chosenIdx].first;\n                bestScore = bestStats.mean;\n                bestSlotSeed = choicePool[chosenIdx].second;\n            }\n        }\n\n        if (bestSlotSeed.empty()) {\n            bestSlotSeed = make_sorted_initial(valKey, false);\n        }\n\n        vector<vector<int>> A(N, vector<int>(N));\n\n        for (int p = 0; p < G; p++) {\n            A[p / N][p % N] = bestSlotSeed[p];\n        }\n\n        return A;\n    }\n\n    void update_X(const vector<vector<int>>& nx) {\n        X = nx;\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    int N, M, T;\n    cin >> N >> M >> T;\n\n    int S = 2 * N * (N - 1);\n    vector<vector<int>> X(S, vector<int>(M));\n\n    for (int i = 0; i < S; i++) {\n        for (int l = 0; l < M; l++) {\n            cin >> X[i][l];\n        }\n    }\n\n    Solver solver(N, M, T, X);\n\n    for (int t = 0; t < T; t++) {\n        auto A = solver.solve_turn(t);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = 0; j < N; j++) {\n                if (j) cout << ' ';\n                cout << A[i][j];\n            }\n            cout << '\\n';\n        }\n        cout.flush();\n\n        vector<vector<int>> nx(S, vector<int>(M));\n\n        for (int i = 0; i < S; i++) {\n            for (int l = 0; l < M; l++) {\n                if (!(cin >> nx[i][l])) return 0;\n            }\n        }\n\n        solver.update_X(nx);\n    }\n\n    return 0;\n}","ahc038":"#include <bits/stdc++.h>\nusing namespace std;\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 Assignment {\n    int f;      // internal finger index\n    int dir;    // absolute direction of fingertip edge\n    int cell;\n};\n\nstruct Estimate {\n    int cnt = 0;\n    int maxrot = 0;\n    int pairCnt = 0;\n};\n\nstruct Choice {\n    bool exists = false;\n    int x = 0, y = 0, gd = 0;\n    double score = 1e100;\n    int cnt = 0;\n    int travel = 0;\n};\n\nstruct NextMove {\n    bool exists = false;\n    int x = 0, y = 0, gd = 0;\n    double score = 1e100;\n    vector<Assignment> assigns;\n};\n\nstruct PlanResult {\n    int Vp = 0;\n    vector<int> parent;\n    vector<int> edgeLen;\n    int initX = 0, initY = 0;\n    vector<string> ops;\n    long long score = (1LL << 60);\n    bool complete = false;\n    bool valid = false;\n};\n\nstruct MEdge {\n    int cellIdx;\n    int dir;\n    int rot;\n};\n\nstatic int oldMatching(const vector<vector<MEdge>>& edges, int R,\n                       vector<int>& matchCell, vector<int>& matchDir) {\n    int L = (int)edges.size();\n    matchCell.assign(R, -1);\n    matchDir.assign(R, -1);\n\n    vector<int> order(L);\n    iota(order.begin(), order.end(), 0);\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        return edges[a].size() < edges[b].size();\n    });\n\n    vector<unsigned char> seen(R);\n\n    function<bool(int)> dfs = [&](int li) -> bool {\n        for (const auto& e : edges[li]) {\n            int ci = e.cellIdx;\n            if (seen[ci]) continue;\n            seen[ci] = 1;\n\n            if (matchCell[ci] == -1 || dfs(matchCell[ci])) {\n                matchCell[ci] = li;\n                matchDir[ci] = e.dir;\n                return true;\n            }\n        }\n        return false;\n    };\n\n    int cnt = 0;\n    for (int li : order) {\n        if (edges[li].empty()) continue;\n        fill(seen.begin(), seen.end(), 0);\n        if (dfs(li)) cnt++;\n    }\n    return cnt;\n}\n\nstatic int limitedMatching(const vector<vector<MEdge>>& edges, int R, int lim,\n                           vector<int>& matchCell, vector<int>& matchDir) {\n    int L = (int)edges.size();\n    matchCell.assign(R, -1);\n    matchDir.assign(R, -1);\n\n    vector<int> order(L), deg(L, 0);\n    iota(order.begin(), order.end(), 0);\n\n    for (int i = 0; i < L; i++) {\n        for (const auto& e : edges[i]) {\n            if (e.rot <= lim) deg[i]++;\n        }\n    }\n\n    sort(order.begin(), order.end(), [&](int a, int b) {\n        if (deg[a] != deg[b]) return deg[a] < deg[b];\n        return a < b;\n    });\n\n    vector<unsigned char> seen(R);\n\n    function<bool(int)> dfs = [&](int li) -> bool {\n        for (const auto& e : edges[li]) {\n            if (e.rot > lim) continue;\n            int ci = e.cellIdx;\n            if (seen[ci]) continue;\n            seen[ci] = 1;\n\n            if (matchCell[ci] == -1 || dfs(matchCell[ci])) {\n                matchCell[ci] = li;\n                matchDir[ci] = e.dir;\n                return true;\n            }\n        }\n        return false;\n    };\n\n    int cnt = 0;\n    for (int li : order) {\n        if (deg[li] == 0) continue;\n        fill(seen.begin(), seen.end(), 0);\n        if (dfs(li)) cnt++;\n    }\n    return cnt;\n}\n\nstatic vector<Assignment> makeAssignments(const vector<int>& fingers,\n                                          const vector<int>& cells,\n                                          const vector<int>& matchCell,\n                                          const vector<int>& matchDir) {\n    vector<Assignment> assigns;\n    for (int ci = 0; ci < (int)cells.size(); ci++) {\n        if (matchCell[ci] == -1) continue;\n        int li = matchCell[ci];\n        assigns.push_back({fingers[li], matchDir[ci], cells[ci]});\n    }\n    sort(assigns.begin(), assigns.end(), [](const Assignment& a, const Assignment& b) {\n        return a.f < b.f;\n    });\n    return assigns;\n}\n\nclass GenericPlanner {\n    static constexpr int PICK = 0;\n    static constexpr int DROP = 1;\n    static constexpr int MAX_TURN = 100000;\n\n    // type 0: star, type 1: palm\n    int type, N, Vlimit, Vp, k, C;\n    int A; // palm shoulder length\n    vector<int> lens;\n\n    // star: dir[f] is absolute direction.\n    // palm: sd is shoulder absolute direction, dir[f] is leaf relative direction.\n    int sd = 0;\n    vector<int> dir;\n    vector<unsigned char> holding;\n\n    vector<unsigned char> srcRem, tgtRem;\n    int remSrc = 0, remT = 0, held = 0;\n\n    int rx = 0, ry = 0;\n    int initX = 0, initY = 0;\n\n    vector<string> ops;\n    bool valid = true;\n    bool aborted = false;\n\n    int scoreMode;\n    int strategy;\n    double pairBonus;\n    bool routeAware;\n    bool refineAssign;\n\n    vector<int> mark;\n    vector<int> tmpIndex;\n    int stamp = 1;\n\npublic:\n    GenericPlanner(int N_, int V_,\n                   int type_,\n                   const vector<unsigned char>& src0,\n                   const vector<unsigned char>& tgt0,\n                   const vector<int>& lengths,\n                   int A_,\n                   int scoreMode_,\n                   int strategy_,\n                   double pairBonus_,\n                   bool routeAware_ = true,\n                   bool refineAssign_ = true)\n        : type(type_), N(N_), Vlimit(V_), C(N_ * N_), A(A_),\n          lens(lengths),\n          srcRem(src0), tgtRem(tgt0),\n          scoreMode(scoreMode_), strategy(strategy_),\n          pairBonus(pairBonus_), routeAware(routeAware_),\n          refineAssign(refineAssign_),\n          mark(N_ * N_, 0), tmpIndex(N_ * N_, -1) {\n        if (type == 0) {\n            k = (int)lens.size();\n            Vp = k + 1;\n        } else {\n            k = (int)lens.size();\n            Vp = k + 2;\n        }\n        dir.assign(k, 0);\n        holding.assign(k, 0);\n\n        for (int i = 0; i < C; i++) {\n            if (srcRem[i]) remSrc++;\n            if (tgtRem[i]) remT++;\n        }\n    }\n\n    PlanResult run() {\n        if (k <= 0 || Vp > Vlimit) {\n            PlanResult bad;\n            bad.valid = false;\n            return bad;\n        }\n\n        selectInitialRoot();\n        initX = rx;\n        initY = ry;\n\n        if (strategy == 0) runBatch();\n        else if (strategy == 1) runDynamic();\n        else if (strategy == 2) runHybrid();\n        else runMixed();\n\n        PlanResult res;\n        res.Vp = Vp;\n        res.parent.assign(Vp, -1);\n        res.edgeLen.assign(Vp, 0);\n\n        if (type == 0) {\n            for (int f = 0; f < k; f++) {\n                int v = vertexOf(f);\n                res.parent[v] = 0;\n                res.edgeLen[v] = lens[f];\n            }\n        } else {\n            res.parent[1] = 0;\n            res.edgeLen[1] = A;\n            for (int f = 0; f < k; f++) {\n                int v = vertexOf(f);\n                res.parent[v] = 1;\n                res.edgeLen[v] = lens[f];\n            }\n        }\n\n        res.initX = initX;\n        res.initY = initY;\n        res.valid = valid;\n        res.complete = valid && remSrc == 0 && remT == 0 && held == 0;\n        res.ops = std::move(ops);\n\n        if (!res.valid) res.score = (1LL << 60);\n        else if (res.complete) res.score = (long long)res.ops.size();\n        else res.score = 100000LL + 1000LL * remT;\n\n        return res;\n    }\n\nprivate:\n    int id(int x, int y) const { return x * N + y; }\n\n    bool inside(int x, int y) const {\n        return 0 <= x && x < N && 0 <= y && y < N;\n    }\n\n    int vertexOf(int f) const {\n        return type == 0 ? f + 1 : f + 2;\n    }\n\n    int gdCount() const {\n        return type == 0 ? 1 : 4;\n    }\n\n    int currentGd() const {\n        return type == 0 ? 0 : sd;\n    }\n\n    int globalRotTo(int gd) const {\n        return type == 0 ? 0 : rotDist(sd, gd);\n    }\n\n    int nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            fill(mark.begin(), mark.end(), 0);\n            stamp = 1;\n        }\n        return stamp;\n    }\n\n    int rotDist(int a, int b) const {\n        int d = abs(a - b);\n        return min(d, 4 - d);\n    }\n\n    int previewRotateDir(int cur, int target) const {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return cur;\n        if (diff == 1 || diff == 2) return (cur + 1) & 3;\n        return (cur + 3) & 3;\n    }\n\n    char rotateStep(int& cur, int target) {\n        int diff = (target - cur + 4) % 4;\n        if (diff == 0) return '.';\n        if (diff == 1 || diff == 2) {\n            cur = (cur + 1) & 3;\n            return 'R';\n        } else {\n            cur = (cur + 3) & 3;\n            return 'L';\n        }\n    }\n\n    int cellAt(int rootX, int rootY, int gd, int f, int code) const {\n        int x = rootX;\n        int y = rootY;\n        if (type == 1) {\n            x += DX[gd] * A;\n            y += DY[gd] * A;\n        }\n        x += DX[code] * lens[f];\n        y += DY[code] * lens[f];\n\n        if (!inside(x, y)) return -1;\n        return id(x, y);\n    }\n\n    int fingerCode(int f) const {\n        if (type == 0) return dir[f];\n        return (sd + dir[f]) & 3;\n    }\n\n    int fingerCell(int f) const {\n        return cellAt(rx, ry, currentGd(), f, fingerCode(f));\n    }\n\n    int rotTo(int f, int code, int gd) const {\n        if (type == 0) return rotDist(dir[f], code);\n        int targetRel = (code - gd + 4) & 3;\n        return rotDist(dir[f], targetRel);\n    }\n\n    bool hasRemaining(int mode, int cid) const {\n        return mode == PICK ? (srcRem[cid] != 0) : (tgtRem[cid] != 0);\n    }\n\n    bool hasOpposite(int mode, int cid) const {\n        return mode == PICK ? (tgtRem[cid] != 0) : (srcRem[cid] != 0);\n    }\n\n    bool eligible(int mode, int f) const {\n        if (mode == PICK) return !holding[f] && remSrc > 0;\n        return holding[f] && remT > 0;\n    }\n\n    bool eligibleMixed(int f) const {\n        if (holding[f]) return remT > 0;\n        return remSrc > 0;\n    }\n\n    bool hasState(int f, int cid) const {\n        if (holding[f]) return tgtRem[cid] != 0;\n        return srcRem[cid] != 0;\n    }\n\n    bool hasOppositeState(int f, int cid) const {\n        if (holding[f]) return srcRem[cid] != 0;\n        return tgtRem[cid] != 0;\n    }\n\n    int maxRotOf(const vector<Assignment>& assigns, int gd) const {\n        int mx = 0;\n        for (const auto& a : assigns) mx = max(mx, rotTo(a.f, a.dir, gd));\n        return mx;\n    }\n\n    Estimate estimateAt(int x, int y, int gd, int mode) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 0; f < k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int code = 0; code < 4; code++) {\n                int cid = cellAt(x, y, gd, f, code);\n                if (cid < 0) continue;\n\n                if (hasOpposite(mode, cid)) hasOther = true;\n                if (!hasRemaining(mode, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int r = rotTo(f, code, gd);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    Estimate estimateAtMixed(int x, int y, int gd) {\n        Estimate e;\n        int st = nextStamp();\n\n        for (int f = 0; f < k; f++) {\n            if (!eligibleMixed(f)) continue;\n\n            int bestCell = -1;\n            int bestRot = 100;\n            bool hasOther = false;\n\n            for (int code = 0; code < 4; code++) {\n                int cid = cellAt(x, y, gd, f, code);\n                if (cid < 0) continue;\n\n                if (hasOppositeState(f, cid)) hasOther = true;\n                if (!hasState(f, cid)) continue;\n                if (mark[cid] == st) continue;\n\n                int r = rotTo(f, code, gd);\n                if (r < bestRot) {\n                    bestRot = r;\n                    bestCell = cid;\n                }\n            }\n\n            if (bestCell >= 0) {\n                mark[bestCell] = st;\n                e.cnt++;\n                e.maxrot = max(e.maxrot, bestRot);\n                if (hasOther) e.pairCnt++;\n            }\n        }\n\n        return e;\n    }\n\n    double rootScore(int travel, int cnt, int dist) const {\n        if (scoreMode == 0) return (travel + 0.3) / cnt + 0.002 * dist;\n        return travel - 1.5 * (cnt - 1) + 0.01 * dist;\n    }\n\n    Choice findBest(int mode) {\n        Choice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int gd = 0; gd < gdCount(); gd++) {\n                    Estimate e = estimateAt(x, y, gd, mode);\n                    if (e.cnt == 0) continue;\n\n                    int dist = abs(rx - x) + abs(ry - y);\n                    int grot = globalRotTo(gd);\n                    int travel = max({dist, grot, e.maxrot, 1});\n                    double sc = rootScore(travel, e.cnt, dist + grot);\n                    sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                    if (!best.exists ||\n                        sc < best.score - 1e-12 ||\n                        (fabs(sc - best.score) < 1e-12 &&\n                         (e.cnt > best.cnt ||\n                          (e.cnt == best.cnt && travel < best.travel)))) {\n                        best.exists = true;\n                        best.x = x;\n                        best.y = y;\n                        best.gd = gd;\n                        best.score = sc;\n                        best.cnt = e.cnt;\n                        best.travel = travel;\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    Choice findBestMixed() {\n        Choice best;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int gd = 0; gd < gdCount(); gd++) {\n                    Estimate e = estimateAtMixed(x, y, gd);\n                    if (e.cnt == 0) continue;\n\n                    int dist = abs(rx - x) + abs(ry - y);\n                    int grot = globalRotTo(gd);\n                    int travel = max({dist, grot, e.maxrot, 1});\n                    double sc = rootScore(travel, e.cnt, dist + grot);\n                    sc -= pairBonus * (double)e.pairCnt / max(1, e.cnt);\n\n                    if (!best.exists ||\n                        sc < best.score - 1e-12 ||\n                        (fabs(sc - best.score) < 1e-12 &&\n                         (e.cnt > best.cnt ||\n                          (e.cnt == best.cnt && travel < best.travel)))) {\n                        best.exists = true;\n                        best.x = x;\n                        best.y = y;\n                        best.gd = gd;\n                        best.score = sc;\n                        best.cnt = e.cnt;\n                        best.travel = travel;\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    void selectInitialRoot() {\n        double bestScore = 1e100;\n        int bestCnt = -1;\n        int bestCenter = 1e9;\n\n        for (int x = 0; x < N; x++) {\n            for (int y = 0; y < N; y++) {\n                for (int gd = 0; gd < gdCount(); gd++) {\n                    Estimate e = estimateAt(x, y, gd, PICK);\n                    if (e.cnt == 0) continue;\n\n                    int grot = type == 0 ? 0 : rotDist(0, gd);\n                    int travel = max({grot, e.maxrot, 1});\n                    int center = abs(x - N / 2) + abs(y - N / 2);\n                    double sc = (travel + 0.3) / e.cnt\n                                - pairBonus * (double)e.pairCnt / max(1, e.cnt)\n                                + 0.0005 * center;\n\n                    if (sc < bestScore - 1e-12 ||\n                        (fabs(sc - bestScore) < 1e-12 &&\n                         (e.cnt > bestCnt ||\n                          (e.cnt == bestCnt && center < bestCenter)))) {\n                        bestScore = sc;\n                        bestCnt = e.cnt;\n                        bestCenter = center;\n                        rx = x;\n                        ry = y;\n                    }\n                }\n            }\n        }\n    }\n\n    vector<Assignment> buildAssignments(const vector<int>& fingers,\n                                        vector<vector<MEdge>>& edges,\n                                        const vector<int>& cells,\n                                        int gd,\n                                        int baseDist) {\n        if (fingers.empty() || cells.empty()) return {};\n\n        int R = (int)cells.size();\n\n        vector<int> curMatch, curDir;\n        int curCnt = oldMatching(edges, R, curMatch, curDir);\n        vector<Assignment> cur = makeAssignments(fingers, cells, curMatch, curDir);\n\n        if (cur.empty() || !refineAssign) return cur;\n\n        vector<int> fullMatch, fullDir;\n        int fullCnt = limitedMatching(edges, R, 2, fullMatch, fullDir);\n\n        if (fullCnt >= curCnt && fullCnt > 0) {\n            vector<int> bestMatch = fullMatch;\n            vector<int> bestDir = fullDir;\n\n            for (int lim = 0; lim <= 2; lim++) {\n                vector<int> m, d;\n                int c = limitedMatching(edges, R, lim, m, d);\n                if (c == fullCnt) {\n                    bestMatch = std::move(m);\n                    bestDir = std::move(d);\n                    break;\n                }\n            }\n\n            vector<Assignment> opt = makeAssignments(fingers, cells, bestMatch, bestDir);\n\n            if ((int)opt.size() > (int)cur.size()) return opt;\n\n            if (opt.size() == cur.size()) {\n                int curMax = maxRotOf(cur, gd);\n                int optMax = maxRotOf(opt, gd);\n                int curTurns = max({baseDist, curMax, 1});\n                int optTurns = max({baseDist, optMax, 1});\n\n                if (optTurns < curTurns) return opt;\n            }\n        }\n\n        return cur;\n    }\n\n    vector<Assignment> getAssignmentsAt(int x, int y, int gd, int mode) {\n        vector<int> fingers;\n        vector<vector<MEdge>> edges;\n        vector<int> cells;\n\n        for (int f = 0; f < k; f++) {\n            if (!eligible(mode, f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n            int li = (int)fingers.size() - 1;\n\n            for (int code = 0; code < 4; code++) {\n                int cid = cellAt(x, y, gd, f, code);\n                if (cid < 0) continue;\n                if (!hasRemaining(mode, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                edges[li].push_back({tmpIndex[cid], code, rotTo(f, code, gd)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const MEdge& a, const MEdge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int base = max(abs(rx - x) + abs(ry - y), globalRotTo(gd));\n        return buildAssignments(fingers, edges, cells, gd, base);\n    }\n\n    vector<Assignment> getAssignmentsAtMixed(int x, int y, int gd) {\n        vector<int> fingers;\n        vector<vector<MEdge>> edges;\n        vector<int> cells;\n\n        for (int f = 0; f < k; f++) {\n            if (!eligibleMixed(f)) continue;\n\n            fingers.push_back(f);\n            edges.emplace_back();\n            int li = (int)fingers.size() - 1;\n\n            for (int code = 0; code < 4; code++) {\n                int cid = cellAt(x, y, gd, f, code);\n                if (cid < 0) continue;\n                if (!hasState(f, cid)) continue;\n\n                if (tmpIndex[cid] == -1) {\n                    tmpIndex[cid] = (int)cells.size();\n                    cells.push_back(cid);\n                }\n                edges[li].push_back({tmpIndex[cid], code, rotTo(f, code, gd)});\n            }\n\n            sort(edges[li].begin(), edges[li].end(), [](const MEdge& a, const MEdge& b) {\n                if (a.rot != b.rot) return a.rot < b.rot;\n                return a.cellIdx < b.cellIdx;\n            });\n        }\n\n        for (int cid : cells) tmpIndex[cid] = -1;\n\n        int base = max(abs(rx - x) + abs(ry - y), globalRotTo(gd));\n        return buildAssignments(fingers, edges, cells, gd, base);\n    }\n\n    NextMove fallbackNext(int mode) {\n        NextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            if (!hasRemaining(mode, cid)) continue;\n            int cx = cid / N;\n            int cy = cid % N;\n\n            for (int f = 0; f < k; f++) {\n                if (!eligible(mode, f)) continue;\n\n                for (int gd = 0; gd < gdCount(); gd++) {\n                    for (int code = 0; code < 4; code++) {\n                        int ox = DX[code] * lens[f];\n                        int oy = DY[code] * lens[f];\n                        if (type == 1) {\n                            ox += DX[gd] * A;\n                            oy += DY[gd] * A;\n                        }\n\n                        int tx = cx - ox;\n                        int ty = cy - oy;\n                        if (!inside(tx, ty)) continue;\n\n                        int md = abs(rx - tx) + abs(ry - ty);\n                        int travel = max({md, globalRotTo(gd), rotTo(f, code, gd), 1});\n                        double sc = travel;\n\n                        if (!best.exists || sc < best.score) {\n                            best.exists = true;\n                            best.x = tx;\n                            best.y = ty;\n                            best.gd = gd;\n                            best.score = sc;\n                            best.assigns = {Assignment{f, code, cid}};\n                        }\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    NextMove fallbackNextMixed() {\n        NextMove best;\n\n        for (int cid = 0; cid < C; cid++) {\n            for (int f = 0; f < k; f++) {\n                if (!eligibleMixed(f)) continue;\n                if (!hasState(f, cid)) continue;\n\n                int cx = cid / N;\n                int cy = cid % N;\n\n                for (int gd = 0; gd < gdCount(); gd++) {\n                    for (int code = 0; code < 4; code++) {\n                        int ox = DX[code] * lens[f];\n                        int oy = DY[code] * lens[f];\n                        if (type == 1) {\n                            ox += DX[gd] * A;\n                            oy += DY[gd] * A;\n                        }\n\n                        int tx = cx - ox;\n                        int ty = cy - oy;\n                        if (!inside(tx, ty)) continue;\n\n                        int md = abs(rx - tx) + abs(ry - ty);\n                        int travel = max({md, globalRotTo(gd), rotTo(f, code, gd), 1});\n                        double sc = travel;\n\n                        if (!best.exists || sc < best.score) {\n                            best.exists = true;\n                            best.x = tx;\n                            best.y = ty;\n                            best.gd = gd;\n                            best.score = sc;\n                            best.assigns = {Assignment{f, code, cid}};\n                        }\n                    }\n                }\n            }\n        }\n\n        return best;\n    }\n\n    NextMove makeNext(int mode, const Choice& ch) {\n        NextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAt(ch.x, ch.y, ch.gd, mode);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.gd = ch.gd;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNext(mode);\n    }\n\n    NextMove makeNextMixed(const Choice& ch) {\n        NextMove nxt;\n\n        if (ch.exists) {\n            auto assigns = getAssignmentsAtMixed(ch.x, ch.y, ch.gd);\n            if (!assigns.empty()) {\n                nxt.exists = true;\n                nxt.x = ch.x;\n                nxt.y = ch.y;\n                nxt.gd = ch.gd;\n                nxt.score = ch.score;\n                nxt.assigns = std::move(assigns);\n                return nxt;\n            }\n        }\n\n        return fallbackNextMixed();\n    }\n\n    NextMove chooseNext(int mode) {\n        return makeNext(mode, findBest(mode));\n    }\n\n    NextMove chooseNextMixed() {\n        return makeNextMixed(findBestMixed());\n    }\n\n    int potentialForRoot(int nx, int ny, int gdAfter,\n                         const vector<unsigned char>& selected,\n                         const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        int cnt = 0;\n        static const int DELTA[3] = {0, 1, 3};\n\n        for (int f = 0; f < k; f++) {\n            if (selected[f]) continue;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int code;\n                if (type == 0) {\n                    code = (dir[f] + DELTA[oi]) & 3;\n                } else {\n                    int nr = (dir[f] + DELTA[oi]) & 3;\n                    code = (gdAfter + nr) & 3;\n                }\n\n                int cid = cellAt(nx, ny, gdAfter, f, code);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                mark[cid] = st;\n                cnt++;\n                break;\n            }\n        }\n\n        return cnt;\n    }\n\n    char chooseMoveChar(int tx, int ty,\n                        const vector<unsigned char>& selected,\n                        const vector<unsigned char>& reserved,\n                        int gdAfter) {\n        vector<pair<char, pair<int, int>>> cand;\n\n        if (rx < tx) cand.push_back({'D', {rx + 1, ry}});\n        if (rx > tx) cand.push_back({'U', {rx - 1, ry}});\n        if (ry < ty) cand.push_back({'R', {rx, ry + 1}});\n        if (ry > ty) cand.push_back({'L', {rx, ry - 1}});\n\n        if (cand.empty()) return '.';\n        if (cand.size() == 1 || !routeAware) return cand[0].first;\n\n        int bestPot = -1;\n        char bestChar = cand[0].first;\n        int bestDimRemain = -1;\n\n        for (auto& c : cand) {\n            int pot = potentialForRoot(c.second.first, c.second.second,\n                                       gdAfter, selected, reserved);\n            bool vertical = (c.first == 'U' || c.first == 'D');\n            int dimRemain = vertical ? abs(tx - rx) : abs(ty - ry);\n\n            if (pot > bestPot || (pot == bestPot && dimRemain > bestDimRemain)) {\n                bestPot = pot;\n                bestChar = c.first;\n                bestDimRemain = dimRemain;\n            }\n        }\n\n        return bestChar;\n    }\n\n    void applyMove(char mv) {\n        if (mv == 'U') rx--;\n        else if (mv == 'D') rx++;\n        else if (mv == 'L') ry--;\n        else if (mv == 'R') ry++;\n    }\n\n    void chooseAutoActions(string& cmd,\n                           const vector<unsigned char>& selected,\n                           const vector<unsigned char>& reserved) {\n        int st = nextStamp();\n        static const int DELTA[3] = {0, 1, 3};\n        static const char RCHAR[3] = {'.', 'R', 'L'};\n\n        int gd = currentGd();\n\n        for (int f = 0; f < k; f++) {\n            if (selected[f]) continue;\n\n            int v = vertexOf(f);\n            if (cmd[v] != '.') continue;\n\n            int chosen = -1;\n            int chosenCell = -1;\n            int chosenDir = -1;\n\n            for (int oi = 0; oi < 3; oi++) {\n                int newDir = (dir[f] + DELTA[oi]) & 3;\n                int code = type == 0 ? newDir : ((gd + newDir) & 3);\n\n                int cid = cellAt(rx, ry, gd, f, code);\n                if (cid < 0) continue;\n                if (reserved[cid]) continue;\n                if (mark[cid] == st) continue;\n\n                if (holding[f]) {\n                    if (!tgtRem[cid]) continue;\n                } else {\n                    if (!srcRem[cid]) continue;\n                }\n\n                chosen = oi;\n                chosenCell = cid;\n                chosenDir = newDir;\n                break;\n            }\n\n            if (chosen != -1) {\n                cmd[v] = RCHAR[chosen];\n                dir[f] = chosenDir;\n                cmd[Vp + v] = 'P';\n                mark[chosenCell] = st;\n            }\n        }\n    }\n\n    void applyActions(const string& cmd) {\n        for (int f = 0; f < k; f++) {\n            int v = vertexOf(f);\n            if (cmd[Vp + v] != 'P') continue;\n\n            int cid = fingerCell(f);\n            if (cid < 0) {\n                valid = false;\n                return;\n            }\n\n            if (holding[f]) {\n                if (!tgtRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                tgtRem[cid] = 0;\n                holding[f] = 0;\n                held--;\n                remT--;\n            } else {\n                if (!srcRem[cid]) {\n                    valid = false;\n                    return;\n                }\n                srcRem[cid] = 0;\n                holding[f] = 1;\n                held++;\n                remSrc--;\n            }\n        }\n    }\n\n    bool perform(int tx, int ty, int targetGd, const vector<Assignment>& assigns) {\n        if (assigns.empty()) return false;\n\n        vector<unsigned char> selected(k, 0);\n        vector<int> targetDir(k, -1);\n        vector<unsigned char> reserved(C, 0);\n\n        int maxrot = 0;\n        for (const auto& a : assigns) {\n            selected[a.f] = 1;\n            targetDir[a.f] = (type == 0 ? a.dir : ((a.dir - targetGd + 4) & 3));\n            reserved[a.cell] = 1;\n            maxrot = max(maxrot, rotDist(dir[a.f], targetDir[a.f]));\n        }\n\n        int md = abs(rx - tx) + abs(ry - ty);\n        int grot = globalRotTo(targetGd);\n        int total = max({md, grot, maxrot, 1});\n\n        for (int turn = 0; turn < total; turn++) {\n            if ((int)ops.size() >= MAX_TURN) {\n                aborted = true;\n                return false;\n            }\n\n            string cmd(2 * Vp, '.');\n\n            int futureGd = currentGd();\n            if (type == 1) futureGd = previewRotateDir(sd, targetGd);\n\n            if (rx != tx || ry != ty) {\n                char mv = chooseMoveChar(tx, ty, selected, reserved, futureGd);\n                cmd[0] = mv;\n                applyMove(mv);\n            }\n\n            if (type == 1 && sd != targetGd) {\n                cmd[1] = rotateStep(sd, targetGd);\n            }\n\n            for (const auto& a : assigns) {\n                int f = a.f;\n                int v = vertexOf(f);\n                if (dir[f] != targetDir[f]) {\n                    cmd[v] = rotateStep(dir[f], targetDir[f]);\n                }\n            }\n\n            chooseAutoActions(cmd, selected, reserved);\n\n            if (turn == total - 1) {\n                if (rx != tx || ry != ty || currentGd() != targetGd) {\n                    valid = false;\n                    return false;\n                }\n\n                for (const auto& a : assigns) {\n                    int f = a.f;\n                    int v = vertexOf(f);\n\n                    if (dir[f] != targetDir[f]) {\n                        valid = false;\n                        return false;\n                    }\n                    if (fingerCell(f) != a.cell) {\n                        valid = false;\n                        return false;\n                    }\n                    cmd[Vp + v] = 'P';\n                }\n            }\n\n            ops.push_back(cmd);\n            applyActions(cmd);\n            if (!valid) return false;\n        }\n\n        return true;\n    }\n\n    void runBatch() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool progressed = false;\n\n            while (remSrc > 0 && held < k && !aborted && valid) {\n                NextMove nxt = chooseNext(PICK);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.gd, nxt.assigns);\n                progressed = true;\n            }\n\n            while (held > 0 && !aborted && valid) {\n                NextMove nxt = chooseNext(DROP);\n                if (!nxt.exists) {\n                    valid = false;\n                    return;\n                }\n                perform(nxt.x, nxt.y, nxt.gd, nxt.assigns);\n                progressed = true;\n            }\n\n            if (!progressed) break;\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runDynamic() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBest(PICK);\n            if (canDrop) cd = findBest(DROP);\n\n            int mode;\n            if (canPick && canDrop) {\n                if (!cp.exists && cd.exists) mode = DROP;\n                else if (cp.exists && !cd.exists) mode = PICK;\n                else if (!cp.exists && !cd.exists) mode = PICK;\n                else {\n                    double ps = cp.score;\n                    double ds = cd.score;\n                    if (held < max(1, k / 2) && remSrc > 0) ds += 0.35;\n                    mode = (ps <= ds ? PICK : DROP);\n                }\n            } else if (canPick) {\n                mode = PICK;\n            } else {\n                mode = DROP;\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.gd, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runHybrid() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            bool canPick = (remSrc > 0 && held < k);\n            bool canDrop = (held > 0);\n\n            if (!canPick && !canDrop) break;\n\n            Choice cp, cd;\n            if (canPick) cp = findBest(PICK);\n            if (canDrop) cd = findBest(DROP);\n\n            int mode;\n            if (canDrop && (!canPick || held == k)) {\n                mode = DROP;\n            } else if (canPick && !canDrop) {\n                mode = PICK;\n            } else {\n                if (cd.exists && cp.exists &&\n                    (cd.travel <= 2 || cd.score + 0.25 < cp.score)) {\n                    mode = DROP;\n                } else {\n                    mode = PICK;\n                }\n            }\n\n            NextMove nxt = makeNext(mode, mode == PICK ? cp : cd);\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.gd, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\n\n    void runMixed() {\n        int guard = 0;\n\n        while ((remSrc > 0 || held > 0) && !aborted && valid) {\n            NextMove nxt = chooseNextMixed();\n            if (!nxt.exists) {\n                valid = false;\n                return;\n            }\n\n            perform(nxt.x, nxt.y, nxt.gd, nxt.assigns);\n\n            if (++guard > 10000) {\n                valid = false;\n                break;\n            }\n        }\n    }\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\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    int C = N * N;\n    vector<unsigned char> src(C, 0), tgt(C, 0);\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            int cid = i * N + j;\n            if (s[i][j] == '1' && t[i][j] == '0') src[cid] = 1;\n            if (s[i][j] == '0' && t[i][j] == '1') tgt[cid] = 1;\n        }\n    }\n\n    int maxL = max(1, N / 2);\n\n    auto buildLengthSets = [&](int K) {\n        vector<vector<int>> sets;\n\n        auto addSet = [&](vector<int> a) {\n            if ((int)a.size() != K) return;\n            for (int& x : a) x = max(1, min(maxL, x));\n            for (auto& b : sets) {\n                if (a == b) return;\n            }\n            sets.push_back(a);\n        };\n\n        if (K <= 0) return sets;\n\n        auto cycleSet = [&](int L) {\n            L = max(1, min(L, maxL));\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = 1 + (i % L);\n            return a;\n        };\n\n        auto repeatVals = [&](vector<int> vals) {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) a[i] = vals[i % vals.size()];\n            return a;\n        };\n\n        addSet(cycleSet(maxL));\n        addSet(cycleSet(6));\n        addSet(cycleSet(4));\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    a[i] = (int)llround(1.0 + (double)i * (maxL - 1) / (K - 1));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                a[i] = (int)llround((i + 0.5) * maxL / K);\n                if (a[i] < 1) a[i] = 1;\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            if (K == 1) a[0] = maxL;\n            else {\n                for (int i = 0; i < K; i++) {\n                    double r = (double)i / (K - 1);\n                    a[i] = (int)llround(pow((double)maxL, r));\n                }\n            }\n            addSet(a);\n        }\n\n        {\n            vector<int> a(K);\n            for (int i = 0; i < K; i++) {\n                if (i % 2 == 0) a[i] = 1 + (i / 2) % maxL;\n                else a[i] = maxL - (i / 2) % maxL;\n            }\n            addSet(a);\n        }\n\n        addSet(vector<int>(K, 1));\n        addSet(vector<int>(K, maxL));\n        addSet(vector<int>(K, max(1, maxL / 2)));\n\n        addSet(repeatVals(vector<int>{1, maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 2), maxL}));\n        addSet(repeatVals(vector<int>{1, max(1, maxL / 3), max(1, 2 * maxL / 3), maxL}));\n        addSet(repeatVals(vector<int>{max(1, maxL / 4), max(1, maxL / 2), max(1, 3 * maxL / 4), maxL}));\n\n        return sets;\n    };\n\n    vector<vector<int>> starLengthSets = buildLengthSets(V - 1);\n\n    auto startTime = chrono::steady_clock::now();\n\n    auto elapsedMs = [&]() {\n        auto now = chrono::steady_clock::now();\n        return chrono::duration_cast<chrono::milliseconds>(now - startTime).count();\n    };\n\n    PlanResult best;\n\n    auto consider = [&](PlanResult&& res) {\n        if (res.valid &&\n            (res.score < best.score ||\n             (res.score == best.score && res.ops.size() < best.ops.size()))) {\n            best = std::move(res);\n        }\n    };\n\n    struct StarParam {\n        int li;\n        int sm;\n        int st;\n        double pb;\n    };\n\n    vector<StarParam> starParams;\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.0});\n\n    int split = (int)starParams.size();\n\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 1, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 1, 0, 0.0});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 0, 0.30});\n    for (int i = 0; i < (int)starLengthSets.size(); i++) starParams.push_back({i, 0, 2, 0.30});\n\n    auto runStarRange = [&](int l, int r, bool routeAware = true, bool refine = true) {\n        for (int idx = l; idx < r; idx++) {\n            if (idx > l && elapsedMs() > 2760) break;\n\n            auto p = starParams[idx];\n\n            GenericPlanner planner(N, V, 0, src, tgt,\n                                   starLengthSets[p.li],\n                                   0, p.sm, p.st, p.pb,\n                                   routeAware, refine);\n            PlanResult res = planner.run();\n            consider(std::move(res));\n        }\n    };\n\n    runStarRange(0, split, true, true);\n\n    // Earlier gated mixed pick/drop variants. Kept very small to preserve the known-good search.\n    if (elapsedMs() < 1500) {\n        int lim = min(3, (int)starLengthSets.size());\n        for (int i = 0; i < lim; i++) {\n            for (double pb : {0.0, 0.25}) {\n                if (elapsedMs() > 2760) break;\n                GenericPlanner planner(N, V, 0, src, tgt,\n                                       starLengthSets[i],\n                                       0, 0, 3, pb,\n                                       true, true);\n                PlanResult res = planner.run();\n                consider(std::move(res));\n            }\n        }\n    }\n\n    vector<vector<int>> palmLengthSets;\n    vector<int> As;\n\n    if (V >= 5) {\n        int kp = V - 2;\n        palmLengthSets = buildLengthSets(kp);\n        As = {\n            maxL,\n            max(1, (2 * maxL + 1) / 3),\n            max(1, maxL / 2)\n        };\n        sort(As.begin(), As.end());\n        As.erase(unique(As.begin(), As.end()), As.end());\n        reverse(As.begin(), As.end());\n    }\n\n    auto runPalm = [&](double pb, int limSets, bool pathAware, bool refine) {\n        if (V < 5) return;\n        limSets = min(limSets, (int)palmLengthSets.size());\n        vector<int> palmStrategies = {0, 2, 1};\n\n        for (int A : As) {\n            for (int li = 0; li < limSets; li++) {\n                for (int stg : palmStrategies) {\n                    if (elapsedMs() > 2760) return;\n\n                    GenericPlanner planner(N, V, 1, src, tgt,\n                                           palmLengthSets[li],\n                                           A, 0, stg, pb,\n                                           pathAware, refine);\n                    PlanResult res = planner.run();\n                    consider(std::move(res));\n                }\n            }\n        }\n    };\n\n    if (elapsedMs() < 2300 && V >= 5) {\n        runPalm(0.25, 5, false, true);\n    }\n\n    if (elapsedMs() < 2760) {\n        runStarRange(split, (int)starParams.size(), true, true);\n    }\n\n    if (elapsedMs() < 2650 && V >= 5) {\n        runPalm(0.0, 3, false, true);\n    }\n\n    if (elapsedMs() < 2700 && V >= 5) {\n        runPalm(0.25, 2, true, true);\n    }\n\n    if (elapsedMs() < 2700) {\n        int lim = min(5, (int)starLengthSets.size());\n        vector<int> stgs = {0, 2};\n        for (int i = 0; i < lim; i++) {\n            for (int stg : stgs) {\n                if (elapsedMs() > 2760) break;\n\n                GenericPlanner planner(N, V, 0, src, tgt,\n                                       starLengthSets[i],\n                                       0, 0, stg, 0.0,\n                                       false, true);\n                PlanResult res = planner.run();\n                consider(std::move(res));\n            }\n        }\n    }\n\n    // Late legacy matching variants.\n    if (elapsedMs() < 2700) {\n        int lim = min(8, (int)starLengthSets.size());\n        vector<tuple<int, int, double, bool>> variants = {\n            {0, 0, 0.0, true},\n            {0, 2, 0.0, true},\n            {0, 0, 0.30, true},\n            {0, 2, 0.30, true},\n            {0, 0, 0.0, false},\n            {0, 2, 0.0, false}\n        };\n\n        for (int i = 0; i < lim; i++) {\n            for (auto [sm, stg, pb, route] : variants) {\n                if (elapsedMs() > 2760) break;\n\n                GenericPlanner planner(N, V, 0, src, tgt,\n                                       starLengthSets[i],\n                                       0, sm, stg, pb,\n                                       route, false);\n                PlanResult res = planner.run();\n                consider(std::move(res));\n            }\n        }\n    }\n\n    if (elapsedMs() < 2680 && V >= 5) {\n        runPalm(0.25, 3, false, false);\n    }\n\n    if (!best.valid) {\n        best.valid = true;\n        best.Vp = V;\n        best.parent.assign(V, -1);\n        best.edgeLen.assign(V, 0);\n\n        vector<int> lens = starLengthSets.empty() ? vector<int>(V - 1, 1) : starLengthSets[0];\n        for (int i = 1; i < V; i++) {\n            best.parent[i] = 0;\n            best.edgeLen[i] = lens[i - 1];\n        }\n\n        best.initX = 0;\n        best.initY = 0;\n        best.ops.clear();\n    }\n\n    cout << best.Vp << '\\n';\n    for (int i = 1; i < best.Vp; i++) {\n        cout << best.parent[i] << ' ' << best.edgeLen[i] << '\\n';\n    }\n    cout << best.initX << ' ' << best.initY << '\\n';\n\n    for (const string& op : best.ops) {\n        cout << op << '\\n';\n    }\n\n    return 0;\n}","ahc039":"#include <bits/stdc++.h>\n#include <atcoder/maxflow>\nusing namespace std;\nusing ll = long long;\nusing uchar = unsigned char;\n\nconstexpr int CMAX = 100000;\nconstexpr int MAXLEN = 400000;\nconstexpr int MAXV = 1000;\nconstexpr int INF = 1e9;\n\nstruct Fish {\n    int x, y, w;\n};\n\nstruct Candidate {\n    int approx;\n    int cat;\n    vector<pair<int,int>> poly;\n};\n\nstruct Rect {\n    int x1, y1, x2, y2;\n};\n\nvector<Fish> fishes;\nvector<int> fishOrderY;\nvector<Candidate> candidates;\n\nvector<pair<int,int>> bestPoly;\nvector<pair<int,int>> bestSafePoly;\nint bestApprox = -1;\nint bestSafeApprox = -1;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nvector<pair<int,int>> square_poly() {\n    return {{0,0}, {CMAX,0}, {CMAX,CMAX}, {0,CMAX}};\n}\n\nuint64_t poly_hash(const vector<pair<int,int>>& p) {\n    uint64_t h = 1469598103934665603ULL;\n    h ^= (uint64_t)p.size();\n    h *= 1099511628211ULL;\n    for (auto [x, y] : p) {\n        h ^= (uint64_t)(x + 1000003LL * y);\n        h *= 1099511628211ULL;\n    }\n    return h;\n}\n\nvoid record_candidate(const vector<pair<int,int>>& poly, int approx, int cat) {\n    if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return;\n    if (approx < 0) return;\n    if (approx == 0 && bestApprox >= 0 && !candidates.empty()) return;\n\n    if (approx > bestApprox) {\n        bestApprox = approx;\n        bestPoly = poly;\n    }\n\n    if ((cat == 0 || cat == 3) && approx > bestSafeApprox) {\n        bestSafeApprox = approx;\n        bestSafePoly = poly;\n    }\n\n    candidates.push_back({approx, cat, poly});\n\n    if (candidates.size() > 900) {\n        nth_element(candidates.begin(), candidates.begin() + 650, candidates.end(),\n                    [](const Candidate& a, const Candidate& b) {\n                        return a.approx > b.approx;\n                    });\n        candidates.resize(650);\n    }\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 <= n; idx += idx & -idx) bit[idx] += val;\n    }\n    int sum(int idx) const {\n        int r = 0;\n        for (; idx > 0; idx -= idx & -idx) r += bit[idx];\n        return r;\n    }\n    int all() const {\n        return sum(n);\n    }\n};\n\nint exact_score(const vector<pair<int,int>>& poly) {\n    int m = (int)poly.size();\n\n    int minx = CMAX, maxx = 0, miny = CMAX, maxy = 0;\n    for (auto [x, y] : poly) {\n        minx = min(minx, x);\n        maxx = max(maxx, x);\n        miny = min(miny, y);\n        maxy = max(maxy, y);\n    }\n\n    struct VEdge {\n        int x, y1, y2;\n    };\n\n    struct Event {\n        int y, xi, delta;\n        bool operator<(const Event& other) const {\n            return y < other.y;\n        }\n    };\n\n    vector<VEdge> vedges;\n    vector<int> xs;\n    unordered_map<int, vector<pair<int,int>>> vmap;\n    unordered_map<int, vector<pair<int,int>>> hmap;\n    vmap.reserve(m * 2 + 10);\n    hmap.reserve(m * 2 + 10);\n\n    for (int i = 0; i < m; i++) {\n        auto [x1, y1] = poly[i];\n        auto [x2, y2] = poly[(i + 1) % m];\n\n        if (x1 == x2) {\n            if (y1 > y2) swap(y1, y2);\n            if (y1 == y2) continue;\n            vedges.push_back({x1, y1, y2});\n            xs.push_back(x1);\n            vmap[x1].push_back({y1, y2});\n        } else {\n            if (x1 > x2) swap(x1, x2);\n            if (x1 == x2) continue;\n            hmap[y1].push_back({x1, x2});\n        }\n    }\n\n    for (auto& kv : vmap) sort(kv.second.begin(), kv.second.end());\n    for (auto& kv : hmap) sort(kv.second.begin(), kv.second.end());\n\n    sort(xs.begin(), xs.end());\n    xs.erase(unique(xs.begin(), xs.end()), xs.end());\n\n    vector<Event> events;\n    events.reserve(vedges.size() * 2);\n\n    for (const auto& e : vedges) {\n        int xi = lower_bound(xs.begin(), xs.end(), e.x) - xs.begin();\n        events.push_back({e.y1, xi, +1});\n        events.push_back({e.y2, xi, -1});\n    }\n\n    sort(events.begin(), events.end());\n\n    Fenwick fw((int)xs.size());\n    int ep = 0;\n    int score = 0;\n\n    auto on_boundary = [&](int px, int py) -> bool {\n        auto itv = vmap.find(px);\n        if (itv != vmap.end()) {\n            for (auto [a, b] : itv->second) {\n                if (a <= py && py <= b) return true;\n            }\n        }\n\n        auto ith = hmap.find(py);\n        if (ith != hmap.end()) {\n            for (auto [a, b] : ith->second) {\n                if (a <= px && px <= b) return true;\n            }\n        }\n\n        return false;\n    };\n\n    for (int id : fishOrderY) {\n        const auto& f = fishes[id];\n\n        if (f.y < miny) continue;\n        if (f.y > maxy) break;\n\n        while (ep < (int)events.size() && events[ep].y <= f.y) {\n            fw.add(events[ep].xi + 1, events[ep].delta);\n            ep++;\n        }\n\n        if (f.x < minx || f.x > maxx) continue;\n\n        if (on_boundary(f.x, f.y)) {\n            score += f.w;\n            continue;\n        }\n\n        int pos = upper_bound(xs.begin(), xs.end(), f.x) - xs.begin();\n        int crossings = fw.all() - fw.sum(pos);\n        if (crossings & 1) score += f.w;\n    }\n\n    return score;\n}\n\nint rect_score(int x1, int y1, int x2, int y2) {\n    if (x1 >= x2 || y1 >= y2) return -INF;\n    int s = 0;\n    for (const auto& f : fishes) {\n        if (x1 <= f.x && f.x <= x2 && y1 <= f.y && f.y <= y2) s += f.w;\n    }\n    return s;\n}\n\nvoid refine_and_record_rectangle(int x1, int y1, int x2, int y2) {\n    if (elapsed_sec() > 1.75) return;\n\n    x1 = max(0, min(CMAX, x1));\n    x2 = max(0, min(CMAX, x2));\n    y1 = max(0, min(CMAX, y1));\n    y2 = max(0, min(CMAX, y2));\n\n    if (x1 >= x2 || y1 >= y2) return;\n\n    auto opt_left = [&]() -> int {\n        int lo = 0, hi = max(0, x2 - 1);\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (y1 <= f.y && f.y <= y2 && f.x <= x2) {\n                pts.push_back({f.x, f.w});\n                if (lo <= f.x && f.x <= hi) cand.push_back(f.x);\n                if (lo <= f.x + 1 && f.x + 1 <= hi) cand.push_back(f.x + 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end(), greater<pair<int,int>>());\n        sort(cand.begin(), cand.end(), greater<int>());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = x1;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first >= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_right = [&]() -> int {\n        int lo = min(CMAX, x1 + 1), hi = CMAX;\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (y1 <= f.y && f.y <= y2 && f.x >= x1) {\n                pts.push_back({f.x, f.w});\n                if (lo <= f.x && f.x <= hi) cand.push_back(f.x);\n                if (lo <= f.x - 1 && f.x - 1 <= hi) cand.push_back(f.x - 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = x2;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first <= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_bottom = [&]() -> int {\n        int lo = 0, hi = max(0, y2 - 1);\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (x1 <= f.x && f.x <= x2 && f.y <= y2) {\n                pts.push_back({f.y, f.w});\n                if (lo <= f.y && f.y <= hi) cand.push_back(f.y);\n                if (lo <= f.y + 1 && f.y + 1 <= hi) cand.push_back(f.y + 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end(), greater<pair<int,int>>());\n        sort(cand.begin(), cand.end(), greater<int>());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = y1;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first >= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    auto opt_top = [&]() -> int {\n        int lo = min(CMAX, y1 + 1), hi = CMAX;\n        vector<pair<int,int>> pts;\n        vector<int> cand = {lo, hi};\n\n        for (auto& f : fishes) {\n            if (x1 <= f.x && f.x <= x2 && f.y >= y1) {\n                pts.push_back({f.y, f.w});\n                if (lo <= f.y && f.y <= hi) cand.push_back(f.y);\n                if (lo <= f.y - 1 && f.y - 1 <= hi) cand.push_back(f.y - 1);\n            }\n        }\n\n        sort(pts.begin(), pts.end());\n        sort(cand.begin(), cand.end());\n        cand.erase(unique(cand.begin(), cand.end()), cand.end());\n\n        int ptr = 0, cur = 0;\n        int bestS = -INF, bestC = y2;\n\n        for (int c : cand) {\n            while (ptr < (int)pts.size() && pts[ptr].first <= c) {\n                cur += pts[ptr].second;\n                ptr++;\n            }\n            if (cur > bestS) {\n                bestS = cur;\n                bestC = c;\n            }\n        }\n        return bestC;\n    };\n\n    for (int it = 0; it < 4; it++) {\n        x1 = opt_left();\n        x2 = opt_right();\n        y1 = opt_bottom();\n        y2 = opt_top();\n        if (x1 >= x2 || y1 >= y2) return;\n    }\n\n    int sc = rect_score(x1, y1, x2, y2);\n    if (sc <= 0) return;\n\n    vector<pair<int,int>> poly = {{x1, y1}, {x2, y1}, {x2, y2}, {x1, y2}};\n    record_candidate(poly, sc, 3);\n}\n\nstruct GridSolver {\n    int D, G, maxEdges, ncell;\n    vector<int> w;\n\n    struct Comp {\n        vector<int> cells;\n        int score = 0;\n        int perim = 0;\n    };\n\n    struct Eval {\n        int score;\n        int len;\n    };\n\n    struct Corridor {\n        int a, b;\n        bool xFirst;\n    };\n\n    GridSolver(int d) : D(d), G(CMAX / d), maxEdges(MAXLEN / d), ncell(G * G), w(ncell, 0) {\n        for (const auto& f : fishes) {\n            int x = f.x / D;\n            int y = f.y / D;\n            if (x >= G) x = G - 1;\n            if (y >= G) y = G - 1;\n            w[idx(x, y)] += f.w;\n        }\n    }\n\n    inline int idx(int x, int y) const {\n        return y * G + x;\n    }\n\n    inline bool in_grid(int x, int y) const {\n        return 0 <= x && x < G && 0 <= y && y < G;\n    }\n\n    int mask_score(const vector<uchar>& mask) const {\n        int s = 0;\n        for (int i = 0; i < ncell; i++) if (mask[i]) s += w[i];\n        return s;\n    }\n\n    int selected_neighbor_count(const vector<uchar>& mask, int x, int y) const {\n        int c = 0;\n        if (x > 0 && mask[idx(x - 1, y)]) c++;\n        if (x + 1 < G && mask[idx(x + 1, y)]) c++;\n        if (y > 0 && mask[idx(x, y - 1)]) c++;\n        if (y + 1 < G && mask[idx(x, y + 1)]) c++;\n        return c;\n    }\n\n    int selected_neighbor_count_id(const vector<uchar>& mask, int v) const {\n        return selected_neighbor_count(mask, v % G, v / G);\n    }\n\n    int boundary_edges(const vector<uchar>& mask) const {\n        int p = 0;\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n                if (x == 0 || !mask[idx(x - 1, y)]) p++;\n                if (x + 1 == G || !mask[idx(x + 1, y)]) p++;\n                if (y == 0 || !mask[idx(x, y - 1)]) p++;\n                if (y + 1 == G || !mask[idx(x, y + 1)]) p++;\n            }\n        }\n        return p;\n    }\n\n    void fix_diagonal(vector<uchar>& mask) const {\n        for (int it = 0; it < 30; it++) {\n            bool changed = false;\n            for (int y = 0; y + 1 < G; y++) {\n                for (int x = 0; x + 1 < G; x++) {\n                    int a = idx(x, y);\n                    int b = idx(x + 1, y);\n                    int c = idx(x, y + 1);\n                    int d = idx(x + 1, y + 1);\n\n                    bool A = mask[a], B = mask[b], C = mask[c], DD = mask[d];\n\n                    if (A && DD && !B && !C) {\n                        int choose = (w[b] >= w[c] ? b : c);\n                        mask[choose] = 1;\n                        changed = true;\n                    } else if (B && C && !A && !DD) {\n                        int choose = (w[a] >= w[d] ? a : d);\n                        mask[choose] = 1;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    void fill_holes(vector<uchar>& mask) const {\n        vector<uchar> out(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto push = [&](int x, int y) {\n            int id = idx(x, y);\n            if (!mask[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < G; x++) {\n            push(x, 0);\n            push(x, G - 1);\n        }\n        for (int y = 0; y < G; y++) {\n            push(0, y);\n            push(G - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % G, y = v / G;\n            const int dx[4] = {1, -1, 0, 0};\n            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 (!in_grid(nx, ny)) continue;\n                int ni = idx(nx, ny);\n                if (!mask[ni] && !out[ni]) {\n                    out[ni] = 1;\n                    q.push_back(ni);\n                }\n            }\n        }\n\n        for (int i = 0; i < ncell; i++) {\n            if (!mask[i] && !out[i]) mask[i] = 1;\n        }\n    }\n\n    vector<Comp> find_components(const vector<uchar>& mask, vector<int>* compIdOut = nullptr) const {\n        vector<int> compId(ncell, -1);\n        vector<Comp> comps;\n        vector<int> q;\n        q.reserve(ncell);\n\n        for (int s = 0; s < ncell; s++) {\n            if (!mask[s] || compId[s] != -1) continue;\n\n            int cid = (int)comps.size();\n            comps.push_back(Comp{});\n            compId[s] = cid;\n            q.clear();\n            q.push_back(s);\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                comps[cid].cells.push_back(v);\n                comps[cid].score += w[v];\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) {\n                        comps[cid].perim++;\n                        continue;\n                    }\n\n                    int ni = idx(nx, ny);\n                    if (!mask[ni]) {\n                        comps[cid].perim++;\n                    } else if (compId[ni] == -1) {\n                        compId[ni] = cid;\n                        q.push_back(ni);\n                    }\n                }\n            }\n        }\n\n        if (compIdOut) *compIdOut = move(compId);\n        return comps;\n    }\n\n    void trim_leaves(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        vector<uchar> inq(ncell, 0);\n        vector<int> q;\n        q.reserve(ncell);\n\n        auto maybe_push = [&](int id) {\n            if (!mask[id] || w[id] > 0 || inq[id]) return;\n            if (selected_neighbor_count_id(mask, id) <= 1) {\n                inq[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int i = 0; i < ncell; i++) maybe_push(i);\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            inq[v] = 0;\n            if (!mask[v] || w[v] > 0) continue;\n            if (sel <= 1) continue;\n\n            int k = selected_neighbor_count_id(mask, v);\n            if (k <= 1) {\n                mask[v] = 0;\n                sel--;\n\n                int x = v % G, y = v / G;\n                const int dx[4] = {1, -1, 0, 0};\n                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 (in_grid(nx, ny)) maybe_push(idx(nx, ny));\n                }\n            }\n        }\n    }\n\n    void add_positive_boundary(vector<uchar>& mask) const {\n        int P = boundary_edges(mask);\n\n        for (int it = 0; it < 4; it++) {\n            bool changed = false;\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n    }\n\n    bool simple_removable(const vector<uchar>& mask, int v) const {\n        int x = v % G, y = v / G;\n        bool occ[3][3] = {};\n        bool vis[3][3] = {};\n        int cnt = 0;\n\n        for (int dy = -1; dy <= 1; dy++) {\n            for (int dx = -1; dx <= 1; dx++) {\n                if (dx == 0 && dy == 0) continue;\n                int nx = x + dx, ny = y + dy;\n                if (in_grid(nx, ny) && mask[idx(nx, ny)]) {\n                    occ[dy + 1][dx + 1] = true;\n                    cnt++;\n                }\n            }\n        }\n\n        if (cnt == 0) return false;\n\n        int comps = 0;\n        const int ddx[4] = {1, -1, 0, 0};\n        const int ddy[4] = {0, 0, 1, -1};\n\n        for (int sy = 0; sy < 3; sy++) {\n            for (int sx = 0; sx < 3; sx++) {\n                if (!occ[sy][sx] || vis[sy][sx]) continue;\n\n                comps++;\n                int qx[9], qy[9], h = 0, t = 0;\n                qx[t] = sx;\n                qy[t] = sy;\n                t++;\n                vis[sy][sx] = true;\n\n                while (h < t) {\n                    int cx = qx[h], cy = qy[h];\n                    h++;\n\n                    for (int dir = 0; dir < 4; dir++) {\n                        int nx = cx + ddx[dir], ny = cy + ddy[dir];\n                        if (0 <= nx && nx < 3 && 0 <= ny && ny < 3 &&\n                            occ[ny][nx] && !vis[ny][nx]) {\n                            vis[ny][nx] = true;\n                            qx[t] = nx;\n                            qy[t] = ny;\n                            t++;\n                        }\n                    }\n                }\n            }\n        }\n\n        return comps == 1;\n    }\n\n    void polish_mask(vector<uchar>& mask) const {\n        int sel = 0;\n        for (uchar v : mask) if (v) sel++;\n\n        int P = boundary_edges(mask);\n\n        for (int pass = 0; pass < 3; pass++) {\n            if (elapsed_sec() > 1.86) break;\n\n            bool changed = false;\n\n            for (int id = 0; id < ncell; id++) {\n                if (!mask[id] || sel <= 1) continue;\n\n                int k = selected_neighbor_count_id(mask, id);\n                if (k == 4) continue;\n\n                int delta = 2 * k - 4;\n                bool ok = false;\n\n                if (w[id] < 0) {\n                    if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                } else if (w[id] == 0 && delta < 0) {\n                    ok = true;\n                }\n\n                if (ok && simple_removable(mask, id)) {\n                    mask[id] = 0;\n                    sel--;\n                    P += delta;\n                    changed = true;\n                }\n            }\n\n            for (int y = 0; y < G; y++) {\n                for (int x = 0; x < G; x++) {\n                    int id = idx(x, y);\n                    if (mask[id]) continue;\n\n                    int k = selected_neighbor_count(mask, x, y);\n                    if (k == 0) continue;\n\n                    int delta = 4 - 2 * k;\n                    bool ok = false;\n\n                    if (w[id] > 0) {\n                        if (delta <= 0 || P + delta <= maxEdges) ok = true;\n                    } else if (w[id] == 0 && delta < 0) {\n                        ok = true;\n                    }\n\n                    if (ok) {\n                        mask[id] = 1;\n                        sel++;\n                        P += delta;\n                        changed = true;\n                    }\n                }\n            }\n\n            if (!changed) break;\n        }\n    }\n\n    bool extract_polygon(const vector<uchar>& mask, vector<pair<int,int>>& poly) const {\n        int V = (G + 1) * (G + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (G + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n        };\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int id = idx(x, y);\n                if (!mask[id]) continue;\n\n                if (y == 0 || !mask[idx(x, y - 1)]) set_edge(x, y, x + 1, y);\n                if (x + 1 == G || !mask[idx(x + 1, y)]) set_edge(x + 1, y, x + 1, y + 1);\n                if (y + 1 == G || !mask[idx(x, y + 1)]) set_edge(x + 1, y + 1, x, y + 1);\n                if (x == 0 || !mask[idx(x - 1, y)]) set_edge(x, y + 1, x, y);\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (1LL * edges * D > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n        int cur = start;\n\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int px = pv % (G + 1), py = pv / (G + 1);\n            int cx = cv % (G + 1), cy = cv / (G + 1);\n            int nx = nv % (G + 1), ny = nv / (G + 1);\n\n            if ((px == cx && cx == nx) || (py == cy && cy == ny)) continue;\n\n            poly.push_back({cx * D, cy * D});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    bool extract_rect_union(const vector<Rect>& inRects, vector<pair<int,int>>& poly) const {\n        vector<Rect> rects;\n        vector<int> xs, ys;\n        rects.reserve(inRects.size());\n        xs.reserve(inRects.size() * 2 + 4);\n        ys.reserve(inRects.size() * 2 + 4);\n\n        for (auto r : inRects) {\n            if (r.x1 > r.x2) swap(r.x1, r.x2);\n            if (r.y1 > r.y2) swap(r.y1, r.y2);\n\n            r.x1 = max(0, min(CMAX, r.x1));\n            r.x2 = max(0, min(CMAX, r.x2));\n            r.y1 = max(0, min(CMAX, r.y1));\n            r.y2 = max(0, min(CMAX, r.y2));\n\n            if (r.x1 >= r.x2 || r.y1 >= r.y2) continue;\n\n            rects.push_back(r);\n            xs.push_back(r.x1);\n            xs.push_back(r.x2);\n            ys.push_back(r.y1);\n            ys.push_back(r.y2);\n        }\n\n        if (rects.empty()) return false;\n\n        sort(xs.begin(), xs.end());\n        xs.erase(unique(xs.begin(), xs.end()), xs.end());\n        sort(ys.begin(), ys.end());\n        ys.erase(unique(ys.begin(), ys.end()), ys.end());\n\n        int NX = (int)xs.size() - 1;\n        int NY = (int)ys.size() - 1;\n        if (NX <= 0 || NY <= 0) return false;\n\n        int Wd = NX + 1;\n        vector<int> diff((NX + 1) * (NY + 1), 0);\n\n        auto did = [&](int x, int y) {\n            return y * Wd + x;\n        };\n\n        for (auto r : rects) {\n            int x1 = lower_bound(xs.begin(), xs.end(), r.x1) - xs.begin();\n            int x2 = lower_bound(xs.begin(), xs.end(), r.x2) - xs.begin();\n            int y1 = lower_bound(ys.begin(), ys.end(), r.y1) - ys.begin();\n            int y2 = lower_bound(ys.begin(), ys.end(), r.y2) - ys.begin();\n\n            diff[did(x1, y1)]++;\n            diff[did(x2, y1)]--;\n            diff[did(x1, y2)]--;\n            diff[did(x2, y2)]++;\n        }\n\n        for (int y = 0; y <= NY; y++) {\n            for (int x = 1; x <= NX; x++) {\n                diff[did(x, y)] += diff[did(x - 1, y)];\n            }\n        }\n        for (int y = 1; y <= NY; y++) {\n            for (int x = 0; x <= NX; x++) {\n                diff[did(x, y)] += diff[did(x, y - 1)];\n            }\n        }\n\n        vector<uchar> cov(NX * NY, 0);\n        for (int y = 0; y < NY; y++) {\n            for (int x = 0; x < NX; x++) {\n                if (diff[did(x, y)] > 0) cov[y * NX + x] = 1;\n            }\n        }\n\n        vector<uchar> out(NX * NY, 0);\n        vector<int> q;\n        q.reserve(NX * NY);\n\n        auto push = [&](int x, int y) {\n            if (x < 0 || x >= NX || y < 0 || y >= NY) return;\n            int id = y * NX + x;\n            if (!cov[id] && !out[id]) {\n                out[id] = 1;\n                q.push_back(id);\n            }\n        };\n\n        for (int x = 0; x < NX; x++) {\n            push(x, 0);\n            push(x, NY - 1);\n        }\n        for (int y = 0; y < NY; y++) {\n            push(0, y);\n            push(NX - 1, y);\n        }\n\n        for (size_t head = 0; head < q.size(); head++) {\n            int v = q[head];\n            int x = v % NX, y = v / NX;\n\n            const int dx[4] = {1, -1, 0, 0};\n            const int dy[4] = {0, 0, 1, -1};\n\n            for (int dir = 0; dir < 4; dir++) {\n                push(x + dx[dir], y + dy[dir]);\n            }\n        }\n\n        for (int i = 0; i < NX * NY; i++) {\n            if (!cov[i] && !out[i]) cov[i] = 1;\n        }\n\n        int V = (NX + 1) * (NY + 1);\n        vector<int> nxt(V, -1);\n        int edges = 0;\n        long long totalLen = 0;\n        bool ok = true;\n\n        auto vid = [&](int x, int y) {\n            return y * (NX + 1) + x;\n        };\n\n        auto set_edge = [&](int sx, int sy, int tx, int ty, int len) {\n            int s = vid(sx, sy);\n            int t = vid(tx, ty);\n            if (nxt[s] != -1) ok = false;\n            else nxt[s] = t;\n            edges++;\n            totalLen += len;\n        };\n\n        for (int y = 0; y < NY; y++) {\n            for (int x = 0; x < NX; x++) {\n                if (!cov[y * NX + x]) continue;\n\n                if (y == 0 || !cov[(y - 1) * NX + x]) {\n                    set_edge(x, y, x + 1, y, xs[x + 1] - xs[x]);\n                }\n                if (x + 1 == NX || !cov[y * NX + (x + 1)]) {\n                    set_edge(x + 1, y, x + 1, y + 1, ys[y + 1] - ys[y]);\n                }\n                if (y + 1 == NY || !cov[(y + 1) * NX + x]) {\n                    set_edge(x + 1, y + 1, x, y + 1, xs[x + 1] - xs[x]);\n                }\n                if (x == 0 || !cov[y * NX + (x - 1)]) {\n                    set_edge(x, y + 1, x, y, ys[y + 1] - ys[y]);\n                }\n            }\n        }\n\n        if (!ok || edges == 0) return false;\n        if (totalLen > MAXLEN) return false;\n\n        int start = -1;\n        for (int i = 0; i < V; i++) {\n            if (nxt[i] != -1) {\n                start = i;\n                break;\n            }\n        }\n        if (start == -1) return false;\n\n        vector<int> path;\n        path.reserve(edges);\n\n        int cur = start;\n        for (int step = 0; step < edges; step++) {\n            if (cur < 0 || cur >= V || nxt[cur] == -1) return false;\n            path.push_back(cur);\n            cur = nxt[cur];\n            if (cur == start && step != edges - 1) return false;\n        }\n        if (cur != start) return false;\n\n        int L = (int)path.size();\n        poly.clear();\n\n        for (int i = 0; i < L; i++) {\n            int pv = path[(i - 1 + L) % L];\n            int cv = path[i];\n            int nv = path[(i + 1) % L];\n\n            int pxi = pv % (NX + 1), pyi = pv / (NX + 1);\n            int cxi = cv % (NX + 1), cyi = cv / (NX + 1);\n            int nxi = nv % (NX + 1), nyi = nv / (NX + 1);\n\n            int px = xs[pxi], py = ys[pyi];\n            int cx = xs[cxi], cy = ys[cyi];\n            int nx = xs[nxi], ny = ys[nyi];\n\n            if ((px == cx && cx == nx) || (py == cy && cy == ny)) continue;\n\n            poly.push_back({cx, cy});\n        }\n\n        if ((int)poly.size() < 4 || (int)poly.size() > MAXV) return false;\n\n        vector<ll> enc;\n        enc.reserve(poly.size());\n        for (auto [x, y] : poly) {\n            if (x < 0 || x > CMAX || y < 0 || y > CMAX) return false;\n            enc.push_back((ll)x * (CMAX + 1) + y);\n        }\n\n        sort(enc.begin(), enc.end());\n        for (int i = 1; i < (int)enc.size(); i++) {\n            if (enc[i] == enc[i - 1]) return false;\n        }\n\n        return true;\n    }\n\n    void finalize_original(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.90) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        trim_leaves(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        add_positive_boundary(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc, 0);\n    }\n\n    void finalize_polish(vector<uchar> mask) const {\n        if (elapsed_sec() > 1.88) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        polish_mask(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        polish_mask(mask);\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        int sc = mask_score(mask);\n        if (sc < 0) return;\n\n        int p = boundary_edges(mask);\n        if (p == 0 || 1LL * p * D > MAXLEN) return;\n\n        vector<pair<int,int>> poly;\n        if (!extract_polygon(mask, poly)) return;\n\n        record_candidate(poly, sc, 1);\n    }\n\n    void finalize_candidate(vector<uchar> mask, int variants = 1) const {\n        if (variants & 1) {\n            auto m = mask;\n            finalize_original(move(m));\n        }\n        if ((variants & 2) && elapsed_sec() < 1.50) {\n            auto m = mask;\n            finalize_polish(move(m));\n        }\n    }\n\n    void finalize_thin(const vector<int>& selectedIds,\n                       const vector<Corridor>& corridors,\n                       const vector<Comp>& comps,\n                       int approx) const {\n        if (elapsed_sec() > 1.88) return;\n        if (selectedIds.empty()) return;\n\n        size_t rcnt = corridors.size() * 2;\n        for (int cid : selectedIds) rcnt += comps[cid].cells.size();\n\n        vector<Rect> rects;\n        rects.reserve(rcnt);\n\n        auto add_rect = [&](int x1, int y1, int x2, int y2) {\n            if (x1 > x2) swap(x1, x2);\n            if (y1 > y2) swap(y1, y2);\n\n            x1 = max(0, min(CMAX, x1));\n            x2 = max(0, min(CMAX, x2));\n            y1 = max(0, min(CMAX, y1));\n            y2 = max(0, min(CMAX, y2));\n\n            if (x1 < x2 && y1 < y2) rects.push_back({x1, y1, x2, y2});\n        };\n\n        for (int cid : selectedIds) {\n            for (int cell : comps[cid].cells) {\n                int x = cell % G;\n                int y = cell / G;\n                add_rect(x * D, y * D, (x + 1) * D, (y + 1) * D);\n            }\n        }\n\n        const int half = 1;\n\n        auto center = [&](int cell) {\n            int x = cell % G;\n            int y = cell / G;\n            return pair<int,int>{x * D + D / 2, y * D + D / 2};\n        };\n\n        auto add_h = [&](int x1, int x2, int y) {\n            if (x1 == x2) return;\n            if (x1 > x2) swap(x1, x2);\n            add_rect(x1, y - half, x2, y + half);\n        };\n\n        auto add_v = [&](int x, int y1, int y2) {\n            if (y1 == y2) return;\n            if (y1 > y2) swap(y1, y2);\n            add_rect(x - half, y1, x + half, y2);\n        };\n\n        for (const auto& c : corridors) {\n            auto [sx, sy] = center(c.a);\n            auto [tx, ty] = center(c.b);\n\n            if (c.xFirst) {\n                add_h(sx, tx, sy);\n                add_v(tx, sy, ty);\n            } else {\n                add_v(sx, sy, ty);\n                add_h(sx, tx, ty);\n            }\n        }\n\n        vector<pair<int,int>> poly;\n        if (!extract_rect_union(rects, poly)) return;\n\n        record_candidate(poly, approx, 2);\n    }\n\n    Eval eval_l_path(int src, int dst, bool xFirst,\n                     const vector<uchar>& cur,\n                     int targetCid,\n                     const vector<int>& compId) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        int score = 0, len = 0;\n\n        auto visit = [&](int x, int y) {\n            int id = idx(x, y);\n            len++;\n            if (!cur[id] && compId[id] != targetCid) score += w[id];\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    visit(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    visit(x, ty);\n                }\n            }\n        }\n\n        return {score, len};\n    }\n\n    vector<int> build_l_path(int src, int dst, bool xFirst) const {\n        int sx = src % G, sy = src / G;\n        int tx = dst % G, ty = dst / G;\n\n        vector<int> res;\n        res.reserve(abs(tx - sx) + abs(ty - sy) + 1);\n\n        auto add = [&](int x, int y) {\n            res.push_back(idx(x, y));\n        };\n\n        if (xFirst) {\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, sy);\n                }\n            }\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(tx, y);\n                }\n            }\n        } else {\n            if (sy != ty) {\n                int step = (ty > sy ? 1 : -1);\n                for (int y = sy; y != ty; ) {\n                    y += step;\n                    add(sx, y);\n                }\n            }\n            if (sx != tx) {\n                int step = (tx > sx ? 1 : -1);\n                for (int x = sx; x != tx; ) {\n                    x += step;\n                    add(x, ty);\n                }\n            }\n        }\n\n        return res;\n    }\n\n    void greedy_connect(const vector<Comp>& comps,\n                        const vector<int>& compId,\n                        const vector<int>& ids,\n                        int maxAdd,\n                        int compLimit,\n                        int variants) const {\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> cur(ncell, 0);\n        vector<int> curCells;\n        curCells.reserve(ncell / 4);\n\n        auto add_cell = [&](int cell) {\n            if (!cur[cell]) {\n                cur[cell] = 1;\n                curCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            for (int cell : comps[cid].cells) add_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0])) addedConsidered++;\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c == 1 || c == 2 || c == 3 || c == 5 || c == 8 ||\n                   c == 13 || c == 21 || c == 34;\n        };\n\n        finalize_candidate(cur, variants);\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : curCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                bool xFirst = true;\n                int gain = 0;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1) continue;\n                int src = root[bestCell];\n                if (src < 0) continue;\n\n                Eval e1 = eval_l_path(src, bestCell, true, cur, cid, compId);\n                Eval e2 = eval_l_path(src, bestCell, false, cur, cid, compId);\n\n                bool xf = true;\n                Eval e = e1;\n\n                if (e2.score > e1.score || (e2.score == e1.score && e2.len < e1.len)) {\n                    e = e2;\n                    xf = false;\n                }\n\n                int gain = comps[cid].score + e.score;\n                if (gain <= 0) continue;\n\n                double metric = (double)gain / (e.len + 5.0) + 0.03 * gain;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = src;\n                    best.dst = bestCell;\n                    best.xFirst = xf;\n                    best.gain = gain;\n                    best.len = e.len;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path = build_l_path(best.src, best.dst, best.xFirst);\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cell : path) add_cell(cell);\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            if (snapshot(addedConsidered)) finalize_candidate(cur, variants);\n\n            if (iter % 3 == 0 && boundary_edges(cur) > maxEdges * 3 / 2) break;\n        }\n\n        finalize_candidate(cur, variants);\n    }\n\n    void thin_greedy_connect(const vector<Comp>& comps,\n                             const vector<int>& compId,\n                             const vector<int>& ids,\n                             int maxAdd,\n                             int compLimit) const {\n        if (elapsed_sec() > 1.78) return;\n\n        int C = (int)comps.size();\n        int limit = min(compLimit, (int)ids.size());\n        if (limit <= 0) return;\n\n        vector<char> considered(C, 0), added(C, 0);\n        for (int i = 0; i < limit; i++) considered[ids[i]] = 1;\n\n        vector<uchar> network(ncell, 0);\n        vector<int> networkCells;\n        vector<int> selectedIds;\n        vector<Corridor> corridors;\n\n        int approx = 0;\n        long long roughLen = 0;\n\n        auto add_network_cell = [&](int cell) {\n            if (!network[cell]) {\n                network[cell] = 1;\n                networkCells.push_back(cell);\n            }\n        };\n\n        auto add_comp = [&](int cid) -> bool {\n            if (added[cid]) return false;\n            added[cid] = 1;\n            selectedIds.push_back(cid);\n            approx += comps[cid].score;\n            roughLen += 1LL * comps[cid].perim * D;\n            for (int cell : comps[cid].cells) add_network_cell(cell);\n            return true;\n        };\n\n        int addedConsidered = 0;\n        if (add_comp(ids[0]) && considered[ids[0]]) addedConsidered++;\n\n        finalize_thin(selectedIds, corridors, comps, approx);\n\n        vector<int> dist(ncell), root(ncell), q;\n        q.reserve(ncell);\n\n        auto snapshot = [&](int c) {\n            return c <= 5 || c == 8 || c == 13 || c == 21 ||\n                   c == 34 || c == 55 || c == 89 || (c > 20 && c % 5 == 0);\n        };\n\n        auto path_bonus = [&](const vector<int>& path) {\n            vector<int> cs;\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && considered[cid] && comps[cid].score > 0) {\n                    cs.push_back(cid);\n                }\n            }\n\n            sort(cs.begin(), cs.end());\n            cs.erase(unique(cs.begin(), cs.end()), cs.end());\n\n            int s = 0;\n            for (int cid : cs) s += comps[cid].score;\n            return s;\n        };\n\n        for (int iter = 1; iter < maxAdd && addedConsidered < limit; iter++) {\n            if (elapsed_sec() > 1.82) break;\n\n            fill(dist.begin(), dist.end(), -1);\n            fill(root.begin(), root.end(), -1);\n            q.clear();\n\n            for (int cell : networkCells) {\n                dist[cell] = 0;\n                root[cell] = cell;\n                q.push_back(cell);\n            }\n\n            for (size_t head = 0; head < q.size(); head++) {\n                int v = q[head];\n                int x = v % G, y = v / G;\n\n                const int dx[4] = {1, -1, 0, 0};\n                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 (!in_grid(nx, ny)) continue;\n\n                    int ni = idx(nx, ny);\n                    if (dist[ni] == -1) {\n                        dist[ni] = dist[v] + 1;\n                        root[ni] = root[v];\n                        q.push_back(ni);\n                    }\n                }\n            }\n\n            struct Choice {\n                int cid = -1;\n                int src = -1;\n                int dst = -1;\n                int len = 0;\n                double metric = -1e100;\n            } best;\n\n            for (int ti = 0; ti < limit; ti++) {\n                int cid = ids[ti];\n                if (added[cid]) continue;\n\n                int bestCell = -1;\n                int bestDist = INT_MAX;\n\n                for (int cell : comps[cid].cells) {\n                    if (dist[cell] >= 0 && dist[cell] < bestDist) {\n                        bestDist = dist[cell];\n                        bestCell = cell;\n                    }\n                }\n\n                if (bestCell == -1 || bestDist <= 0) continue;\n\n                long long addCost = 2LL * bestDist * D + 1LL * comps[cid].perim * D;\n                if (roughLen + addCost > 700000LL) continue;\n\n                double costK = addCost / 1000.0;\n                double metric = (double)comps[cid].score / (costK + 2.0) + 0.025 * comps[cid].score;\n\n                if (metric > best.metric) {\n                    best.cid = cid;\n                    best.src = root[bestCell];\n                    best.dst = bestCell;\n                    best.len = bestDist;\n                    best.metric = metric;\n                }\n            }\n\n            if (best.cid == -1) break;\n\n            vector<int> path1 = build_l_path(best.src, best.dst, true);\n            vector<int> path2 = build_l_path(best.src, best.dst, false);\n\n            int b1 = path_bonus(path1);\n            int b2 = path_bonus(path2);\n\n            bool xf = true;\n            vector<int> path;\n\n            if (b2 > b1) {\n                xf = false;\n                path = move(path2);\n            } else {\n                path = move(path1);\n            }\n\n            corridors.push_back({best.src, best.dst, xf});\n            roughLen += 2LL * (int)path.size() * D + 8;\n\n            for (int cell : path) add_network_cell(cell);\n\n            vector<int> toAdd;\n            toAdd.push_back(best.cid);\n\n            for (int cell : path) {\n                int cid = compId[cell];\n                if (cid >= 0 && !added[cid] && considered[cid] && comps[cid].score > 0) {\n                    toAdd.push_back(cid);\n                }\n            }\n\n            sort(toAdd.begin(), toAdd.end());\n            toAdd.erase(unique(toAdd.begin(), toAdd.end()), toAdd.end());\n\n            for (int cid : toAdd) {\n                if (add_comp(cid) && considered[cid]) addedConsidered++;\n            }\n\n            int cnum = (int)selectedIds.size();\n            if (snapshot(cnum) || (roughLen > 300000 && cnum % 3 == 0)) {\n                finalize_thin(selectedIds, corridors, comps, approx);\n            }\n\n            if (roughLen > 620000LL) break;\n        }\n\n        finalize_thin(selectedIds, corridors, comps, approx);\n    }\n\n    void process_mask(vector<uchar> mask, int maxAdd, int compLimit, int mode = 3, int variants = 1) const {\n        if (elapsed_sec() > 1.82) return;\n\n        bool any = false;\n        for (uchar v : mask) if (v) {\n            any = true;\n            break;\n        }\n        if (!any) return;\n\n        fix_diagonal(mask);\n        fill_holes(mask);\n\n        vector<int> compId;\n        vector<Comp> comps = find_components(mask, &compId);\n        if (comps.empty()) return;\n\n        vector<int> ids;\n        for (int i = 0; i < (int)comps.size(); i++) {\n            if (comps[i].score > 0) ids.push_back(i);\n        }\n        if (ids.empty()) return;\n\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return comps[a].score > comps[b].score;\n        });\n\n        if (mode & 1) {\n            int alone = min(3, (int)ids.size());\n\n            for (int k = 0; k < alone; k++) {\n                vector<uchar> cur(ncell, 0);\n                for (int cell : comps[ids[k]].cells) cur[cell] = 1;\n                finalize_candidate(cur, variants);\n            }\n\n            if ((int)ids.size() >= 2) {\n                greedy_connect(comps, compId, ids, maxAdd, compLimit, variants);\n            }\n        }\n\n        if ((mode & 2) && elapsed_sec() < 1.78) {\n            int tMax = max(maxAdd, D <= 250 ? 100 : 45);\n            int tLimit = min(compLimit, D <= 250 ? 350 : 140);\n\n            thin_greedy_connect(comps, compId, ids, tMax, tLimit);\n\n            if (D <= 250 && elapsed_sec() < 1.78) {\n                vector<int> ids2 = ids;\n                sort(ids2.begin(), ids2.end(), [&](int a, int b) {\n                    long long lhs = 1LL * comps[a].score * (comps[b].perim + 1);\n                    long long rhs = 1LL * comps[b].score * (comps[a].perim + 1);\n                    if (lhs != rhs) return lhs > rhs;\n                    return comps[a].score > comps[b].score;\n                });\n\n                thin_greedy_connect(comps, compId, ids2, max(60, maxAdd / 2), min(tLimit, 180));\n            }\n        }\n    }\n\n    void run_best_rectangle(int variants = 1) const {\n        if (elapsed_sec() > 1.80) return;\n\n        int best = INT_MIN;\n        int bx1 = 0, bx2 = 0, by1 = 0, by2 = 0;\n\n        vector<int> col(G, 0);\n\n        for (int x1 = 0; x1 < G; x1++) {\n            fill(col.begin(), col.end(), 0);\n\n            for (int x2 = x1; x2 < G; x2++) {\n                for (int y = 0; y < G; y++) col[y] += w[idx(x2, y)];\n\n                int cur = 0, st = 0;\n                for (int y = 0; y < G; y++) {\n                    if (y == 0 || cur <= 0) {\n                        cur = col[y];\n                        st = y;\n                    } else {\n                        cur += col[y];\n                    }\n\n                    if (cur > best) {\n                        best = cur;\n                        bx1 = x1;\n                        bx2 = x2;\n                        by1 = st;\n                        by2 = y;\n                    }\n                }\n            }\n        }\n\n        if (best <= 0) return;\n\n        vector<uchar> mask(ncell, 0);\n        for (int y = by1; y <= by2; y++) {\n            for (int x = bx1; x <= bx2; x++) {\n                mask[idx(x, y)] = 1;\n            }\n        }\n\n        finalize_candidate(mask, variants);\n\n        refine_and_record_rectangle(bx1 * D, by1 * D, (bx2 + 1) * D, (by2 + 1) * D);\n    }\n\n    vector<double> gaussian_blur(double sigma) const {\n        int r = max(1, (int)ceil(3.0 * sigma));\n        vector<double> ker(2 * r + 1);\n        double sum = 0.0;\n\n        for (int d = -r; d <= r; d++) {\n            double v = exp(-(double)d * d / (2.0 * sigma * sigma));\n            ker[d + r] = v;\n            sum += v;\n        }\n        for (double& v : ker) v /= sum;\n\n        vector<double> src(ncell), tmp(ncell), out(ncell);\n        for (int i = 0; i < ncell; i++) src[i] = (double)w[i];\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int nx = x + d;\n                    if (0 <= nx && nx < G) s += src[idx(nx, y)] * ker[d + r];\n                }\n                tmp[idx(x, y)] = s;\n            }\n        }\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                double s = 0.0;\n                for (int d = -r; d <= r; d++) {\n                    int ny = y + d;\n                    if (0 <= ny && ny < G) s += tmp[idx(x, ny)] * ker[d + r];\n                }\n                out[idx(x, y)] = s;\n            }\n        }\n\n        return out;\n    }\n\n    void run_smoothing(const vector<double>& sigmas,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime,\n                       int mode = 1,\n                       int variants = 1) const {\n        vector<double> ratios = {-0.05, -0.02, 0.0, 0.02, 0.05, 0.10, 0.18, 0.30};\n\n        for (double sigma : sigmas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<double> blur = gaussian_blur(sigma);\n            double mx = *max_element(blur.begin(), blur.end());\n            if (mx <= 1e-12) continue;\n\n            for (double r : ratios) {\n                if (elapsed_sec() > stopTime) return;\n\n                double th = mx * r;\n                vector<uchar> mask(ncell, 0);\n                int cnt = 0;\n\n                for (int i = 0; i < ncell; i++) {\n                    if (blur[i] > th) {\n                        mask[i] = 1;\n                        cnt++;\n                    }\n                }\n\n                if (cnt == 0 || cnt == ncell) continue;\n                process_mask(move(mask), maxAdd, compLimit, mode, variants);\n            }\n        }\n    }\n\n    void run_weight_thresholds(const vector<int>& thresholds,\n                               int maxAdd,\n                               int compLimit,\n                               double stopTime,\n                               int mode = 3,\n                               int variants = 1) const {\n        for (int th : thresholds) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask(ncell, 0);\n            int cnt = 0;\n\n            for (int i = 0; i < ncell; i++) {\n                if (w[i] >= th) {\n                    mask[i] = 1;\n                    cnt++;\n                }\n            }\n\n            if (cnt == 0) continue;\n            process_mask(move(mask), maxAdd, compLimit, mode, variants);\n        }\n    }\n\n    vector<uchar> graph_cut_mask(int lam, int scale) const {\n        int S = ncell;\n        int T = ncell + 1;\n        atcoder::mf_graph<ll> g(ncell + 2);\n\n        for (int y = 0; y < G; y++) {\n            for (int x = 0; x < G; x++) {\n                int v = idx(x, y);\n                ll profit = (ll)w[v] * scale;\n\n                if (profit > 0) g.add_edge(S, v, profit);\n                else if (profit < 0) g.add_edge(v, T, -profit);\n\n                int bs = 0;\n                if (x == 0) bs++;\n                if (x + 1 == G) bs++;\n                if (y == 0) bs++;\n                if (y + 1 == G) bs++;\n\n                if (bs) g.add_edge(v, T, (ll)lam * bs);\n\n                if (x + 1 < G) {\n                    int u = idx(x + 1, y);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n                if (y + 1 < G) {\n                    int u = idx(x, y + 1);\n                    g.add_edge(v, u, lam);\n                    g.add_edge(u, v, lam);\n                }\n            }\n        }\n\n        g.flow(S, T);\n        auto cut = g.min_cut(S);\n\n        vector<uchar> mask(ncell, 0);\n        for (int i = 0; i < ncell; i++) mask[i] = cut[i] ? 1 : 0;\n        return mask;\n    }\n\n    void run_graph_cut(const vector<int>& lambdas,\n                       int scale,\n                       int maxAdd,\n                       int compLimit,\n                       double stopTime,\n                       int mode = 3,\n                       int variants = 1) const {\n        for (int lam : lambdas) {\n            if (elapsed_sec() > stopTime) return;\n\n            vector<uchar> mask = graph_cut_mask(lam, scale);\n            process_mask(move(mask), maxAdd, compLimit, mode, variants);\n        }\n    }\n};\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START_TIME = chrono::steady_clock::now();\n\n    int N;\n    cin >> N;\n\n    fishes.reserve(2 * N);\n\n    for (int i = 0; i < 2 * N; i++) {\n        int x, y;\n        cin >> x >> y;\n\n        int w = (i < N ? 1 : -1);\n        fishes.push_back({x, y, w});\n    }\n\n    fishOrderY.resize(fishes.size());\n    iota(fishOrderY.begin(), fishOrderY.end(), 0);\n    sort(fishOrderY.begin(), fishOrderY.end(), [&](int a, int b) {\n        if (fishes[a].y != fishes[b].y) return fishes[a].y < fishes[b].y;\n        return fishes[a].x < fishes[b].x;\n    });\n\n    bestApprox = -1;\n    bestSafeApprox = -1;\n\n    record_candidate(square_poly(), 0, 0);\n\n    GridSolver g500(500);\n\n    g500.run_best_rectangle(1);\n\n    // Keep thin-corridor candidates, but skip expensive polished variants here.\n    g500.run_weight_thresholds(vector<int>{1, 2, 3}, 32, 140, 0.56, 3, 1);\n\n    g500.run_smoothing(vector<double>{2.0, 3.5, 5.5, 8.0, 12.0}, 18, 90, 1.00, 1, 1);\n\n    if (elapsed_sec() < 1.25) {\n        g500.run_graph_cut(vector<int>{10, 16, 25, 40, 70, 120}, 100, 24, 120, 1.40, 3, 1);\n    }\n\n    if (elapsed_sec() < 1.62) {\n        GridSolver g400(400);\n        g400.run_best_rectangle(1);\n        g400.run_smoothing(vector<double>{2.5, 4.0, 6.5, 10.0, 14.0}, 14, 80, 1.72, 1, 1);\n    }\n\n    if (elapsed_sec() < 1.76) {\n        GridSolver g250(250);\n        g250.run_weight_thresholds(vector<int>{1, 2, 3}, 100, 350, 1.86, 2, 0);\n    }\n\n    vector<pair<int,int>> output;\n    if (!bestSafePoly.empty()) output = bestSafePoly;\n    else if (!bestPoly.empty()) output = bestPoly;\n    else output = square_poly();\n\n    if (bestApprox >= 0 && !bestPoly.empty()) {\n        candidates.push_back({bestApprox, 2, bestPoly});\n    }\n    if (bestSafeApprox >= 0 && !bestSafePoly.empty()) {\n        candidates.push_back({bestSafeApprox, 0, bestSafePoly});\n    }\n\n    if (elapsed_sec() < 1.84) {\n        int bestExact = exact_score(output);\n        vector<pair<int,int>> exactBest = output;\n\n        if (bestExact < 0) {\n            bestExact = 0;\n            exactBest = square_poly();\n        }\n\n        vector<int> order;\n        vector<char> usedIdx(candidates.size(), 0);\n\n        auto add_idx = [&](int id) {\n            if (id < 0 || id >= (int)candidates.size()) return;\n            if (usedIdx[id]) return;\n            usedIdx[id] = 1;\n            order.push_back(id);\n        };\n\n        vector<int> all(candidates.size());\n        iota(all.begin(), all.end(), 0);\n        sort(all.begin(), all.end(), [&](int a, int b) {\n            return candidates[a].approx > candidates[b].approx;\n        });\n\n        if ((int)candidates.size() <= 260) {\n            for (int id : all) add_idx(id);\n        } else {\n            for (int i = 0; i < min(120, (int)all.size()); i++) add_idx(all[i]);\n\n            for (int cat = 0; cat <= 3; cat++) {\n                vector<int> v;\n                for (int i = 0; i < (int)candidates.size(); i++) {\n                    if (candidates[i].cat == cat) v.push_back(i);\n                }\n\n                sort(v.begin(), v.end(), [&](int a, int b) {\n                    return candidates[a].approx > candidates[b].approx;\n                });\n\n                for (int i = 0; i < min(60, (int)v.size()); i++) add_idx(v[i]);\n            }\n        }\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(order.size() * 2 + 10);\n        seen.insert(poly_hash(output));\n\n        for (int id : order) {\n            if (elapsed_sec() > 1.965) break;\n\n            uint64_t h = poly_hash(candidates[id].poly);\n            if (seen.find(h) != seen.end()) continue;\n            seen.insert(h);\n\n            int sc = exact_score(candidates[id].poly);\n            if (sc > bestExact) {\n                bestExact = sc;\n                exactBest = candidates[id].poly;\n            }\n        }\n\n        output = exactBest;\n    }\n\n    cout << output.size() << '\\n';\n    for (auto [x, y] : output) {\n        cout << x << ' ' << y << '\\n';\n    }\n\n    return 0;\n}","ahc040":"#include <bits/stdc++.h>\nusing namespace std;\n\nstruct RectD {\n    double w, h;\n};\n\nstruct Op {\n    int p;\n    int r;\n    char d;\n    int b;\n};\n\nstruct Candidate {\n    vector<Op> ops;\n    double estScore = 1e100;\n    double baseW = 0, baseH = 0;\n    uint64_t hash = 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};\n\nstatic constexpr double TRUE_U = 100000.0;\nstatic constexpr double TRUE_L_MIN = 10000.0;\nstatic constexpr double TRUE_L_MAX = 50000.0;\nstatic constexpr double INF = 1e100;\n\nint N, T;\ndouble SIGMA;\nvector<double> sumWObs, sumHObs;\nvector<int> cntWObs, cntHObs;\n\nmt19937_64 rng(123456789);\n\ndouble normal_pdf(double x) {\n    static const double INV_SQRT_2PI = 0.39894228040143267794;\n    return INV_SQRT_2PI * exp(-0.5 * x * x);\n}\n\ndouble normal_cdf(double x) {\n    return 0.5 * erfc(-x / sqrt(2.0));\n}\n\ndouble clamp_double(double x, double lo, double hi) {\n    return max(lo, min(hi, x));\n}\n\ndouble truncated_normal_mean(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    double a = (L - obsMean) / sd;\n    double b = (U - obsMean) / sd;\n    double Z = normal_cdf(b) - normal_cdf(a);\n    if (Z < 1e-12) return clamp_double(obsMean, L, U);\n    double m = obsMean + sd * (normal_pdf(a) - normal_pdf(b)) / Z;\n    return clamp_double(m, L, U);\n}\n\ndouble sample_truncated_normal(double obsMean, double sd, double L, double U) {\n    if (sd < 1e-9) return clamp_double(obsMean, L, U);\n    normal_distribution<double> nd(obsMean, sd);\n    for (int t = 0; t < 200; t++) {\n        double x = nd(rng);\n        if (L <= x && x <= U) return x;\n    }\n    return clamp_double(obsMean, L, U);\n}\n\ndouble estimate_L_from_current_observations() {\n    vector<double> vals;\n    vector<double> noiseVars;\n    vals.reserve(2 * N);\n    noiseVars.reserve(2 * N);\n\n    for (int i = 0; i < N; i++) {\n        vals.push_back(sumWObs[i] / cntWObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntWObs[i]);\n        vals.push_back(sumHObs[i] / cntHObs[i]);\n        noiseVars.push_back(SIGMA * SIGMA / cntHObs[i]);\n    }\n\n    double mean = accumulate(vals.begin(), vals.end(), 0.0) / vals.size();\n    double L1 = 2.0 * mean - TRUE_U;\n\n    double var = 0.0;\n    for (double x : vals) var += (x - mean) * (x - mean);\n    var /= vals.size();\n\n    double avgNoise = accumulate(noiseVars.begin(), noiseVars.end(), 0.0) / noiseVars.size();\n    double trueVar = max(0.0, var - avgNoise);\n    double L2 = TRUE_U - sqrt(max(0.0, 12.0 * trueVar));\n\n    double L = 0.72 * L1 + 0.28 * L2;\n    return clamp_double(L, TRUE_L_MIN, TRUE_L_MAX);\n}\n\nstruct LPosterior {\n    vector<double> Ls;\n    vector<double> ws;\n    double meanL = 30000.0;\n    double mapL = 30000.0;\n};\n\nLPosterior compute_L_posterior_grid() {\n    const int G = 161;\n    LPosterior post;\n    post.Ls.resize(G);\n    post.ws.resize(G);\n\n    vector<double> logw(G, 0.0);\n\n    for (int g = 0; g < G; g++) {\n        double L = TRUE_L_MIN + (TRUE_L_MAX - TRUE_L_MIN) * g / (G - 1);\n        post.Ls[g] = L;\n\n        double ll = 0.0;\n        double len = TRUE_U - L;\n\n        for (int i = 0; i < N; i++) {\n            {\n                double m = sumWObs[i] / cntWObs[i];\n                double sd = SIGMA / sqrt((double)cntWObs[i]);\n                double a = (L - m) / sd;\n                double b = (TRUE_U - m) / sd;\n                double p = normal_cdf(b) - normal_cdf(a);\n                p = max(p, 1e-300);\n                ll += log(p) - log(len);\n            }\n            {\n                double m = sumHObs[i] / cntHObs[i];\n                double sd = SIGMA / sqrt((double)cntHObs[i]);\n                double a = (L - m) / sd;\n                double b = (TRUE_U - m) / sd;\n                double p = normal_cdf(b) - normal_cdf(a);\n                p = max(p, 1e-300);\n                ll += log(p) - log(len);\n            }\n        }\n\n        logw[g] = ll;\n    }\n\n    double mx = *max_element(logw.begin(), logw.end());\n    double sm = 0.0;\n\n    int mapId = 0;\n    for (int g = 0; g < G; g++) {\n        if (logw[g] > logw[mapId]) mapId = g;\n        post.ws[g] = exp(logw[g] - mx);\n        sm += post.ws[g];\n    }\n\n    if (sm <= 0.0 || !isfinite(sm)) {\n        fill(post.ws.begin(), post.ws.end(), 1.0 / G);\n    } else {\n        for (double& x : post.ws) x /= sm;\n    }\n\n    post.meanL = 0.0;\n    for (int g = 0; g < G; g++) post.meanL += post.ws[g] * post.Ls[g];\n\n    post.mapL = post.Ls[mapId];\n    return post;\n}\n\ndouble posterior_L_quantile(const LPosterior& post, double q) {\n    double acc = 0.0;\n    for (int i = 0; i < (int)post.Ls.size(); i++) {\n        acc += post.ws[i];\n        if (acc >= q) return post.Ls[i];\n    }\n    return post.Ls.back();\n}\n\nvector<RectD> posterior_mean_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = truncated_normal_mean(mw, sw, L, TRUE_U);\n        res[i].h = truncated_normal_mean(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> posterior_bayes_mean_rects(const LPosterior& post) {\n    vector<RectD> res(N);\n\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n\n        double ew = 0.0, eh = 0.0;\n        for (int g = 0; g < (int)post.Ls.size(); g++) {\n            double L = post.Ls[g];\n            double wg = post.ws[g];\n            ew += wg * truncated_normal_mean(mw, sw, L, TRUE_U);\n            eh += wg * truncated_normal_mean(mh, sh, L, TRUE_U);\n        }\n\n        res[i].w = ew;\n        res[i].h = eh;\n    }\n\n    return res;\n}\n\nvector<RectD> posterior_sample_rects(double L) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        double mw = sumWObs[i] / cntWObs[i];\n        double mh = sumHObs[i] / cntHObs[i];\n        double sw = SIGMA / sqrt((double)cntWObs[i]);\n        double sh = SIGMA / sqrt((double)cntHObs[i]);\n        res[i].w = sample_truncated_normal(mw, sw, L, TRUE_U);\n        res[i].h = sample_truncated_normal(mh, sh, L, TRUE_U);\n    }\n    return res;\n}\n\nvector<RectD> blend_rects(const vector<RectD>& a, const vector<RectD>& b, double t) {\n    vector<RectD> res(N);\n    for (int i = 0; i < N; i++) {\n        res[i].w = (1.0 - t) * a[i].w + t * b[i].w;\n        res[i].h = (1.0 - t) * a[i].h + t * b[i].h;\n    }\n    return res;\n}\n\nstatic inline bool overlap_interval(double l1, double r1, double l2, double r2) {\n    return max(l1, l2) < min(r1, r2) - 1e-9;\n}\n\npair<double, double> simulate_ops(const vector<Op>& ops, const vector<RectD>& rects) {\n    vector<double> x(N, 0), y(N, 0), w(N, 0), h(N, 0);\n    vector<int> placed;\n    placed.reserve(ops.size());\n\n    double W = 0, H = 0;\n\n    for (const Op& op : ops) {\n        int p = op.p;\n        double rw = op.r ? rects[p].h : rects[p].w;\n        double rh = op.r ? rects[p].w : rects[p].h;\n\n        double nx = 0, ny = 0;\n        if (op.d == 'U') {\n            nx = (op.b == -1 ? 0.0 : x[op.b] + w[op.b]);\n            ny = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(nx, nx + rw, x[q], x[q] + w[q])) {\n                    ny = max(ny, y[q] + h[q]);\n                }\n            }\n        } else {\n            ny = (op.b == -1 ? 0.0 : y[op.b] + h[op.b]);\n            nx = 0.0;\n            for (int q : placed) {\n                if (overlap_interval(ny, ny + rh, y[q], y[q] + h[q])) {\n                    nx = max(nx, x[q] + w[q]);\n                }\n            }\n        }\n\n        x[p] = nx;\n        y[p] = ny;\n        w[p] = rw;\n        h[p] = rh;\n        placed.push_back(p);\n        W = max(W, nx + rw);\n        H = max(H, ny + rh);\n    }\n    return {W, H};\n}\n\nuint64_t splitmix64_u(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\nuint64_t hash_ops(const vector<Op>& ops) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (const Op& op : ops) {\n        uint64_t v = (uint64_t)(op.p + 1);\n        v = v * 1315423911ULL + (uint64_t)(op.r + 3);\n        v = v * 1315423911ULL + (uint64_t)(op.d == 'L' ? 7 : 11);\n        v = v * 1315423911ULL + (uint64_t)(op.b + 2);\n        h ^= splitmix64_u(v + h);\n    }\n    return h;\n}\n\nvoid add_candidate(vector<Candidate>& pool,\n                   unordered_set<uint64_t>& seen,\n                   const vector<Op>& ops,\n                   const vector<RectD>& baseRects) {\n    if ((int)ops.size() != N) return;\n\n    uint64_t hv = hash_ops(ops);\n    if (seen.find(hv) != seen.end()) return;\n    seen.insert(hv);\n\n    auto [W, H] = simulate_ops(ops, baseRects);\n    if (!isfinite(W) || !isfinite(H)) return;\n\n    Candidate c;\n    c.ops = ops;\n    c.baseW = W;\n    c.baseH = H;\n    c.estScore = W + H;\n    c.hash = hv;\n    pool.push_back(std::move(c));\n}\n\nstruct ShelfResult {\n    bool ok = false;\n    vector<Op> ops;\n};\n\n// mode 0: vertical columns using U\n// mode 1: horizontal rows using L\nShelfResult make_shelf_layout(const vector<RectD>& planRects, int mode, double cap) {\n    vector<array<double, 2>> cross(N), len(N);\n\n    for (int i = 0; i < N; i++) {\n        double w = planRects[i].w;\n        double h = planRects[i].h;\n        if (mode == 0) {\n            cross[i][0] = w; len[i][0] = h;\n            cross[i][1] = h; len[i][1] = w;\n        } else {\n            cross[i][0] = h; len[i][0] = w;\n            cross[i][1] = w; len[i][1] = h;\n        }\n    }\n\n    vector<double> vals;\n    vals.reserve(2 * N);\n    for (int i = 0; i < N; i++) {\n        vals.push_back(cross[i][0]);\n        vals.push_back(cross[i][1]);\n    }\n    sort(vals.begin(), vals.end());\n    vals.erase(unique(vals.begin(), vals.end(), [](double a, double b) {\n        return fabs(a - b) <= 1e-7 * max(1.0, max(fabs(a), fabs(b)));\n    }), vals.end());\n\n    int C = vals.size();\n\n    vector<vector<double>> pref(C, vector<double>(N + 1, 0.0));\n    for (int m = 0; m < C; m++) {\n        double M = vals[m];\n        for (int i = 0; i < N; i++) {\n            double bestLen = INF;\n            if (cross[i][0] <= M + 1e-7) bestLen = min(bestLen, len[i][0]);\n            if (cross[i][1] <= M + 1e-7) bestLen = min(bestLen, len[i][1]);\n            if (bestLen >= INF / 2 || pref[m][i] >= INF / 2) pref[m][i + 1] = INF;\n            else pref[m][i + 1] = min(INF, pref[m][i] + bestLen);\n        }\n    }\n\n    auto get_cost_idx = [&](int l, int r) -> int {\n        int lo = 0, hi = C;\n        while (lo < hi) {\n            int mid = (lo + hi) >> 1;\n            double s = pref[mid][r] - pref[mid][l];\n            if (s <= cap + 1e-7) hi = mid;\n            else lo = mid + 1;\n        }\n        if (lo == C) return -1;\n        return lo;\n    };\n\n    vector<double> dp(N + 1, INF);\n    vector<int> prv(N + 1, -1), prvM(N + 1, -1);\n    dp[0] = 0.0;\n\n    for (int r = 1; r <= N; r++) {\n        for (int l = 0; l < r; l++) {\n            if (dp[l] >= INF / 2) continue;\n            int mi = get_cost_idx(l, r);\n            if (mi < 0) continue;\n            double ndp = dp[l] + vals[mi];\n            if (ndp < dp[r]) {\n                dp[r] = ndp;\n                prv[r] = l;\n                prvM[r] = mi;\n            }\n        }\n    }\n\n    if (prv[N] < 0) return {};\n\n    vector<pair<int, int>> segs;\n    for (int r = N; r > 0; r = prv[r]) {\n        segs.push_back({prv[r], r});\n    }\n    reverse(segs.begin(), segs.end());\n\n    vector<int> orient(N, 0);\n    vector<int> anchorOfSeg(segs.size(), -1);\n\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        int mi = get_cost_idx(l, r);\n        double M = vals[mi];\n\n        int anchor = l;\n        double bestCross = -1.0;\n\n        for (int i = l; i < r; i++) {\n            int chosen = 0;\n            double bestLen = INF, bestCr = INF;\n\n            for (int rr = 0; rr < 2; rr++) {\n                if (cross[i][rr] <= M + 1e-7) {\n                    if (len[i][rr] < bestLen - 1e-7 ||\n                        (fabs(len[i][rr] - bestLen) <= 1e-7 && cross[i][rr] < bestCr)) {\n                        bestLen = len[i][rr];\n                        bestCr = cross[i][rr];\n                        chosen = rr;\n                    }\n                }\n            }\n            orient[i] = chosen;\n\n            double cr = cross[i][chosen];\n            if (cr > bestCross) {\n                bestCross = cr;\n                anchor = i;\n            }\n        }\n        anchorOfSeg[si] = anchor;\n    }\n\n    vector<Op> ops;\n    ops.reserve(N);\n\n    int boundaryRef = -1;\n    for (int si = 0; si < (int)segs.size(); si++) {\n        auto [l, r] = segs[si];\n        for (int i = l; i < r; i++) {\n            Op op;\n            op.p = i;\n            op.r = orient[i];\n            op.d = (mode == 0 ? 'U' : 'L');\n            op.b = boundaryRef;\n            ops.push_back(op);\n        }\n        boundaryRef = anchorOfSeg[si];\n    }\n\n    ShelfResult res;\n    res.ok = true;\n    res.ops = std::move(ops);\n    return res;\n}\n\nvector<double> make_caps(const vector<RectD>& rects, int mode, int cnt) {\n    (void)mode;\n\n    double area = 0.0;\n    double minCap = 0.0;\n    for (int i = 0; i < N; i++) {\n        area += rects[i].w * rects[i].h;\n        minCap = max(minCap, min(rects[i].w, rects[i].h));\n    }\n\n    double S = sqrt(max(1.0, area));\n    vector<double> caps;\n\n    double loF = 0.52, hiF = 2.35;\n    for (int k = 0; k < cnt; k++) {\n        double u = (cnt == 1 ? 0.5 : (double)k / (cnt - 1));\n        double f = exp(log(loF) + u * (log(hiF) - log(loF)));\n        caps.push_back(max(minCap, S * f));\n    }\n\n    for (double f : {0.72, 0.80, 0.88, 0.96, 1.04, 1.12, 1.20, 1.32, 1.48}) {\n        caps.push_back(max(minCap, S * f));\n    }\n\n    sort(caps.begin(), caps.end());\n    vector<double> uniq;\n    for (double x : caps) {\n        if (uniq.empty() || fabs(x - uniq.back()) > 1e-6 * max(1.0, x)) uniq.push_back(x);\n    }\n    return uniq;\n}\n\ndouble min_final_perimeter_lb(double W, double H, double A) {\n    double S = sqrt(max(1.0, A));\n    double ans = INF;\n\n    if (W <= S && H <= S) ans = min(ans, 2.0 * S);\n    ans = min(ans, W + max(H, A / max(W, 1.0)));\n    ans = min(ans, H + max(W, A / max(H, 1.0)));\n    ans = max(ans, W + H);\n    return ans;\n}\n\nvector<Op> make_greedy_layout(const vector<RectD>& planRects,\n                              double aspect,\n                              double scale,\n                              double wOverflow,\n                              double wWaste,\n                              double wBal,\n                              double wLB,\n                              double jitter) {\n    vector<Op> ops;\n    ops.reserve(N);\n\n    vector<double> x(N), y(N), ww(N), hh(N);\n    double W = 0.0, H = 0.0;\n    double totalArea = 0.0;\n    for (auto& r : planRects) totalArea += r.w * r.h;\n\n    double S = sqrt(max(1.0, totalArea)) * scale;\n    double Wlim = S * sqrt(aspect);\n    double Hlim = S / sqrt(aspect);\n\n    double usedArea = 0.0;\n    uniform_real_distribution<double> ud(0.0, 1.0);\n\n    for (int i = 0; i < N; i++) {\n        double itemArea = planRects[i].w * planRects[i].h;\n\n        double bestCost = INF;\n        Op bestOp{i, 0, 'U', -1};\n        double bestX = 0, bestY = 0, bestW = 0, bestH = 0;\n        double bestBW = 0, bestBH = 0;\n\n        for (int r = 0; r < 2; r++) {\n            double rw = r ? planRects[i].h : planRects[i].w;\n            double rh = r ? planRects[i].w : planRects[i].h;\n\n            for (int dd = 0; dd < 2; dd++) {\n                char d = (dd == 0 ? 'U' : 'L');\n                for (int b = -1; b < i; b++) {\n                    double nx = 0, ny = 0;\n\n                    if (d == 'U') {\n                        nx = (b == -1 ? 0.0 : x[b] + ww[b]);\n                        ny = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(nx, nx + rw, x[q], x[q] + ww[q])) {\n                                ny = max(ny, y[q] + hh[q]);\n                            }\n                        }\n                    } else {\n                        ny = (b == -1 ? 0.0 : y[b] + hh[b]);\n                        nx = 0.0;\n                        for (int q = 0; q < i; q++) {\n                            if (overlap_interval(ny, ny + rh, y[q], y[q] + hh[q])) {\n                                nx = max(nx, x[q] + ww[q]);\n                            }\n                        }\n                    }\n\n                    double nW = max(W, nx + rw);\n                    double nH = max(H, ny + rh);\n                    double nUsed = usedArea + itemArea;\n\n                    double overflow = max(0.0, nW - Wlim) + max(0.0, nH - Hlim);\n                    double wasteLen = max(0.0, nW * nH - nUsed) / sqrt(max(1.0, nUsed));\n                    double bal = fabs(nW / Wlim - nH / Hlim) * sqrt(totalArea);\n                    double lb = min_final_perimeter_lb(nW, nH, totalArea);\n                    double progress = 0.25 + 0.75 * (double)(i + 1) / N;\n\n                    double cost =\n                        wLB * lb +\n                        progress * (nW + nH) +\n                        wOverflow * overflow +\n                        wWaste * wasteLen +\n                        wBal * bal +\n                        0.0007 * (nx + ny) +\n                        jitter * ud(rng) * sqrt(totalArea);\n\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestOp = {i, r, d, b};\n                        bestX = nx;\n                        bestY = ny;\n                        bestW = rw;\n                        bestH = rh;\n                        bestBW = nW;\n                        bestBH = nH;\n                    }\n                }\n            }\n        }\n\n        ops.push_back(bestOp);\n        x[i] = bestX;\n        y[i] = bestY;\n        ww[i] = bestW;\n        hh[i] = bestH;\n        W = bestBW;\n        H = bestBH;\n        usedArea += itemArea;\n    }\n\n    return ops;\n}\n\nvoid output_query(const vector<Op>& ops) {\n    cout << ops.size() << '\\n';\n    for (const Op& 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    Timer timer;\n\n    cin >> N >> T >> SIGMA;\n\n    sumWObs.assign(N, 0.0);\n    sumHObs.assign(N, 0.0);\n    cntWObs.assign(N, 1);\n    cntHObs.assign(N, 1);\n\n    for (int i = 0; i < N; i++) {\n        long long w, h;\n        cin >> w >> h;\n        sumWObs[i] = (double)w;\n        sumHObs[i] = (double)h;\n    }\n\n    // Improved measurement policy:\n    // Use high-noise extra turns for repeated single-rectangle measurements,\n    // while still leaving at least about 2N turns for full packing trials.\n    double noiseFactor = clamp_double((SIGMA - 3000.0) / 7000.0, 0.0, 1.0);\n    int maxMeasureQ = max(0, T - 2 * N);\n    int measureQ = min(maxMeasureQ, (int)round(maxMeasureQ * noiseFactor));\n\n    if (measureQ > 0) {\n        double L0 = estimate_L_from_current_observations();\n        vector<RectD> base0 = posterior_mean_rects(L0);\n\n        vector<int> ids(N);\n        iota(ids.begin(), ids.end(), 0);\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            double ia = base0[a].w * base0[a].h +\n                        0.25 * (base0[a].w + base0[a].h) * sqrt(base0[a].w * base0[a].h);\n            double ib = base0[b].w * base0[b].h +\n                        0.25 * (base0[b].w + base0[b].h) * sqrt(base0[b].w * base0[b].h);\n            return ia > ib;\n        });\n\n        for (int k = 0; k < measureQ; k++) {\n            int i = ids[k % N];\n\n            vector<Op> ops;\n            ops.push_back({i, 0, 'U', -1});\n            output_query(ops);\n\n            long long Wm, Hm;\n            if (!(cin >> Wm >> Hm)) return 0;\n\n            sumWObs[i] += (double)Wm;\n            sumHObs[i] += (double)Hm;\n            cntWObs[i]++;\n            cntHObs[i]++;\n        }\n    }\n\n    int remainingTurns = T - measureQ;\n    if (remainingTurns <= 0) return 0;\n\n    double Lest = estimate_L_from_current_observations();\n    vector<RectD> baseRects = posterior_mean_rects(Lest);\n\n    LPosterior lpost = compute_L_posterior_grid();\n    vector<RectD> bayesRects = posterior_bayes_mean_rects(lpost);\n\n    double avgBayesDiff = 0.0;\n    for (int i = 0; i < N; i++) {\n        avgBayesDiff += fabs(baseRects[i].w - bayesRects[i].w);\n        avgBayesDiff += fabs(baseRects[i].h - bayesRects[i].h);\n    }\n    avgBayesDiff /= (2.0 * N);\n\n    bool useBayes = (avgBayesDiff > 120.0);\n\n    int randomScenarioCount = (N <= 50 ? 10 : 8);\n    if (remainingTurns <= 30) randomScenarioCount = min(randomScenarioCount, 6);\n\n    vector<vector<RectD>> scenarios;\n    scenarios.push_back(baseRects);\n    for (int s = 0; s < randomScenarioCount; s++) {\n        scenarios.push_back(posterior_sample_rects(Lest));\n    }\n\n    int originalScenarioCount = scenarios.size();\n\n    if (useBayes) {\n        scenarios.push_back(bayesRects);\n    }\n\n    int S = scenarios.size();\n\n    vector<Candidate> pool;\n    unordered_set<uint64_t> seen;\n    seen.reserve(8192);\n\n    int targetPool = max(450, min(1300, remainingTurns * 3));\n\n    int planScenarios = min(originalScenarioCount, 5);\n\n    // Original stable shelf candidates.\n    for (int ps = 0; ps < planScenarios; ps++) {\n        const auto& plan = scenarios[ps];\n        int capCnt = (ps == 0 ? 82 : 42);\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(plan, mode, capCnt);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Original randomized greedy candidates.\n    uniform_real_distribution<double> ud(0.0, 1.0);\n    int greedyAttempts = 0;\n    while ((int)pool.size() < targetPool && timer.elapsed() < 2.12) {\n        int ps = greedyAttempts % planScenarios;\n        const auto& plan = scenarios[ps];\n\n        double aspect = exp(log(0.48) + ud(rng) * (log(2.10) - log(0.48)));\n        double scale = 1.00 + 0.42 * ud(rng);\n\n        double wOverflow = 2.0 + 18.0 * ud(rng);\n        double wWaste = 0.05 + 2.50 * ud(rng);\n        double wBal = 0.02 + 1.10 * ud(rng);\n        double wLB = 1.0 + 6.0 * ud(rng);\n        double jitter = 0.000 + 0.035 * ud(rng);\n\n        vector<Op> ops = make_greedy_layout(plan, aspect, scale, wOverflow, wWaste, wBal, wLB, jitter);\n        add_candidate(pool, seen, ops, baseRects);\n        greedyAttempts++;\n    }\n\n    // Conservative extra candidates from Bayesian-estimated rectangles.\n    if (useBayes && timer.elapsed() < 2.32) {\n        for (int mode = 0; mode < 2; mode++) {\n            vector<double> caps = make_caps(bayesRects, mode, 56);\n            for (double cap : caps) {\n                ShelfResult sr = make_shelf_layout(bayesRects, mode, cap);\n                if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n            }\n        }\n    }\n\n    // Alternative posterior-L planning rectangles.\n    if (useBayes && avgBayesDiff > 180.0 && timer.elapsed() < 2.45) {\n        vector<vector<RectD>> altPlans;\n\n        altPlans.push_back(blend_rects(baseRects, bayesRects, 0.50));\n        altPlans.push_back(blend_rects(baseRects, bayesRects, 0.25));\n        altPlans.push_back(blend_rects(baseRects, bayesRects, 0.75));\n\n        double q25 = posterior_L_quantile(lpost, 0.25);\n        double q75 = posterior_L_quantile(lpost, 0.75);\n\n        if (fabs(lpost.mapL - Lest) > 400.0) {\n            altPlans.push_back(posterior_mean_rects(lpost.mapL));\n        }\n        if (fabs(q25 - Lest) > 700.0) {\n            altPlans.push_back(posterior_mean_rects(q25));\n        }\n        if (fabs(q75 - Lest) > 700.0) {\n            altPlans.push_back(posterior_mean_rects(q75));\n        }\n\n        int addedPlan = 0;\n        for (const auto& plan : altPlans) {\n            if (timer.elapsed() > 2.50) break;\n\n            int capCnt = (addedPlan < 3 ? 44 : 32);\n            for (int mode = 0; mode < 2; mode++) {\n                vector<double> caps = make_caps(plan, mode, capCnt);\n                for (double cap : caps) {\n                    ShelfResult sr = make_shelf_layout(plan, mode, cap);\n                    if (sr.ok) add_candidate(pool, seen, sr.ops, baseRects);\n                }\n            }\n            addedPlan++;\n        }\n    }\n\n    if (pool.empty()) {\n        vector<Op> ops;\n        for (int i = 0; i < N; i++) ops.push_back({i, 0, 'U', -1});\n        add_candidate(pool, seen, ops, baseRects);\n    }\n\n    // Slightly favor candidates that are good under both moment and Bayesian estimates.\n    if (useBayes) {\n        for (Candidate& c : pool) {\n            auto [bW, bH] = simulate_ops(c.ops, bayesRects);\n            double baseScore = c.baseW + c.baseH;\n            double bayesScore = bW + bH;\n            c.estScore = 0.86 * baseScore + 0.14 * bayesScore;\n        }\n    }\n\n    sort(pool.begin(), pool.end(), [](const Candidate& a, const Candidate& b) {\n        return a.estScore < b.estScore;\n    });\n\n    int maxKeep = max(remainingTurns, min((int)pool.size(), 1350));\n    if ((int)pool.size() > maxKeep) pool.resize(maxKeep);\n\n    int C = pool.size();\n\n    vector<float> predW(C * S), predH(C * S), predScore(C * S);\n\n    for (int c = 0; c < C; c++) {\n        for (int s = 0; s < S; s++) {\n            pair<double, double> wh;\n            if (s == 0) wh = {pool[c].baseW, pool[c].baseH};\n            else wh = simulate_ops(pool[c].ops, scenarios[s]);\n            predW[c * S + s] = (float)wh.first;\n            predH[c * S + s] = (float)wh.second;\n            predScore[c * S + s] = (float)(wh.first + wh.second);\n        }\n    }\n\n    vector<double> logWeight(S, 0.0);\n    vector<double> weight(S, 1.0 / S);\n    vector<double> bestScenarioScore(S, INF);\n    vector<char> used(C, 0);\n\n    int bestBaseIdx = 0;\n\n    for (int turn = 0; turn < remainingTurns; turn++) {\n        int chosen = -1;\n        double bestVal = INF;\n\n        for (int c = 0; c < C; c++) {\n            if (used[c]) continue;\n            double val = 0.0;\n            for (int s = 0; s < S; s++) {\n                double sc = predScore[c * S + s];\n                val += weight[s] * min(bestScenarioScore[s], sc);\n            }\n            val += 1e-9 * pool[c].estScore;\n            if (val < bestVal) {\n                bestVal = val;\n                chosen = c;\n            }\n        }\n\n        if (chosen < 0) chosen = bestBaseIdx;\n\n        output_query(pool[chosen].ops);\n\n        long long Wobs, Hobs;\n        if (!(cin >> Wobs >> Hobs)) return 0;\n\n        if (chosen >= 0 && chosen < C) {\n            used[chosen] = 1;\n\n            for (int s = 0; s < S; s++) {\n                bestScenarioScore[s] = min(bestScenarioScore[s], (double)predScore[chosen * S + s]);\n            }\n\n            double effSigma = max(2500.0, 2.25 * SIGMA);\n            for (int s = 0; s < S; s++) {\n                double dw = (double)Wobs - predW[chosen * S + s];\n                double dh = (double)Hobs - predH[chosen * S + s];\n                logWeight[s] += -0.5 * (dw * dw + dh * dh) / (effSigma * effSigma);\n            }\n\n            double mx = *max_element(logWeight.begin(), logWeight.end());\n            double sm = 0.0;\n            for (int s = 0; s < S; s++) {\n                weight[s] = exp(logWeight[s] - mx);\n                sm += weight[s];\n            }\n            if (sm <= 0 || !isfinite(sm)) {\n                fill(weight.begin(), weight.end(), 1.0 / S);\n            } else {\n                for (int s = 0; s < S; s++) {\n                    weight[s] = weight[s] / sm;\n                    weight[s] = 0.965 * weight[s] + 0.035 / S;\n                }\n            }\n        }\n    }\n\n    return 0;\n}","ahc041":"#pragma GCC optimize(\"O3\")\n#include <bits/stdc++.h>\nusing namespace std;\n\nint N, M, HH;\nvector<int> A;\nvector<vector<int>> adj;\nvector<int> highOrder, lowOrder;\nvector<vector<int>> dpCost;\n\nstruct RNG {\n    uint64_t x = 88172645463325252ULL;\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) {\n        return (int)(next() % (uint64_t)n);\n    }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n} rng;\n\nchrono::steady_clock::time_point START_TIME;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START_TIME).count();\n}\n\nstruct State {\n    vector<int> d;\n    vector<int> cnt;\n    long long val = 0;\n};\n\nvoid repairState(State& s);\n\nbool hasNeighborDepth(const vector<int>& d, int v, int dep) {\n    for (int u : adj[v]) if (d[u] == dep) return true;\n    return false;\n}\n\nvoid initState(State& s, const vector<int>& depth) {\n    s.d = depth;\n    s.cnt.assign(N, 0);\n    s.val = 0;\n\n    for (int v = 0; v < N; v++) {\n        s.val += 1LL * s.d[v] * A[v];\n        if (s.d[v] > 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) s.cnt[v]++;\n            }\n        }\n    }\n}\n\nbool verifyState(const State& s) {\n    if ((int)s.d.size() != N) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (s.d[v] < 0 || s.d[v] > HH) return false;\n\n        if (s.d[v] > 0) {\n            bool ok = false;\n            for (int u : adj[v]) {\n                if (s.d[u] == s.d[v] - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n            if (!ok) return false;\n        }\n    }\n\n    return true;\n}\n\nbool canMove(const State& s, int v, int nd) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n\n    return true;\n}\n\nbool canMoveExcept(const State& s, int v, int nd, int exceptChild) {\n    int od = s.d[v];\n    if (nd == od || nd < 0 || nd > HH) return false;\n\n    if (nd > 0) {\n        bool ok = false;\n        for (int u : adj[v]) {\n            if (s.d[u] == nd - 1) {\n                ok = true;\n                break;\n            }\n        }\n        if (!ok) return false;\n    }\n\n    int childDepth = od + 1;\n    if (childDepth <= HH) {\n        for (int w : adj[v]) {\n            if (w == exceptChild) continue;\n            if (s.d[w] == childDepth && s.cnt[w] <= 1) return false;\n        }\n    }\n\n    return true;\n}\n\nvoid applyMove(State& s, int v, int nd) {\n    int od = s.d[v];\n    if (od == nd) return;\n\n    for (int w : adj[v]) {\n        if (s.d[w] > 0) {\n            if (s.d[w] - 1 == od) s.cnt[w]--;\n            if (s.d[w] - 1 == nd) s.cnt[w]++;\n        }\n    }\n\n    s.val += 1LL * (nd - od) * A[v];\n    s.d[v] = nd;\n\n    int c = 0;\n    if (nd > 0) {\n        for (int u : adj[v]) if (s.d[u] == nd - 1) c++;\n    }\n    s.cnt[v] = c;\n}\n\nbool tryRaise(State& s, int v) {\n    int od = s.d[v];\n\n    for (int nd = HH; nd > od; nd--) {\n        if (canMove(s, v, nd)) {\n            applyMove(s, v, nd);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool greedyImprove(State& s, int maxPass = 10) {\n    bool any = false;\n\n    for (int pass = 0; pass < maxPass; pass++) {\n        bool moved = false;\n\n        for (int v : highOrder) {\n            if (tryRaise(s, v)) {\n                moved = true;\n                any = true;\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nvector<int> aroundMark;\nint aroundStamp = 1;\n\nvoid greedyAround(State& s, int v) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n\n    auto add = [&](int x) {\n        if (aroundMark[x] != aroundStamp) {\n            aroundMark[x] = aroundStamp;\n            list.push_back(x);\n        }\n    };\n\n    add(v);\n    for (int u : adj[v]) {\n        add(u);\n        for (int w : adj[u]) add(w);\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int pass = 0; pass < 2; pass++) {\n        for (int x : list) tryRaise(s, x);\n    }\n}\n\nvoid greedyRegion(State& s, int start, int radius, int passes) {\n    if (++aroundStamp == INT_MAX) {\n        fill(aroundMark.begin(), aroundMark.end(), 0);\n        aroundStamp = 1;\n    }\n\n    vector<int> list;\n    queue<pair<int, int>> q;\n\n    aroundMark[start] = aroundStamp;\n    q.push({start, 0});\n    list.push_back(start);\n\n    while (!q.empty()) {\n        auto [v, dist] = q.front();\n        q.pop();\n\n        if (dist >= radius) continue;\n\n        for (int u : adj[v]) {\n            if (aroundMark[u] == aroundStamp) continue;\n\n            aroundMark[u] = aroundStamp;\n            list.push_back(u);\n            q.push({u, dist + 1});\n        }\n    }\n\n    sort(list.begin(), list.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int p = 0; p < passes; p++) {\n        for (int v : list) tryRaise(s, v);\n    }\n}\n\nvoid computeDPCost() {\n    const int INF = 1e9;\n    dpCost.assign(HH, vector<int>(N, INF));\n    if (HH <= 0) return;\n\n    for (int v = 0; v < N; v++) {\n        dpCost[0][v] = HH * A[v];\n    }\n\n    for (int k = 1; k < HH; k++) {\n        for (int v = 0; v < N; v++) {\n            int best = INF;\n            for (int u : adj[v]) best = min(best, dpCost[k - 1][u]);\n            dpCost[k][v] = best + (HH - k) * A[v];\n        }\n    }\n}\n\nstruct Mode {\n    bool indepTop;\n    bool indepLower;\n    bool lookahead;\n    int kind;\n    double noise;\n    double dpWeight;\n};\n\ndouble coverScore(int cov, double cost, int future, int kind, double noise) {\n    double c = (double)cov;\n    double score;\n\n    if ((kind & 3) == 0) {\n        score = c / cost;\n    } else if ((kind & 3) == 1) {\n        score = c * c / cost;\n    } else if ((kind & 3) == 2) {\n        score = c / sqrt(cost);\n    } else {\n        score = c * sqrt(c) / cost;\n    }\n\n    score *= (1.0 + 0.025 * future);\n\n    if (noise > 0) {\n        score *= (1.0 + noise * (rng.nextDouble() - 0.5));\n    }\n\n    return score;\n}\n\nbool selectCoverLevel(\n    int k,\n    const vector<int>& target,\n    vector<int>& depth,\n    vector<char>& used,\n    bool independent,\n    const Mode& mode\n) {\n    vector<char> targetMark(N, 0), covered(N, 0), banned(N, 0);\n\n    for (int t : target) targetMark[t] = 1;\n\n    int rem = (int)target.size();\n    vector<int> selected;\n\n    auto candidateCost = [&](int c) -> double {\n        double base = (double)(HH - k) * A[c];\n\n        if (mode.dpWeight > 0 && k >= 0 && k < HH && !dpCost.empty()) {\n            double extra = max(0, dpCost[k][c] - (HH - k) * A[c]);\n            base += mode.dpWeight * extra;\n        }\n\n        return max(1.0, base);\n    };\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (used[c]) continue;\n            if (independent && banned[c]) continue;\n\n            int future = 0;\n            if (k > 0) {\n                for (int u : adj[c]) if (!used[u]) future++;\n                if (mode.lookahead && future == 0) continue;\n            }\n\n            int cov = 0;\n            if (k == HH - 1 && targetMark[c] && !covered[c]) cov++;\n            for (int u : adj[c]) {\n                if (targetMark[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = coverScore(cov, candidateCost(c), future, mode.kind, mode.noise);\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        used[best] = 1;\n        depth[best] = k;\n        selected.push_back(best);\n\n        if (independent) {\n            banned[best] = 1;\n            for (int u : adj[best]) banned[u] = 1;\n        }\n\n        auto mark = [&](int x) {\n            if (targetMark[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        if (k == HH - 1) mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    auto addCover = [&](int c, int delta) {\n        if (k == HH - 1) {\n            coverCnt[c] += delta;\n            for (int u : adj[c]) coverCnt[u] += delta;\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u]) coverCnt[u] += delta;\n            }\n        }\n    };\n\n    for (int c : selected) {\n        if (used[c] && depth[c] == k) addCover(c, 1);\n    }\n\n    for (int t : target) {\n        if (coverCnt[t] <= 0) return false;\n    }\n\n    sort(selected.begin(), selected.end(), [&](int a, int b) {\n        return A[a] > A[b];\n    });\n\n    for (int c : selected) {\n        if (!used[c] || depth[c] != k) continue;\n\n        if (k < HH - 1 && !hasNeighborDepth(depth, c, HH - 1)) continue;\n\n        bool ok = true;\n\n        if (k == HH - 1) {\n            if (coverCnt[c] <= 1) ok = false;\n\n            if (ok) {\n                for (int u : adj[c]) {\n                    if (coverCnt[u] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n            }\n        } else {\n            for (int u : adj[c]) {\n                if (targetMark[u] && coverCnt[u] <= 1) {\n                    ok = false;\n                    break;\n                }\n            }\n        }\n\n        if (ok) {\n            addCover(c, -1);\n            used[c] = 0;\n            depth[c] = HH;\n        }\n    }\n\n    return true;\n}\n\nbool buildChain(vector<int>& outDepth, const Mode& mode) {\n    vector<int> depth(N, HH);\n    vector<char> used(N, 0);\n\n    for (int k = HH - 1; k >= 0; k--) {\n        vector<int> target;\n\n        if (k == HH - 1) {\n            target.resize(N);\n            iota(target.begin(), target.end(), 0);\n        } else {\n            for (int v = 0; v < N; v++) {\n                if (depth[v] == k + 1) target.push_back(v);\n            }\n        }\n\n        if (target.empty()) continue;\n\n        bool independent = (k == HH - 1 ? mode.indepTop : mode.indepLower);\n\n        if (!selectCoverLevel(k, target, depth, used, independent, mode)) {\n            return false;\n        }\n    }\n\n    State s;\n    initState(s, depth);\n\n    if (!verifyState(s)) return false;\n\n    outDepth = depth;\n    return true;\n}\n\nbool localImproveCover(\n    const vector<char>& targetMark,\n    const vector<char>& candidate,\n    vector<char>& selected,\n    const vector<char>& forced,\n    const vector<double>& cost,\n    bool topClosed,\n    int maxLoops\n) {\n    vector<vector<int>> cover(N);\n\n    for (int c = 0; c < N; c++) {\n        if (!candidate[c] && !selected[c]) continue;\n\n        if (topClosed && targetMark[c]) cover[c].push_back(c);\n\n        for (int u : adj[c]) {\n            if (targetMark[u]) cover[c].push_back(u);\n        }\n    }\n\n    vector<int> coverCnt(N, 0);\n\n    for (int c = 0; c < N; c++) {\n        if (!selected[c]) continue;\n        for (int t : cover[c]) coverCnt[t]++;\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    vector<int> candList;\n    for (int c = 0; c < N; c++) {\n        if (candidate[c]) candList.push_back(c);\n    }\n\n    auto removableActual = [&](int c) -> bool {\n        if (forced[c]) return false;\n        if (cost[c] <= 1e-9 || cost[c] > 1e17) return false;\n\n        for (int t : cover[c]) {\n            if (coverCnt[t] <= 1) return false;\n        }\n\n        return true;\n    };\n\n    auto pruneActual = [&]() {\n        vector<int> sels;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c]) sels.push_back(c);\n        }\n\n        sort(sels.begin(), sels.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        for (int c : sels) {\n            if (!selected[c]) continue;\n            if (!removableActual(c)) continue;\n\n            selected[c] = 0;\n            for (int t : cover[c]) coverCnt[t]--;\n        }\n    };\n\n    pruneActual();\n\n    if (maxLoops <= 0) {\n        for (int t = 0; t < N; t++) {\n            if (targetMark[t] && coverCnt[t] <= 0) return false;\n        }\n        return true;\n    }\n\n    vector<int> tmpCnt(N);\n\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                selOrder.push_back(c);\n            }\n        }\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        double bestGain = 1e-6;\n        int bestC = -1;\n        vector<int> bestRem;\n\n        for (int c : candList) {\n            if (selected[c]) continue;\n            if (cover[c].empty()) continue;\n            if (cost[c] <= 1e-9 || cost[c] > 1e17) continue;\n\n            copy(coverCnt.begin(), coverCnt.end(), tmpCnt.begin());\n\n            for (int t : cover[c]) tmpCnt[t]++;\n\n            double gain = -cost[c];\n            vector<int> rems;\n\n            for (int s : selOrder) {\n                bool ok = true;\n\n                for (int t : cover[s]) {\n                    if (tmpCnt[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    for (int t : cover[s]) tmpCnt[t]--;\n                    gain += cost[s];\n                    rems.push_back(s);\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestC = c;\n                bestRem.swap(rems);\n            }\n        }\n\n        if (bestC == -1) break;\n\n        selected[bestC] = 1;\n        for (int t : cover[bestC]) coverCnt[t]++;\n\n        for (int r : bestRem) {\n            if (!selected[r]) continue;\n\n            selected[r] = 0;\n            for (int t : cover[r]) coverCnt[t]--;\n        }\n\n        pruneActual();\n    }\n\n    for (int loop = 0; loop < maxLoops; loop++) {\n        vector<int> selOrder;\n\n        for (int c = 0; c < N; c++) {\n            if (selected[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                selOrder.push_back(c);\n            }\n        }\n\n        if (selOrder.empty()) break;\n\n        sort(selOrder.begin(), selOrder.end(), [&](int a, int b) {\n            return cost[a] > cost[b];\n        });\n\n        int trialLimit = min((int)selOrder.size(), 80 + 20 * maxLoops);\n\n        double bestGain = 1e-6;\n        vector<char> bestSel;\n        vector<int> bestCnt;\n\n        for (int ii = 0; ii < trialLimit; ii++) {\n            int r = selOrder[ii];\n\n            vector<char> tmpSel = selected;\n            vector<int> tc = coverCnt;\n\n            tmpSel[r] = 0;\n            for (int t : cover[r]) tc[t]--;\n\n            vector<char> need(N, 0);\n            int rem = 0;\n\n            for (int t : cover[r]) {\n                if (tc[t] == 0 && !need[t]) {\n                    need[t] = 1;\n                    rem++;\n                }\n            }\n\n            double addCost = 0.0;\n            bool fail = false;\n            int steps = 0;\n\n            while (rem > 0 && steps < 12) {\n                int bestA = -1;\n                int bestCov = 0;\n                double bestScore = -1;\n\n                for (int c : candList) {\n                    if (tmpSel[c]) continue;\n                    if (cost[c] <= 1e-9 || cost[c] > 1e17) continue;\n\n                    int cov = 0;\n                    for (int t : cover[c]) {\n                        if (need[t]) cov++;\n                    }\n\n                    if (cov == 0) continue;\n\n                    double sc = (double)cov * cov / cost[c];\n\n                    if (sc > bestScore) {\n                        bestScore = sc;\n                        bestA = c;\n                        bestCov = cov;\n                    }\n                }\n\n                if (bestA == -1 || bestCov == 0) {\n                    fail = true;\n                    break;\n                }\n\n                tmpSel[bestA] = 1;\n                addCost += cost[bestA];\n\n                for (int t : cover[bestA]) {\n                    tc[t]++;\n                    if (need[t]) {\n                        need[t] = 0;\n                        rem--;\n                    }\n                }\n\n                steps++;\n            }\n\n            if (fail || rem > 0) continue;\n\n            double gain = cost[r] - addCost;\n\n            vector<int> tmpOrder;\n            for (int c = 0; c < N; c++) {\n                if (tmpSel[c] && !forced[c] && cost[c] > 1e-9 && cost[c] < 1e17) {\n                    tmpOrder.push_back(c);\n                }\n            }\n\n            sort(tmpOrder.begin(), tmpOrder.end(), [&](int a, int b) {\n                return cost[a] > cost[b];\n            });\n\n            for (int c : tmpOrder) {\n                if (!tmpSel[c]) continue;\n\n                bool ok = true;\n                for (int t : cover[c]) {\n                    if (tc[t] <= 1) {\n                        ok = false;\n                        break;\n                    }\n                }\n\n                if (ok) {\n                    tmpSel[c] = 0;\n                    for (int t : cover[c]) tc[t]--;\n                    gain += cost[c];\n                }\n            }\n\n            if (gain > bestGain) {\n                bestGain = gain;\n                bestSel.swap(tmpSel);\n                bestCnt.swap(tc);\n            }\n        }\n\n        if (bestGain > 1e-6) {\n            selected.swap(bestSel);\n            coverCnt.swap(bestCnt);\n            pruneActual();\n        } else {\n            break;\n        }\n    }\n\n    for (int t = 0; t < N; t++) {\n        if (targetMark[t] && coverCnt[t] <= 0) return false;\n    }\n\n    return true;\n}\n\nbool reoptTop(State& s, int improveLoops) {\n    if (HH == 0) return false;\n\n    int k = HH - 1;\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0), candidate(N, 0), selected(N, 0), covered(N, 0), forced(N, 0);\n    vector<double> cost(N, 1e18);\n\n    int rem = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] >= k) {\n            target[v] = 1;\n            rem++;\n        }\n    }\n\n    if (rem == 0) return false;\n\n    for (int v = 0; v < N; v++) {\n        if (!target[v]) continue;\n\n        if (k == 0 || hasNeighborDepth(d, v, k - 1)) {\n            candidate[v] = 1;\n            cost[v] = A[v];\n        }\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n            if (target[c] && !covered[c]) cov++;\n\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = (double)cov / A[c];\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n\n        auto mark = [&](int x) {\n            if (target[x] && !covered[x]) {\n                covered[x] = 1;\n                rem--;\n            }\n        };\n\n        mark(best);\n        for (int u : adj[best]) mark(u);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, true, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n\n    for (int v = 0; v < N; v++) {\n        if (target[v]) nd[v] = HH;\n    }\n\n    for (int v = 0; v < N; v++) {\n        if (selected[v]) nd[v] = k;\n    }\n\n    State ns;\n    initState(ns, nd);\n\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n\n    return false;\n}\n\nbool reoptLevel(State& s, int k, int improveLoops) {\n    if (k < 0 || k >= HH - 1) return false;\n\n    const vector<int>& d = s.d;\n\n    vector<char> target(N, 0);\n    int targetCount = 0;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k + 1) {\n            target[v] = 1;\n            targetCount++;\n        }\n    }\n\n    if (targetCount == 0) return false;\n\n    vector<char> candidate(N, 0), selected(N, 0), forced(N, 0), covered(N, 0);\n    vector<char> demoteTarget(N, 0), lowerLeaf(N, 0);\n    vector<double> cost(N, 1e18);\n    vector<int> retireDepth(N, -1);\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            candidate[v] = 1;\n            selected[v] = 0;\n\n            int bestRetire = -1;\n\n            for (int dep = HH; dep >= k + 2; dep--) {\n                if (hasNeighborDepth(d, v, dep - 1)) {\n                    bestRetire = dep;\n                    break;\n                }\n            }\n\n            if (bestRetire == -1) {\n                forced[v] = 1;\n                selected[v] = 1;\n                retireDepth[v] = k;\n                cost[v] = 0;\n            } else {\n                retireDepth[v] = bestRetire;\n                cost[v] = (bestRetire - k) * A[v];\n            }\n        } else if (d[v] == HH) {\n            bool supp = (k == 0) || hasNeighborDepth(d, v, k - 1);\n\n            if (supp) {\n                candidate[v] = 1;\n                cost[v] = (HH - k) * A[v];\n            }\n        } else if (improveLoops >= 5 && d[v] == k + 1) {\n            // Refined: not only leaves. If children have alternative supports,\n            // canMove() already certifies that demoting this target is safe.\n            if (canMove(s, v, k)) {\n                candidate[v] = 1;\n                demoteTarget[v] = 1;\n                cost[v] = A[v];\n            }\n        } else if (improveLoops >= 6 && d[v] > k + 1 && d[v] < HH) {\n            // Refined: intermediate non-leaves may also be usable as supports\n            // when their current children do not depend uniquely on them.\n            if (canMove(s, v, k)) {\n                candidate[v] = 1;\n                lowerLeaf[v] = 1;\n                cost[v] = (d[v] - k) * A[v];\n            }\n        }\n    }\n\n    int rem = targetCount;\n\n    auto markBy = [&](int c) {\n        if (demoteTarget[c] && target[c] && !covered[c]) {\n            covered[c] = 1;\n            rem--;\n        }\n\n        for (int u : adj[c]) {\n            if (target[u] && !covered[u]) {\n                covered[u] = 1;\n                rem--;\n            }\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (forced[v]) markBy(v);\n    }\n\n    while (rem > 0) {\n        int best = -1;\n        double bestScore = -1;\n\n        for (int c = 0; c < N; c++) {\n            if (!candidate[c] || selected[c]) continue;\n\n            int cov = 0;\n\n            if (demoteTarget[c] && target[c] && !covered[c]) cov++;\n\n            for (int u : adj[c]) {\n                if (target[u] && !covered[u]) cov++;\n            }\n\n            if (cov == 0) continue;\n\n            double sc = (double)cov / max(1.0, cost[c]);\n\n            if (sc > bestScore) {\n                bestScore = sc;\n                best = c;\n            }\n        }\n\n        if (best == -1) return false;\n\n        selected[best] = 1;\n        markBy(best);\n    }\n\n    if (!localImproveCover(target, candidate, selected, forced, cost, true, improveLoops)) {\n        return false;\n    }\n\n    vector<int> nd = d;\n\n    for (int v = 0; v < N; v++) {\n        if (d[v] == k) {\n            if (selected[v]) {\n                nd[v] = k;\n            } else {\n                if (retireDepth[v] == -1) return false;\n                nd[v] = retireDepth[v];\n            }\n        } else if (d[v] == HH && selected[v]) {\n            nd[v] = k;\n        } else if (d[v] == k + 1 && demoteTarget[v] && selected[v]) {\n            nd[v] = k;\n        } else if (lowerLeaf[v] && selected[v]) {\n            nd[v] = k;\n        }\n    }\n\n    State ns;\n    initState(ns, nd);\n\n    if (verifyState(ns) && ns.val > s.val) {\n        s = ns;\n        return true;\n    }\n\n    return false;\n}\n\nbool supportReplaceImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    vector<int> childIndex(N, -1);\n    vector<int> candMark(N, 0);\n    int stamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n\n        for (int p : highOrder) {\n            if ((chk++ & 15) == 0 && elapsed() > stopTime) return any;\n\n            int k = s.d[p];\n            if (k >= HH) continue;\n\n            vector<int> childs;\n\n            for (int w : adj[p]) {\n                if (s.d[w] == k + 1 && s.cnt[w] <= 1) {\n                    childs.push_back(w);\n                }\n            }\n\n            if (childs.empty()) {\n                if (tryRaise(s, p)) {\n                    moved = true;\n                    any = true;\n                }\n                continue;\n            }\n\n            int C = (int)childs.size();\n            if (C > 8) continue;\n\n            for (int i = 0; i < C; i++) childIndex[childs[i]] = i;\n\n            if (++stamp == INT_MAX) {\n                fill(candMark.begin(), candMark.end(), 0);\n                stamp = 1;\n            }\n\n            vector<int> raw;\n\n            auto addRaw = [&](int u) {\n                if (u == p) return;\n                if (candMark[u] != stamp) {\n                    candMark[u] = stamp;\n                    raw.push_back(u);\n                }\n            };\n\n            for (int w : childs) addRaw(w);\n\n            for (int w : childs) {\n                for (int u : adj[w]) {\n                    addRaw(u);\n                }\n            }\n\n            vector<int> cands, masks, deltas;\n\n            for (int u : raw) {\n                if (s.d[u] == k) continue;\n\n                int mask = 0;\n\n                int selfIdx = childIndex[u];\n                if (selfIdx >= 0) mask |= 1 << selfIdx;\n\n                for (int x : adj[u]) {\n                    int idx = childIndex[x];\n                    if (idx >= 0) mask |= 1 << idx;\n                }\n\n                if (mask == 0) continue;\n                if (!canMove(s, u, k)) continue;\n\n                cands.push_back(u);\n                masks.push_back(mask);\n                deltas.push_back((k - s.d[u]) * A[u]);\n            }\n\n            for (int x : childs) childIndex[x] = -1;\n\n            int K = (int)cands.size();\n            if (K == 0) continue;\n\n            if (K > 90) {\n                vector<int> ord(K);\n                iota(ord.begin(), ord.end(), 0);\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    int pa = __builtin_popcount((unsigned)masks[a]);\n                    int pb = __builtin_popcount((unsigned)masks[b]);\n                    return deltas[a] + 18 * pa > deltas[b] + 18 * pb;\n                });\n\n                vector<int> nc, nm, ndlt;\n                for (int i = 0; i < 90; i++) {\n                    int id = ord[i];\n                    nc.push_back(cands[id]);\n                    nm.push_back(masks[id]);\n                    ndlt.push_back(deltas[id]);\n                }\n                cands.swap(nc);\n                masks.swap(nm);\n                deltas.swap(ndlt);\n                K = 90;\n            }\n\n            int S = 1 << C;\n            int FULL = S - 1;\n            const int NEG = -1000000000;\n\n            vector<vector<int>> dp(K + 1, vector<int>(S, NEG));\n            vector<vector<unsigned char>> take(K + 1, vector<unsigned char>(S, 0));\n            vector<vector<int>> pre(K + 1, vector<int>(S, -1));\n\n            dp[0][0] = 0;\n\n            for (int i = 0; i < K; i++) {\n                for (int m = 0; m < S; m++) {\n                    if (dp[i][m] <= NEG / 2) continue;\n\n                    if (dp[i][m] > dp[i + 1][m]) {\n                        dp[i + 1][m] = dp[i][m];\n                    }\n\n                    int nm = m | masks[i];\n                    if (nm == m) continue;\n\n                    int nv = dp[i][m] + deltas[i];\n                    if (nv > dp[i + 1][nm]) {\n                        dp[i + 1][nm] = nv;\n                        take[i + 1][nm] = 1;\n                        pre[i + 1][nm] = m;\n                    }\n                }\n            }\n\n            if (dp[K][FULL] <= NEG / 2) continue;\n\n            vector<int> chosen;\n            int mask = FULL;\n\n            for (int i = K; i >= 1; i--) {\n                if (take[i][mask]) {\n                    chosen.push_back(cands[i - 1]);\n                    mask = pre[i][mask];\n                }\n            }\n\n            vector<pair<int, int>> oldDepth;\n            bool ok = true;\n            int altDelta = 0;\n\n            for (int u : chosen) {\n                int od = s.d[u];\n                oldDepth.push_back({u, od});\n\n                if (!canMove(s, u, k)) {\n                    ok = false;\n                    break;\n                }\n\n                applyMove(s, u, k);\n                altDelta += (k - od) * A[u];\n            }\n\n            int bestNd = -1;\n\n            if (ok) {\n                for (int nd = HH; nd > k; nd--) {\n                    if (canMove(s, p, nd)) {\n                        bestNd = nd;\n                        break;\n                    }\n                }\n            }\n\n            bool accepted = false;\n\n            if (bestNd != -1) {\n                int net = altDelta + (bestNd - k) * A[p];\n\n                if (net > 0) {\n                    applyMove(s, p, bestNd);\n                    greedyAround(s, p);\n                    moved = true;\n                    any = true;\n                    accepted = true;\n                }\n            }\n\n            if (!accepted) {\n                for (int i = (int)oldDepth.size() - 1; i >= 0; i--) {\n                    applyMove(s, oldDepth[i].first, oldDepth[i].second);\n                }\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nbool combinedSupportParentImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    vector<int> childIndex(N, -1);\n    vector<int> candMark(N, 0);\n    vector<int> changedMark(N, 0);\n    int candStamp = 1;\n    int changedStamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool movedPass = false;\n        int chk = 0;\n\n        for (int p : highOrder) {\n            if ((chk++ & 15) == 0 && elapsed() > stopTime) return any;\n\n            int k = s.d[p];\n            if (k >= HH) continue;\n\n            vector<int> childs;\n            for (int w : adj[p]) {\n                if (s.d[w] == k + 1 && s.cnt[w] <= 1) {\n                    childs.push_back(w);\n                }\n            }\n\n            int C = (int)childs.size();\n            if (C == 0 || C > 8) continue;\n\n            for (int i = 0; i < C; i++) childIndex[childs[i]] = i;\n\n            if (++candStamp == INT_MAX) {\n                fill(candMark.begin(), candMark.end(), 0);\n                candStamp = 1;\n            }\n\n            vector<int> raw;\n\n            auto addRaw = [&](int u) {\n                if (u == p) return;\n                if (candMark[u] != candStamp) {\n                    candMark[u] = candStamp;\n                    raw.push_back(u);\n                }\n            };\n\n            for (int w : childs) addRaw(w);\n            for (int w : childs) {\n                for (int u : adj[w]) addRaw(u);\n            }\n\n            vector<int> cands, masks, deltas;\n\n            for (int u : raw) {\n                if (s.d[u] == k) continue;\n\n                int mask = 0;\n\n                int selfIdx = childIndex[u];\n                if (selfIdx >= 0) mask |= 1 << selfIdx;\n\n                for (int x : adj[u]) {\n                    int idx = childIndex[x];\n                    if (idx >= 0) mask |= 1 << idx;\n                }\n\n                if (mask == 0) continue;\n                if (!canMove(s, u, k)) continue;\n\n                cands.push_back(u);\n                masks.push_back(mask);\n                deltas.push_back((k - s.d[u]) * A[u]);\n            }\n\n            for (int x : childs) childIndex[x] = -1;\n\n            int K = (int)cands.size();\n            if (K == 0) continue;\n\n            if (K > 80) {\n                vector<int> ord(K);\n                iota(ord.begin(), ord.end(), 0);\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    int pa = __builtin_popcount((unsigned)masks[a]);\n                    int pb = __builtin_popcount((unsigned)masks[b]);\n                    return deltas[a] + 20 * pa > deltas[b] + 20 * pb;\n                });\n\n                vector<int> nc, nm, ndlt;\n                for (int i = 0; i < 80; i++) {\n                    int id = ord[i];\n                    nc.push_back(cands[id]);\n                    nm.push_back(masks[id]);\n                    ndlt.push_back(deltas[id]);\n                }\n                cands.swap(nc);\n                masks.swap(nm);\n                deltas.swap(ndlt);\n                K = 80;\n            }\n\n            int S = 1 << C;\n            int FULL = S - 1;\n            const int NEG = -1000000000;\n\n            vector<vector<int>> dp(K + 1, vector<int>(S, NEG));\n            vector<vector<unsigned char>> take(K + 1, vector<unsigned char>(S, 0));\n            vector<vector<int>> pre(K + 1, vector<int>(S, -1));\n\n            dp[0][0] = 0;\n\n            for (int i = 0; i < K; i++) {\n                for (int m = 0; m < S; m++) {\n                    if (dp[i][m] <= NEG / 2) continue;\n\n                    if (dp[i][m] > dp[i + 1][m]) {\n                        dp[i + 1][m] = dp[i][m];\n                        take[i + 1][m] = 0;\n                    }\n\n                    int nm = m | masks[i];\n                    if (nm == m) continue;\n\n                    int nv = dp[i][m] + deltas[i];\n                    if (nv > dp[i + 1][nm]) {\n                        dp[i + 1][nm] = nv;\n                        take[i + 1][nm] = 1;\n                        pre[i + 1][nm] = m;\n                    }\n                }\n            }\n\n            if (dp[K][FULL] <= NEG / 2) continue;\n\n            vector<int> chosen;\n            int mask = FULL;\n\n            for (int i = K; i >= 1; i--) {\n                if (take[i][mask]) {\n                    chosen.push_back(i - 1);\n                    mask = pre[i][mask];\n                }\n            }\n\n            State tmp = s;\n            long long before = s.val;\n\n            if (++changedStamp == INT_MAX) {\n                fill(changedMark.begin(), changedMark.end(), 0);\n                changedStamp = 1;\n            }\n\n            bool ok = true;\n\n            for (int id : chosen) {\n                int u = cands[id];\n\n                if (changedMark[u] == changedStamp) continue;\n                if (!canMove(tmp, u, k)) {\n                    ok = false;\n                    break;\n                }\n\n                changedMark[u] = changedStamp;\n                applyMove(tmp, u, k);\n            }\n\n            if (!ok) continue;\n\n            long long bestNet = 0;\n            int bestNd = -1;\n            int bestQ = -1;\n            int bestNeed = -1;\n\n            for (int nd = HH; nd > k; nd--) {\n                if (canMove(tmp, p, nd)) {\n                    long long net = tmp.val - before + 1LL * (nd - k) * A[p];\n\n                    if (net > bestNet) {\n                        bestNet = net;\n                        bestNd = nd;\n                        bestQ = -1;\n                        bestNeed = -1;\n                    }\n                }\n\n                int need = nd - 1;\n\n                for (int q : adj[p]) {\n                    if (q == p) continue;\n                    if (changedMark[q] == changedStamp) continue;\n                    if (tmp.d[q] == need) continue;\n\n                    if (!canMoveExcept(tmp, q, need, p)) continue;\n\n                    int oldq = tmp.d[q];\n\n                    applyMove(tmp, q, need);\n                    if (canMove(tmp, p, nd)) {\n                        long long net = tmp.val - before + 1LL * (nd - k) * A[p];\n\n                        if (net > bestNet) {\n                            bestNet = net;\n                            bestNd = nd;\n                            bestQ = q;\n                            bestNeed = need;\n                        }\n                    }\n                    applyMove(tmp, q, oldq);\n                }\n            }\n\n            if (bestNd == -1 || bestNet <= 0) continue;\n\n            if (bestQ != -1) {\n                if (!canMoveExcept(tmp, bestQ, bestNeed, p)) continue;\n                applyMove(tmp, bestQ, bestNeed);\n            }\n\n            if (!canMove(tmp, p, bestNd)) continue;\n            applyMove(tmp, p, bestNd);\n\n            if (tmp.val > before && verifyState(tmp)) {\n                s = std::move(tmp);\n                greedyAround(s, p);\n                any = true;\n                movedPass = true;\n            }\n        }\n\n        if (!movedPass) break;\n    }\n\n    return any;\n}\n\nbool pairRaiseImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n\n        for (int v : highOrder) {\n            if ((chk++ & 31) == 0 && elapsed() > stopTime) return any;\n\n            int dv = s.d[v];\n            if (dv >= HH) continue;\n\n            int bestNet = 0;\n            int bestNd = -1;\n            int bestU = -1;\n            int bestNeed = -1;\n\n            for (int nd = dv + 1; nd <= HH; nd++) {\n                int directNet = (nd - dv) * A[v];\n\n                if (canMove(s, v, nd)) {\n                    if (directNet > bestNet) {\n                        bestNet = directNet;\n                        bestNd = nd;\n                        bestU = -1;\n                    }\n                    continue;\n                }\n\n                int need = nd - 1;\n\n                for (int u : adj[v]) {\n                    if (s.d[u] == need) continue;\n                    if (!canMoveExcept(s, u, need, v)) continue;\n\n                    int oldu = s.d[u];\n                    int deltaU = (need - oldu) * A[u];\n                    int net = directNet + deltaU;\n\n                    if (net <= bestNet) continue;\n\n                    applyMove(s, u, need);\n                    bool ok = canMove(s, v, nd);\n                    applyMove(s, u, oldu);\n\n                    if (ok) {\n                        bestNet = net;\n                        bestNd = nd;\n                        bestU = u;\n                        bestNeed = need;\n                    }\n                }\n            }\n\n            if (bestNd == -1 || bestNet <= 0) continue;\n\n            if (bestU == -1) {\n                if (canMove(s, v, bestNd)) {\n                    applyMove(s, v, bestNd);\n                    moved = true;\n                    any = true;\n                }\n            } else {\n                long long before = s.val;\n                int oldu = s.d[bestU];\n                int oldv = s.d[v];\n\n                applyMove(s, bestU, bestNeed);\n\n                if (canMove(s, v, bestNd)) {\n                    applyMove(s, v, bestNd);\n\n                    if (verifyState(s) && s.val > before) {\n                        moved = true;\n                        any = true;\n                    } else {\n                        applyMove(s, v, oldv);\n                        applyMove(s, bestU, oldu);\n                    }\n                } else {\n                    applyMove(s, bestU, oldu);\n                }\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nbool liftClosureImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    vector<int> mark(N, 0), suppIn(N, 0);\n    int stamp = 1;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool movedPass = false;\n        int chk = 0;\n\n        for (int seed : highOrder) {\n            if ((chk++ & 15) == 0 && elapsed() > stopTime) return any;\n\n            int base = s.d[seed];\n            if (base >= HH) continue;\n\n            if (++stamp == INT_MAX) {\n                fill(mark.begin(), mark.end(), 0);\n                stamp = 1;\n            }\n\n            vector<int> nodes;\n            vector<int> touched;\n            bool fail = false;\n\n            auto addNode = [&](int x) {\n                if (mark[x] == stamp) return;\n                if (s.d[x] >= HH) {\n                    fail = true;\n                    return;\n                }\n                mark[x] = stamp;\n                nodes.push_back(x);\n            };\n\n            addNode(seed);\n\n            for (int qi = 0; qi < (int)nodes.size() && !fail; qi++) {\n                int x = nodes[qi];\n                int t = s.d[x];\n\n                for (int y : adj[x]) {\n                    if (s.d[y] != t + 1) continue;\n\n                    if (suppIn[y] == 0) touched.push_back(y);\n                    suppIn[y]++;\n\n                    if (mark[y] != stamp && suppIn[y] >= s.cnt[y]) {\n                        addNode(y);\n                        if (fail) break;\n                    }\n                }\n            }\n\n            for (int x : touched) suppIn[x] = 0;\n\n            if (fail || nodes.empty()) continue;\n\n            long long gain = 0;\n            for (int x : nodes) gain += A[x];\n\n            bool hasSameSupport = false;\n            for (int u : adj[seed]) {\n                if (s.d[u] == base && mark[u] != stamp) {\n                    hasSameSupport = true;\n                    break;\n                }\n            }\n\n            vector<pair<int, int>> options;\n\n            if (hasSameSupport) {\n                options.push_back({-1, 0});\n            } else {\n                for (int q : adj[seed]) {\n                    if (mark[q] == stamp) continue;\n                    if (s.d[q] == base) continue;\n                    if (!canMove(s, q, base)) continue;\n\n                    int delta = (base - s.d[q]) * A[q];\n                    if (gain + delta > 0) {\n                        options.push_back({q, delta});\n                    }\n                }\n\n                sort(options.begin(), options.end(), [&](auto a, auto b) {\n                    return a.second > b.second;\n                });\n            }\n\n            if (options.empty()) continue;\n\n            sort(nodes.begin(), nodes.end(), [&](int a, int b) {\n                if (s.d[a] != s.d[b]) return s.d[a] < s.d[b];\n                return a < b;\n            });\n\n            bool acceptedAny = false;\n\n            for (auto [supportVertex, delta] : options) {\n                long long before = s.val;\n                vector<pair<int, int>> changed;\n\n                auto doMove = [&](int x, int nd) {\n                    if (s.d[x] == nd) return;\n                    changed.push_back({x, s.d[x]});\n                    applyMove(s, x, nd);\n                };\n\n                auto revert = [&]() {\n                    for (int i = (int)changed.size() - 1; i >= 0; i--) {\n                        applyMove(s, changed[i].first, changed[i].second);\n                    }\n                };\n\n                if (supportVertex != -1) {\n                    doMove(supportVertex, base);\n                }\n\n                for (int x : nodes) {\n                    doMove(x, s.d[x] + 1);\n                }\n\n                if (verifyState(s) && s.val > before) {\n                    movedPass = true;\n                    any = true;\n                    acceptedAny = true;\n                    break;\n                } else {\n                    revert();\n                }\n            }\n\n            if (acceptedAny) {\n                continue;\n            }\n        }\n\n        if (!movedPass) break;\n    }\n\n    return any;\n}\n\nbool addSupportImprove(State& s, int passes, double stopTime) {\n    bool any = false;\n\n    for (int pass = 0; pass < passes; pass++) {\n        bool moved = false;\n        int chk = 0;\n        int destructiveChecks = 0;\n\n        for (int u : lowOrder) {\n            if ((chk++ & 7) == 0 && elapsed() > stopTime) return any;\n\n            int old = s.d[u];\n            if (old <= 0) continue;\n\n            int limit = (A[u] <= 15 ? 8 : 5);\n            vector<int> tries;\n            vector<char> seen(HH + 1, 0);\n\n            for (int nd = old - 1; nd >= 0 && (int)tries.size() < limit; nd--) {\n                if (!seen[nd]) {\n                    seen[nd] = 1;\n                    tries.push_back(nd);\n                }\n            }\n\n            State bestTmp;\n            long long bestVal = s.val;\n            bool found = false;\n\n            for (int nd : tries) {\n                if (elapsed() > stopTime) return any;\n\n                bool safe = canMove(s, u, nd);\n\n                if (!safe) {\n                    if (A[u] > 22) continue;\n                    if (destructiveChecks >= 120) continue;\n                    if (old - nd > 4 && nd != 0) continue;\n                    destructiveChecks++;\n                }\n\n                State tmp = s;\n                applyMove(tmp, u, nd);\n\n                if (!safe) {\n                    repairState(tmp);\n                }\n\n                if (!verifyState(tmp)) continue;\n\n                greedyRegion(tmp, u, 3, 3);\n\n                if (tmp.val > bestVal && verifyState(tmp)) {\n                    bestVal = tmp.val;\n                    bestTmp = std::move(tmp);\n                    found = true;\n                }\n            }\n\n            if (found) {\n                s = std::move(bestTmp);\n                moved = true;\n                any = true;\n            }\n        }\n\n        if (!moved) break;\n    }\n\n    return any;\n}\n\nvoid polish(State& s, int passes, int improveLoops, double stopTime) {\n    for (int p = 0; p < passes; p++) {\n        if (elapsed() > stopTime) return;\n\n        reoptTop(s, improveLoops);\n\n        for (int k = HH - 2; k >= 0; k--) {\n            if (elapsed() > stopTime) return;\n            reoptLevel(s, k, improveLoops);\n        }\n\n        greedyImprove(s, 8);\n\n        if (improveLoops > 0 && elapsed() < stopTime) {\n            supportReplaceImprove(s, 1, stopTime);\n            greedyImprove(s, 4);\n        }\n    }\n}\n\nvoid finalMicroPolish(State& s, double stopTime) {\n    if (elapsed() > stopTime) return;\n\n    reoptTop(s, 5);\n\n    for (int k = HH - 2; k >= 0; k--) {\n        if (elapsed() > stopTime) return;\n\n        int loops;\n        if (k >= HH - 4) loops = 6;       // stronger on high-impact top layers\n        else if (k >= HH - 6) loops = 2;\n        else loops = 1;\n\n        reoptLevel(s, k, loops);\n    }\n\n    greedyImprove(s, 3);\n}\n\nState makeFallback() {\n    vector<int> dist(N, -1);\n    queue<int> q;\n\n    dist[0] = 0;\n    q.push(0);\n\n    while (!q.empty()) {\n        int v = q.front();\n        q.pop();\n\n        for (int u : adj[v]) {\n            if (dist[u] == -1) {\n                dist[u] = dist[v] + 1;\n                q.push(u);\n            }\n        }\n    }\n\n    vector<int> depth(N, 0);\n\n    for (int v = 0; v < N; v++) {\n        if (dist[v] < 0) depth[v] = 0;\n        else depth[v] = dist[v] % (HH + 1);\n    }\n\n    State s;\n    initState(s, depth);\n\n    if (!verifyState(s)) {\n        fill(depth.begin(), depth.end(), 0);\n        initState(s, depth);\n    }\n\n    greedyImprove(s, 12);\n    return s;\n}\n\nvoid anneal(State& best, double endTime) {\n    State cur = best;\n\n    double st = elapsed();\n    double duration = max(0.001, endTime - st);\n\n    double T0 = 120.0;\n    double T1 = 0.8;\n    double T = T0;\n\n    int iter = 0;\n\n    while (true) {\n        if ((iter & 4095) == 0) {\n            double now = elapsed();\n\n            if (now >= endTime) break;\n\n            double prog = min(1.0, (now - st) / duration);\n            T = T0 * pow(T1 / T0, prog);\n\n            if ((iter & 65535) == 0 && iter > 0) {\n                greedyImprove(cur, 3);\n                if (cur.val > best.val) best = cur;\n                if (cur.val + 7000 < best.val) cur = best;\n            }\n        }\n\n        iter++;\n\n        int v = -1, nd = -1;\n        bool prechecked = false;\n\n        int type = rng.nextInt(100);\n\n        if (type < 30) {\n            int w = -1;\n\n            for (int t = 0; t < 6; t++) {\n                int cand = rng.nextInt(N);\n\n                if (cur.d[cand] > 0 && cur.cnt[cand] <= 1) {\n                    w = cand;\n                    break;\n                }\n            }\n\n            if (w == -1) {\n                int cand = rng.nextInt(N);\n                if (cur.d[cand] == 0) continue;\n                w = cand;\n            }\n\n            nd = cur.d[w] - 1;\n\n            int bestU = -1;\n            int bestDelta = INT_MIN;\n\n            for (int u : adj[w]) {\n                if (cur.d[u] == nd) continue;\n                if (!canMove(cur, u, nd)) continue;\n\n                int delta = (nd - cur.d[u]) * A[u];\n\n                if (delta > bestDelta) {\n                    bestDelta = delta;\n                    bestU = u;\n                }\n            }\n\n            if (bestU == -1) continue;\n\n            v = bestU;\n            prechecked = true;\n        } else if (type < 55) {\n            int K = min(N, 450);\n            v = lowOrder[rng.nextInt(K)];\n            if (cur.d[v] == 0) continue;\n            nd = rng.nextInt(cur.d[v]);\n        } else if (type < 85) {\n            int K = min(N, 750);\n            v = highOrder[rng.nextInt(K)];\n\n            if (cur.d[v] == HH) continue;\n\n            nd = -1;\n\n            for (int x = HH; x > cur.d[v]; x--) {\n                if (canMove(cur, v, x)) {\n                    nd = x;\n                    break;\n                }\n            }\n\n            if (nd == -1) continue;\n            prechecked = true;\n        } else {\n            v = rng.nextInt(N);\n            nd = rng.nextInt(HH + 1);\n            if (nd == cur.d[v]) continue;\n        }\n\n        if (!prechecked && !canMove(cur, v, nd)) continue;\n\n        int delta = (nd - cur.d[v]) * A[v];\n\n        bool accept = false;\n\n        if (delta >= 0) {\n            accept = true;\n        } else {\n            if (delta > -30.0 * T) {\n                double prob = exp(delta / T);\n                if (rng.nextDouble() < prob) accept = true;\n            }\n        }\n\n        if (!accept) continue;\n\n        applyMove(cur, v, nd);\n\n        if (delta < 0) {\n            greedyAround(cur, v);\n        }\n\n        if (cur.val > best.val) {\n            best = cur;\n        }\n    }\n\n    greedyImprove(best, 10);\n}\n\nbool isBad(const State& s, int v) {\n    return s.d[v] > 0 && s.cnt[v] <= 0;\n}\n\nvoid repairState(State& s) {\n    deque<int> q;\n    vector<char> inq(N, 0);\n\n    auto push = [&](int v) {\n        if (!inq[v]) {\n            inq[v] = 1;\n            q.push_back(v);\n        }\n    };\n\n    for (int v = 0; v < N; v++) {\n        if (isBad(s, v)) push(v);\n    }\n\n    int guard = 0;\n\n    while (!q.empty() && guard < 50000) {\n        int v = q.front();\n        q.pop_front();\n        inq[v] = 0;\n\n        if (!isBad(s, v)) continue;\n\n        int old = s.d[v];\n        int need = old - 1;\n\n        int bestU = -1;\n        int bestDelta = INT_MIN;\n\n        if (need >= 0) {\n            for (int u : adj[v]) {\n                if (s.d[u] == need) continue;\n\n                if (canMove(s, u, need)) {\n                    int delta = (need - s.d[u]) * A[u];\n                    if (delta > bestDelta) {\n                        bestDelta = delta;\n                        bestU = u;\n                    }\n                }\n            }\n        }\n\n        int nd = 0;\n\n        for (int x = old - 1; x >= 1; x--) {\n            bool ok = false;\n\n            for (int u : adj[v]) {\n                if (s.d[u] == x - 1) {\n                    ok = true;\n                    break;\n                }\n            }\n\n            if (ok) {\n                nd = x;\n                break;\n            }\n        }\n\n        int lowerDelta = (nd - old) * A[v];\n\n        if (bestU != -1 && bestDelta > lowerDelta) {\n            applyMove(s, bestU, need);\n\n            push(v);\n            push(bestU);\n            for (int u : adj[bestU]) push(u);\n            for (int u : adj[v]) push(u);\n        } else {\n            applyMove(s, v, nd);\n\n            push(v);\n            for (int u : adj[v]) push(u);\n        }\n\n        guard++;\n    }\n\n    if (!verifyState(s)) {\n        vector<int> zero(N, 0);\n        initState(s, zero);\n    }\n}\n\nbool forceRaiseRepairImprove(State& s, int maxTrials, double stopTime) {\n    bool any = false;\n\n    vector<int> ord;\n    ord.reserve(N);\n\n    for (int v = 0; v < N; v++) {\n        if (s.d[v] < HH) ord.push_back(v);\n    }\n\n    auto eval = [&](int v) -> long long {\n        long long potential = 1LL * (HH - s.d[v]) * A[v];\n\n        long long childPenalty = 0;\n        int cd = s.d[v] + 1;\n        if (cd <= HH) {\n            for (int w : adj[v]) {\n                if (s.d[w] == cd && s.cnt[w] <= 1) {\n                    childPenalty += A[w];\n                }\n            }\n        }\n\n        return potential * 4 - childPenalty;\n    };\n\n    sort(ord.begin(), ord.end(), [&](int a, int b) {\n        long long ea = eval(a);\n        long long eb = eval(b);\n        if (ea != eb) return ea > eb;\n        return A[a] > A[b];\n    });\n\n    int trials = 0;\n    int chk = 0;\n\n    for (int p : ord) {\n        if ((chk++ & 1) == 0 && elapsed() > stopTime) return any;\n        if (trials >= maxTrials) break;\n        if (s.d[p] >= HH) continue;\n\n        int potential = (HH - s.d[p]) * A[p];\n        if (potential <= 0) continue;\n\n        trials++;\n\n        long long before = s.val;\n        long long bestVal = before;\n        State bestTmp;\n        bool found = false;\n\n        int tried = 0;\n        for (int targetDepth = HH; targetDepth > s.d[p] && tried < 4; targetDepth--, tried++) {\n            if (elapsed() > stopTime) return any;\n\n            State tmp = s;\n\n            applyMove(tmp, p, targetDepth);\n            repairState(tmp);\n\n            if (!verifyState(tmp)) continue;\n\n            greedyRegion(tmp, p, 3, (targetDepth == HH ? 3 : 2));\n            greedyImprove(tmp, 2);\n\n            if (tmp.val > bestVal && verifyState(tmp)) {\n                bestVal = tmp.val;\n                bestTmp = std::move(tmp);\n                found = true;\n            }\n        }\n\n        if (found) {\n            s = std::move(bestTmp);\n            any = true;\n        }\n    }\n\n    return any;\n}\n\nvoid lns(State& best, double endTime) {\n    State base = best;\n\n    while (elapsed() < endTime) {\n        State s = (rng.nextInt(100) < 85 ? best : base);\n\n        int remCnt = 2 + rng.nextInt(12);\n        if (rng.nextInt(100) < 15) remCnt += rng.nextInt(20);\n\n        for (int i = 0; i < remCnt; i++) {\n            int v = -1;\n\n            for (int t = 0; t < 60; t++) {\n                int cand;\n\n                if (rng.nextInt(100) < 65) {\n                    cand = highOrder[rng.nextInt(min(N, 800))];\n                } else {\n                    cand = rng.nextInt(N);\n                }\n\n                if (s.d[cand] < HH) {\n                    v = cand;\n                    break;\n                }\n            }\n\n            if (v != -1) {\n                applyMove(s, v, HH);\n            }\n        }\n\n        int addCnt = 4 + rng.nextInt(24);\n\n        for (int i = 0; i < addCnt; i++) {\n            int K = min(N, 250 + rng.nextInt(550));\n            int v = lowOrder[rng.nextInt(K)];\n\n            int nd;\n\n            if (rng.nextInt(100) < 70) {\n                nd = rng.nextInt(HH);\n            } else {\n                nd = max(0, s.d[v] - 1 - rng.nextInt(3));\n            }\n\n            if (nd < 0) nd = 0;\n            if (nd > HH) nd = HH;\n\n            applyMove(s, v, nd);\n        }\n\n        for (int t = 0; t < 35; t++) {\n            int v = rng.nextInt(N);\n\n            if (!isBad(s, v)) continue;\n\n            int need = s.d[v] - 1;\n            if (need < 0) continue;\n\n            int bu = -1;\n            int bestCost = INT_MAX;\n\n            for (int u : adj[v]) {\n                int c = abs(s.d[u] - need) * A[u] + A[u];\n\n                if (c < bestCost) {\n                    bestCost = c;\n                    bu = u;\n                }\n            }\n\n            if (bu != -1) {\n                applyMove(s, bu, need);\n            }\n        }\n\n        repairState(s);\n\n        if (!verifyState(s)) continue;\n\n        greedyImprove(s, 5);\n\n        if (s.val > best.val - 3000 && elapsed() < endTime - 0.03) {\n            polish(s, 1, 1, endTime);\n        }\n\n        if (s.val > best.val) {\n            best = s;\n            base = s;\n        } else if (s.val > base.val || rng.nextInt(100) < 5) {\n            base = s;\n        }\n    }\n\n    greedyImprove(best, 8);\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> M >> HH;\n\n    A.resize(N);\n    uint64_t seed = 1234567891234567ULL;\n\n    for (int i = 0; i < N; i++) {\n        cin >> A[i];\n        seed = seed * 1000003ULL + A[i] + 97;\n    }\n\n    adj.assign(N, {});\n\n    for (int i = 0; i < M; i++) {\n        int u, v;\n        cin >> u >> v;\n\n        adj[u].push_back(v);\n        adj[v].push_back(u);\n\n        seed ^= (uint64_t)(u + 1) * 1000000007ULL + (uint64_t)(v + 1) * 1000003ULL;\n    }\n\n    for (int i = 0; i < N; i++) {\n        int x, y;\n        cin >> x >> y;\n\n        seed ^= ((uint64_t)x << 32) ^ (uint64_t)y ^ ((uint64_t)i * 11995408973635179863ULL);\n    }\n\n    if (seed == 0) seed = 88172645463325252ULL;\n    rng.x = seed;\n\n    START_TIME = chrono::steady_clock::now();\n\n    highOrder.resize(N);\n    lowOrder.resize(N);\n\n    iota(highOrder.begin(), highOrder.end(), 0);\n    iota(lowOrder.begin(), lowOrder.end(), 0);\n\n    sort(highOrder.begin(), highOrder.end(), [&](int a, int b) {\n        if (A[a] != A[b]) return A[a] > A[b];\n        return adj[a].size() > adj[b].size();\n    });\n\n    sort(lowOrder.begin(), lowOrder.end(), [&](int a, int b) {\n        if (A[a] != A[b]) return A[a] < A[b];\n        return adj[a].size() > adj[b].size();\n    });\n\n    aroundMark.assign(N, 0);\n\n    computeDPCost();\n\n    State best = makeFallback();\n    polish(best, 1, 0, 0.20);\n\n    vector<State> pool;\n\n    auto addPool = [&](const State& s) {\n        if (!verifyState(s)) return;\n\n        const int POOL_SIZE = 4;\n\n        if ((int)pool.size() < POOL_SIZE) {\n            pool.push_back(s);\n            return;\n        }\n\n        int worst = 0;\n        for (int i = 1; i < POOL_SIZE; i++) {\n            if (pool[i].val < pool[worst].val) worst = i;\n        }\n\n        if (s.val > pool[worst].val) {\n            pool[worst] = s;\n        }\n    };\n\n    addPool(best);\n\n    const double CONSTRUCT_LIMIT = 0.70;\n    int attempt = 0;\n\n    double dpWs[] = {0.0, 0.0, 0.015, 0.03, 0.06, 0.10};\n\n    while (attempt < 220 && elapsed() < CONSTRUCT_LIMIT) {\n        Mode mode;\n\n        if (attempt < 24) {\n            mode.indepTop = (attempt & 1);\n            mode.indepLower = (attempt & 2);\n            mode.kind = (attempt / 6) & 3;\n            mode.noise = 0.0;\n            mode.dpWeight = dpWs[(attempt / 4) % 6];\n        } else {\n            mode.indepTop = (rng.nextInt(100) < 45);\n            mode.indepLower = (rng.nextInt(100) < 25);\n            mode.kind = rng.nextInt(4);\n            mode.noise = 0.20 + 0.70 * rng.nextDouble();\n            mode.dpWeight = dpWs[rng.nextInt(6)] * (0.7 + 0.8 * rng.nextDouble());\n        }\n\n        mode.lookahead = true;\n\n        vector<int> depth;\n\n        if (buildChain(depth, mode)) {\n            State s;\n            initState(s, depth);\n\n            polish(s, 1, 0, CONSTRUCT_LIMIT);\n\n            if (s.val > best.val) best = s;\n            addPool(s);\n        }\n\n        attempt++;\n    }\n\n    for (State s : pool) {\n        if (elapsed() > 0.95) break;\n\n        polish(s, 1, 4, 0.98);\n\n        if (s.val > best.val) best = s;\n    }\n\n    polish(best, 1, 5, 1.08);\n\n    anneal(best, 1.56);\n\n    polish(best, 1, 4, 1.67);\n\n    lns(best, 1.83);\n\n    polish(best, 1, 6, 1.875);\n    supportReplaceImprove(best, 1, 1.888);\n\n    combinedSupportParentImprove(best, 1, 1.900);\n    pairRaiseImprove(best, 1, 1.912);\n    liftClosureImprove(best, 2, 1.928);\n    pairRaiseImprove(best, 1, 1.938);\n\n    addSupportImprove(best, 1, 1.950);\n    forceRaiseRepairImprove(best, 150, 1.966);\n    pairRaiseImprove(best, 1, 1.972);\n\n    finalMicroPolish(best, 1.982);\n\n    greedyImprove(best, 10);\n\n    if (!verifyState(best)) {\n        best = makeFallback();\n    }\n\n    vector<int> parent(N, -1);\n    bool ok = true;\n\n    for (int v = 0; v < N; v++) {\n        if (best.d[v] == 0) {\n            parent[v] = -1;\n        } else {\n            int p = -1;\n\n            for (int u : adj[v]) {\n                if (best.d[u] == best.d[v] - 1) {\n                    p = u;\n                    break;\n                }\n            }\n\n            if (p == -1) {\n                ok = false;\n                break;\n            }\n\n            parent[v] = p;\n        }\n    }\n\n    if (!ok) {\n        for (int i = 0; i < N; i++) parent[i] = -1;\n    }\n\n    for (int i = 0; i < N; i++) {\n        if (i) cout << ' ';\n        cout << parent[i];\n    }\n    cout << '\\n';\n\n    return 0;\n}","ahc042":"#include <bits/stdc++.h>\nusing namespace std;\n\nint N;\nuint32_t FULL;\nconst int MAXN = 20;\n\nstruct Op { char d; int p; };\nstruct GAct { char d; int p; int k; };\n\nstruct State {\n    array<uint32_t, MAXN> x{}, o{};\n    int xcnt = 0;\n};\n\nState INIT;\nvector<pair<int,int>> initialXs;\nint idxAt[MAXN][MAXN];\n\nchrono::steady_clock::time_point START;\n\ndouble elapsed() {\n    return chrono::duration<double>(chrono::steady_clock::now() - START).count();\n}\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed ? seed : 1) {}\n    uint64_t next() {\n        x ^= x << 7;\n        x ^= x >> 9;\n        return x;\n    }\n    int nextInt(int n) { return (int)(next() % n); }\n    double nextDouble() {\n        return (next() >> 11) * (1.0 / 9007199254740992.0);\n    }\n};\n\nint popc(uint32_t v) { return __builtin_popcount(v); }\nint firstBit(uint32_t m) { return m ? __builtin_ctz(m) : N; }\nint lastBit(uint32_t m) { return m ? 31 - __builtin_clz(m) : -1; }\n\nchar invDir(char d) {\n    if (d == 'L') return 'R';\n    if (d == 'R') return 'L';\n    if (d == 'U') return 'D';\n    return 'U';\n}\n\nvoid appendOps(vector<Op>& ops, char d, int p, int k) {\n    for (int i = 0; i < k; i++) ops.push_back({d, p});\n}\n\nbool edgeO(const State& s, const Op& op) {\n    int p = op.p;\n    uint32_t bit = 1u << p;\n    if (op.d == 'L') return s.o[p] & 1u;\n    if (op.d == 'R') return s.o[p] & (1u << (N - 1));\n    if (op.d == 'U') return s.o[0] & bit;\n    return s.o[N - 1] & bit;\n}\n\ninline void setBit(uint32_t& m, uint32_t bit, bool v) {\n    if (v) m |= bit;\n    else m &= ~bit;\n}\n\nvoid applyOp(State& s, const Op& op) {\n    int p = op.p;\n    if (op.d == 'L') {\n        if (s.x[p] & 1u) s.xcnt--;\n        s.x[p] >>= 1;\n        s.o[p] >>= 1;\n    } else if (op.d == 'R') {\n        if (s.x[p] & (1u << (N - 1))) s.xcnt--;\n        s.x[p] = (s.x[p] << 1) & FULL;\n        s.o[p] = (s.o[p] << 1) & FULL;\n    } else if (op.d == 'U') {\n        uint32_t bit = 1u << p;\n        if (s.x[0] & bit) s.xcnt--;\n        for (int i = 0; i < N - 1; i++) {\n            bool xb = s.x[i + 1] & bit;\n            bool ob = s.o[i + 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[N - 1] &= ~bit;\n        s.o[N - 1] &= ~bit;\n    } else {\n        uint32_t bit = 1u << p;\n        if (s.x[N - 1] & bit) s.xcnt--;\n        for (int i = N - 1; i >= 1; i--) {\n            bool xb = s.x[i - 1] & bit;\n            bool ob = s.o[i - 1] & bit;\n            setBit(s.x[i], bit, xb);\n            setBit(s.o[i], bit, ob);\n        }\n        s.x[0] &= ~bit;\n        s.o[0] &= ~bit;\n    }\n}\n\nvoid applyGAct(State& s, const GAct& a) {\n    Op op{a.d, a.p};\n    for (int i = 0; i < a.k; i++) applyOp(s, op);\n}\n\nvector<Op> expandGSeq(const vector<GAct>& gs) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& g : gs) total += g.k;\n    ops.reserve(total);\n    for (auto& g : gs) appendOps(ops, g.d, g.p, g.k);\n    return ops;\n}\n\nbool isPerfectFull(const vector<Op>& ops) {\n    if ((int)ops.size() > 4 * N * N) return false;\n    State s = INIT;\n    for (auto& op : ops) {\n        if (edgeO(s, op)) return false;\n        applyOp(s, op);\n    }\n    return s.xcnt == 0;\n}\n\nbool truncateToPerfectPrefix(vector<Op>& ops) {\n    if (INIT.xcnt == 0) {\n        ops.clear();\n        return true;\n    }\n\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) {\n            ops.resize(t + 1);\n            return true;\n        }\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkip(const vector<Op>& ops, int l, int r) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (l <= t && t < r) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkipTwo(const vector<Op>& ops, int a, int b) {\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (t == a || t == b) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nbool canPerfectSkipSet(const vector<Op>& ops, const vector<int>& ids) {\n    vector<char> skip(ops.size(), 0);\n    for (int id : ids) {\n        if (0 <= id && id < (int)ops.size()) skip[id] = 1;\n    }\n\n    State s = INIT;\n    int executed = 0;\n    for (int t = 0; t < (int)ops.size(); t++) {\n        if (skip[t]) continue;\n        if (executed >= 4 * N * N) return false;\n        if (edgeO(s, ops[t])) return false;\n        applyOp(s, ops[t]);\n        executed++;\n        if (s.xcnt == 0) return true;\n    }\n    return s.xcnt == 0;\n}\n\nvoid pruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n\n        int maxLen = min(55, (int)seq.size());\n        for (int len = maxLen; len >= 2 && elapsed() < until; len--) {\n            for (int i = 0; i + len <= (int)seq.size() && elapsed() < until; ) {\n                if (canPerfectSkip(seq, i, i + len)) {\n                    seq.erase(seq.begin() + i, seq.begin() + i + len);\n                    truncateToPerfectPrefix(seq);\n                    changed = true;\n                    i = max(0, i - len);\n                } else {\n                    i++;\n                }\n            }\n        }\n\n        for (int i = 0; i < (int)seq.size() && elapsed() < until; ) {\n            if (canPerfectSkip(seq, i, i + 1)) {\n                seq.erase(seq.begin() + i);\n                truncateToPerfectPrefix(seq);\n                changed = true;\n                if (i > 0) i--;\n            } else {\n                i++;\n            }\n        }\n    }\n}\n\nvoid pairPruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n        int n = (int)seq.size();\n\n        for (int pass = 0; pass < 2 && !changed && elapsed() < until; pass++) {\n            for (int i = 0; i < n && !changed && elapsed() < until; i++) {\n                for (int j = n - 1; j > i && elapsed() < until; j--) {\n                    bool invSameLine = (seq[i].p == seq[j].p && invDir(seq[i].d) == seq[j].d);\n                    if (pass == 0 && !invSameLine) continue;\n                    if (pass == 1 && invSameLine) continue;\n\n                    if (canPerfectSkipTwo(seq, i, j)) {\n                        seq.erase(seq.begin() + j);\n                        seq.erase(seq.begin() + i);\n                        truncateToPerfectPrefix(seq);\n                        changed = true;\n                        break;\n                    }\n                }\n            }\n        }\n    }\n}\n\nvoid randomSubsetPrune(vector<Op>& seq, double until, RNG& rng) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    while (elapsed() < until) {\n        int n = (int)seq.size();\n        if (n < 3) break;\n\n        int m = min(n, 3 + rng.nextInt(2));\n        vector<int> ids;\n\n        if (rng.nextInt(2) == 0) {\n            for (int tr = 0; tr < 25 && ids.empty(); tr++) {\n                int a = rng.nextInt(n);\n                int b = rng.nextInt(n);\n                if (a == b) continue;\n                if (seq[a].p == seq[b].p && invDir(seq[a].d) == seq[b].d) {\n                    ids.push_back(a);\n                    ids.push_back(b);\n                }\n            }\n        }\n\n        while ((int)ids.size() < m) {\n            int v = rng.nextInt(n);\n            bool ok = true;\n            for (int u : ids) if (u == v) ok = false;\n            if (ok) ids.push_back(v);\n        }\n\n        sort(ids.begin(), ids.end());\n        ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n        if (canPerfectSkipSet(seq, ids)) {\n            sort(ids.rbegin(), ids.rend());\n            for (int id : ids) seq.erase(seq.begin() + id);\n            truncateToPerfectPrefix(seq);\n        }\n    }\n}\n\nvoid relocatePruneSequence(vector<Op>& seq, double until) {\n    if (!truncateToPerfectPrefix(seq)) return;\n\n    bool changed = true;\n    while (changed && elapsed() < until) {\n        changed = false;\n        int n = (int)seq.size();\n        if (n < 4) return;\n\n        int jStart = max(0, n - 35);\n        for (int j = n - 1; j >= jStart && !changed && elapsed() < until; j--) {\n            int iStart = max(0, j - 70);\n            for (int i = iStart; i < j && elapsed() < until; i++) {\n                vector<Op> tmp = seq;\n                Op op = tmp[j];\n                tmp.erase(tmp.begin() + j);\n                tmp.insert(tmp.begin() + i, op);\n\n                if (truncateToPerfectPrefix(tmp) && (int)tmp.size() < (int)seq.size() && isPerfectFull(tmp)) {\n                    seq = std::move(tmp);\n                    changed = true;\n                    break;\n                }\n            }\n        }\n    }\n}\n\nstruct OInfo {\n    int firstRow[MAXN], lastRow[MAXN], rowCnt[MAXN];\n    int firstCol[MAXN], lastCol[MAXN], colCnt[MAXN];\n};\n\nvoid computeOInfo(const State& s, OInfo& info) {\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.o[i];\n        info.firstRow[i] = firstBit(m);\n        info.lastRow[i] = lastBit(m);\n        info.rowCnt[i] = popc(m);\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t cm = 0;\n        uint32_t bit = 1u << j;\n        for (int i = 0; i < N; i++) {\n            if (s.o[i] & bit) cm |= 1u << i;\n        }\n        info.firstCol[j] = firstBit(cm);\n        info.lastCol[j] = lastBit(cm);\n        info.colCnt[j] = popc(cm);\n    }\n}\n\nstruct Analysis {\n    int xcnt = 0;\n    int invis = 0;\n    double sumMin = 0;\n};\n\nAnalysis analyzeState(const State& s) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    Analysis a;\n    a.xcnt = s.xcnt;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            int md = 100;\n\n            if (j < info.firstRow[i]) vis++, md = min(md, j + 1);\n            if (j > info.lastRow[i]) vis++, md = min(md, N - j);\n            if (i < info.firstCol[j]) vis++, md = min(md, i + 1);\n            if (i > info.lastCol[j]) vis++, md = min(md, N - i);\n\n            if (vis == 0) {\n                a.invis++;\n                a.sumMin += N;\n            } else {\n                a.sumMin += md;\n            }\n        }\n    }\n    return a;\n}\n\nstruct GenParam {\n    double alpha = 1.0;\n    double critW = 6.0;\n    double twoW = 2.0;\n    double multiW = 1.0;\n    double damageW = 0.0;\n};\n\nstruct Cand {\n    char d;\n    int p, k;\n    int cnt;\n    double benefit;\n    double score;\n};\n\nvector<Cand> genCandidates(const State& s, const GenParam& gp) {\n    OInfo info;\n    computeOInfo(s, info);\n\n    static double w[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) w[i][j] = 0.0;\n\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n\n            int vis = 0;\n            if (j < info.firstRow[i]) vis++;\n            if (j > info.lastRow[i]) vis++;\n            if (i < info.firstCol[j]) vis++;\n            if (i > info.lastCol[j]) vis++;\n\n            if (vis == 1) w[i][j] = gp.critW;\n            else if (vis == 2) w[i][j] = gp.twoW;\n            else if (vis >= 3) w[i][j] = gp.multiW;\n        }\n    }\n\n    vector<Cand> res;\n    res.reserve(160);\n\n    auto addCand = [&](char d, int p, int k, int cnt, double benefit, int movedO) {\n        if (cnt <= 0) return;\n        double b = max(1e-9, benefit);\n        double sc = (double)k / pow(b, gp.alpha) + gp.damageW * movedO * k;\n        res.push_back({d, p, k, cnt, benefit, sc});\n    };\n\n    for (int i = 0; i < N; i++) {\n        int clear = info.firstRow[i];\n        int cnt = 0;\n        double ben = 0;\n        for (int j = 0; j < clear; j++) {\n            if (s.x[i] & (1u << j)) {\n                cnt++;\n                ben += w[i][j];\n                addCand('L', i, j + 1, cnt, ben, info.rowCnt[i]);\n            }\n        }\n\n        clear = N - 1 - info.lastRow[i];\n        cnt = 0;\n        ben = 0;\n        for (int t = 0; t < clear; t++) {\n            int j = N - 1 - t;\n            if (s.x[i] & (1u << j)) {\n                cnt++;\n                ben += w[i][j];\n                addCand('R', i, t + 1, cnt, ben, info.rowCnt[i]);\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n\n        int clear = info.firstCol[j];\n        int cnt = 0;\n        double ben = 0;\n        for (int i = 0; i < clear; i++) {\n            if (s.x[i] & bit) {\n                cnt++;\n                ben += w[i][j];\n                addCand('U', j, i + 1, cnt, ben, info.colCnt[j]);\n            }\n        }\n\n        clear = N - 1 - info.lastCol[j];\n        cnt = 0;\n        ben = 0;\n        for (int t = 0; t < clear; t++) {\n            int i = N - 1 - t;\n            if (s.x[i] & bit) {\n                cnt++;\n                ben += w[i][j];\n                addCand('D', j, t + 1, cnt, ben, info.colCnt[j]);\n            }\n        }\n    }\n\n    return res;\n}\n\nstruct CoverCand {\n    char d;\n    int p, k;\n    uint64_t mask;\n};\n\nvector<CoverCand> buildCoverCandidates() {\n    vector<CoverCand> cands;\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        for (int j = 0; j < N; j++) {\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'L', i, j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int j = N - 1 - t;\n            uint32_t bit = 1u << j;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'R', i, t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint32_t bit = 1u << j;\n\n        uint64_t mask = 0;\n        for (int i = 0; i < N; i++) {\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'U', j, i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        for (int t = 0; t < N; t++) {\n            int i = N - 1 - t;\n            if (INIT.o[i] & bit) break;\n            if (INIT.x[i] & bit) {\n                mask |= 1ULL << idxAt[i][j];\n                cands.push_back({'D', j, t + 1, mask});\n            }\n        }\n    }\n\n    return cands;\n}\n\nuint64_t unionIds(const vector<int>& ids, const vector<CoverCand>& cands) {\n    uint64_t m = 0;\n    for (int id : ids) m |= cands[id].mask;\n    return m;\n}\n\nint objectiveCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    if (ids.empty()) return 0;\n    int sum = 0, mx = 0;\n    for (int id : ids) {\n        sum += 2 * cands[id].k;\n        mx = max(mx, cands[id].k);\n    }\n    return sum - mx;\n}\n\nint sumKCover(const vector<int>& ids, const vector<CoverCand>& cands) {\n    int s = 0;\n    for (int id : ids) s += cands[id].k;\n    return s;\n}\n\nvoid removeRedundant(vector<int>& ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    bool changed = true;\n    while (changed) {\n        changed = false;\n        for (int a = 0; a < (int)ids.size(); a++) {\n            uint64_t u = 0;\n            for (int b = 0; b < (int)ids.size(); b++) {\n                if (a != b) u |= cands[ids[b]].mask;\n            }\n            if (u == ALL) {\n                ids.erase(ids.begin() + a);\n                changed = true;\n                break;\n            }\n        }\n    }\n}\n\ndouble coverScore(const CoverCand& c, int nc, int mode) {\n    int cost = 2 * c.k;\n    if (mode == 0) return cost / (double)nc;\n    if (mode == 1) return cost / pow((double)nc, 1.3);\n    if (mode == 2) return (cost - 0.3 * c.k) / pow((double)nc, 1.1);\n    if (mode == 3) return cost / (double)(nc * nc);\n    return (cost + 0.05 * __builtin_popcountll(c.mask)) / pow((double)nc, 1.5);\n}\n\nvector<int> greedyCoverMulti(vector<int> ids, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    sort(ids.begin(), ids.end());\n    ids.erase(unique(ids.begin(), ids.end()), ids.end());\n\n    uint64_t covered = unionIds(ids, cands);\n\n    while (covered != ALL) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            uint64_t nm = cands[i].mask & ~covered;\n            if (!nm) continue;\n\n            int nc = __builtin_popcountll(nm);\n            double sc = coverScore(cands[i], nc, mode);\n\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) break;\n        ids.push_back(best);\n        covered |= cands[best].mask;\n    }\n\n    removeRedundant(ids, cands, ALL);\n    return ids;\n}\n\nvector<int> greedyCover(int pre, int mode, const vector<CoverCand>& cands, uint64_t ALL) {\n    vector<int> ids;\n    if (pre >= 0) ids.push_back(pre);\n    return greedyCoverMulti(ids, mode, cands, ALL);\n}\n\nvector<int> improveCoverPlan(vector<int> ids, const vector<CoverCand>& cands, uint64_t ALL) {\n    removeRedundant(ids, cands, ALL);\n\n    for (int iter = 0; iter < 6; iter++) {\n        int curObj = objectiveCover(ids, cands);\n        vector<int> bestIds = ids;\n        int bestObj = curObj;\n\n        vector<char> in(cands.size(), 0);\n        for (int id : ids) in[id] = 1;\n\n        for (int c = 0; c < (int)cands.size(); c++) {\n            if (in[c]) continue;\n            vector<int> tmp = ids;\n            tmp.push_back(c);\n            removeRedundant(tmp, cands, ALL);\n            if (unionIds(tmp, cands) != ALL) continue;\n\n            int obj = objectiveCover(tmp, cands);\n            if (obj < bestObj) {\n                bestObj = obj;\n                bestIds = tmp;\n            }\n        }\n\n        for (int r = 0; r < (int)ids.size(); r++) {\n            vector<int> base = ids;\n            base.erase(base.begin() + r);\n\n            for (int mode = 0; mode < 5; mode++) {\n                vector<int> tmp = greedyCoverMulti(base, mode, cands, ALL);\n                if (unionIds(tmp, cands) != ALL) continue;\n\n                int obj = objectiveCover(tmp, cands);\n                if (obj < bestObj) {\n                    bestObj = obj;\n                    bestIds = tmp;\n                }\n            }\n        }\n\n        if (bestObj < curObj) ids = bestIds;\n        else break;\n    }\n\n    return ids;\n}\n\nstruct Plan {\n    vector<int> ids;\n    int obj;\n};\n\nstring keyIds(vector<int> ids) {\n    sort(ids.begin(), ids.end());\n    string s;\n    for (int id : ids) {\n        s += to_string(id);\n        s += ',';\n    }\n    return s;\n}\n\nvector<Plan> generateCoverPlans(const vector<CoverCand>& cands) {\n    int M = (int)initialXs.size();\n    uint64_t ALL = ((1ULL << M) - 1);\n\n    vector<Plan> plans;\n    unordered_set<string> seen;\n\n    auto addPlan = [&](vector<int> ids) {\n        if (ids.empty()) return;\n        removeRedundant(ids, cands, ALL);\n        if (unionIds(ids, cands) != ALL) return;\n        string key = keyIds(ids);\n        if (seen.insert(key).second) {\n            plans.push_back({ids, objectiveCover(ids, cands)});\n        }\n    };\n\n    for (int mode = 0; mode < 5; mode++) {\n        addPlan(greedyCover(-1, mode, cands, ALL));\n        for (int pre = 0; pre < (int)cands.size(); pre++) {\n            addPlan(greedyCover(pre, mode, cands, ALL));\n        }\n    }\n\n    vector<pair<double,int>> rank;\n    for (int i = 0; i < (int)cands.size(); i++) {\n        int pc = max(1, __builtin_popcountll(cands[i].mask));\n        double sc = (2.0 * cands[i].k) / pow((double)pc, 1.25) - 0.05 * cands[i].k;\n        rank.push_back({sc, i});\n    }\n    sort(rank.begin(), rank.end());\n\n    int P = min(22, (int)rank.size());\n    for (int mode = 0; mode < 4; mode++) {\n        for (int a = 0; a < P; a++) {\n            for (int b = a + 1; b < P; b++) {\n                addPlan(greedyCoverMulti({rank[a].second, rank[b].second}, mode, cands, ALL));\n            }\n        }\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    int top = min(25, (int)plans.size());\n    for (int i = 0; i < top; i++) {\n        addPlan(improveCoverPlan(plans[i].ids, cands, ALL));\n    }\n\n    sort(plans.begin(), plans.end(), [](const Plan& a, const Plan& b) {\n        return a.obj < b.obj;\n    });\n\n    if ((int)plans.size() > 80) plans.resize(80);\n    return plans;\n}\n\nvector<int> orderedIds(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = plan.ids;\n\n    if (variant == 1) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant == 2) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            return cands[a].k > cands[b].k;\n        });\n    } else if (variant == 3) {\n        sort(ids.begin(), ids.end(), [&](int a, int b) {\n            if (cands[a].d != cands[b].d) return cands[a].d < cands[b].d;\n            if (cands[a].p != cands[b].p) return cands[a].p < cands[b].p;\n            return cands[a].k < cands[b].k;\n        });\n    } else if (variant >= 4) {\n        for (int i = (int)ids.size() - 1; i >= 1; i--) {\n            int j = rng.nextInt(i + 1);\n            swap(ids[i], ids[j]);\n        }\n    }\n\n    return ids;\n}\n\nvector<Op> buildRoundTripOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n    if (ids.empty()) return ops;\n\n    int maxK = -1;\n    vector<int> finals;\n    for (int id : ids) {\n        if (cands[id].k > maxK) {\n            maxK = cands[id].k;\n            finals.clear();\n            finals.push_back(id);\n        } else if (cands[id].k == maxK) {\n            finals.push_back(id);\n        }\n    }\n\n    int finalId = finals[variant % finals.size()];\n\n    for (int id : ids) {\n        if (id == finalId) continue;\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n        appendOps(ops, invDir(c.d), c.p, c.k);\n    }\n\n    auto& f = cands[finalId];\n    appendOps(ops, f.d, f.p, f.k);\n    return ops;\n}\n\nvector<Op> buildOneWayOps(const Plan& plan, const vector<CoverCand>& cands, int variant, RNG& rng) {\n    vector<int> ids = orderedIds(plan, cands, variant, rng);\n    vector<Op> ops;\n\n    for (int id : ids) {\n        auto& c = cands[id];\n        appendOps(ops, c.d, c.p, c.k);\n    }\n    return ops;\n}\n\nvector<Op> makeHintSequence() {\n    vector<Op> ops;\n\n    for (auto [i, j] : initialXs) {\n        int bestK = 1e9;\n        char bestD = 'L';\n\n        auto upd = [&](char d, int k) {\n            if (k < bestK) {\n                bestK = k;\n                bestD = d;\n            }\n        };\n\n        uint32_t leftMask = (j == 0 ? 0u : ((1u << j) - 1));\n        if ((INIT.o[i] & leftMask) == 0) upd('L', j + 1);\n\n        uint32_t rightMask = FULL & ~((1u << (j + 1)) - 1);\n        if ((INIT.o[i] & rightMask) == 0) upd('R', N - j);\n\n        uint32_t bit = 1u << j;\n\n        bool ok = true;\n        for (int r = 0; r < i; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('U', i + 1);\n\n        ok = true;\n        for (int r = i + 1; r < N; r++) if (INIT.o[r] & bit) ok = false;\n        if (ok) upd('D', N - i);\n\n        if (bestK < 1e9) {\n            int p = (bestD == 'L' || bestD == 'R') ? i : j;\n            appendOps(ops, bestD, p, bestK);\n            appendOps(ops, invDir(bestD), p, bestK);\n        }\n    }\n\n    return ops;\n}\n\nuint64_t splitmix64(uint64_t z) {\n    z += 0x9e3779b97f4a7c15ULL;\n    z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n    z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n    return z ^ (z >> 31);\n}\n\nuint64_t hashState(const State& s) {\n    uint64_t h = 0x123456789abcdef0ULL;\n    for (int i = 0; i < N; i++) {\n        uint64_t v = ((uint64_t)s.x[i] << 32) ^ s.o[i] ^ (uint64_t)i * 0x9e3779b97f4a7c15ULL;\n        h ^= splitmix64(v + h);\n    }\n    return h;\n}\n\ndouble stateHeuristic(const State& s) {\n    Analysis a = analyzeState(s);\n    return 0.32 * a.sumMin + 4.5 * a.invis + 0.15 * a.xcnt;\n}\n\nstruct EstCand {\n    int cost;\n    uint64_t mask;\n};\n\nunordered_map<uint64_t, float> ESTCACHE;\n\ndouble staticGreedyEstimateRaw(const State& s) {\n    if (s.xcnt == 0) return 0;\n\n    int id[MAXN][MAXN];\n    for (int i = 0; i < N; i++) for (int j = 0; j < N; j++) id[i][j] = -1;\n\n    int M = 0;\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n            id[i][j] = M++;\n        }\n    }\n\n    OInfo info;\n    computeOInfo(s, info);\n\n    vector<EstCand> cs;\n    cs.reserve(180);\n\n    for (int i = 0; i < N; i++) {\n        uint64_t mask = 0;\n        int clear = info.firstRow[i];\n        for (int j = 0; j < clear; j++) {\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({j + 1, mask});\n            }\n        }\n\n        mask = 0;\n        clear = N - 1 - info.lastRow[i];\n        for (int t = 0; t < clear; t++) {\n            int j = N - 1 - t;\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({t + 1, mask});\n            }\n        }\n    }\n\n    for (int j = 0; j < N; j++) {\n        uint64_t mask = 0;\n        int clear = info.firstCol[j];\n        for (int i = 0; i < clear; i++) {\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({i + 1, mask});\n            }\n        }\n\n        mask = 0;\n        clear = N - 1 - info.lastCol[j];\n        for (int t = 0; t < clear; t++) {\n            int i = N - 1 - t;\n            if (id[i][j] >= 0) {\n                mask |= 1ULL << id[i][j];\n                cs.push_back({t + 1, mask});\n            }\n        }\n    }\n\n    uint64_t ALL = (1ULL << M) - 1;\n    uint64_t covered = 0;\n    double total = 0;\n\n    for (int iter = 0; iter < M && covered != ALL; iter++) {\n        int best = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cs.size(); i++) {\n            uint64_t nm = cs[i].mask & ~covered;\n            if (!nm) continue;\n            int nc = __builtin_popcountll(nm);\n            double sc = cs[i].cost / pow((double)nc, 1.25);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = i;\n            }\n        }\n\n        if (best < 0) {\n            Analysis a = analyzeState(s);\n            int rem = M - __builtin_popcountll(covered);\n            return total + 230.0 + 15.0 * rem + 6.0 * a.invis + 0.20 * a.sumMin;\n        }\n\n        total += cs[best].cost;\n        covered |= cs[best].mask;\n    }\n\n    return total;\n}\n\ndouble staticGreedyEstimateCached(const State& s) {\n    if (s.xcnt == 0) return 0;\n    uint64_t key = hashState(s) ^ 0x9ddfea08eb382d69ULL;\n    auto it = ESTCACHE.find(key);\n    if (it != ESTCACHE.end()) return it->second;\n\n    double v = staticGreedyEstimateRaw(s);\n    if ((int)ESTCACHE.size() < 200000) ESTCACHE.emplace(key, (float)v);\n    return v;\n}\n\nstruct TrialParam {\n    GenParam gen;\n    double noise = 0.0;\n    int topK = 1;\n    double topBias = 2.0;\n    double lookInvW = 0.0;\n    double lookSumW = 0.0;\n};\n\nTrialParam makeTrialParam(int t, RNG& rng) {\n    TrialParam p;\n\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.lookInvW = 4.0;\n        p.lookSumW = 0.015;\n    } else if (t == 1) {\n        p.gen = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.lookInvW = 3.0;\n        p.lookSumW = 0.010;\n    } else if (t == 2) {\n        p.gen = {1.5, 4.0, 1.8, 1.0, 0.02};\n    } else if (t == 3) {\n        p.gen = {0.85, 10.0, 2.5, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.15;\n        p.lookInvW = 2.0;\n    } else if (t == 4) {\n        p.gen = {1.2, 8.0, 3.0, 1.0, 0.03};\n        p.topK = 2;\n    } else if (t == 5) {\n        p.gen = {0.55, 5.0, 1.5, 1.0, 0.00};\n    } else if (t == 6) {\n        p.gen = {1.75, 5.0, 1.7, 1.0, 0.02};\n        p.lookInvW = 2.5;\n    } else if (t == 7) {\n        p.gen = {0.70, 12.0, 3.2, 1.0, 0.01};\n        p.topK = 3;\n        p.noise = 0.12;\n        p.lookInvW = 1.5;\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.9;\n        p.gen.critW = 3.0 + rng.nextDouble() * 8.0;\n        p.gen.twoW = 1.2 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.04;\n        p.noise = 0.15 + rng.nextDouble() * 0.9;\n        p.topK = 1 + rng.nextInt(8);\n        p.topBias = 1.5 + rng.nextDouble() * 3.0;\n\n        if (t % 7 == 0) {\n            p.lookInvW = 1.5 + rng.nextDouble() * 3.0;\n            p.lookSumW = 0.004 + rng.nextDouble() * 0.012;\n        }\n    }\n\n    return p;\n}\n\nvector<Op> directTrialFrom(const State& start, const TrialParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n\n        vector<Cand> viable;\n        viable.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            double score = c.score;\n\n            if (tp.lookInvW > 0 || tp.lookSumW > 0) {\n                State tmp = st;\n                applyGAct(tmp, {c.d, c.p, c.k});\n                Analysis a = analyzeState(tmp);\n\n                if (a.xcnt > 0 && a.invis == a.xcnt) score += 1e6;\n                score += tp.lookInvW * a.invis;\n                score += tp.lookSumW * a.sumMin;\n            }\n\n            if (tp.noise > 0) {\n                double z = tp.noise * (2.0 * rng.nextDouble() - 1.0);\n                score *= exp(z);\n            }\n\n            c.score = score;\n            viable.push_back(c);\n        }\n\n        if (viable.empty()) return {};\n\n        sort(viable.begin(), viable.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        int m = min(tp.topK, (int)viable.size());\n        int idx = 0;\n        if (m > 1) {\n            idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.topBias) * m));\n        }\n\n        Cand ch = viable[idx];\n\n        GAct ga{ch.d, ch.p, ch.k};\n        applyGAct(st, ga);\n        seq.push_back(ga);\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nvector<Op> directTrial(const TrialParam& tp, int moveLimit, RNG& rng) {\n    return directTrialFrom(INIT, tp, moveLimit, rng);\n}\n\nstruct LookParam {\n    GenParam gen;\n    double estW = 1.0;\n    double baseW = 0.1;\n    double noise = 0.0;\n    int topK = 1;\n    int preLimit = 45;\n    double bias = 2.0;\n};\n\nLookParam makeLookParam(int t, RNG& rng) {\n    LookParam p;\n    if (t == 0) {\n        p.gen = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.estW = 1.0;\n        p.baseW = 0.10;\n        p.preLimit = 45;\n        p.topK = 1;\n    } else if (t == 1) {\n        p.gen = {1.25, 6.5, 2.2, 1.0, 0.01};\n        p.estW = 0.85;\n        p.baseW = 0.25;\n        p.preLimit = 55;\n        p.topK = 2;\n        p.noise = 0.08;\n    } else if (t == 2) {\n        p.gen = {0.85, 10.0, 2.6, 1.0, 0.015};\n        p.estW = 1.15;\n        p.baseW = 0.05;\n        p.preLimit = 65;\n        p.topK = 3;\n        p.noise = 0.12;\n    } else {\n        p.gen.alpha = 0.75 + rng.nextDouble() * 0.8;\n        p.gen.critW = 4.0 + rng.nextDouble() * 7.0;\n        p.gen.twoW = 1.3 + rng.nextDouble() * 2.5;\n        p.gen.multiW = 1.0;\n        p.gen.damageW = rng.nextDouble() * 0.025;\n        p.estW = 0.75 + rng.nextDouble() * 0.65;\n        p.baseW = rng.nextDouble() * 0.35;\n        p.noise = 0.10 + rng.nextDouble() * 0.35;\n        p.topK = 1 + rng.nextInt(5);\n        p.preLimit = 35 + rng.nextInt(45);\n        p.bias = 1.5 + rng.nextDouble() * 3.0;\n    }\n    return p;\n}\n\nvector<Op> directStaticTrialFrom(const State& start, const LookParam& tp, int moveLimit, RNG& rng) {\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    while (st.xcnt > 0 && (int)seq.size() <= 45) {\n        vector<Cand> cands = genCandidates(st, tp.gen);\n        if (cands.empty()) return {};\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        if ((int)cands.size() > tp.preLimit) cands.resize(tp.preLimit);\n\n        vector<pair<double, Cand>> scored;\n        scored.reserve(cands.size());\n\n        for (auto c : cands) {\n            if (moves + c.k > moveLimit) continue;\n\n            State tmp = st;\n            applyGAct(tmp, {c.d, c.p, c.k});\n\n            double score = c.k + tp.estW * staticGreedyEstimateCached(tmp) + tp.baseW * c.score;\n\n            if (tmp.xcnt > 0) {\n                Analysis a = analyzeState(tmp);\n                if (a.invis == a.xcnt) score += 10000;\n                score += 1.0 * a.invis;\n            }\n\n            if (tp.noise > 0) {\n                score *= exp(tp.noise * (2.0 * rng.nextDouble() - 1.0));\n            }\n\n            scored.push_back({score, c});\n        }\n\n        if (scored.empty()) return {};\n\n        sort(scored.begin(), scored.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        int m = min(tp.topK, (int)scored.size());\n        int idx = 0;\n        if (m > 1) idx = min(m - 1, (int)(pow(rng.nextDouble(), tp.bias) * m));\n\n        Cand ch = scored[idx].second;\n        applyGAct(st, {ch.d, ch.p, ch.k});\n        seq.push_back({ch.d, ch.p, ch.k});\n        moves += ch.k;\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nvector<Op> directStaticTrial(const LookParam& tp, int moveLimit, RNG& rng) {\n    return directStaticTrialFrom(INIT, tp, moveLimit, rng);\n}\n\nstruct RollParam {\n    GenParam mainGp;\n    GenParam finishGp;\n    double lookInvW = 2.0;\n    double lookSumW = 0.006;\n    double baseW = 0.03;\n    double noise = 0.0;\n    int top = 10;\n};\n\nRollParam makeRollParam(int t, RNG& rng) {\n    RollParam p;\n    if (t == 0) {\n        p.mainGp = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.finishGp = {1.0, 8.0, 2.2, 1.0, 0.01};\n        p.top = 10;\n        p.lookInvW = 2.5;\n    } else if (t == 1) {\n        p.mainGp = {0.85, 10.0, 2.6, 1.0, 0.015};\n        p.finishGp = {1.3, 6.0, 2.0, 1.0, 0.00};\n        p.top = 12;\n        p.lookInvW = 2.0;\n        p.noise = 0.04;\n    } else if (t == 2) {\n        p.mainGp = {1.4, 5.0, 1.8, 1.0, 0.02};\n        p.finishGp = {0.75, 9.0, 2.8, 1.0, 0.01};\n        p.top = 9;\n        p.lookInvW = 3.0;\n    } else {\n        p.mainGp.alpha = 0.75 + rng.nextDouble() * 0.85;\n        p.mainGp.critW = 4.0 + rng.nextDouble() * 8.0;\n        p.mainGp.twoW = 1.3 + rng.nextDouble() * 2.8;\n        p.mainGp.multiW = 1.0;\n        p.mainGp.damageW = rng.nextDouble() * 0.03;\n\n        p.finishGp.alpha = 0.75 + rng.nextDouble() * 0.85;\n        p.finishGp.critW = 4.0 + rng.nextDouble() * 8.0;\n        p.finishGp.twoW = 1.3 + rng.nextDouble() * 2.8;\n        p.finishGp.multiW = 1.0;\n        p.finishGp.damageW = rng.nextDouble() * 0.03;\n\n        p.top = 7 + rng.nextInt(7);\n        p.lookInvW = 1.0 + rng.nextDouble() * 3.5;\n        p.lookSumW = rng.nextDouble() * 0.012;\n        p.noise = rng.nextDouble() * 0.12;\n    }\n    return p;\n}\n\nint greedyFinishCost(State st, int limit, const RollParam& rp, double until) {\n    const int INF = 1e9;\n    int moves = 0;\n\n    for (int step = 0; step < 50 && elapsed() < until; step++) {\n        if (st.xcnt == 0) return moves;\n\n        vector<Cand> cands = genCandidates(st, rp.finishGp);\n        if (cands.empty()) return INF;\n\n        int bestId = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size(); i++) {\n            auto& c = cands[i];\n            if (moves + c.k > limit) continue;\n\n            State tmp = st;\n            applyGAct(tmp, {c.d, c.p, c.k});\n\n            double score = c.score;\n            if (tmp.xcnt > 0) {\n                Analysis a = analyzeState(tmp);\n                if (a.invis == a.xcnt) score += 1e6;\n                score += rp.lookInvW * a.invis + rp.lookSumW * a.sumMin;\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestId = i;\n            }\n        }\n\n        if (bestId < 0) return INF;\n\n        Cand ch = cands[bestId];\n        applyGAct(st, {ch.d, ch.p, ch.k});\n        moves += ch.k;\n    }\n\n    return st.xcnt == 0 ? moves : INF;\n}\n\nvector<Op> rolloutTrial(const State& start, int moveLimit, double until, RNG& rng, int mode) {\n    RollParam rp = makeRollParam(mode, rng);\n\n    State st = start;\n    vector<GAct> seq;\n    int moves = 0;\n\n    for (int step = 0; step < 48 && st.xcnt > 0 && elapsed() < until; step++) {\n        vector<Cand> cands = genCandidates(st, rp.mainGp);\n        if (cands.empty()) return {};\n\n        sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n        if ((int)cands.size() > rp.top) cands.resize(rp.top);\n\n        int bestId = -1;\n        double bestScore = 1e100;\n\n        for (int i = 0; i < (int)cands.size() && elapsed() < until; i++) {\n            Cand c = cands[i];\n            if (moves + c.k > moveLimit) continue;\n\n            State tmp = st;\n            applyGAct(tmp, {c.d, c.p, c.k});\n\n            int rest = greedyFinishCost(tmp, moveLimit - moves - c.k, rp, until);\n            if (rest >= 1e9) continue;\n\n            double score = c.k + rest + rp.baseW * c.score;\n            if (rp.noise > 0) {\n                score *= exp(rp.noise * (2.0 * rng.nextDouble() - 1.0));\n            }\n\n            if (score < bestScore) {\n                bestScore = score;\n                bestId = i;\n            }\n        }\n\n        if (bestId < 0) return {};\n\n        Cand ch = cands[bestId];\n        applyGAct(st, {ch.d, ch.p, ch.k});\n        seq.push_back({ch.d, ch.p, ch.k});\n        moves += ch.k;\n        if (moves > moveLimit) return {};\n    }\n\n    if (st.xcnt == 0) return expandGSeq(seq);\n    return {};\n}\n\nstruct BeamState {\n    State st;\n    int g;\n    vector<GAct> seq;\n    double eval;\n    uint64_t h;\n};\n\nvector<Op> beamSearchFrom(const State& start, int moveLimit, double until, RNG& rng, bool useSetup) {\n    (void)rng;\n    moveLimit = min(moveLimit, 4 * N * N);\n\n    GenParam gp;\n    gp.alpha = 1.15;\n    gp.critW = 7.5;\n    gp.twoW = 2.4;\n    gp.multiW = 1.0;\n    gp.damageW = 0.015;\n\n    const int WIDTH = 260;\n    const int PER_STATE = 12;\n    const int SETUP_PER_STATE = 3;\n\n    vector<BeamState> beam;\n    beam.push_back({start, 0, {}, stateHeuristic(start), hashState(start)});\n\n    int bestG = INT_MAX;\n    vector<GAct> bestSeq;\n\n    for (int depth = 0; depth < 45 && elapsed() < until; depth++) {\n        vector<BeamState> next;\n        next.reserve(WIDTH * (PER_STATE + SETUP_PER_STATE));\n\n        for (auto& bs : beam) {\n            if (elapsed() >= until) break;\n            if (bs.st.xcnt == 0) {\n                if (bs.g < bestG) {\n                    bestG = bs.g;\n                    bestSeq = bs.seq;\n                }\n                continue;\n            }\n\n            vector<Cand> cands = genCandidates(bs.st, gp);\n            vector<Cand> selected;\n\n            if (!cands.empty()) {\n                sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) {\n                    return a.score < b.score;\n                });\n\n                int take = min(PER_STATE, (int)cands.size());\n                for (int ci = 0; ci < take; ci++) selected.push_back(cands[ci]);\n            }\n\n            if (useSetup && depth < 32) {\n                double baseH = stateHeuristic(bs.st);\n                vector<Cand> setups;\n\n                for (int p = 0; p < N; p++) {\n                    Op ops[4] = {{'L', p}, {'R', p}, {'U', p}, {'D', p}};\n                    for (auto op : ops) {\n                        if (edgeO(bs.st, op)) continue;\n\n                        State ns = bs.st;\n                        int before = ns.xcnt;\n                        applyOp(ns, op);\n\n                        if (ns.xcnt != before) continue;\n\n                        double h2 = stateHeuristic(ns);\n                        double gain = baseH - h2;\n\n                        if (gain > 0.35) {\n                            double sc = 0.85 - 0.08 * gain;\n                            setups.push_back({op.d, op.p, 1, 0, gain, sc});\n                        }\n                    }\n                }\n\n                sort(setups.begin(), setups.end(), [](const Cand& a, const Cand& b) {\n                    return a.score < b.score;\n                });\n\n                int take = min(SETUP_PER_STATE, (int)setups.size());\n                for (int i = 0; i < take; i++) selected.push_back(setups[i]);\n            }\n\n            if (selected.empty()) continue;\n\n            for (const Cand& c : selected) {\n                int ng = bs.g + c.k;\n                if (ng > moveLimit) continue;\n\n                State ns = bs.st;\n                applyGAct(ns, {c.d, c.p, c.k});\n\n                BeamState child;\n                child.st = ns;\n                child.g = ng;\n                child.seq = bs.seq;\n                child.seq.push_back({c.d, c.p, c.k});\n                child.h = hashState(ns);\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestG) {\n                        bestG = ng;\n                        bestSeq = child.seq;\n                    }\n                    continue;\n                }\n\n                child.eval = ng + stateHeuristic(ns);\n                next.push_back(std::move(child));\n            }\n        }\n\n        if (next.empty()) break;\n\n        sort(next.begin(), next.end(), [](const BeamState& a, const BeamState& b) {\n            return a.eval < b.eval;\n        });\n\n        vector<BeamState> nb;\n        nb.reserve(WIDTH);\n\n        unordered_set<uint64_t> seen;\n        seen.reserve(WIDTH * 2);\n\n        for (auto& s : next) {\n            if (seen.insert(s.h).second) {\n                nb.push_back(std::move(s));\n                if ((int)nb.size() >= WIDTH) break;\n            }\n        }\n\n        beam = std::move(nb);\n    }\n\n    if (bestG < INT_MAX) return expandGSeq(bestSeq);\n    return {};\n}\n\nstruct MAct {\n    char d;\n    int p;\n    int k;\n    bool rt;\n    int cost;\n    double score;\n};\n\nvoid applyMAct(State& s, const MAct& m) {\n    if (!m.rt) {\n        applyGAct(s, {m.d, m.p, m.k});\n        return;\n    }\n\n    int k = m.k;\n    if (m.d == 'L') {\n        uint32_t mask = (1u << k) - 1;\n        uint32_t rem = s.x[m.p] & mask;\n        s.xcnt -= popc(rem);\n        s.x[m.p] &= ~mask;\n    } else if (m.d == 'R') {\n        uint32_t mask = FULL & ~((1u << (N - k)) - 1);\n        uint32_t rem = s.x[m.p] & mask;\n        s.xcnt -= popc(rem);\n        s.x[m.p] &= ~mask;\n    } else if (m.d == 'U') {\n        uint32_t bit = 1u << m.p;\n        for (int i = 0; i < k; i++) {\n            if (s.x[i] & bit) {\n                s.x[i] &= ~bit;\n                s.xcnt--;\n            }\n        }\n    } else {\n        uint32_t bit = 1u << m.p;\n        for (int i = N - k; i < N; i++) {\n            if (s.x[i] & bit) {\n                s.x[i] &= ~bit;\n                s.xcnt--;\n            }\n        }\n    }\n}\n\nvector<Op> expandMActs(const vector<MAct>& ms) {\n    vector<Op> ops;\n    int total = 0;\n    for (auto& m : ms) total += m.cost;\n    ops.reserve(total);\n\n    for (auto& m : ms) {\n        appendOps(ops, m.d, m.p, m.k);\n        if (m.rt) appendOps(ops, invDir(m.d), m.p, m.k);\n    }\n\n    return ops;\n}\n\nint dirId(char d) {\n    if (d == 'L') return 0;\n    if (d == 'R') return 1;\n    if (d == 'U') return 2;\n    return 3;\n}\n\nvector<MAct> genTailMacros(const State& s) {\n    GenParam gp{1.1, 8.0, 2.4, 1.0, 0.012};\n    vector<Cand> cs = genCandidates(s, gp);\n\n    vector<MAct> ms;\n    unordered_set<int> seen;\n    seen.reserve(cs.size() * 2 + 10);\n\n    for (auto& c : cs) {\n        int baseCode = ((dirId(c.d) * N + c.p) * (N + 1) + c.k) * 2;\n\n        if (seen.insert(baseCode).second) {\n            ms.push_back({c.d, c.p, c.k, false, c.k, c.score});\n        }\n\n        if (c.cnt < s.xcnt) {\n            int code = baseCode | 1;\n            if (seen.insert(code).second) {\n                ms.push_back({c.d, c.p, c.k, true, 2 * c.k, c.score * 1.8 + 0.08 * c.k});\n            }\n        }\n    }\n\n    sort(ms.begin(), ms.end(), [](const MAct& a, const MAct& b) {\n        return a.score < b.score;\n    });\n\n    if ((int)ms.size() > 95) ms.resize(95);\n    return ms;\n}\n\nint boardLowerBound(const State& s) {\n    int lb = 0;\n    for (int i = 0; i < N; i++) {\n        uint32_t m = s.x[i];\n        while (m) {\n            int j = __builtin_ctz(m);\n            m &= m - 1;\n            int d = min(min(i + 1, N - i), min(j + 1, N - j));\n            lb = max(lb, d);\n        }\n    }\n    return lb;\n}\n\nstruct TailNode {\n    State st;\n    int g;\n    int parent;\n    MAct act;\n    uint64_t key;\n};\n\nstruct TailItem {\n    double f;\n    int idx;\n    bool operator<(const TailItem& other) const {\n        return f > other.f;\n    }\n};\n\nvector<Op> tailMacroSearch(const State& start, int limit, double until) {\n    if (start.xcnt == 0 || limit <= 0) return {};\n\n    vector<TailNode> nodes;\n    nodes.reserve(30000);\n\n    priority_queue<TailItem> pq;\n    unordered_map<uint64_t, int> dist;\n    dist.reserve(50000);\n\n    uint64_t skey = hashState(start);\n    nodes.push_back({start, 0, -1, MAct(), skey});\n    dist[skey] = 0;\n    pq.push({0.35 * stateHeuristic(start), 0});\n\n    int bestCost = limit + 1;\n    int bestIdx = -1;\n\n    while (!pq.empty() && elapsed() < until && (int)nodes.size() < 36000) {\n        auto it = pq.top();\n        pq.pop();\n\n        int idx = it.idx;\n        TailNode& nd = nodes[idx];\n\n        auto dit = dist.find(nd.key);\n        if (dit == dist.end() || dit->second != nd.g) continue;\n        if (nd.g >= bestCost) continue;\n        if (nd.g + boardLowerBound(nd.st) >= bestCost) continue;\n\n        if (nd.st.xcnt == 0) {\n            if (nd.g < bestCost) {\n                bestCost = nd.g;\n                bestIdx = idx;\n            }\n            continue;\n        }\n\n        vector<MAct> acts = genTailMacros(nd.st);\n        if (acts.empty()) continue;\n\n        for (auto& a : acts) {\n            int ng = nd.g + a.cost;\n            if (ng >= bestCost || ng > limit) continue;\n\n            State ns = nd.st;\n            applyMAct(ns, a);\n\n            int lb = boardLowerBound(ns);\n            if (ng + lb >= bestCost) continue;\n\n            uint64_t key = hashState(ns);\n            auto dit2 = dist.find(key);\n            if (dit2 != dist.end() && dit2->second <= ng) continue;\n\n            int ni = (int)nodes.size();\n            nodes.push_back({ns, ng, idx, a, key});\n            dist[key] = ng;\n\n            if (ns.xcnt == 0) {\n                if (ng < bestCost) {\n                    bestCost = ng;\n                    bestIdx = ni;\n                }\n            } else {\n                double f = ng + 0.35 * stateHeuristic(ns);\n                pq.push({f, ni});\n            }\n        }\n    }\n\n    if (bestIdx < 0) return {};\n\n    vector<MAct> ms;\n    for (int v = bestIdx; nodes[v].parent != -1; v = nodes[v].parent) {\n        ms.push_back(nodes[v].act);\n    }\n    reverse(ms.begin(), ms.end());\n\n    return expandMActs(ms);\n}\n\nstruct SNode {\n    State st;\n    int g;\n    int parent;\n    Op act;\n    uint64_t key;\n};\n\nstruct SItem {\n    double f;\n    int idx;\n    bool operator<(const SItem& other) const {\n        return f > other.f;\n    }\n};\n\nvector<Op> singleTailSearch(const State& start, int limit, double until) {\n    if (start.xcnt == 0 || limit <= 0) return {};\n\n    vector<SNode> nodes;\n    nodes.reserve(50000);\n\n    priority_queue<SItem> pq;\n    unordered_map<uint64_t, int> dist;\n    dist.reserve(80000);\n\n    uint64_t skey = hashState(start);\n    nodes.push_back({start, 0, -1, Op(), skey});\n    dist[skey] = 0;\n    pq.push({0.40 * stateHeuristic(start), 0});\n\n    int bestCost = limit + 1;\n    int bestIdx = -1;\n\n    while (!pq.empty() && elapsed() < until && (int)nodes.size() < 55000) {\n        auto item = pq.top();\n        pq.pop();\n\n        int idx = item.idx;\n        SNode& nd = nodes[idx];\n\n        auto dit = dist.find(nd.key);\n        if (dit == dist.end() || dit->second != nd.g) continue;\n        if (nd.g >= bestCost) continue;\n        if (nd.g + boardLowerBound(nd.st) >= bestCost) continue;\n\n        if (nd.st.xcnt == 0) {\n            if (nd.g < bestCost) {\n                bestCost = nd.g;\n                bestIdx = idx;\n            }\n            continue;\n        }\n\n        for (int p = 0; p < N; p++) {\n            Op ops[4] = {{'L', p}, {'R', p}, {'U', p}, {'D', p}};\n            for (auto op : ops) {\n                if (edgeO(nd.st, op)) continue;\n\n                int ng = nd.g + 1;\n                if (ng >= bestCost || ng > limit) continue;\n\n                State ns = nd.st;\n                applyOp(ns, op);\n\n                int lb = boardLowerBound(ns);\n                if (ng + lb >= bestCost) continue;\n\n                uint64_t key = hashState(ns);\n                auto dit2 = dist.find(key);\n                if (dit2 != dist.end() && dit2->second <= ng) continue;\n\n                int ni = (int)nodes.size();\n                nodes.push_back({ns, ng, idx, op, key});\n                dist[key] = ng;\n\n                if (ns.xcnt == 0) {\n                    if (ng < bestCost) {\n                        bestCost = ng;\n                        bestIdx = ni;\n                    }\n                } else {\n                    double f = ng + 0.40 * stateHeuristic(ns);\n                    pq.push({f, ni});\n                }\n            }\n        }\n    }\n\n    if (bestIdx < 0) return {};\n\n    vector<Op> ops;\n    for (int v = bestIdx; nodes[v].parent != -1; v = nodes[v].parent) {\n        ops.push_back(nodes[v].act);\n    }\n    reverse(ops.begin(), ops.end());\n    return ops;\n}\n\nvector<State> buildPrefixStates(const vector<Op>& ops) {\n    vector<State> states;\n    states.reserve(ops.size() + 1);\n\n    State s = INIT;\n    states.push_back(s);\n\n    for (auto& op : ops) {\n        if (edgeO(s, op)) break;\n        applyOp(s, op);\n        states.push_back(s);\n        if (s.xcnt == 0) break;\n    }\n\n    return states;\n}\n\nvoid suffixDirectImprove(vector<Op>& best, double until, RNG& rng) {\n    bool improved = true;\n    int globalAttempt = 0;\n\n    while (improved && elapsed() < until) {\n        improved = false;\n\n        vector<State> states = buildPrefixStates(best);\n        if ((int)states.size() <= 1) return;\n\n        vector<int> cuts;\n\n        auto addCut = [&](int t) {\n            if (t <= 0 || t >= (int)states.size()) return;\n            int rem = states[t].xcnt;\n            if (rem <= 0 || rem > 28) return;\n            if ((int)best.size() - t <= 2) return;\n            cuts.push_back(t);\n        };\n\n        int prev = states[0].xcnt;\n        for (int t = 1; t < (int)states.size(); t++) {\n            if (states[t].xcnt < prev) {\n                addCut(t);\n                prev = states[t].xcnt;\n            }\n        }\n\n        int st = max(1, (int)states.size() - 75);\n        for (int t = st; t + 1 < (int)states.size(); t += 4) {\n            addCut(t);\n        }\n\n        sort(cuts.begin(), cuts.end());\n        cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n        sort(cuts.begin(), cuts.end(), [&](int a, int b) {\n            int ra = states[a].xcnt, rb = states[b].xcnt;\n            if (ra != rb) return ra < rb;\n            return a > b;\n        });\n\n        if ((int)cuts.size() > 28) cuts.resize(28);\n\n        for (int cut : cuts) {\n            if (elapsed() >= until) break;\n\n            int limit = (int)best.size() - cut - 1;\n            if (limit <= 0) continue;\n\n            for (int z = 0; z < 5 && elapsed() < until; z++) {\n                vector<Op> comp;\n\n                if (z < 3) {\n                    TrialParam tp = makeTrialParam(z, rng);\n                    comp = directTrialFrom(states[cut], tp, limit, rng);\n                } else if (z == 3) {\n                    LookParam lp = makeLookParam(100 + globalAttempt, rng);\n                    lp.preLimit = min(lp.preLimit, 45);\n                    comp = directStaticTrialFrom(states[cut], lp, limit, rng);\n                } else {\n                    comp = rolloutTrial(states[cut], limit, min(until, elapsed() + 0.020), rng, 100 + globalAttempt);\n                }\n\n                globalAttempt++;\n\n                if (!comp.empty()) {\n                    vector<Op> ops;\n                    ops.reserve(cut + comp.size());\n                    ops.insert(ops.end(), best.begin(), best.begin() + cut);\n                    ops.insert(ops.end(), comp.begin(), comp.end());\n\n                    if (truncateToPerfectPrefix(ops) && isPerfectFull(ops) && ops.size() < best.size()) {\n                        best = std::move(ops);\n                        pruneSequence(best, min(until, elapsed() + 0.012));\n                        improved = true;\n                        break;\n                    }\n                }\n            }\n\n            if (improved) break;\n        }\n    }\n}\n\nvoid tailImprove(vector<Op>& best, double until, RNG& rng) {\n    (void)rng;\n    bool improved = true;\n\n    while (improved && elapsed() < until) {\n        improved = false;\n\n        vector<State> states = buildPrefixStates(best);\n        if ((int)states.size() <= 1) return;\n\n        vector<int> cuts;\n        auto addCut = [&](int t) {\n            if (t <= 0 || t >= (int)states.size()) return;\n            if (states[t].xcnt <= 0 || states[t].xcnt > 14) return;\n            if ((int)best.size() - t <= 1) return;\n            cuts.push_back(t);\n        };\n\n        int prev = states[0].xcnt;\n        for (int t = 1; t < (int)states.size(); t++) {\n            if (states[t].xcnt < prev) {\n                addCut(t);\n                prev = states[t].xcnt;\n            }\n        }\n\n        int st = max(1, (int)states.size() - 45);\n        for (int t = st; t + 1 < (int)states.size(); t += 3) {\n            if (states[t].xcnt <= 10) addCut(t);\n        }\n\n        sort(cuts.begin(), cuts.end());\n        cuts.erase(unique(cuts.begin(), cuts.end()), cuts.end());\n\n        sort(cuts.begin(), cuts.end(), [&](int a, int b) {\n            if (states[a].xcnt != states[b].xcnt) return states[a].xcnt < states[b].xcnt;\n            return a > b;\n        });\n\n        if ((int)cuts.size() > 26) cuts.resize(26);\n\n        for (int cut : cuts) {\n            if (elapsed() >= until) break;\n\n            int rem = states[cut].xcnt;\n            int limit = (int)best.size() - cut - 1;\n            if (limit <= 0) continue;\n\n            vector<Op> comp;\n\n            if (rem <= 6 && elapsed() < until) {\n                comp = singleTailSearch(states[cut], limit, min(until, elapsed() + 0.026));\n            }\n\n            if (comp.empty() && elapsed() < until) {\n                comp = tailMacroSearch(states[cut], limit, min(until, elapsed() + 0.026));\n            }\n\n            if (!comp.empty()) {\n                vector<Op> ops;\n                ops.reserve(cut + comp.size());\n                ops.insert(ops.end(), best.begin(), best.begin() + cut);\n                ops.insert(ops.end(), comp.begin(), comp.end());\n\n                if (truncateToPerfectPrefix(ops) && isPerfectFull(ops) && ops.size() < best.size()) {\n                    best = std::move(ops);\n                    pruneSequence(best, min(until, elapsed() + 0.015));\n                    improved = true;\n                    break;\n                }\n            }\n        }\n    }\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    START = chrono::steady_clock::now();\n\n    cin >> N;\n    FULL = (1u << N) - 1;\n\n    INIT.x.fill(0);\n    INIT.o.fill(0);\n    INIT.xcnt = 0;\n    memset(idxAt, -1, sizeof(idxAt));\n\n    vector<string> C(N);\n    for (int i = 0; i < N; i++) cin >> C[i];\n\n    for (int i = 0; i < N; i++) {\n        for (int j = 0; j < N; j++) {\n            if (C[i][j] == 'x') {\n                idxAt[i][j] = (int)initialXs.size();\n                initialXs.push_back({i, j});\n                INIT.x[i] |= 1u << j;\n                INIT.xcnt++;\n            } else if (C[i][j] == 'o') {\n                INIT.o[i] |= 1u << j;\n            }\n        }\n    }\n\n    uint64_t seed = hashState(INIT) ^ 0xa5a5a5a5deadbeefULL;\n    RNG rng(seed);\n    RNG rng2(seed ^ 0x9e3779b97f4a7c15ULL);\n\n    const double HARD = 1.90;\n\n    vector<Op> best = makeHintSequence();\n    truncateToPerfectPrefix(best);\n\n    vector<CoverCand> coverCands = buildCoverCandidates();\n    vector<Plan> plans = generateCoverPlans(coverCands);\n\n    auto consider = [&](vector<Op> ops, double pruneUntil) {\n        if (ops.empty()) return;\n        if (!truncateToPerfectPrefix(ops)) return;\n        if (pruneUntil > elapsed()) pruneSequence(ops, pruneUntil);\n        if (isPerfectFull(ops) && ops.size() < best.size()) {\n            best = std::move(ops);\n        }\n    };\n\n    if (!plans.empty()) {\n        vector<Op> ops = buildRoundTripOps(plans[0], coverCands, 0, rng);\n        consider(ops, 0.20);\n    }\n\n    pruneSequence(best, min(0.22, HARD));\n\n    for (int pi = 0; pi < (int)plans.size() && pi < 10 && elapsed() < 0.45; pi++) {\n        for (int v = 0; v < 6 && elapsed() < 0.45; v++) {\n            vector<Op> ops1 = buildOneWayOps(plans[pi], coverCands, v, rng);\n            consider(ops1, min(0.45, elapsed() + 0.020));\n\n            vector<Op> ops2 = buildRoundTripOps(plans[pi], coverCands, v, rng);\n            consider(ops2, min(0.45, elapsed() + 0.025));\n        }\n    }\n\n    if (!plans.empty() && elapsed() < 0.50) {\n        vector<int> ord(plans.size());\n        iota(ord.begin(), ord.end(), 0);\n        sort(ord.begin(), ord.end(), [&](int a, int b) {\n            return sumKCover(plans[a].ids, coverCands) < sumKCover(plans[b].ids, coverCands);\n        });\n\n        int lim = min(10, (int)ord.size());\n        for (int ii = 0; ii < lim && elapsed() < 0.50; ii++) {\n            int pi = ord[ii];\n            for (int v = 0; v < 5 && elapsed() < 0.50; v++) {\n                vector<Op> ops = buildOneWayOps(plans[pi], coverCands, v + 2, rng);\n                consider(ops, min(0.50, elapsed() + 0.014));\n            }\n        }\n    }\n\n    pruneSequence(best, min(0.52, HARD));\n\n    if (elapsed() < 0.98) {\n        vector<Op> bops = beamSearchFrom(INIT, (int)best.size() + 70, 0.98, rng, false);\n        consider(bops, min(1.03, elapsed() + 0.055));\n    }\n\n    if (elapsed() < 1.10) {\n        vector<Op> bops = beamSearchFrom(INIT, (int)best.size() + 65, 1.10, rng, true);\n        consider(bops, min(1.13, elapsed() + 0.035));\n    }\n\n    if (elapsed() < 1.22) {\n        for (int t = 0; t < 5 && elapsed() < 1.22; t++) {\n            int limit = min(4 * N * N, (int)best.size() + 60);\n            vector<Op> ops = rolloutTrial(INIT, limit, min(1.22, elapsed() + 0.035), rng2, t);\n            if (!ops.empty()) {\n                double until = elapsed();\n                if ((int)ops.size() < (int)best.size() + 45) {\n                    until = min(1.23, elapsed() + 0.012);\n                }\n                consider(ops, until);\n            }\n        }\n    }\n\n    if (elapsed() < 1.27) {\n        for (int t = 0; t < 4 && elapsed() < 1.27; t++) {\n            LookParam lp = makeLookParam(t, rng2);\n            int limit = min(4 * N * N, (int)best.size() + 60);\n            vector<Op> ops = directStaticTrial(lp, limit, rng2);\n\n            if (!ops.empty()) {\n                double until = elapsed();\n                if ((int)ops.size() < (int)best.size() + 45) {\n                    until = min(1.28, elapsed() + 0.012);\n                }\n                consider(ops, until);\n            }\n        }\n    }\n\n    int trial = 0;\n    int pruneCnt = 0;\n    while (elapsed() < 1.70) {\n        vector<Op> ops;\n\n        if (trial % 13 == 9 && elapsed() < 1.63) {\n            LookParam lp = makeLookParam(100 + trial, rng2);\n            int limit = min(4 * N * N, (int)best.size() + 60);\n            ops = directStaticTrial(lp, limit, rng2);\n        } else {\n            TrialParam tp = makeTrialParam(trial, rng);\n            int limit = min(4 * N * N, (int)best.size() + 70);\n            ops = directTrial(tp, limit, rng);\n        }\n\n        if (!ops.empty()) {\n            double until = elapsed();\n            if ((int)ops.size() < (int)best.size() + 50 && pruneCnt < 26) {\n                until = min(1.715, elapsed() + 0.017);\n                pruneCnt++;\n            }\n            consider(ops, until);\n        }\n\n        trial++;\n    }\n\n    if (elapsed() < 1.73) {\n        pruneSequence(best, min(1.73, HARD));\n    }\n\n    if (elapsed() < 1.805) {\n        suffixDirectImprove(best, 1.805, rng2);\n    }\n\n    if (elapsed() < 1.86) {\n        tailImprove(best, 1.86, rng2);\n    }\n\n    if (elapsed() < 1.885) {\n        pairPruneSequence(best, 1.885);\n    }\n\n    if (elapsed() < 1.895) {\n        randomSubsetPrune(best, 1.895, rng2);\n    }\n\n    if (elapsed() < 1.898) {\n        relocatePruneSequence(best, 1.898);\n    }\n\n    if (elapsed() < HARD) {\n        pruneSequence(best, HARD);\n    }\n\n    if (!isPerfectFull(best)) {\n        best = makeHintSequence();\n        truncateToPerfectPrefix(best);\n    }\n\n    for (auto& op : best) {\n        cout << op.d << ' ' << op.p << '\\n';\n    }\n\n    return 0;\n}","ahc044":"#include <bits/stdc++.h>\nusing namespace std;\n\nconstexpr int MAXN = 100;\nconstexpr int MAXE = 200;\n\nint N, L;\narray<int, MAXN> T, Cdes, demandIn;\nvector<int> activeChoices, validZs;\n\nstruct RNG {\n    uint64_t x;\n    RNG(uint64_t seed = 1) : x(seed) {}\n    uint64_t next() {\n        uint64_t z = (x += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n    int randint(int n) { return (int)(next() % (uint64_t)n); }\n} rng;\n\ntemplate<class Tvec>\nvoid shuffle_vec(vector<Tvec>& v) {\n    for (int i = (int)v.size() - 1; i > 0; --i) {\n        int j = rng.randint(i + 1);\n        swap(v[i], v[j]);\n    }\n}\n\nchrono::steady_clock::time_point st_time;\n\ndouble elapsed_sec() {\n    return chrono::duration<double>(chrono::steady_clock::now() - st_time).count();\n}\n\nstruct Cand {\n    array<int, MAXN> a, b;\n    array<unsigned char, MAXE> prot;\n};\n\nstruct SimResult {\n    long long err;\n    array<int, MAXN> cnt;\n    int last;\n};\n\nstruct Entry {\n    long long err;\n    Cand cand;\n    SimResult res;\n};\n\nCand bestCand;\nSimResult bestRes;\nlong long bestErr = (1LL << 60);\nvector<Entry> pool;\n\ninline long long absl(long long x) { return x >= 0 ? x : -x; }\n\nlong long cellCost(long long diff, int mode) {\n    long long a = absl(diff);\n    if (mode == 0) return diff * diff;\n    if (mode == 1) return a;\n    return diff * diff + 1000LL * a;\n}\n\nvoid getDest(const Cand& c, array<int, MAXE>& dest) {\n    for (int i = 0; i < N; ++i) {\n        dest[2 * i] = c.a[i];\n        dest[2 * i + 1] = c.b[i];\n    }\n}\n\nvoid setEdge(Cand& c, int e, int to) {\n    int v = e / 2;\n    if (e & 1) c.b[v] = to;\n    else c.a[v] = to;\n}\n\nvoid flipVertex(Cand& c, int v) {\n    swap(c.a[v], c.b[v]);\n    swap(c.prot[2 * v], c.prot[2 * v + 1]);\n}\n\nSimResult simulate(const Cand& c) {\n    SimResult r;\n    r.cnt.fill(0);\n\n    int x = 0;\n    r.cnt[0] = 1;\n\n    for (int step = 1; step < L; ++step) {\n        int nx = (r.cnt[x] & 1) ? c.a[x] : c.b[x];\n        x = nx;\n        ++r.cnt[x];\n    }\n\n    r.last = x;\n    long long e = 0;\n    for (int i = 0; i < N; ++i) e += llabs((long long)r.cnt[i] - T[i]);\n    r.err = e;\n    return r;\n}\n\nbool addEvaluated(const Cand& c, const SimResult& r) {\n    bool improved = false;\n\n    if (r.err < bestErr) {\n        bestErr = r.err;\n        bestCand = c;\n        bestRes = r;\n        improved = true;\n    }\n\n    if ((int)pool.size() < 16 || r.err < pool.back().err) {\n        pool.push_back({r.err, c, r});\n        sort(pool.begin(), pool.end(), [](const Entry& x, const Entry& y) {\n            return x.err < y.err;\n        });\n        while ((int)pool.size() > 16) pool.pop_back();\n    }\n\n    return improved;\n}\n\nbool consider(const Cand& c) {\n    SimResult r = simulate(c);\n    return addEvaluated(c, r);\n}\n\nbool considerOnlyIfBest(const Cand& c) {\n    SimResult r = simulate(c);\n    if (r.err < bestErr) {\n        addEvaluated(c, r);\n        return true;\n    }\n    return false;\n}\n\nlong long moveDeltaCost(\n    const array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int e,\n    int y\n) {\n    int old = dest[e];\n    int ww = w[e];\n\n    if (old == y) return 0;\n\n    return\n        cellCost(loads[old] - ww - dem[old], objMode) +\n        cellCost(loads[y] + ww - dem[y], objMode) -\n        cellCost(loads[old] - dem[old], objMode) -\n        cellCost(loads[y] - dem[y], objMode);\n}\n\nvoid applyMove(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    int e,\n    int y\n) {\n    int old = dest[e];\n    if (old == y) return;\n\n    int ww = w[e];\n    loads[old] -= ww;\n    loads[y] += ww;\n    dest[e] = y;\n}\n\nvoid optimizeItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty() || items.empty()) return;\n\n    vector<int> order = items;\n\n    for (int pass = 0; pass < maxPass; ++pass) {\n        bool improved = false;\n\n        if (randomize) shuffle_vec(order);\n\n        for (int e : order) {\n            int ww = w[e];\n            if (ww == 0) continue;\n\n            int old = dest[e];\n            long long oldCostOld = cellCost(loads[old] - dem[old], objMode);\n            long long bestDelta = 0;\n            int bestY = old;\n\n            for (int y : choices) {\n                if (y == old) continue;\n\n                long long delta =\n                    cellCost(loads[old] - ww - dem[old], objMode) +\n                    cellCost(loads[y] + ww - dem[y], objMode) -\n                    oldCostOld -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < bestDelta) {\n                    bestDelta = delta;\n                    bestY = y;\n                }\n            }\n\n            if (bestY != old) {\n                loads[old] -= ww;\n                loads[bestY] += ww;\n                dest[e] = bestY;\n                improved = true;\n            }\n        }\n\n        int M = (int)order.size();\n\n        for (int ii = 0; ii < M; ++ii) {\n            int e = order[ii];\n            int we = w[e];\n            if (we == 0) continue;\n\n            for (int jj = ii + 1; jj < M; ++jj) {\n                int f = order[jj];\n                int wf = w[f];\n\n                if (wf == 0 || we == wf) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n\n                if (x == y) continue;\n\n                long long nx = loads[x] - we + wf;\n                long long ny = loads[y] - wf + we;\n\n                long long delta =\n                    cellCost(nx - dem[x], objMode) +\n                    cellCost(ny - dem[y], objMode) -\n                    cellCost(loads[x] - dem[x], objMode) -\n                    cellCost(loads[y] - dem[y], objMode);\n\n                if (delta < 0) {\n                    loads[x] = nx;\n                    loads[y] = ny;\n                    swap(dest[e], dest[f]);\n                    improved = true;\n                }\n            }\n        }\n\n        if (randomize && M >= 3) {\n            int attempts = 1600;\n\n            for (int at = 0; at < attempts; ++at) {\n                int i = rng.randint(M);\n                int j = rng.randint(M);\n                int k = rng.randint(M);\n\n                if (i == j || j == k || k == i) continue;\n\n                int e = order[i];\n                int f = order[j];\n                int g = order[k];\n\n                int we = w[e];\n                int wf = w[f];\n                int wg = w[g];\n\n                if (we == 0 || wf == 0 || wg == 0) continue;\n\n                int x = dest[e];\n                int y = dest[f];\n                int z = dest[g];\n\n                if (x == y || y == z || z == x) continue;\n\n                {\n                    long long nx = loads[x] - we + wg;\n                    long long ny = loads[y] - wf + we;\n                    long long nz = loads[z] - wg + wf;\n\n                    long long delta =\n                        cellCost(nx - dem[x], objMode) +\n                        cellCost(ny - dem[y], objMode) +\n                        cellCost(nz - dem[z], objMode) -\n                        cellCost(loads[x] - dem[x], objMode) -\n                        cellCost(loads[y] - dem[y], objMode) -\n                        cellCost(loads[z] - dem[z], objMode);\n\n                    if (delta < 0) {\n                        loads[x] = nx;\n                        loads[y] = ny;\n                        loads[z] = nz;\n\n                        dest[e] = y;\n                        dest[f] = z;\n                        dest[g] = x;\n\n                        improved = true;\n                        continue;\n                    }\n                }\n\n                {\n                    long long nx = loads[x] - we + wf;\n                    long long ny = loads[y] - wf + wg;\n                    long long nz = loads[z] - wg + we;\n\n                    long long delta =\n                        cellCost(nx - dem[x], objMode) +\n                        cellCost(ny - dem[y], objMode) +\n                        cellCost(nz - dem[z], objMode) -\n                        cellCost(loads[x] - dem[x], objMode) -\n                        cellCost(loads[y] - dem[y], objMode) -\n                        cellCost(loads[z] - dem[z], objMode);\n\n                    if (delta < 0) {\n                        loads[x] = nx;\n                        loads[y] = ny;\n                        loads[z] = nz;\n\n                        dest[e] = z;\n                        dest[f] = x;\n                        dest[g] = y;\n\n                        improved = true;\n                    }\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n}\n\nvoid assignItems(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    if (choices.empty()) return;\n\n    vector<int> order = items;\n\n    if (randomize) shuffle_vec(order);\n\n    stable_sort(order.begin(), order.end(), [&](int e1, int e2) {\n        return w[e1] > w[e2];\n    });\n\n    int root = choices[0];\n\n    for (int e : order) {\n        int ww = w[e];\n\n        if (ww == 0) {\n            dest[e] = root;\n            continue;\n        }\n\n        vector<pair<long long, int>> cand;\n        cand.reserve(choices.size());\n\n        for (int y : choices) {\n            long long delta =\n                cellCost(loads[y] + ww - dem[y], objMode) -\n                cellCost(loads[y] - dem[y], objMode);\n            cand.push_back({delta, y});\n        }\n\n        int take = min((int)cand.size(), max(1, topR));\n\n        nth_element(cand.begin(), cand.begin() + take - 1, cand.end());\n        sort(cand.begin(), cand.begin() + take);\n\n        int idx = 0;\n        if (randomize && take > 1) {\n            int r = rng.randint(100);\n            if (r >= 70) idx = 1 + rng.randint(take - 1);\n        }\n\n        int y = cand[idx].second;\n        dest[e] = y;\n        loads[y] += ww;\n    }\n\n    optimizeItems(dest, w, items, choices, loads, dem, objMode, maxPass, randomize);\n}\n\nbool optimizePairwiseBins(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const vector<int>& items,\n    const vector<int>& choices,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    int maxRounds\n) {\n    if (choices.size() < 2 || items.empty()) return false;\n\n    bool any = false;\n    vector<int> bins = choices;\n    const int LIMIT = 12;\n\n    for (int round = 0; round < maxRounds; ++round) {\n        vector<vector<int>> bucket(N);\n\n        for (int e : items) {\n            if (w[e] <= 0) continue;\n            int d = dest[e];\n            if (0 <= d && d < N) bucket[d].push_back(e);\n        }\n\n        sort(bins.begin(), bins.end(), [&](int x, int y) {\n            long long rx = llabs(loads[x] - dem[x]);\n            long long ry = llabs(loads[y] - dem[y]);\n            if (rx != ry) return rx > ry;\n            return x < y;\n        });\n\n        bool improved = false;\n\n        for (int ii = 0; ii < (int)bins.size() && !improved; ++ii) {\n            int x = bins[ii];\n\n            for (int jj = ii + 1; jj < (int)bins.size() && !improved; ++jj) {\n                int y = bins[jj];\n\n                vector<int> sel;\n                sel.reserve(bucket[x].size() + bucket[y].size());\n\n                for (int e : bucket[x]) sel.push_back(e);\n                for (int e : bucket[y]) sel.push_back(e);\n\n                if ((int)sel.size() < 2) continue;\n\n                if ((int)sel.size() > LIMIT) {\n                    vector<int> ns;\n                    array<unsigned char, MAXE> seen{};\n                    seen.fill(0);\n\n                    auto add = [&](int e) {\n                        if ((int)ns.size() >= LIMIT) return;\n                        if (!seen[e]) {\n                            seen[e] = 1;\n                            ns.push_back(e);\n                        }\n                    };\n\n                    vector<int> all = sel;\n\n                    sort(all.begin(), all.end(), [&](int e1, int e2) {\n                        if (w[e1] != w[e2]) return w[e1] > w[e2];\n                        return e1 < e2;\n                    });\n                    for (int i = 0; i < (int)all.size() && i < 4; ++i) add(all[i]);\n\n                    sort(all.begin(), all.end(), [&](int e1, int e2) {\n                        if (w[e1] != w[e2]) return w[e1] < w[e2];\n                        return e1 < e2;\n                    });\n                    for (int i = 0; i < (int)all.size() && i < 2; ++i) add(all[i]);\n\n                    long long rx = loads[x] - dem[x];\n                    long long ry = loads[y] - dem[y];\n\n                    int high = (rx >= ry ? x : y);\n                    long long target = max(1LL, llabs(rx - ry) / 2);\n\n                    vector<int> dir;\n                    for (int e : sel) {\n                        if (dest[e] == high) dir.push_back(e);\n                    }\n\n                    sort(dir.begin(), dir.end(), [&](int e1, int e2) {\n                        long long s1 = llabs((long long)w[e1] - target);\n                        long long s2 = llabs((long long)w[e2] - target);\n                        if (s1 != s2) return s1 < s2;\n                        return w[e1] > w[e2];\n                    });\n                    for (int i = 0; i < (int)dir.size() && i < 4; ++i) add(dir[i]);\n\n                    long long target2 = max(1LL, target / 2);\n                    all = sel;\n                    sort(all.begin(), all.end(), [&](int e1, int e2) {\n                        long long s1 = llabs((long long)w[e1] - target2);\n                        long long s2 = llabs((long long)w[e2] - target2);\n                        if (s1 != s2) return s1 < s2;\n                        return w[e1] > w[e2];\n                    });\n                    for (int e : all) add(e);\n\n                    if ((int)ns.size() < LIMIT) {\n                        all = sel;\n                        sort(all.begin(), all.end(), [&](int e1, int e2) {\n                            if (w[e1] != w[e2]) return w[e1] > w[e2];\n                            return e1 < e2;\n                        });\n                        for (int e : all) add(e);\n                    }\n\n                    sel = ns;\n                }\n\n                int M = (int)sel.size();\n\n                long long baseX = loads[x];\n                long long baseY = loads[y];\n                long long total = 0;\n\n                for (int e : sel) {\n                    total += w[e];\n\n                    if (dest[e] == x) baseX -= w[e];\n                    else if (dest[e] == y) baseY -= w[e];\n                }\n\n                long long oldCost =\n                    cellCost(loads[x] - dem[x], objMode) +\n                    cellCost(loads[y] - dem[y], objMode);\n\n                long long bestCost = oldCost;\n                int bestMask = -1;\n                long long bestSX = 0;\n\n                int lim = 1 << M;\n\n                for (int mask = 0; mask < lim; ++mask) {\n                    long long sx = 0;\n\n                    for (int k = 0; k < M; ++k) {\n                        if (mask & (1 << k)) sx += w[sel[k]];\n                    }\n\n                    long long lx = baseX + sx;\n                    long long ly = baseY + (total - sx);\n\n                    long long cost =\n                        cellCost(lx - dem[x], objMode) +\n                        cellCost(ly - dem[y], objMode);\n\n                    if (cost < bestCost) {\n                        bestCost = cost;\n                        bestMask = mask;\n                        bestSX = sx;\n                    }\n                }\n\n                if (bestMask != -1) {\n                    loads[x] = baseX + bestSX;\n                    loads[y] = baseY + (total - bestSX);\n\n                    for (int k = 0; k < M; ++k) {\n                        dest[sel[k]] = (bestMask & (1 << k)) ? x : y;\n                    }\n\n                    improved = true;\n                    any = true;\n                }\n            }\n        }\n\n        if (!improved) break;\n    }\n\n    return any;\n}\n\nint computeSCC(const array<int, MAXE>& dest, vector<int>& comp, vector<vector<int>>& comps) {\n    comp.assign(N, -1);\n    comps.clear();\n\n    if (activeChoices.empty()) return 0;\n\n    array<char, MAXN> active{};\n    active.fill(0);\n    for (int v : activeChoices) active[v] = 1;\n\n    vector<int> g[MAXN], rg[MAXN];\n\n    for (int v : activeChoices) {\n        for (int p = 0; p < 2; ++p) {\n            int to = dest[2 * v + p];\n\n            if (0 <= to && to < N && active[to]) {\n                g[v].push_back(to);\n                rg[to].push_back(v);\n            }\n        }\n    }\n\n    vector<int> order;\n    array<char, MAXN> vis{};\n    vis.fill(0);\n\n    function<void(int)> dfs1 = [&](int v) {\n        vis[v] = 1;\n\n        for (int to : g[v]) {\n            if (!vis[to]) dfs1(to);\n        }\n\n        order.push_back(v);\n    };\n\n    function<void(int, int)> dfs2 = [&](int v, int id) {\n        comp[v] = id;\n        comps[id].push_back(v);\n\n        for (int to : rg[v]) {\n            if (comp[to] == -1) dfs2(to, id);\n        }\n    };\n\n    for (int v : activeChoices) {\n        if (!vis[v]) dfs1(v);\n    }\n\n    for (int i = (int)order.size() - 1; i >= 0; --i) {\n        int v = order[i];\n\n        if (comp[v] == -1) {\n            comps.push_back({});\n            dfs2(v, (int)comps.size() - 1);\n        }\n    }\n\n    return (int)comps.size();\n}\n\nstruct EdgeChoice {\n    long long delta;\n    int e;\n    int y;\n};\n\nEdgeChoice findBestChange(\n    int A,\n    int B,\n    const vector<vector<int>>& comps,\n    const array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    const array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    const array<unsigned char, MAXE>* banned = nullptr\n) {\n    const long long INF = (1LL << 60);\n\n    EdgeChoice best{INF, -1, -1};\n\n    if (A == B) return best;\n\n    for (int positivePass = 0; positivePass < 2; ++positivePass) {\n        best = {INF, -1, -1};\n\n        for (int s : comps[A]) {\n            for (int p = 0; p < 2; ++p) {\n                int e = 2 * s + p;\n\n                if (banned && (*banned)[e]) continue;\n                if (positivePass == 0 && w[e] == 0) continue;\n\n                for (int y : comps[B]) {\n                    long long delta = moveDeltaCost(dest, w, loads, dem, objMode, e, y);\n\n                    if (\n                        delta < best.delta ||\n                        (delta == best.delta && (best.e == -1 || w[e] < w[best.e]))\n                    ) {\n                        best = {delta, e, y};\n                    }\n                }\n            }\n        }\n\n        if (best.e != -1) return best;\n    }\n\n    return best;\n}\n\nvoid applyEdgeChoice(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    array<unsigned char, MAXE>& prot,\n    const EdgeChoice& ch\n) {\n    if (ch.e == -1) return;\n\n    applyMove(dest, w, loads, ch.e, ch.y);\n    prot[ch.e] = 1;\n}\n\nvoid repairStrongFull(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 4; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        vector<int> order(K);\n        iota(order.begin(), order.end(), 0);\n\n        sort(order.begin(), order.end(), [&](int x, int y) {\n            long long sx = 0;\n            long long sy = 0;\n\n            for (int v : comps[x]) sx += dem[v];\n            for (int v : comps[y]) sy += dem[v];\n\n            long long lhs = sx * (long long)comps[y].size();\n            long long rhs = sy * (long long)comps[x].size();\n\n            if (lhs != rhs) return lhs > rhs;\n            return x < y;\n        });\n\n        array<unsigned char, MAXE> used{};\n        used.fill(0);\n\n        bool changed = false;\n\n        for (int i = 0; i < K; ++i) {\n            int A = order[i];\n            int B = order[(i + 1) % K];\n\n            EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode, &used);\n            if (ch.e == -1) continue;\n\n            int old = dest[ch.e];\n\n            applyEdgeChoice(dest, w, loads, prot, ch);\n            used[ch.e] = 1;\n\n            if (old != ch.y) changed = true;\n        }\n\n        if (!changed) return;\n    }\n}\n\nvoid repairStrongSmart(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot\n) {\n    if ((int)activeChoices.size() <= 1) return;\n\n    for (int iter = 0; iter < 6; ++iter) {\n        vector<int> comp;\n        vector<vector<int>> comps;\n\n        int K = computeSCC(dest, comp, comps);\n        if (K <= 1) return;\n\n        vector<vector<int>> cg(K);\n        vector<int> indeg(K, 0), outdeg(K, 0);\n\n        for (int v : activeChoices) {\n            int cv = comp[v];\n\n            for (int p = 0; p < 2; ++p) {\n                int to = dest[2 * v + p];\n\n                if (to < 0 || to >= N) continue;\n\n                int cu = comp[to];\n\n                if (cu == -1 || cu == cv) continue;\n\n                cg[cv].push_back(cu);\n                ++outdeg[cv];\n                ++indeg[cu];\n            }\n        }\n\n        vector<int> sources, sinks;\n\n        for (int c = 0; c < K; ++c) {\n            if (indeg[c] == 0) sources.push_back(c);\n            if (outdeg[c] == 0) sinks.push_back(c);\n        }\n\n        if (sources.empty() || sinks.empty()) {\n            repairStrongFull(dest, w, loads, dem, objMode, prot);\n            return;\n        }\n\n        vector<int> indegTopo(K, 0);\n\n        for (int c = 0; c < K; ++c) {\n            for (int to : cg[c]) ++indegTopo[to];\n        }\n\n        queue<int> q;\n\n        for (int c = 0; c < K; ++c) {\n            if (indegTopo[c] == 0) q.push(c);\n        }\n\n        vector<int> topo;\n\n        while (!q.empty()) {\n            int v = q.front();\n            q.pop();\n            topo.push_back(v);\n\n            for (int to : cg[v]) {\n                --indegTopo[to];\n\n                if (indegTopo[to] == 0) q.push(to);\n            }\n        }\n\n        vector<int> pos(K, 0);\n\n        for (int i = 0; i < (int)topo.size(); ++i) {\n            pos[topo[i]] = i;\n        }\n\n        sort(sources.begin(), sources.end(), [&](int x, int y) {\n            return pos[x] < pos[y];\n        });\n\n        sort(sinks.begin(), sinks.end(), [&](int x, int y) {\n            return pos[x] < pos[y];\n        });\n\n        int M = max((int)sources.size(), (int)sinks.size());\n\n        vector<int> seqS(M), seqZ(M);\n\n        for (int i = 0; i < M; ++i) {\n            seqS[i] = sources[i % sources.size()];\n            seqZ[i] = sinks[i % sinks.size()];\n        }\n\n        const long long INF = (1LL << 60);\n\n        int bestShift = -1;\n        long long bestTotal = INF;\n\n        for (int shift = 0; shift < M; ++shift) {\n            long long total = 0;\n            bool ok = true;\n\n            for (int i = 0; i < M; ++i) {\n                int A = seqZ[i];\n                int B = seqS[(i + 1 + shift) % M];\n\n                if (A == B) {\n                    ok = false;\n                    break;\n                }\n\n                EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode);\n\n                if (ch.e == -1) {\n                    ok = false;\n                    break;\n                }\n\n                total += ch.delta;\n\n                if (total > bestTotal) break;\n            }\n\n            if (ok && total < bestTotal) {\n                bestTotal = total;\n                bestShift = shift;\n            }\n        }\n\n        if (bestShift == -1) bestShift = 0;\n\n        array<unsigned char, MAXE> used{};\n        used.fill(0);\n\n        bool changed = false;\n\n        for (int i = 0; i < M; ++i) {\n            int A = seqZ[i];\n            int B = seqS[(i + 1 + bestShift) % M];\n\n            if (A == B) {\n                for (int s : sources) {\n                    if (s != A) {\n                        B = s;\n                        break;\n                    }\n                }\n\n                if (A == B) continue;\n            }\n\n            EdgeChoice ch = findBestChange(A, B, comps, dest, w, loads, dem, objMode, &used);\n\n            if (ch.e == -1) continue;\n\n            int old = dest[ch.e];\n\n            applyEdgeChoice(dest, w, loads, prot, ch);\n            used[ch.e] = 1;\n\n            if (old != ch.y) changed = true;\n        }\n\n        if (!changed) {\n            repairStrongFull(dest, w, loads, dem, objMode, prot);\n            return;\n        }\n    }\n\n    repairStrongFull(dest, w, loads, dem, objMode, prot);\n}\n\nvoid optimizeNonProtected(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot,\n    int passes,\n    bool randomize\n) {\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (!prot[e] && w[e] > 0) items.push_back(e);\n    }\n\n    if (!items.empty()) {\n        optimizeItems(dest, w, items, activeChoices, loads, dem,\n                      objMode, passes, randomize);\n    }\n}\n\nvoid applyRepairType(\n    array<int, MAXE>& dest,\n    const array<int, MAXE>& w,\n    array<long long, MAXN>& loads,\n    const array<int, MAXN>& dem,\n    int objMode,\n    array<unsigned char, MAXE>& prot,\n    int repairType,\n    bool randomize\n) {\n    if (repairType == 0) return;\n\n    if (repairType == 1) {\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n        optimizeNonProtected(dest, w, loads, dem, objMode, prot, 2, randomize);\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n    } else {\n        repairStrongFull(dest, w, loads, dem, objMode, prot);\n        optimizeNonProtected(dest, w, loads, dem, objMode, prot, 2, randomize);\n        repairStrongSmart(dest, w, loads, dem, objMode, prot);\n    }\n}\n\nCand buildSimpleCycle(bool activeOnly) {\n    Cand c;\n    c.prot.fill(0);\n\n    if (activeOnly && !activeChoices.empty()) {\n        int root = activeChoices[0];\n\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = root;\n            c.b[i] = root;\n        }\n\n        int m = (int)activeChoices.size();\n\n        for (int k = 0; k < m; ++k) {\n            int v = activeChoices[k];\n            int to = activeChoices[(k + 1) % m];\n\n            c.a[v] = to;\n            c.b[v] = to;\n        }\n    } else {\n        for (int i = 0; i < N; ++i) {\n            c.a[i] = (i + 1) % N;\n            c.b[i] = (i + 1) % N;\n        }\n    }\n\n    return c;\n}\n\nCand buildFree(\n    int z,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    int repairType\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] > 0) items.push_back(e);\n        else dest[e] = root;\n    }\n\n    assignItems(dest, w, items, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand buildBackbone(\n    int fixedParity,\n    int z,\n    int K,\n    int noiseAmp,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize\n) {\n    array<int, MAXE> dest;\n    array<int, MAXE> w;\n    array<unsigned char, MAXE> prot;\n    array<long long, MAXN> loads;\n\n    prot.fill(0);\n    loads.fill(0);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n    dest.fill(root);\n\n    for (int i = 0; i < N; ++i) {\n        int q = Cdes[i] - (i == z ? 1 : 0);\n\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct NK {\n        int key;\n        int dem;\n        int node;\n    };\n\n    vector<NK> keys;\n    keys.reserve(activeChoices.size());\n\n    for (int v : activeChoices) {\n        int key = demandIn[v];\n\n        if (noiseAmp > 0) {\n            key += rng.randint(2 * noiseAmp + 1) - noiseAmp;\n        }\n\n        keys.push_back({key, demandIn[v], v});\n    }\n\n    sort(keys.begin(), keys.end(), [](const NK& x, const NK& y) {\n        if (x.key != y.key) return x.key > y.key;\n        if (x.dem != y.dem) return x.dem > y.dem;\n        return x.node < y.node;\n    });\n\n    vector<int> base;\n\n    for (auto& x : keys) base.push_back(x.node);\n\n    vector<int> order;\n    int m = (int)base.size();\n\n    if (m == 0) {\n        order.push_back(0);\n    } else {\n        K = max(1, min(K, m));\n\n        for (int r = 0; r < K; ++r) {\n            for (int idx = r; idx < m; idx += K) {\n                order.push_back(base[idx]);\n            }\n        }\n    }\n\n    root = order[0];\n    dest.fill(root);\n\n    array<char, MAXN> isAct{};\n    isAct.fill(0);\n\n    for (int v : order) isAct[v] = 1;\n\n    vector<int> flexItems;\n    flexItems.reserve(MAXE);\n\n    for (int k = 0; k < (int)order.size(); ++k) {\n        int s = order[k];\n        int to = order[(k + 1) % order.size()];\n\n        int fixedIdx = 2 * s + fixedParity;\n        int flexIdx = 2 * s + (1 - fixedParity);\n\n        dest[fixedIdx] = to;\n        prot[fixedIdx] = 1;\n        loads[to] += w[fixedIdx];\n\n        flexItems.push_back(flexIdx);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (isAct[i]) continue;\n\n        for (int p = 0; p < 2; ++p) {\n            int e = 2 * i + p;\n\n            if (w[e] > 0) flexItems.push_back(e);\n            else dest[e] = root;\n        }\n    }\n\n    assignItems(dest, w, flexItems, activeChoices, loads, demandIn,\n                objMode, topR, maxPass, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand rebalanceCandidate(\n    const Entry& base,\n    bool fullReassign,\n    int objMode,\n    int topR,\n    int maxPass,\n    bool randomize,\n    int repairType\n) {\n    array<int, MAXE> dest;\n    getDest(base.cand, dest);\n\n    array<unsigned char, MAXE> prot = base.cand.prot;\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = base.res.cnt[i] - (base.res.last == i ? 1 : 0);\n\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    array<long long, MAXN> loads;\n    loads.fill(0);\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    int root = activeChoices.empty() ? 0 : activeChoices[0];\n\n    if (fullReassign) {\n        for (int e = 0; e < 2 * N; ++e) {\n            if (prot[e]) {\n                loads[dest[e]] += w[e];\n            } else {\n                items.push_back(e);\n                dest[e] = root;\n            }\n        }\n\n        assignItems(dest, w, items, activeChoices, loads, demandIn,\n                    objMode, topR, maxPass, randomize);\n    } else {\n        for (int e = 0; e < 2 * N; ++e) {\n            loads[dest[e]] += w[e];\n\n            if (!prot[e]) items.push_back(e);\n        }\n\n        optimizeItems(dest, w, items, activeChoices, loads, demandIn,\n                      objMode, maxPass, randomize);\n    }\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, randomize);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nCand pairPolishCandidate(\n    const Entry& base,\n    int objMode,\n    int repairType,\n    bool unlockProt,\n    int rounds\n) {\n    array<int, MAXE> dest;\n    getDest(base.cand, dest);\n\n    array<unsigned char, MAXE> prot = base.cand.prot;\n\n    if (unlockProt) prot.fill(0);\n\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = base.res.cnt[i] - (base.res.last == i ? 1 : 0);\n\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    array<long long, MAXN> loads;\n    loads.fill(0);\n\n    vector<int> items;\n    items.reserve(MAXE);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        loads[dest[e]] += w[e];\n\n        if (!prot[e] && w[e] > 0) items.push_back(e);\n    }\n\n    optimizeItems(dest, w, items, activeChoices, loads, demandIn,\n                  objMode, 3, false);\n\n    optimizePairwiseBins(dest, w, items, activeChoices, loads, demandIn,\n                         objMode, rounds);\n\n    applyRepairType(dest, w, loads, demandIn, objMode, prot, repairType, false);\n\n    Cand c;\n\n    for (int i = 0; i < N; ++i) {\n        c.a[i] = dest[2 * i];\n        c.b[i] = dest[2 * i + 1];\n    }\n\n    c.prot = prot;\n    return c;\n}\n\nbool validZ(int z) {\n    if (z < 0 || z >= N) return false;\n    if (Cdes[z] <= 0) return false;\n    if (z == 0 && Cdes[0] <= 1) return false;\n    return true;\n}\n\nint randomZ() {\n    if (!validZs.empty()) {\n        return validZs[rng.randint((int)validZs.size())];\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (Cdes[i] > 0) return i;\n    }\n\n    return 0;\n}\n\nbool tryLocalImprove(double TL) {\n    if (activeChoices.empty()) return false;\n\n    array<int, MAXE> dest;\n    getDest(bestCand, dest);\n\n    array<int, MAXE> w;\n\n    for (int i = 0; i < N; ++i) {\n        int q = bestRes.cnt[i] - (bestRes.last == i ? 1 : 0);\n\n        if (q < 0) q = 0;\n\n        w[2 * i] = (q + 1) / 2;\n        w[2 * i + 1] = q / 2;\n    }\n\n    struct Change {\n        long long delta;\n        int type;\n        int e;\n        int f;\n        int y;\n    };\n\n    vector<Change> moves;\n    moves.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        int ww = w[e];\n\n        if (ww == 0) continue;\n\n        int old = dest[e];\n\n        for (int y : activeChoices) {\n            if (y == old) continue;\n\n            long long delta =\n                llabs((long long)bestRes.cnt[old] - ww - T[old]) +\n                llabs((long long)bestRes.cnt[y] + ww - T[y]) -\n                llabs((long long)bestRes.cnt[old] - T[old]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) moves.push_back({delta, 0, e, -1, y});\n        }\n    }\n\n    sort(moves.begin(), moves.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    int testLimit = min(48, (int)moves.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n        setEdge(c, moves[i].e, moves[i].y);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    vector<Change> swaps;\n    swaps.reserve(20000);\n\n    for (int e = 0; e < 2 * N; ++e) {\n        if (w[e] == 0) continue;\n\n        for (int f = e + 1; f < 2 * N; ++f) {\n            if (w[f] == 0) continue;\n\n            int x = dest[e];\n            int y = dest[f];\n\n            if (x == y) continue;\n\n            int we = w[e];\n            int wf = w[f];\n\n            if (we == wf) continue;\n\n            long long nx = (long long)bestRes.cnt[x] - we + wf;\n            long long ny = (long long)bestRes.cnt[y] - wf + we;\n\n            long long delta =\n                llabs(nx - T[x]) +\n                llabs(ny - T[y]) -\n                llabs((long long)bestRes.cnt[x] - T[x]) -\n                llabs((long long)bestRes.cnt[y] - T[y]);\n\n            if (delta < 0) swaps.push_back({delta, 1, e, f, -1});\n        }\n    }\n\n    sort(swaps.begin(), swaps.end(), [](const Change& a, const Change& b) {\n        return a.delta < b.delta;\n    });\n\n    testLimit = min(48, (int)swaps.size());\n\n    for (int i = 0; i < testLimit && elapsed_sec() < TL; ++i) {\n        Cand c = bestCand;\n\n        int e = swaps[i].e;\n        int f = swaps[i].f;\n\n        setEdge(c, e, dest[f]);\n        setEdge(c, f, dest[e]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nbool tryFlipImprove(double TL) {\n    vector<int> verts;\n    verts.reserve(N);\n\n    for (int i = 0; i < N; ++i) {\n        if (bestCand.a[i] != bestCand.b[i]) verts.push_back(i);\n    }\n\n    if (verts.empty()) return false;\n\n    sort(verts.begin(), verts.end(), [&](int x, int y) {\n        if (bestRes.cnt[x] != bestRes.cnt[y]) return bestRes.cnt[x] > bestRes.cnt[y];\n        return x < y;\n    });\n\n    int singleLimit = min(55, (int)verts.size());\n\n    for (int idx = 0; idx < singleLimit && elapsed_sec() < TL; ++idx) {\n        Cand c = bestCand;\n        flipVertex(c, verts[idx]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    if (elapsed_sec() > TL - 0.07) return false;\n\n    int attempts = 16;\n\n    for (int at = 0; at < attempts && elapsed_sec() < TL; ++at) {\n        Cand c = bestCand;\n\n        vector<int> order = verts;\n        shuffle_vec(order);\n\n        int k = 2 + rng.randint(3);\n        k = min(k, (int)order.size());\n\n        for (int i = 0; i < k; ++i) flipVertex(c, order[i]);\n\n        SimResult r = simulate(c);\n\n        if (r.err < bestErr) {\n            addEvaluated(c, r);\n            return true;\n        }\n    }\n\n    return false;\n}\n\nEntry pickEliteBase(int topK, int bestPercent) {\n    int sz = (int)pool.size();\n\n    if (sz == 1 || rng.randint(100) < bestPercent) return pool[0];\n\n    int k = min(topK, sz);\n    return pool[rng.randint(k)];\n}\n\nint main() {\n    ios::sync_with_stdio(false);\n    cin.tie(nullptr);\n\n    cin >> N >> L;\n\n    uint64_t seed = 123456789;\n\n    for (int i = 0; i < N; ++i) {\n        cin >> T[i];\n        seed = seed * 1000003ULL + (uint64_t)(T[i] + 1);\n    }\n\n    rng = RNG(seed);\n    st_time = chrono::steady_clock::now();\n\n    Cdes = T;\n\n    if (T[0] == 0) {\n        Cdes[0] = 1;\n\n        int k = 1;\n\n        for (int i = 1; i < N; ++i) {\n            if (T[i] > T[k]) k = i;\n        }\n\n        --Cdes[k];\n    }\n\n    for (int i = 0; i < N; ++i) demandIn[i] = Cdes[i];\n\n    --demandIn[0];\n\n    if (demandIn[0] < 0) demandIn[0] = 0;\n\n    for (int i = 0; i < N; ++i) {\n        if (demandIn[i] > 0) activeChoices.push_back(i);\n    }\n\n    if (activeChoices.empty()) {\n        int k = max_element(Cdes.begin(), Cdes.begin() + N) - Cdes.begin();\n        activeChoices.push_back(k);\n    }\n\n    for (int i = 0; i < N; ++i) {\n        if (validZ(i)) validZs.push_back(i);\n    }\n\n    if (validZs.empty()) {\n        for (int i = 0; i < N; ++i) {\n            if (Cdes[i] > 0) validZs.push_back(i);\n        }\n    }\n\n    consider(buildSimpleCycle(false));\n    consider(buildSimpleCycle(true));\n\n    vector<int> zlist;\n\n    auto addZ = [&](int z) {\n        if (!validZ(z)) return;\n\n        if (find(zlist.begin(), zlist.end(), z) == zlist.end()) {\n            zlist.push_back(z);\n        }\n    };\n\n    vector<int> ids(N);\n    iota(ids.begin(), ids.end(), 0);\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        return Cdes[x] > Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) addZ(ids[i]);\n\n    sort(ids.begin(), ids.end(), [&](int x, int y) {\n        if ((Cdes[x] > 0) != (Cdes[y] > 0)) return Cdes[x] > 0;\n        return Cdes[x] < Cdes[y];\n    });\n\n    for (int i = 0; i < N && i < 8; ++i) addZ(ids[i]);\n\n    addZ(0);\n\n    if (zlist.empty() && !validZs.empty()) zlist.push_back(validZs[0]);\n\n    const double TL = 1.86;\n    const double PHASE_FREE_DET = 0.55;\n    const double PHASE_FREE_RAND = 1.04;\n    const double PHASE_REBAL = 1.58;\n    const double PHASE_FLIP_START = 1.70;\n\n    for (int z : zlist) {\n        if (elapsed_sec() > PHASE_FREE_DET) break;\n\n        for (int repairType : {1, 0, 2}) {\n            if (elapsed_sec() > PHASE_FREE_DET) break;\n\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() > PHASE_FREE_DET) break;\n\n                Cand c = buildFree(z, mode, 1, 8, false, repairType);\n                consider(c);\n            }\n        }\n    }\n\n    for (int z : zlist) {\n        if (elapsed_sec() > 0.78) break;\n\n        for (int fixed = 0; fixed < 2; ++fixed) {\n            if (elapsed_sec() > 0.78) break;\n\n            for (int K = 1; K <= 4; ++K) {\n                if (elapsed_sec() > 0.78) break;\n\n                Cand c = buildBackbone(fixed, z, K, 0, 0, 1, 4, false);\n                consider(c);\n            }\n        }\n    }\n\n    while (elapsed_sec() < PHASE_FREE_RAND) {\n        int z = randomZ();\n        int mode = rng.randint(3);\n        int topR = 1 + rng.randint(5);\n        int maxPass = 3 + rng.randint(5);\n\n        int r = rng.randint(100);\n        int repairType;\n\n        if (r < 72) repairType = 1;\n        else if (r < 90) repairType = 2;\n        else repairType = 0;\n\n        Cand c = buildFree(z, mode, topR, maxPass, true, repairType);\n        consider(c);\n    }\n\n    for (int rep = 0; rep < 4 && elapsed_sec() < 1.25 && !pool.empty(); ++rep) {\n        Entry base = pool[0];\n\n        for (int fullInt = 0; fullInt < 2; ++fullInt) {\n            for (int mode : {0, 1, 2}) {\n                if (elapsed_sec() >= 1.25) break;\n\n                bool full = fullInt != 0;\n                int maxPass = full ? 7 : 10;\n\n                Cand c = rebalanceCandidate(base, full, mode, 1, maxPass, false, 1);\n                consider(c);\n            }\n        }\n    }\n\n    if (!pool.empty() && elapsed_sec() < 1.32) {\n        bool polImp = false;\n\n        for (int mode : {0, 2}) {\n            if (elapsed_sec() >= 1.32) break;\n\n            Entry base = pool[0];\n            Cand c = pairPolishCandidate(base, mode, 1, false, 8);\n\n            if (considerOnlyIfBest(c)) polImp = true;\n        }\n\n        if ((polImp || bestErr > 2050) && elapsed_sec() < 1.38) {\n            struct Plan {\n                int mode;\n                int repair;\n                bool unlock;\n                int rounds;\n                int idx;\n            };\n\n            vector<Plan> plans = {\n                {1, 1, false, 6, 0},\n                {0, 1, true, 6, 0},\n                {2, 1, true, 6, 0},\n                {0, 2, true, 5, 0}\n            };\n\n            if ((polImp || bestErr > 2100) && (int)pool.size() > 1) {\n                plans.push_back({0, 1, false, 4, 1});\n                plans.push_back({2, 1, false, 4, 1});\n            }\n\n            if (bestErr > 2400 && (int)pool.size() > 2) {\n                plans.push_back({0, 1, false, 4, 2});\n            }\n\n            for (auto p : plans) {\n                if (elapsed_sec() >= 1.38) break;\n\n                int idx = min(p.idx, (int)pool.size() - 1);\n                Entry base = pool[idx];\n                Cand c = pairPolishCandidate(base, p.mode, p.repair, p.unlock, p.rounds);\n                considerOnlyIfBest(c);\n            }\n        }\n    }\n\n    int it = 0;\n\n    while (elapsed_sec() < PHASE_REBAL && !pool.empty()) {\n        Entry base;\n\n        if (it % 2 == 0) base = pool[0];\n        else base = pickEliteBase(6, 45);\n\n        bool full = (it % 3 != 1);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? (4 + rng.randint(4)) : (6 + rng.randint(4));\n        int repairType = (rng.randint(100) < 85) ? 1 : 2;\n\n        Cand c = rebalanceCandidate(base, full, mode, topR, maxPass, true, repairType);\n        consider(c);\n\n        ++it;\n    }\n\n    bool localAllowed = true;\n    bool flipAllowed = true;\n    bool latePolishAllowed = true;\n\n    while (elapsed_sec() < TL) {\n        if (bestErr == 0) break;\n\n        if (localAllowed) {\n            if (tryLocalImprove(TL)) {\n                localAllowed = true;\n                flipAllowed = true;\n                latePolishAllowed = true;\n                continue;\n            }\n\n            localAllowed = false;\n        }\n\n        if (\n            latePolishAllowed &&\n            bestErr > 1600 &&\n            elapsed_sec() > 1.60 &&\n            elapsed_sec() < 1.73 &&\n            !pool.empty()\n        ) {\n            latePolishAllowed = false;\n            bool imp = false;\n\n            struct Plan {\n                int mode;\n                int repair;\n                bool unlock;\n                int rounds;\n                int idx;\n            };\n\n            vector<Plan> plans;\n\n            if (bestErr > 2100) {\n                plans = {\n                    {0, 1, false, 5, 0},\n                    {2, 1, false, 5, 0},\n                    {1, 1, false, 4, 0},\n                    {0, 1, false, 4, 1},\n                    {2, 1, false, 4, 1},\n                    {0, 1, true, 4, 0}\n                };\n\n                if (bestErr > 2400 && (int)pool.size() > 2) {\n                    plans.push_back({0, 1, false, 4, 2});\n                }\n            } else if (bestErr > 1850) {\n                plans = {\n                    {0, 1, false, 4, 0},\n                    {2, 1, false, 4, 0},\n                    {1, 1, false, 4, 0}\n                };\n            } else {\n                plans = {\n                    {0, 1, false, 4, 0},\n                    {2, 1, false, 4, 0}\n                };\n            }\n\n            for (auto p : plans) {\n                if (elapsed_sec() >= 1.73) break;\n\n                int idx = min(p.idx, (int)pool.size() - 1);\n                Entry base = pool[idx];\n                Cand c = pairPolishCandidate(base, p.mode, p.repair, p.unlock, p.rounds);\n\n                if (considerOnlyIfBest(c)) imp = true;\n            }\n\n            if (imp) {\n                localAllowed = true;\n                flipAllowed = true;\n                continue;\n            }\n        }\n\n        if (flipAllowed && elapsed_sec() > PHASE_FLIP_START) {\n            if (tryFlipImprove(TL)) {\n                localAllowed = true;\n                flipAllowed = true;\n                latePolishAllowed = true;\n                continue;\n            }\n\n            flipAllowed = false;\n        }\n\n        if (pool.empty() || elapsed_sec() >= TL) break;\n\n        Entry base = pickEliteBase(6, 40);\n\n        bool full = rng.randint(2);\n        int mode = rng.randint(3);\n        int topR = full ? (1 + rng.randint(5)) : 1;\n        int maxPass = full ? 4 : 7;\n        int repairType = (rng.randint(100) < 88) ? 1 : 2;\n\n        bool imp = consider(\n            rebalanceCandidate(base, full, mode, topR, maxPass, true, repairType)\n        );\n\n        if (imp) {\n            localAllowed = true;\n            flipAllowed = true;\n            latePolishAllowed = true;\n        }\n    }\n\n    for (int i = 0; i < N; ++i) {\n        cout << bestCand.a[i] << ' ' << bestCand.b[i] << '\\n';\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, varp, norm2;\n    vector<int> sx_int, sy_int;\n    vector<unsigned long long> hilb;\n\n    vector<float> distBase;\n    vector<float> distRank;\n    vector<unsigned char> known;      // 0 none, 1 prequery, 2 final/internal query\n    vector<unsigned char> forbidden;  // certainly non-MST inside final group\n    vector<unsigned char> softBad;    // weak non-MST evidence\n\n    vector<float> bonusMat;\n    vector<vector<pair<int, float>>> bonusAdj;\n\n    unordered_set<unsigned long long> usedQueries;\n    unordered_map<unsigned long long, vector<pair<int,int>>> responseMap;\n\n    struct QueryRecord {\n        vector<int> subset;\n        vector<pair<int,int>> edges;\n    };\n    vector<QueryRecord> queryRecords;\n\n    int queryCount = 0;\n    float knownEvalFactor;\n    float knownFinalFactor;\n    float knownFinalGroupFactor;\n\n    mt19937 rng{1234567};\n\n    int ID(int i, int j) const { return i * N + j; }\n\n    static unsigned long long hilbertOrder(int x, int y) {\n        const int B = 14;\n        const int SZ = 1 << B;\n        unsigned long long d = 0;\n        for (int s = SZ / 2; s > 0; s >>= 1) {\n            int rx = (x & s) ? 1 : 0;\n            int ry = (y & s) ? 1 : 0;\n            d += (unsigned long long)s * (unsigned long long)s * ((3 * rx) ^ ry);\n            if (ry == 0) {\n                if (rx == 1) {\n                    x = SZ - 1 - x;\n                    y = SZ - 1 - y;\n                }\n                swap(x, y);\n            }\n        }\n        return d;\n    }\n\n    static unsigned long long mortonOrder(int x, int y) {\n        unsigned long long z = 0;\n        for (int b = 0; b < 14; b++) {\n            z |= (unsigned long long)((x >> b) & 1) << (2 * b);\n            z |= (unsigned long long)((y >> b) & 1) << (2 * b + 1);\n        }\n        return z;\n    }\n\n    unsigned long long subsetHash(vector<int> s) const {\n        sort(s.begin(), s.end());\n        unsigned long long h = 1469598103934665603ULL;\n        h ^= (unsigned long long)s.size();\n        h *= 1099511628211ULL;\n        for (int v : s) {\n            h ^= (unsigned long long)(v + 1000003);\n            h *= 1099511628211ULL;\n        }\n        return h;\n    }\n\n    void readInput() {\n        cin >> N >> M >> Q >> L >> W;\n\n        G.resize(M);\n        for (int i = 0; i < M; i++) cin >> G[i];\n\n        lx.resize(N);\n        rx.resize(N);\n        ly.resize(N);\n        ry.resize(N);\n        cx.resize(N);\n        cy.resize(N);\n        varp.resize(N);\n        norm2.resize(N);\n        sx_int.resize(N);\n        sy_int.resize(N);\n        hilb.resize(N);\n\n        for (int i = 0; i < N; i++) {\n            cin >> lx[i] >> rx[i] >> ly[i] >> ry[i];\n\n            cx[i] = 0.5 * (lx[i] + rx[i]);\n            cy[i] = 0.5 * (ly[i] + ry[i]);\n\n            double wx = rx[i] - lx[i];\n            double wy = ry[i] - ly[i];\n\n            varp[i] = (wx * wx + wy * wy) / 12.0;\n            norm2[i] = cx[i] * cx[i] + cy[i] * cy[i];\n        }\n\n        const int SZ = 1 << 14;\n        for (int i = 0; i < N; i++) {\n            sx_int[i] = min(SZ - 1, max(0, (int)llround(cx[i] * (SZ - 1) / 10000.0)));\n            sy_int[i] = min(SZ - 1, max(0, (int)llround(cy[i] * (SZ - 1) / 10000.0)));\n            hilb[i] = hilbertOrder(sx_int[i], sy_int[i]);\n        }\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        knownEvalFactor = (float)(0.72 - 0.22 * unc);\n        knownFinalFactor = (float)(0.82 - 0.22 * unc);\n        knownFinalGroupFactor = max(0.45f, knownFinalFactor * 0.85f);\n    }\n\n    void computeDistances() {\n        distBase.assign(N * N, 0.0f);\n        distRank.assign(N * N, 0.0f);\n\n        vector<array<double, 9>> qx(N), qy(N), qw(N);\n\n        const double p[3] = {\n            -sqrt(3.0 / 5.0),\n            0.0,\n            sqrt(3.0 / 5.0)\n        };\n\n        const double w1[3] = {\n            5.0 / 18.0,\n            8.0 / 18.0,\n            5.0 / 18.0\n        };\n\n        for (int i = 0; i < N; i++) {\n            double mx = 0.5 * (lx[i] + rx[i]);\n            double my = 0.5 * (ly[i] + ry[i]);\n            double hx = 0.5 * (rx[i] - lx[i]);\n            double hy = 0.5 * (ry[i] - ly[i]);\n\n            int id = 0;\n            for (int a = 0; a < 3; a++) {\n                for (int b = 0; b < 3; b++) {\n                    qx[i][id] = mx + hx * p[a];\n                    qy[i][id] = my + hy * p[b];\n                    qw[i][id] = w1[a] * w1[b];\n                    id++;\n                }\n            }\n        }\n\n        const double alpha = 0.70;\n\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 cd = sqrt(dx * dx + dy * dy);\n\n                double oldBase = sqrt(dx * dx + dy * dy + alpha * (varp[i] + varp[j]));\n\n                double quad = 0.0;\n                for (int a = 0; a < 9; a++) {\n                    for (int b = 0; b < 9; b++) {\n                        double ddx = qx[i][a] - qx[j][b];\n                        double ddy = qy[i][a] - qy[j][b];\n                        quad += qw[i][a] * qw[j][b] * sqrt(ddx * ddx + ddy * ddy);\n                    }\n                }\n\n                double base = 0.80 * quad + 0.20 * oldBase;\n\n                double gx = 0.0, gy = 0.0;\n\n                if (rx[i] < lx[j]) gx = lx[j] - rx[i];\n                else if (rx[j] < lx[i]) gx = lx[i] - rx[j];\n\n                if (ry[i] < ly[j]) gy = ly[j] - ry[i];\n                else if (ry[j] < ly[i]) gy = ly[i] - ry[j];\n\n                double minRect = sqrt(gx * gx + gy * gy);\n                double rankd = 0.70 * minRect + 0.30 * cd;\n\n                distBase[ID(i, j)] = distBase[ID(j, i)] = (float)base;\n                distRank[ID(i, j)] = distRank[ID(j, i)] = (float)rankd;\n            }\n        }\n\n        known.assign(N * N, 0);\n        forbidden.assign(N * N, 0);\n        softBad.assign(N * N, 0);\n    }\n\n    vector<pair<int,int>> askNew(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        usedQueries.insert(h);\n\n        cout << \"? \" << subset.size();\n        for (int v : subset) cout << ' ' << v;\n        cout << '\\n';\n        cout.flush();\n\n        vector<pair<int,int>> ret;\n        int l = (int)subset.size();\n        ret.reserve(l - 1);\n\n        for (int i = 0; i < l - 1; i++) {\n            int a, b;\n            if (!(cin >> a >> b)) exit(0);\n            if (a < 0 || b < 0) exit(0);\n            if (a > b) swap(a, b);\n            ret.emplace_back(a, b);\n        }\n\n        queryCount++;\n        responseMap[h] = ret;\n        queryRecords.push_back({subset, ret});\n        return ret;\n    }\n\n    vector<pair<int,int>> getOrAsk(const vector<int>& subset) {\n        unsigned long long h = subsetHash(subset);\n        auto it = responseMap.find(h);\n\n        if (it != responseMap.end() && (int)it->second.size() == (int)subset.size() - 1) {\n            return it->second;\n        }\n\n        if (queryCount >= Q) return {};\n        return askNew(subset);\n    }\n\n    void addKnownEdges(const vector<pair<int,int>>& es, unsigned char level = 1) {\n        for (auto [a, b] : es) {\n            if (a > b) swap(a, b);\n            int id1 = ID(a, b), id2 = ID(b, a);\n            if (known[id1] < level) known[id1] = level;\n            if (known[id2] < level) known[id2] = level;\n        }\n    }\n\n    void addQueryInfo(\n        const vector<int>& subset,\n        const vector<pair<int,int>>& es,\n        unsigned char level,\n        bool markForbidden\n    ) {\n        addKnownEdges(es, level);\n\n        if (!markForbidden) return;\n\n        bool tree[16][16] = {};\n        vector<int> loc(N, -1);\n        int l = (int)subset.size();\n\n        for (int i = 0; i < l; i++) loc[subset[i]] = i;\n\n        for (auto [a, b] : es) {\n            int ia = loc[a], ib = loc[b];\n            if (ia >= 0 && ib >= 0) {\n                tree[ia][ib] = tree[ib][ia] = true;\n            }\n        }\n\n        for (int i = 0; i < l; i++) {\n            for (int j = i + 1; j < l; j++) {\n                if (tree[i][j]) continue;\n\n                int a = subset[i];\n                int b = subset[j];\n                if (a > b) swap(a, b);\n                forbidden[ID(a, b)] = forbidden[ID(b, a)] = 1;\n            }\n        }\n    }\n\n    vector<int> buildSubsetGlobal(int center, int variant, int mode) {\n        vector<pair<float,int>> arr;\n        arr.reserve(N - 1);\n\n        for (int v = 0; v < N; v++) {\n            if (v == center) continue;\n            float d = (mode == 0 ? distRank[ID(center, v)] : distBase[ID(center, v)]);\n            arr.emplace_back(d, v);\n        }\n\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n\n            for (int i = 0; i < common; i++) {\n                sub.push_back(arr[i].second);\n            }\n\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n\n        return sub;\n    }\n\n    vector<int> buildSubsetInGroup(int center, const vector<int>& group, int variant) {\n        vector<pair<float,int>> arr;\n        arr.reserve(group.size());\n\n        for (int v : group) {\n            if (v == center) continue;\n            arr.emplace_back(distBase[ID(center, v)], v);\n        }\n\n        sort(arr.begin(), arr.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 k = min(L - 1, (int)arr.size());\n\n        vector<int> sub;\n        sub.reserve(k + 1);\n        sub.push_back(center);\n\n        if (variant == 0) {\n            for (int i = 0; i < k; i++) sub.push_back(arr[i].second);\n        } else {\n            int common = max(0, k - 1);\n\n            for (int i = 0; i < common; i++) {\n                sub.push_back(arr[i].second);\n            }\n\n            int idx = k - 1 + variant;\n            if (idx >= (int)arr.size()) idx = k - 1;\n            if (idx >= 0) sub.push_back(arr[idx].second);\n        }\n\n        return sub;\n    }\n\n    int reserveFinalQueryCount() const {\n        int res = 0;\n        int chunk = L - 1;\n\n        for (int g : G) {\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                res++;\n            } else {\n                int total = g - 1;\n                int full = total / chunk;\n                int rem = total % chunk;\n\n                res += full;\n                if (rem >= 2) res++;\n            }\n        }\n\n        return min(res, Q);\n    }\n\n    void performPrequeries(int targetQueries) {\n        if (targetQueries <= 0) return;\n\n        vector<int> byUnc(N), byHilb(N);\n        iota(byUnc.begin(), byUnc.end(), 0);\n        iota(byHilb.begin(), byHilb.end(), 0);\n\n        sort(byUnc.begin(), byUnc.end(), [&](int a, int b) {\n            if (varp[a] != varp[b]) return varp[a] > varp[b];\n            return a < b;\n        });\n\n        sort(byHilb.begin(), byHilb.end(), [&](int a, int b) {\n            if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n            return a < b;\n        });\n\n        vector<int> centers;\n        vector<char> seen(N, 0);\n\n        for (int t = 0; t < N; t++) {\n            int c1 = byUnc[t];\n\n            if (!seen[c1]) {\n                seen[c1] = 1;\n                centers.push_back(c1);\n            }\n\n            int c2 = byHilb[(t * 37) % N];\n\n            if (!seen[c2]) {\n                seen[c2] = 1;\n                centers.push_back(c2);\n            }\n        }\n\n        for (int c : centers) {\n            if (queryCount >= targetQueries) break;\n\n            for (int v = 0; v < 4 && queryCount < targetQueries; v++) {\n                int mode = v & 1;\n                int variant = v / 2;\n\n                auto sub = buildSubsetGlobal(c, variant, mode);\n                if ((int)sub.size() < 2) continue;\n\n                unsigned long long h = subsetHash(sub);\n                if (usedQueries.count(h)) continue;\n\n                auto ret = askNew(sub);\n                addKnownEdges(ret, 1);\n                break;\n            }\n        }\n\n        int attempts = 0;\n\n        while (queryCount < targetQueries && attempts < 5000) {\n            int c = attempts % N;\n            int variant = (attempts / N) % 6;\n            int mode = (attempts / (N * 6)) & 1;\n            attempts++;\n\n            auto sub = buildSubsetGlobal(c, variant, mode);\n            if ((int)sub.size() < 2) continue;\n\n            unsigned long long h = subsetHash(sub);\n            if (usedQueries.count(h)) continue;\n\n            auto ret = askNew(sub);\n            addKnownEdges(ret, 1);\n        }\n    }\n\n    float evalWeight(int u, int v) const {\n        float d = distBase[ID(u, v)];\n        if (known[ID(u, v)]) d *= knownEvalFactor;\n        return d;\n    }\n\n    double primCostEval(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        if (n <= 1) return 0.0;\n\n        vector<float> best(n, 1e30f);\n        vector<char> used(n, 0);\n        best[0] = 0.0f;\n\n        double cost = 0.0;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) v = i;\n            }\n\n            used[v] = 1;\n            cost += best[v];\n\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    float w = evalWeight(vs[v], vs[u]);\n                    if (w < best[u]) best[u] = w;\n                }\n            }\n        }\n\n        return cost;\n    }\n\n    double evalCandidate(const vector<int>& gid) const {\n        vector<vector<int>> groups(M);\n        for (int k = 0; k < M; k++) groups[k].reserve(G[k]);\n\n        for (int i = 0; i < N; i++) {\n            if (gid[i] < 0 || gid[i] >= M) return 1e100;\n            groups[gid[i]].push_back(i);\n        }\n\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) return 1e100;\n        }\n\n        double score = 0.0;\n        for (int k = 0; k < M; k++) score += primCostEval(groups[k]);\n\n        return score;\n    }\n\n    vector<vector<int>> makeCityOrders() {\n        vector<vector<int>> orders;\n        const int S = (1 << 14) - 1;\n\n        auto addHilbert = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n\n                    if (type == 1) {\n                        tx = y;\n                        ty = x;\n                    } else if (type == 2) {\n                        tx = S - x;\n                        ty = y;\n                    } else if (type == 3) {\n                        tx = x;\n                        ty = S - y;\n                    } else if (type == 4) {\n                        tx = S - x;\n                        ty = S - y;\n                    } else if (type == 5) {\n                        tx = S - y;\n                        ty = x;\n                    }\n\n                    return hilbertOrder(tx, ty);\n                };\n\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 6; t++) addHilbert(t);\n\n        auto addMorton = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                auto key = [&](int i) {\n                    int x = sx_int[i], y = sy_int[i];\n                    int tx = x, ty = y;\n\n                    if (type == 1) {\n                        tx = y;\n                        ty = x;\n                    } else if (type == 2) {\n                        tx = S - x;\n                        ty = y;\n                    } else if (type == 3) {\n                        tx = x;\n                        ty = S - y;\n                    }\n\n                    return mortonOrder(tx, ty);\n                };\n\n                auto ka = key(a), kb = key(b);\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addMorton(t);\n\n        auto addSnake = [&](int axis) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n            const int B = 28;\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                int ba, bb, ia, ib;\n\n                if (axis == 0) {\n                    ba = sx_int[a] * B / (S + 1);\n                    bb = sx_int[b] * B / (S + 1);\n                    ia = (ba & 1) ? (S - sy_int[a]) : sy_int[a];\n                    ib = (bb & 1) ? (S - sy_int[b]) : sy_int[b];\n\n                    if (ba != bb) return ba < bb;\n                    if (ia != ib) return ia < ib;\n                    return sx_int[a] < sx_int[b];\n                } else {\n                    ba = sy_int[a] * B / (S + 1);\n                    bb = sy_int[b] * B / (S + 1);\n                    ia = (ba & 1) ? (S - sx_int[a]) : sx_int[a];\n                    ib = (bb & 1) ? (S - sx_int[b]) : sx_int[b];\n\n                    if (ba != bb) return ba < bb;\n                    if (ia != ib) return ia < ib;\n                    return sy_int[a] < sy_int[b];\n                }\n            });\n\n            orders.push_back(ids);\n        };\n\n        addSnake(0);\n        addSnake(1);\n\n        auto addSort = [&](int type) {\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                double ka, kb;\n\n                if (type == 0) {\n                    ka = cx[a] * 10001.0 + cy[a];\n                    kb = cx[b] * 10001.0 + cy[b];\n                } else if (type == 1) {\n                    ka = cy[a] * 10001.0 + cx[a];\n                    kb = cy[b] * 10001.0 + cx[b];\n                } else if (type == 2) {\n                    ka = cx[a] + cy[a];\n                    kb = cx[b] + cy[b];\n                } else {\n                    ka = cx[a] - cy[a];\n                    kb = cx[b] - cy[b];\n                }\n\n                if (ka != kb) return ka < kb;\n                return a < b;\n            });\n\n            orders.push_back(ids);\n        };\n\n        for (int t = 0; t < 4; t++) addSort(t);\n\n        return orders;\n    }\n\n    vector<vector<int>> makeGroupOrders() {\n        vector<vector<int>> orders;\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n\n        orders.push_back(ids);\n\n        vector<int> rev = ids;\n        reverse(rev.begin(), rev.end());\n        orders.push_back(rev);\n\n        vector<int> asc = ids;\n        vector<int> desc = ids;\n\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        orders.push_back(asc);\n        orders.push_back(desc);\n\n        vector<int> zigBigSmall;\n        vector<int> zigSmallBig;\n        zigBigSmall.reserve(M);\n        zigSmallBig.reserve(M);\n\n        for (int l = 0, r = M - 1; l <= r; l++, r--) {\n            zigSmallBig.push_back(asc[l]);\n            if (l != r) zigSmallBig.push_back(asc[r]);\n        }\n\n        for (int l = 0, r = M - 1; l <= r; l++, r--) {\n            zigBigSmall.push_back(desc[l]);\n            if (l != r) zigBigSmall.push_back(desc[r]);\n        }\n\n        orders.push_back(zigSmallBig);\n        orders.push_back(zigBigSmall);\n\n        for (int r = 0; r < 6; r++) {\n            vector<int> p = ids;\n            shuffle(p.begin(), p.end(), rng);\n            orders.push_back(p);\n        }\n\n        return orders;\n    }\n\n    vector<int> gapGreedyGroupOrder(const vector<int>& cityOrder, int mode) {\n        vector<double> gap(N + 1, 0.0), pref(N + 1, 0.0);\n\n        for (int p = 1; p < N; p++) {\n            gap[p] = distBase[ID(cityOrder[p - 1], cityOrder[p])];\n        }\n\n        for (int p = 1; p < N; p++) {\n            pref[p] = pref[p - 1] + gap[p];\n        }\n\n        vector<char> usedG(M, 0);\n        vector<int> order;\n        order.reserve(M);\n\n        int pos = 0;\n\n        for (int step = 0; step < M; step++) {\n            int remSum = N - pos;\n            int remGroups = M - step;\n\n            int best = -1;\n            double bestVal = -1e100;\n\n            for (int k = 0; k < M; k++) {\n                if (usedG[k]) continue;\n\n                int s = G[k];\n                if (s > remSum) continue;\n\n                if (remGroups > 1 && s == remSum) continue;\n\n                double val;\n\n                if (remGroups == 1) {\n                    val = 1e90;\n                } else {\n                    int b = pos + s;\n                    if (b <= 0 || b >= N) continue;\n\n                    double boundary = gap[b];\n\n                    double internalAvg = 0.0;\n                    if (s >= 2) {\n                        internalAvg = (pref[pos + s - 1] - pref[pos]) / (s - 1);\n                    }\n\n                    if (mode == 0) {\n                        val = boundary;\n                    } else if (mode == 1) {\n                        val = boundary / (0.8 + sqrt((double)s));\n                    } else {\n                        val = boundary - 0.15 * internalAvg;\n                    }\n                }\n\n                if (val > bestVal || (val == bestVal && (best == -1 || k < best))) {\n                    bestVal = val;\n                    best = k;\n                }\n            }\n\n            if (best == -1) {\n                for (int k = 0; k < M; k++) {\n                    if (!usedG[k] && G[k] <= remSum) {\n                        best = k;\n                        break;\n                    }\n                }\n            }\n\n            if (best == -1) {\n                for (int k = 0; k < M; k++) {\n                    if (!usedG[k]) {\n                        best = k;\n                        break;\n                    }\n                }\n            }\n\n            usedG[best] = 1;\n            order.push_back(best);\n            pos += G[best];\n        }\n\n        return order;\n    }\n\n    vector<int> partitionCandidate(const vector<int>& cityOrder, const vector<int>& groupOrder) {\n        vector<int> gid(N, -1);\n        int pos = 0;\n\n        for (int g : groupOrder) {\n            for (int t = 0; t < G[g]; t++) {\n                gid[cityOrder[pos++]] = g;\n            }\n        }\n\n        return gid;\n    }\n\n    struct EP {\n        float w;\n        int u, v;\n\n        bool operator<(const EP& other) const {\n            if (w != other.w) return w < other.w;\n            if (u != other.u) return u < other.u;\n            return v < other.v;\n        }\n    };\n\n    vector<EP> makeSortedPairs() {\n        vector<EP> ps;\n        ps.reserve(N * (N - 1) / 2);\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                ps.push_back({evalWeight(i, j), i, j});\n            }\n        }\n\n        sort(ps.begin(), ps.end());\n        return ps;\n    }\n\n    vector<int> greedyCandidate(const vector<int>& groupOrder, const vector<EP>& pairs) {\n        vector<int> gid(N, -1);\n        vector<char> alive(N, 1);\n        int rem = N;\n        int ptr = 0;\n\n        auto addCity = [&](vector<int>& sel, int v) {\n            if (!alive[v]) return;\n            alive[v] = 0;\n            rem--;\n            sel.push_back(v);\n        };\n\n        for (int gr : groupOrder) {\n            int need = G[gr];\n            vector<int> sel;\n            sel.reserve(need);\n\n            if (need == rem) {\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        gid[i] = gr;\n                        alive[i] = 0;\n                    }\n                }\n                rem = 0;\n                continue;\n            }\n\n            if (need == 1) {\n                double mx = 0.0, my = 0.0;\n\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        mx += cx[i];\n                        my += cy[i];\n                    }\n                }\n\n                mx /= rem;\n                my /= rem;\n\n                int best = -1;\n                double bestVal = -1.0;\n\n                for (int i = 0; i < N; i++) {\n                    if (alive[i]) {\n                        double dx = cx[i] - mx;\n                        double dy = cy[i] - my;\n                        double val = dx * dx + dy * dy + 0.05 * varp[i];\n\n                        if (val > bestVal) {\n                            bestVal = val;\n                            best = i;\n                        }\n                    }\n                }\n\n                addCity(sel, best);\n            } else {\n                while (ptr < (int)pairs.size() && !(alive[pairs[ptr].u] && alive[pairs[ptr].v])) {\n                    ptr++;\n                }\n\n                if (ptr < (int)pairs.size()) {\n                    addCity(sel, pairs[ptr].u);\n                    addCity(sel, pairs[ptr].v);\n                } else {\n                    for (int i = 0; i < N && (int)sel.size() < min(2, need); i++) {\n                        if (alive[i]) addCity(sel, i);\n                    }\n                }\n\n                vector<float> best(N, 1e30f);\n\n                for (int v = 0; v < N; v++) {\n                    if (alive[v]) {\n                        for (int s : sel) {\n                            best[v] = min(best[v], evalWeight(v, s));\n                        }\n                    }\n                }\n\n                while ((int)sel.size() < need) {\n                    int bv = -1;\n\n                    for (int v = 0; v < N; v++) {\n                        if (alive[v]) {\n                            if (bv == -1 || best[v] < best[bv]) bv = v;\n                        }\n                    }\n\n                    if (bv == -1) break;\n\n                    addCity(sel, bv);\n\n                    for (int v = 0; v < N; v++) {\n                        if (alive[v]) {\n                            best[v] = min(best[v], evalWeight(v, bv));\n                        }\n                    }\n                }\n            }\n\n            for (int v : sel) gid[v] = gr;\n        }\n\n        return gid;\n    }\n\n    void kdRec(vector<int> cities, vector<int> gids, vector<int>& assign, int depth, int mode, mt19937& rr) {\n        if (gids.size() == 1) {\n            int g = gids[0];\n            for (int c : cities) assign[c] = g;\n            return;\n        }\n\n        int n = (int)cities.size();\n\n        double minx = 1e100, maxx = -1e100;\n        double miny = 1e100, maxy = -1e100;\n\n        for (int c : cities) {\n            minx = min(minx, cx[c]);\n            maxx = max(maxx, cx[c]);\n            miny = min(miny, cy[c]);\n            maxy = max(maxy, cy[c]);\n        }\n\n        double rxr = maxx - minx;\n        double ryr = maxy - miny;\n\n        int axis;\n\n        if (mode % 3 == 0) axis = (rxr >= ryr ? 0 : 1);\n        else if (mode % 3 == 1) axis = depth & 1;\n        else axis = (rxr < ryr ? 0 : 1);\n\n        sort(cities.begin(), cities.end(), [&](int a, int b) {\n            double ka = axis == 0 ? cx[a] : cy[a];\n            double kb = axis == 0 ? cx[b] : cy[b];\n\n            if (ka != kb) return ka < kb;\n            return a < b;\n        });\n\n        vector<int> order = gids;\n\n        if (mode >= 3) {\n            shuffle(order.begin(), order.end(), rr);\n        } else if (mode == 1) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] > G[b];\n                return a < b;\n            });\n        } else if (mode == 2) {\n            sort(order.begin(), order.end(), [&](int a, int b) {\n                if (G[a] != G[b]) return G[a] < G[b];\n                return a < b;\n            });\n        }\n\n        vector<char> dp(n + 1, 0);\n        vector<int> parS(n + 1, -1), parG(n + 1, -1);\n\n        dp[0] = 1;\n\n        for (int g : order) {\n            int s = G[g];\n\n            for (int sum = n - s; sum >= 0; sum--) {\n                if (dp[sum] && !dp[sum + s]) {\n                    dp[sum + s] = 1;\n                    parS[sum + s] = sum;\n                    parG[sum + s] = g;\n                }\n            }\n        }\n\n        int target = n / 2;\n        int best = -1;\n        int bd = 1e9;\n\n        for (int s = 1; s < n; s++) {\n            if (dp[s]) {\n                int d = abs(s - target);\n\n                if (d < bd) {\n                    bd = d;\n                    best = s;\n                }\n            }\n        }\n\n        if (best == -1) best = G[gids[0]];\n\n        vector<char> selected(M, 0);\n        int cur = best;\n\n        while (cur > 0) {\n            int g = parG[cur];\n            if (g < 0) break;\n            selected[g] = 1;\n            cur = parS[cur];\n        }\n\n        vector<int> leftG, rightG;\n\n        for (int g : gids) {\n            if (selected[g]) leftG.push_back(g);\n            else rightG.push_back(g);\n        }\n\n        if (leftG.empty() || rightG.empty()) {\n            leftG.clear();\n            rightG.clear();\n\n            int acc = 0;\n            for (int g : gids) {\n                if (acc + G[g] <= best && leftG.empty() == false) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else if (acc < best) {\n                    leftG.push_back(g);\n                    acc += G[g];\n                } else {\n                    rightG.push_back(g);\n                }\n            }\n\n            if (leftG.empty() || rightG.empty()) {\n                leftG = {gids[0]};\n                rightG.assign(gids.begin() + 1, gids.end());\n                best = G[gids[0]];\n            }\n        }\n\n        bool flip = (mode >= 3 && ((depth + mode) & 1));\n\n        vector<int> leftC, rightC;\n\n        if (!flip) {\n            leftC.assign(cities.begin(), cities.begin() + best);\n            rightC.assign(cities.begin() + best, cities.end());\n        } else {\n            leftC.assign(cities.end() - best, cities.end());\n            rightC.assign(cities.begin(), cities.end() - best);\n        }\n\n        kdRec(leftC, leftG, assign, depth + 1, mode, rr);\n        kdRec(rightC, rightG, assign, depth + 1, mode, rr);\n    }\n\n    vector<int> kdCandidate(int mode) {\n        vector<int> cities(N), gids(M), assign(N, -1);\n\n        iota(cities.begin(), cities.end(), 0);\n        iota(gids.begin(), gids.end(), 0);\n\n        mt19937 rr(1000 + mode * 97);\n        kdRec(cities, gids, assign, 0, mode, rr);\n\n        return assign;\n    }\n\n    void buildBonus() {\n        bonusMat.assign(N * N, 0.0f);\n        bonusAdj.assign(N, {});\n\n        double unc = max(0.0, min(1.0, (W - 500) / 2000.0));\n        double coef = 0.20 + 0.30 * unc;\n        double cap = 2.0e6;\n\n        for (int i = 0; i < N; i++) {\n            for (int j = i + 1; j < N; j++) {\n                if (!known[ID(i, j)]) continue;\n\n                double d = distBase[ID(i, j)];\n                float b = (float)min(cap, coef * d * d);\n\n                bonusMat[ID(i, j)] = bonusMat[ID(j, i)] = b;\n                bonusAdj[i].push_back({j, b});\n                bonusAdj[j].push_back({i, b});\n            }\n        }\n    }\n\n    void localSearch(vector<int>& gid, int maxPass) {\n        vector<double> sxg(M, 0.0), syg(M, 0.0), sqg(M, 0.0);\n\n        for (int i = 0; i < N; i++) {\n            int g = gid[i];\n\n            sxg[g] += cx[i];\n            syg[g] += cy[i];\n            sqg[g] += norm2[i];\n        }\n\n        vector<float> ktg((size_t)N * M, 0.0f);\n\n        for (int u = 0; u < N; u++) {\n            for (auto [v, b] : bonusAdj[u]) {\n                if (u < v) {\n                    ktg[(size_t)u * M + gid[v]] += b;\n                    ktg[(size_t)v * M + gid[u]] += b;\n                }\n            }\n        }\n\n        auto deltaReplace = [&](int g, int out, int in) -> double {\n            double nsx = sxg[g] - cx[out] + cx[in];\n            double nsy = syg[g] - cy[out] + cy[in];\n\n            double oldS2 = sxg[g] * sxg[g] + syg[g] * syg[g];\n            double newS2 = nsx * nsx + nsy * nsy;\n\n            return (-norm2[out] + norm2[in]) - (newS2 - oldS2) / G[g];\n        };\n\n        auto applySwap = [&](int i, int j, int A, int B) {\n            sxg[A] += -cx[i] + cx[j];\n            syg[A] += -cy[i] + cy[j];\n            sqg[A] += -norm2[i] + norm2[j];\n\n            sxg[B] += -cx[j] + cx[i];\n            syg[B] += -cy[j] + cy[i];\n            sqg[B] += -norm2[j] + norm2[i];\n\n            for (auto [t, b] : bonusAdj[i]) {\n                ktg[(size_t)t * M + A] -= b;\n                ktg[(size_t)t * M + B] += b;\n            }\n\n            for (auto [t, b] : bonusAdj[j]) {\n                ktg[(size_t)t * M + B] -= b;\n                ktg[(size_t)t * M + A] += b;\n            }\n\n            gid[i] = B;\n            gid[j] = A;\n        };\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            int swaps = 0;\n\n            for (int i = 0; i < N; i++) {\n                for (int j = i + 1; j < N; j++) {\n                    int A = gid[i];\n                    int B = gid[j];\n\n                    if (A == B) continue;\n\n                    double ds = deltaReplace(A, i, j) + deltaReplace(B, j, i);\n\n                    float bij = bonusMat[ID(i, j)];\n                    double before = ktg[(size_t)i * M + A] + ktg[(size_t)j * M + B];\n                    double after = ktg[(size_t)i * M + B] + ktg[(size_t)j * M + A] - 2.0 * bij;\n\n                    double delta = ds - (after - before);\n\n                    if (delta < -1e-7) {\n                        applySwap(i, j, A, B);\n                        swaps++;\n                    }\n                }\n            }\n\n            if (swaps == 0) break;\n        }\n    }\n\n    vector<int> makeGrouping() {\n        if (M == 1) return vector<int>(N, 0);\n\n        struct Cand {\n            double score;\n            vector<int> gid;\n        };\n\n        vector<Cand> top;\n        const int TOPK = 8;\n\n        auto addCand = [&](vector<int> gid) {\n            double sc = evalCandidate(gid);\n            if (sc > 1e90) return;\n\n            if ((int)top.size() < TOPK) {\n                top.push_back({sc, move(gid)});\n            } else {\n                int worst = 0;\n\n                for (int i = 1; i < (int)top.size(); i++) {\n                    if (top[i].score > top[worst].score) worst = i;\n                }\n\n                if (sc < top[worst].score) {\n                    top[worst] = {sc, move(gid)};\n                }\n            }\n        };\n\n        auto cityOrders = makeCityOrders();\n        auto groupOrders = makeGroupOrders();\n\n        for (auto& co : cityOrders) {\n            for (auto& go : groupOrders) {\n                addCand(partitionCandidate(co, go));\n            }\n\n            for (int mode = 0; mode < 3; mode++) {\n                auto go = gapGreedyGroupOrder(co, mode);\n                addCand(partitionCandidate(co, go));\n            }\n        }\n\n        auto pairs = makeSortedPairs();\n\n        vector<int> ids(M);\n        iota(ids.begin(), ids.end(), 0);\n\n        vector<int> asc = ids;\n        vector<int> desc = ids;\n\n        sort(asc.begin(), asc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] < G[b];\n            return a < b;\n        });\n\n        sort(desc.begin(), desc.end(), [&](int a, int b) {\n            if (G[a] != G[b]) return G[a] > G[b];\n            return a < b;\n        });\n\n        addCand(greedyCandidate(asc, pairs));\n        addCand(greedyCandidate(ids, pairs));\n        addCand(greedyCandidate(desc, pairs));\n\n        for (int mode = 0; mode < 6; mode++) {\n            addCand(kdCandidate(mode));\n        }\n\n        if (top.empty()) {\n            auto co = cityOrders[0];\n            auto go = groupOrders[0];\n            return partitionCandidate(co, go);\n        }\n\n        sort(top.begin(), top.end(), [](const Cand& a, const Cand& b) {\n            return a.score < b.score;\n        });\n\n        buildBonus();\n\n        vector<int> best = top[0].gid;\n        double bestScore = top[0].score;\n\n        int lim = min(6, (int)top.size());\n        int passes = (M > 250 ? 12 : 9);\n\n        for (int i = 0; i < lim; i++) {\n            vector<int> gid = top[i].gid;\n\n            localSearch(gid, passes);\n\n            double sc = evalCandidate(gid);\n            if (sc < bestScore) {\n                bestScore = sc;\n                best = move(gid);\n            }\n        }\n\n        return best;\n    }\n\n    vector<vector<int>> buildGroups(const vector<int>& gid) {\n        vector<vector<int>> groups(M);\n\n        for (int k = 0; k < M; k++) {\n            groups[k].reserve(G[k]);\n        }\n\n        for (int i = 0; i < N; i++) {\n            groups[gid[i]].push_back(i);\n        }\n\n        bool ok = true;\n\n        for (int k = 0; k < M; k++) {\n            if ((int)groups[k].size() != G[k]) ok = false;\n        }\n\n        if (!ok) {\n            groups.assign(M, {});\n\n            vector<int> ids(N);\n            iota(ids.begin(), ids.end(), 0);\n\n            sort(ids.begin(), ids.end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n\n            int pos = 0;\n\n            for (int k = 0; k < M; k++) {\n                for (int t = 0; t < G[k]; t++) {\n                    groups[k].push_back(ids[pos++]);\n                }\n            }\n        }\n\n        return groups;\n    }\n\n    void promoteUsefulPreviousQueries(const vector<vector<int>>& groups) {\n        vector<int> gid(N, -1);\n        for (int k = 0; k < M; k++) {\n            for (int v : groups[k]) gid[v] = k;\n        }\n\n        vector<int> loc(N, -1);\n\n        for (const auto& rec : queryRecords) {\n            int l = (int)rec.subset.size();\n            if (l <= 1) continue;\n\n            for (int v : rec.subset) loc[v] = -1;\n            for (int i = 0; i < l; i++) loc[rec.subset[i]] = i;\n\n            vector<vector<int>> adj(l);\n            bool tree[16][16] = {};\n\n            for (auto [a, b] : rec.edges) {\n                int ia = loc[a];\n                int ib = loc[b];\n                if (ia < 0 || ib < 0) continue;\n\n                adj[ia].push_back(ib);\n                adj[ib].push_back(ia);\n                tree[ia][ib] = tree[ib][ia] = true;\n\n                if (gid[a] == gid[b]) {\n                    int id1 = ID(a, b), id2 = ID(b, a);\n                    known[id1] = max<unsigned char>(known[id1], 2);\n                    known[id2] = max<unsigned char>(known[id2], 2);\n                }\n            }\n\n            for (int si = 0; si < l; si++) {\n                for (int ti = si + 1; ti < l; ti++) {\n                    if (tree[si][ti]) continue;\n\n                    int a = rec.subset[si];\n                    int b = rec.subset[ti];\n                    if (gid[a] < 0 || gid[a] != gid[b]) continue;\n\n                    int targetGroup = gid[a];\n\n                    vector<int> parent(l, -1);\n                    queue<int> qu;\n                    parent[si] = si;\n                    qu.push(si);\n\n                    while (!qu.empty()) {\n                        int v = qu.front();\n                        qu.pop();\n\n                        if (v == ti) break;\n\n                        for (int to : adj[v]) {\n                            if (parent[to] == -1) {\n                                parent[to] = v;\n                                qu.push(to);\n                            }\n                        }\n                    }\n\n                    if (parent[ti] == -1) continue;\n\n                    bool pathInside = true;\n                    int cur = ti;\n\n                    while (cur != si) {\n                        if (gid[rec.subset[cur]] != targetGroup) {\n                            pathInside = false;\n                            break;\n                        }\n                        cur = parent[cur];\n                    }\n\n                    if (gid[rec.subset[si]] != targetGroup) pathInside = false;\n\n                    int u = a, v = b;\n                    if (u > v) swap(u, v);\n\n                    if (pathInside) {\n                        forbidden[ID(u, v)] = forbidden[ID(v, u)] = 1;\n                    } else {\n                        int id1 = ID(u, v), id2 = ID(v, u);\n                        unsigned char nv = min<int>(3, softBad[id1] + 1);\n                        softBad[id1] = softBad[id2] = nv;\n                    }\n                }\n            }\n\n            for (int v : rec.subset) loc[v] = -1;\n        }\n    }\n\n    struct FinalTask {\n        double priority;\n        int type; // 0 exact whole group, 1 large-group chunk\n        int group;\n        int chunkIndex;\n        vector<int> subset;\n    };\n\n    void performFinalQueries(\n        vector<vector<int>>& groups,\n        vector<char>& exact,\n        vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        exact.assign(M, 0);\n        exactEdges.assign(M, {});\n\n        vector<FinalTask> tasks;\n        tasks.reserve(1000);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n\n            if (g <= 2) continue;\n\n            if (g <= L) {\n                FinalTask task;\n                task.priority = 1.20 * (g - 1);\n                task.type = 0;\n                task.group = k;\n                task.chunkIndex = 0;\n                task.subset = groups[k];\n\n                tasks.push_back(move(task));\n            } else {\n                vector<int> ord = groups[k];\n\n                sort(ord.begin(), ord.end(), [&](int a, int b) {\n                    if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                    return a < b;\n                });\n\n                int connector = ord[0];\n                int pos = 1;\n                int chunkIndex = 0;\n\n                while (pos < g) {\n                    int s = min(L - 1, g - pos);\n\n                    if (s >= 2) {\n                        FinalTask task;\n                        task.priority = 0.80 * s;\n                        task.type = 1;\n                        task.group = k;\n                        task.chunkIndex = chunkIndex;\n                        task.subset.reserve(s + 1);\n                        task.subset.push_back(connector);\n\n                        for (int t = 0; t < s; t++) {\n                            task.subset.push_back(ord[pos + t]);\n                        }\n\n                        tasks.push_back(move(task));\n                    }\n\n                    connector = ord[pos + s - 1];\n                    pos += s;\n                    chunkIndex++;\n                }\n            }\n        }\n\n        sort(tasks.begin(), tasks.end(), [](const FinalTask& a, const FinalTask& b) {\n            if (a.priority != b.priority) return a.priority > b.priority;\n            if (a.type != b.type) return a.type < b.type;\n            if (a.chunkIndex != b.chunkIndex) return a.chunkIndex < b.chunkIndex;\n            return a.group < b.group;\n        });\n\n        for (auto& task : tasks) {\n            unsigned long long h = subsetHash(task.subset);\n\n            if (queryCount >= Q && responseMap.find(h) == responseMap.end()) {\n                continue;\n            }\n\n            auto ret = getOrAsk(task.subset);\n            if (ret.empty()) continue;\n\n            addQueryInfo(task.subset, ret, 2, true);\n\n            if (task.type == 0) {\n                int k = task.group;\n                int g = (int)groups[k].size();\n\n                if ((int)ret.size() == g - 1) {\n                    exact[k] = 1;\n                    exactEdges[k] = ret;\n                }\n            }\n        }\n\n        if (queryCount >= Q) return;\n\n        vector<int> candGroups;\n        int maxG = 0;\n        vector<vector<int>> ords(M);\n\n        for (int k = 0; k < M; k++) {\n            if (exact[k]) continue;\n\n            int g = (int)groups[k].size();\n            if (g < 3) continue;\n\n            candGroups.push_back(k);\n            ords[k] = groups[k];\n\n            sort(ords[k].begin(), ords[k].end(), [&](int a, int b) {\n                if (hilb[a] != hilb[b]) return hilb[a] < hilb[b];\n                return a < b;\n            });\n\n            maxG = max(maxG, g);\n        }\n\n        for (int variant = 0; variant < 5 && queryCount < Q; variant++) {\n            for (int r = 0; r < maxG && queryCount < Q; r++) {\n                for (int k : candGroups) {\n                    if (queryCount >= Q) break;\n                    if (r >= (int)ords[k].size()) continue;\n\n                    int center = ords[k][r];\n                    auto sub = buildSubsetInGroup(center, groups[k], variant);\n\n                    if ((int)sub.size() < 3) continue;\n\n                    unsigned long long h = subsetHash(sub);\n\n                    if (usedQueries.count(h)) {\n                        auto it = responseMap.find(h);\n                        if (it != responseMap.end()) {\n                            addQueryInfo(sub, it->second, 2, true);\n                        }\n                        continue;\n                    }\n\n                    auto ret = askNew(sub);\n                    addQueryInfo(sub, ret, 2, true);\n                }\n            }\n        }\n    }\n\n    vector<pair<int,int>> finalPrimEdges(const vector<int>& vs) const {\n        int n = (int)vs.size();\n        vector<pair<int,int>> edges;\n\n        if (n <= 1) return edges;\n\n        vector<float> best(n, 1e30f);\n        vector<int> par(n, -1);\n        vector<char> used(n, 0);\n\n        best[0] = 0.0f;\n\n        for (int it = 0; it < n; it++) {\n            int v = -1;\n\n            for (int i = 0; i < n; i++) {\n                if (!used[i] && (v == -1 || best[i] < best[v])) {\n                    v = i;\n                }\n            }\n\n            used[v] = 1;\n\n            if (par[v] != -1) {\n                edges.push_back({vs[v], vs[par[v]]});\n            }\n\n            for (int u = 0; u < n; u++) {\n                if (!used[u]) {\n                    int a = vs[v];\n                    int b = vs[u];\n\n                    int id = ID(a, b);\n                    float w = distBase[id];\n\n                    if (forbidden[id]) {\n                        w = w * 100.0f + 1000000.0f;\n                    } else {\n                        unsigned char lv = known[id];\n\n                        if (lv == 0 && softBad[id]) {\n                            w *= 1.0f + 0.05f * min<int>(3, softBad[id]);\n                        }\n\n                        if (lv >= 2) w *= knownFinalGroupFactor;\n                        else if (lv == 1) w *= knownFinalFactor;\n                    }\n\n                    if (w < best[u]) {\n                        best[u] = w;\n                        par[u] = v;\n                    }\n                }\n            }\n        }\n\n        return edges;\n    }\n\n    void outputAnswer(\n        const vector<vector<int>>& groups,\n        const vector<char>& exact,\n        const vector<vector<pair<int,int>>>& exactEdges\n    ) {\n        vector<vector<pair<int,int>>> ansEdges(M);\n\n        for (int k = 0; k < M; k++) {\n            int g = (int)groups[k].size();\n\n            if (g <= 1) {\n                ansEdges[k] = {};\n            } else if (g == 2) {\n                ansEdges[k] = {{groups[k][0], groups[k][1]}};\n            } else if (exact[k]) {\n                ansEdges[k] = exactEdges[k];\n            } else {\n                ansEdges[k] = finalPrimEdges(groups[k]);\n            }\n        }\n\n        cout << \"!\\n\";\n\n        for (int k = 0; k < M; k++) {\n            for (int i = 0; i < (int)groups[k].size(); i++) {\n                if (i) cout << ' ';\n                cout << groups[k][i];\n            }\n            cout << '\\n';\n\n            for (auto [a, b] : ansEdges[k]) {\n                cout << a << ' ' << b << '\\n';\n            }\n        }\n\n        cout.flush();\n    }\n\n    void solve() {\n        readInput();\n        computeDistances();\n\n        usedQueries.reserve(Q * 4 + 10);\n        responseMap.reserve(Q * 4 + 10);\n        queryRecords.reserve(Q + 10);\n\n        int reserveQ = reserveFinalQueryCount();\n        int preBudget = max(0, Q - reserveQ);\n\n        performPrequeries(preBudget);\n\n        vector<int> gid = makeGrouping();\n        auto groups = buildGroups(gid);\n\n        promoteUsefulPreviousQueries(groups);\n\n        vector<char> exact;\n        vector<vector<pair<int,int>>> exactEdges;\n\n        performFinalQueries(groups, exact, exactEdges);\n\n        outputAnswer(groups, exact, exactEdges);\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}","ahc046":"#include <bits/stdc++.h>\nusing namespace std;\n\nstatic const int MAXN = 20;\nstatic const int MAXV = 400;\nstatic const int INF = 1e9;\n\nstruct Grid {\n    uint32_t row[MAXN];\n    uint32_t col[MAXN];\n    int cnt;\n    uint64_t hash;\n    Grid() {\n        memset(row, 0, sizeof(row));\n        memset(col, 0, sizeof(col));\n        cnt = 0;\n        hash = 0;\n    }\n};\n\nstruct Solver {\n    int N, M, V;\n    int LIMIT;\n    uint32_t FULL;\n    vector<int> pos;\n\n    int rr[MAXV], cc[MAXV];\n    int mv[MAXV][4];\n    int targetIdx[MAXV];\n\n    int dr[4] = {-1, 1, 0, 0};\n    int dc[4] = {0, 0, -1, 1};\n    int opp[4] = {1, 0, 3, 2};\n\n    bool future[45][MAXV];\n    int adjVal[45][MAXV];\n\n    uint64_t zob[MAXV];\n    uint64_t rngState;\n\n    int seen[MAXV], distArr[MAXV], prevArr[MAXV], que[MAXV];\n    unsigned char actArr[MAXV];\n    int stamp = 1;\n\n    int validBits[45], inBits[45];\n    bool isPlanOpt[45][16];\n    bool isPlanFOpt[45][16];\n    vector<int> planOpts[45];\n    vector<int> planFOpts[45];\n\n    struct Plan2Opt {\n        int mask;\n        int leave;\n    };\n    vector<Plan2Opt> plan2Opts[45];\n\n    chrono::steady_clock::time_point startTime;\n\n    vector<string> candidates;\n    string pureFallback;\n\n    inline double elapsed() const {\n        return chrono::duration<double>(chrono::steady_clock::now() - startTime).count();\n    }\n\n    uint64_t rnd() {\n        uint64_t z = (rngState += 0x9e3779b97f4a7c15ULL);\n        z = (z ^ (z >> 30)) * 0xbf58476d1ce4e5b9ULL;\n        z = (z ^ (z >> 27)) * 0x94d049bb133111ebULL;\n        return z ^ (z >> 31);\n    }\n\n    inline char enc(int type, int d) const {\n        return char(type * 4 + d);\n    }\n\n    inline bool isBlocked(const Grid& g, int v) const {\n        return (g.row[rr[v]] >> cc[v]) & 1u;\n    }\n\n    inline void setBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (!(g.row[r] & br)) {\n            g.row[r] |= br;\n            g.col[c] |= (1u << r);\n            g.cnt++;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void clearBlock(Grid& g, int v) {\n        int r = rr[v], c = cc[v];\n        uint32_t br = 1u << c;\n        if (g.row[r] & br) {\n            g.row[r] &= ~br;\n            g.col[c] &= ~(1u << r);\n            g.cnt--;\n            g.hash ^= zob[v];\n        }\n    }\n\n    inline void toggleBlock(Grid& g, int v) {\n        if (isBlocked(g, v)) clearBlock(g, v);\n        else setBlock(g, v);\n    }\n\n    inline int highestBit(uint32_t x) const {\n        return 31 - __builtin_clz(x);\n    }\n\n    inline int slideDestRC(const Grid& g, int r, int c, int d) const {\n        if (d == 0) {\n            uint32_t mask = g.col[c] & ((1u << r) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return (b + 1) * N + c;\n            }\n            return c;\n        } else if (d == 1) {\n            uint32_t mask = g.col[c] & (FULL ^ ((1u << (r + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return (b - 1) * N + c;\n            }\n            return (N - 1) * N + c;\n        } else if (d == 2) {\n            uint32_t mask = g.row[r] & ((1u << c) - 1u);\n            if (mask) {\n                int b = highestBit(mask);\n                return r * N + (b + 1);\n            }\n            return r * N;\n        } else {\n            uint32_t mask = g.row[r] & (FULL ^ ((1u << (c + 1)) - 1u));\n            if (mask) {\n                int b = __builtin_ctz(mask);\n                return r * N + (b - 1);\n            }\n            return r * N + (N - 1);\n        }\n    }\n\n    inline int slideDest(const Grid& g, int v, int d) const {\n        return slideDestRC(g, rr[v], cc[v], d);\n    }\n\n    void nextStamp() {\n        ++stamp;\n        if (stamp == INT_MAX) {\n            memset(seen, 0, sizeof(seen));\n            stamp = 1;\n        }\n    }\n\n    int bfsSearch(const Grid& g, int s, int t, bool storePath) {\n        if (s < 0 || t < 0) return INF;\n        if (isBlocked(g, s) || isBlocked(g, t)) return INF;\n        if (s == t) return 0;\n\n        nextStamp();\n        int head = 0, tail = 0;\n        que[tail++] = s;\n        seen[s] = stamp;\n        distArr[s] = 0;\n        if (storePath) prevArr[s] = -1;\n\n        while (head < tail) {\n            int v = que[head++];\n            int nd = distArr[v] + 1;\n            int r = rr[v], c = cc[v];\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDestRC(g, r, c, d);\n                if (to == v) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(1, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[v][d];\n                if (to < 0 || isBlocked(g, to)) continue;\n                if (seen[to] == stamp) continue;\n                seen[to] = stamp;\n                distArr[to] = nd;\n                if (storePath) {\n                    prevArr[to] = v;\n                    actArr[to] = enc(0, d);\n                }\n                if (to == t) return nd;\n                que[tail++] = to;\n            }\n        }\n        return INF;\n    }\n\n    int bfsDist(const Grid& g, int s, int t) {\n        return bfsSearch(g, s, t, false);\n    }\n\n    bool bfsPath(const Grid& g, int s, int t, string& out) {\n        int d = bfsSearch(g, s, t, true);\n        if (d >= INF) return false;\n        out.clear();\n        int v = t;\n        while (v != s) {\n            out.push_back(char(actArr[v]));\n            v = prevArr[v];\n            if (v < 0) return false;\n        }\n        reverse(out.begin(), out.end());\n        return true;\n    }\n\n    int gridValue(const Grid& g, int stage) const {\n        if (stage < 0) stage = 0;\n        if (stage >= M) stage = M - 1;\n        int val = 0;\n        for (int r = 0; r < N; r++) {\n            uint32_t bits = g.row[r];\n            while (bits) {\n                int c = __builtin_ctz(bits);\n                val += adjVal[stage][r * N + c];\n                bits &= bits - 1;\n            }\n        }\n        return val;\n    }\n\n    void init() {\n        V = N * N;\n        LIMIT = 2 * N * M;\n        FULL = (1u << N) - 1u;\n\n        for (int v = 0; v < V; v++) {\n            rr[v] = v / N;\n            cc[v] = v % N;\n            targetIdx[v] = -1;\n        }\n        for (int i = 0; i < M; i++) targetIdx[pos[i]] = i;\n\n        for (int v = 0; v < V; v++) {\n            for (int d = 0; d < 4; d++) {\n                int nr = rr[v] + dr[d];\n                int nc = cc[v] + dc[d];\n                if (0 <= nr && nr < N && 0 <= nc && nc < N) mv[v][d] = nr * N + nc;\n                else mv[v][d] = -1;\n            }\n        }\n\n        memset(future, 0, sizeof(future));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) future[k][pos[t]] = true;\n        }\n\n        memset(adjVal, 0, sizeof(adjVal));\n        for (int k = 0; k < M; k++) {\n            for (int t = k + 1; t < M; t++) {\n                int w = max(1, 8 - (t - k));\n                for (int d = 0; d < 4; d++) {\n                    int v = mv[pos[t]][d];\n                    if (v >= 0) adjVal[k][v] += w;\n                }\n            }\n        }\n\n        rngState = 1234567891234567ULL;\n        for (int p : pos) {\n            rngState ^= uint64_t(p + 1009) * 0x9e3779b97f4a7c15ULL;\n            rnd();\n        }\n        for (int i = 0; i < V; i++) zob[i] = rnd();\n\n        memset(seen, 0, sizeof(seen));\n        memset(isPlanOpt, 0, sizeof(isPlanOpt));\n        memset(isPlanFOpt, 0, sizeof(isPlanFOpt));\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            inBits[k] = 0;\n            validBits[k] = 0;\n            for (int d = 0; d < 4; d++) {\n                int q = mv[p][d];\n                if (q < 0) continue;\n                inBits[k] |= (1 << d);\n                if (!future[k][q]) validBits[k] |= (1 << d);\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~validBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planOpts[k].push_back(sub);\n                isPlanOpt[k][sub] = true;\n            }\n            if (planOpts[k].empty()) {\n                planOpts[k].push_back(0);\n                isPlanOpt[k][0] = true;\n            }\n\n            for (int sub = 0; sub < 16; sub++) {\n                if (sub & ~inBits[k]) continue;\n                if (__builtin_popcount((unsigned)sub) > 3) continue;\n                if ((sub & inBits[k]) == inBits[k]) continue;\n                planFOpts[k].push_back(sub);\n                isPlanFOpt[k][sub] = true;\n            }\n            if (planFOpts[k].empty()) {\n                planFOpts[k].push_back(0);\n                isPlanFOpt[k][0] = true;\n            }\n\n            for (int m : planOpts[k]) {\n                plan2Opts[k].push_back({m, -1});\n                for (int d = 0; d < 4; d++) {\n                    if (mv[p][d] < 0) continue;\n                    if (m & (1 << d)) continue;\n                    plan2Opts[k].push_back({m, d});\n                }\n            }\n        }\n    }\n\n    string makePureMoves() {\n        string s;\n        int r = rr[pos[0]], c = cc[pos[0]];\n        for (int k = 1; k < M; k++) {\n            int gr = rr[pos[k]], gc = cc[pos[k]];\n            while (r < gr) s.push_back(enc(0, 1)), r++;\n            while (r > gr) s.push_back(enc(0, 0)), r--;\n            while (c < gc) s.push_back(enc(0, 3)), c++;\n            while (c > gc) s.push_back(enc(0, 2)), c--;\n        }\n        return s;\n    }\n\n    int firstCompletionPrefix(const string& acts) {\n        if (M <= 1) return 0;\n\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return -1;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return -1;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(g, p, d);\n            } else {\n                int to = mv[p][d];\n                if (to < 0) return -1;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                nxt++;\n                if (nxt == M) return t + 1;\n            }\n        }\n        return -1;\n    }\n\n    void addCandidate(const string& acts) {\n        int p = firstCompletionPrefix(acts);\n        if (p < 0 || p > LIMIT) return;\n        candidates.push_back(acts.substr(0, p));\n    }\n\n    string greedyDelete(string a, double endTime = 1.90) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return \"\";\n        a.resize(pref);\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (size_t i = 0; i < a.size();) {\n                if (elapsed() > endTime) return a;\n                string b = a;\n                b.erase(b.begin() + i);\n                int p = firstCompletionPrefix(b);\n                if (p >= 0 && p <= LIMIT) {\n                    b.resize(p);\n                    a.swap(b);\n                    changed = true;\n                    if (i > 0) --i;\n                    if (i > a.size()) i = a.size();\n                } else {\n                    ++i;\n                }\n            }\n            if (!changed) break;\n        }\n\n        for (int w = 2; w <= 3; w++) {\n            bool any = true;\n            while (any) {\n                any = false;\n                for (size_t i = 0; i + w <= a.size();) {\n                    if (elapsed() > endTime + 0.02) return a;\n                    string b = a;\n                    b.erase(i, w);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        a.swap(b);\n                        any = true;\n                        if (i > 0) --i;\n                        if (i > a.size()) i = a.size();\n                    } else {\n                        ++i;\n                    }\n                }\n            }\n        }\n\n        return a;\n    }\n\n    string replaceImprove(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        a = greedyDelete(a, min(endTime, 1.91));\n\n        for (int pass = 0; pass < 2; pass++) {\n            bool changed = false;\n            for (int i = 0; i < (int)a.size() && elapsed() < endTime; i++) {\n                string bestLocal;\n                int bestLen = (int)a.size();\n\n                for (int code = 0; code < 12 && elapsed() < endTime; code++) {\n                    if (code == (unsigned char)a[i]) continue;\n\n                    string b = a;\n                    b[i] = char(code);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        } else if ((int)b.size() == (int)a.size()) {\n                            int L = max(0, i - 6);\n                            int R = min((int)b.size(), i + 12);\n                            for (int j = L; j < R && elapsed() < endTime; j++) {\n                                string c = b;\n                                c.erase(c.begin() + j);\n                                int pp = firstCompletionPrefix(c);\n                                if (pp >= 0 && pp <= LIMIT) {\n                                    c.resize(pp);\n                                    if ((int)c.size() < bestLen) {\n                                        bestLen = (int)c.size();\n                                        bestLocal = c;\n                                    }\n                                }\n                            }\n                        }\n                    }\n                }\n\n                if (i + 1 < (int)a.size() && elapsed() < endTime) {\n                    string b = a;\n                    swap(b[i], b[i + 1]);\n                    int p = firstCompletionPrefix(b);\n                    if (p >= 0 && p <= LIMIT) {\n                        b.resize(p);\n                        if ((int)b.size() < bestLen) {\n                            bestLen = (int)b.size();\n                            bestLocal = b;\n                        }\n                    }\n                }\n\n                if (!bestLocal.empty() && bestLen < (int)a.size()) {\n                    string del = greedyDelete(bestLocal, min(endTime, 1.93));\n                    int pp = firstCompletionPrefix(del);\n                    if (pp >= 0 && pp <= LIMIT) {\n                        del.resize(pp);\n                        if (del.size() < bestLocal.size()) bestLocal.swap(del);\n                    }\n                    if (bestLocal.size() < a.size()) {\n                        a.swap(bestLocal);\n                        changed = true;\n                        i = max(-1, i - 6);\n                    }\n                }\n            }\n            if (!changed) break;\n        }\n        return a;\n    }\n\n    bool sameGrid(const Grid& a, const Grid& b) const {\n        for (int r = 0; r < N; r++) {\n            if (a.row[r] != b.row[r]) return false;\n        }\n        return true;\n    }\n\n    struct SegInfo {\n        int k, l, r;\n        Grid sg, eg;\n    };\n\n    bool simulateSegments(const string& acts, vector<SegInfo>& segs) {\n        segs.clear();\n        Grid g;\n        int p = pos[0];\n        int nxt = 1;\n        int segL = 0;\n        Grid sg = g;\n\n        for (int t = 0; t < (int)acts.size(); t++) {\n            int code = (unsigned char)acts[t];\n            if (code < 0 || code >= 12) return false;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(g, to)) return false;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(g, p, d);\n            } else {\n                int to = mv[p][d];\n                if (to < 0) return false;\n                toggleBlock(g, to);\n            }\n\n            if (type != 2 && nxt < M && p == pos[nxt]) {\n                segs.push_back({nxt - 1, segL, t + 1, sg, g});\n                nxt++;\n                segL = t + 1;\n                sg = g;\n                if (nxt == M) return true;\n            }\n        }\n        return nxt == M;\n    }\n\n    string optimizeOneSegment(const SegInfo& seg, const string& orig, double endTime) {\n        if ((int)orig.size() <= 1) return orig;\n        if (elapsed() > endTime) return orig;\n\n        const int CAP = 10;\n        array<int, MAXV> mark;\n        mark.fill(-1);\n        vector<int> cells;\n\n        auto addCell = [&](int v) {\n            if (v < 0) return;\n            if (mark[v] == -1) {\n                mark[v] = (int)cells.size();\n                cells.push_back(v);\n            }\n        };\n\n        Grid tg = seg.sg;\n        int p = pos[seg.k];\n        int goal = pos[seg.k + 1];\n        vector<int> stops;\n        stops.push_back(p);\n\n        for (unsigned char ch : orig) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(tg, to)) return orig;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(tg, p, d);\n            } else {\n                int q = mv[p][d];\n                if (q < 0) return orig;\n                addCell(q);\n                toggleBlock(tg, q);\n            }\n            stops.push_back(p);\n        }\n\n        if (p != goal) return orig;\n        if (!sameGrid(tg, seg.eg)) return orig;\n\n        for (int v = 0; v < V; v++) {\n            if (isBlocked(seg.sg, v) != isBlocked(seg.eg, v)) addCell(v);\n        }\n\n        if ((int)cells.size() > CAP) return orig;\n\n        array<char, MAXV> exSeen{};\n        vector<pair<int, int>> extras;\n\n        for (int st : stops) {\n            for (int d = 0; d < 4; d++) {\n                int q = mv[st][d];\n                if (q < 0) continue;\n                if (mark[q] != -1 || exSeen[q]) continue;\n                exSeen[q] = 1;\n\n                int sc = adjVal[seg.k][q];\n                if (isBlocked(seg.sg, q)) sc += 50;\n                if (isBlocked(seg.eg, q)) sc += 20;\n\n                int dg = abs(rr[q] - rr[goal]) + abs(cc[q] - cc[goal]);\n                int ds = abs(rr[q] - rr[pos[seg.k]]) + abs(cc[q] - cc[pos[seg.k]]);\n                if (dg == 1) sc += 6;\n                if (ds == 1) sc += 2;\n\n                if (targetIdx[q] >= seg.k + 1) sc -= 8;\n                extras.push_back({-sc, q});\n            }\n        }\n\n        sort(extras.begin(), extras.end());\n        int baseK = (int)cells.size();\n        int neutralLimit = min(CAP, baseK + 2);\n\n        for (auto [negSc, q] : extras) {\n            if ((int)cells.size() >= CAP) break;\n            int sc = -negSc;\n            bool safeNeutral = (targetIdx[q] < seg.k + 1);\n            if (sc > 0 || ((int)cells.size() < neutralLimit && safeNeutral)) {\n                addCell(q);\n            }\n        }\n\n        int K = (int)cells.size();\n        if (K > CAP) return orig;\n        int S = 1 << K;\n\n        array<int, MAXV> cid;\n        cid.fill(-1);\n        for (int i = 0; i < K; i++) cid[cells[i]] = i;\n\n        int endMask = 0;\n        for (int i = 0; i < K; i++) {\n            int v = cells[i];\n            if (isBlocked(seg.sg, v) != isBlocked(seg.eg, v)) endMask |= (1 << i);\n        }\n\n        vector<array<uint32_t, MAXN>> rows(S), cols(S);\n        for (int r = 0; r < N; r++) rows[0][r] = seg.sg.row[r];\n        for (int c = 0; c < N; c++) cols[0][c] = seg.sg.col[c];\n\n        for (int m = 1; m < S; m++) {\n            int b = __builtin_ctz((unsigned)m);\n            int pm = m & (m - 1);\n            rows[m] = rows[pm];\n            cols[m] = cols[pm];\n\n            int v = cells[b];\n            rows[m][rr[v]] ^= (1u << cc[v]);\n            cols[m][cc[v]] ^= (1u << rr[v]);\n        }\n\n        auto blockedM = [&](int mask, int v) -> bool {\n            return (rows[mask][rr[v]] >> cc[v]) & 1u;\n        };\n\n        if (blockedM(0, pos[seg.k])) return orig;\n        if (blockedM(endMask, goal)) return orig;\n\n        auto slideM = [&](int mask, int v, int d) -> int {\n            int r = rr[v], c = cc[v];\n            if (d == 0) {\n                uint32_t bits = cols[mask][c] & ((1u << r) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return (b + 1) * N + c;\n                }\n                return c;\n            } else if (d == 1) {\n                uint32_t bits = cols[mask][c] & (FULL ^ ((1u << (r + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return (b - 1) * N + c;\n                }\n                return (N - 1) * N + c;\n            } else if (d == 2) {\n                uint32_t bits = rows[mask][r] & ((1u << c) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return r * N + (b + 1);\n                }\n                return r * N;\n            } else {\n                uint32_t bits = rows[mask][r] & (FULL ^ ((1u << (c + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return r * N + (b - 1);\n                }\n                return r * N + (N - 1);\n            }\n        };\n\n        int total = S * V;\n        vector<int> dist(total, -1), par(total, -1);\n        vector<unsigned char> pact(total, 255);\n        vector<int> q;\n        q.reserve(min(total, 200000));\n\n        int startState = pos[seg.k];\n        int goalState = endMask * V + goal;\n        dist[startState] = 0;\n        q.push_back(startState);\n\n        bool found = (startState == goalState);\n        int head = 0;\n        int maxDepth = (int)orig.size() - 1;\n\n        auto tryAdd = [&](int id, int nm, int np, unsigned char ac) -> bool {\n            if (np == goal && nm != endMask) return false;\n            int nid = nm * V + np;\n            if (dist[nid] != -1) return false;\n\n            dist[nid] = dist[id] + 1;\n            par[nid] = id;\n            pact[nid] = ac;\n\n            if (nid == goalState) return true;\n            q.push_back(nid);\n            return false;\n        };\n\n        while (head < (int)q.size() && !found) {\n            if (elapsed() > endTime) return orig;\n            int id = q[head++];\n            int mask = id / V;\n            int v = id - mask * V;\n\n            if (dist[id] >= maxDepth) continue;\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = slideM(mask, v, d);\n                if (to == v) continue;\n                found = tryAdd(id, mask, to, enc(1, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = mv[v][d];\n                if (to < 0 || blockedM(mask, to)) continue;\n                found = tryAdd(id, mask, to, enc(0, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int cell = mv[v][d];\n                if (cell < 0) continue;\n                int ci = cid[cell];\n                if (ci < 0) continue;\n                int nm = mask ^ (1 << ci);\n                found = tryAdd(id, nm, v, enc(2, d));\n            }\n        }\n\n        if (!found || dist[goalState] < 0) return orig;\n        if (dist[goalState] >= (int)orig.size()) return orig;\n\n        string res;\n        int id = goalState;\n        while (id != startState) {\n            res.push_back(char(pact[id]));\n            id = par[id];\n            if (id < 0) return orig;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    string optimizeOnePair(const SegInfo& s1, const SegInfo& s2, const string& orig, double endTime) {\n        if ((int)orig.size() <= 2) return orig;\n        if (elapsed() > endTime) return orig;\n\n        const int CAP = 10;\n        int k = s1.k;\n        int start = pos[k];\n        int mid = pos[k + 1];\n        int goal = pos[k + 2];\n\n        array<int, MAXV> mark;\n        mark.fill(-1);\n        vector<int> cells;\n\n        auto addCell = [&](int v) {\n            if (v < 0) return;\n            if (mark[v] == -1) {\n                mark[v] = (int)cells.size();\n                cells.push_back(v);\n            }\n        };\n\n        Grid tg = s1.sg;\n        int p = start;\n        int nxt = k + 1;\n        vector<int> stops;\n        stops.push_back(p);\n\n        for (unsigned char ch : orig) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(tg, to)) return orig;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(tg, p, d);\n            } else {\n                int q = mv[p][d];\n                if (q < 0) return orig;\n                addCell(q);\n                toggleBlock(tg, q);\n            }\n\n            stops.push_back(p);\n\n            if (type != 2 && nxt <= k + 2 && p == pos[nxt]) {\n                nxt++;\n            }\n        }\n\n        if (p != goal || nxt != k + 3) return orig;\n        if (!sameGrid(tg, s2.eg)) return orig;\n\n        for (int v = 0; v < V; v++) {\n            if (isBlocked(s1.sg, v) != isBlocked(s2.eg, v)) addCell(v);\n        }\n\n        if ((int)cells.size() > CAP) return orig;\n\n        array<char, MAXV> exSeen{};\n        vector<pair<int, int>> extras;\n\n        for (int st : stops) {\n            for (int d = 0; d < 4; d++) {\n                int q = mv[st][d];\n                if (q < 0) continue;\n                if (mark[q] != -1 || exSeen[q]) continue;\n                exSeen[q] = 1;\n\n                int sc = adjVal[k][q];\n                if (isBlocked(s1.sg, q)) sc += 40;\n                if (isBlocked(s2.eg, q)) sc += 20;\n\n                int dm = abs(rr[q] - rr[mid]) + abs(cc[q] - cc[mid]);\n                int dg = abs(rr[q] - rr[goal]) + abs(cc[q] - cc[goal]);\n                if (dm == 1) sc += 5;\n                if (dg == 1) sc += 5;\n\n                if (targetIdx[q] >= k + 1) sc -= 8;\n                extras.push_back({-sc, q});\n            }\n        }\n\n        sort(extras.begin(), extras.end());\n\n        int baseK = (int)cells.size();\n        int neutralLimit = min(CAP, baseK + 2);\n        for (auto [negSc, q] : extras) {\n            if ((int)cells.size() >= CAP) break;\n            int sc = -negSc;\n            bool safeNeutral = (targetIdx[q] < k + 1);\n            if (sc > 0 || ((int)cells.size() < neutralLimit && safeNeutral)) {\n                addCell(q);\n            }\n        }\n\n        int K = (int)cells.size();\n        if (K > CAP) return orig;\n        int S = 1 << K;\n\n        array<int, MAXV> cid;\n        cid.fill(-1);\n        for (int i = 0; i < K; i++) cid[cells[i]] = i;\n\n        int endMask = 0;\n        for (int i = 0; i < K; i++) {\n            int v = cells[i];\n            if (isBlocked(s1.sg, v) != isBlocked(s2.eg, v)) endMask |= (1 << i);\n        }\n\n        vector<array<uint32_t, MAXN>> rows(S), cols(S);\n        for (int r = 0; r < N; r++) rows[0][r] = s1.sg.row[r];\n        for (int c = 0; c < N; c++) cols[0][c] = s1.sg.col[c];\n\n        for (int m = 1; m < S; m++) {\n            int b = __builtin_ctz((unsigned)m);\n            int pm = m & (m - 1);\n            rows[m] = rows[pm];\n            cols[m] = cols[pm];\n\n            int v = cells[b];\n            rows[m][rr[v]] ^= (1u << cc[v]);\n            cols[m][cc[v]] ^= (1u << rr[v]);\n        }\n\n        auto blockedM = [&](int mask, int v) -> bool {\n            return (rows[mask][rr[v]] >> cc[v]) & 1u;\n        };\n\n        if (blockedM(0, start)) return orig;\n        if (blockedM(endMask, goal)) return orig;\n\n        auto slideM = [&](int mask, int v, int d) -> int {\n            int r = rr[v], c = cc[v];\n            if (d == 0) {\n                uint32_t bits = cols[mask][c] & ((1u << r) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return (b + 1) * N + c;\n                }\n                return c;\n            } else if (d == 1) {\n                uint32_t bits = cols[mask][c] & (FULL ^ ((1u << (r + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return (b - 1) * N + c;\n                }\n                return (N - 1) * N + c;\n            } else if (d == 2) {\n                uint32_t bits = rows[mask][r] & ((1u << c) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return r * N + (b + 1);\n                }\n                return r * N;\n            } else {\n                uint32_t bits = rows[mask][r] & (FULL ^ ((1u << (c + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return r * N + (b - 1);\n                }\n                return r * N + (N - 1);\n            }\n        };\n\n        int phaseMul = S * V;\n        int total = 2 * phaseMul;\n\n        vector<int> dist(total, -1), par(total, -1);\n        vector<unsigned char> pact(total, 255);\n        vector<int> q;\n        q.reserve(min(total, 200000));\n\n        auto stateId = [&](int phase, int mask, int v) {\n            return phase * phaseMul + mask * V + v;\n        };\n\n        int startState = stateId(0, 0, start);\n        int goalState = stateId(1, endMask, goal);\n\n        dist[startState] = 0;\n        q.push_back(startState);\n\n        bool found = (startState == goalState);\n        int head = 0;\n        int maxDepth = (int)orig.size() - 1;\n\n        auto tryAdd = [&](int id, int nphase, int nm, int np, unsigned char ac) -> bool {\n            if (nphase == 1 && np == goal && nm != endMask) return false;\n\n            int nid = stateId(nphase, nm, np);\n            if (dist[nid] != -1) return false;\n\n            dist[nid] = dist[id] + 1;\n            par[nid] = id;\n            pact[nid] = ac;\n\n            if (nid == goalState) return true;\n            q.push_back(nid);\n            return false;\n        };\n\n        while (head < (int)q.size() && !found) {\n            if (elapsed() > endTime) return orig;\n            int id = q[head++];\n\n            int phase = id / phaseMul;\n            int rem = id - phase * phaseMul;\n            int mask = rem / V;\n            int v = rem - mask * V;\n\n            if (dist[id] >= maxDepth) continue;\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = slideM(mask, v, d);\n                if (to == v) continue;\n                int np = phase;\n                if (phase == 0 && to == mid) np = 1;\n                found = tryAdd(id, np, mask, to, enc(1, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = mv[v][d];\n                if (to < 0 || blockedM(mask, to)) continue;\n                int np = phase;\n                if (phase == 0 && to == mid) np = 1;\n                found = tryAdd(id, np, mask, to, enc(0, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int cell = mv[v][d];\n                if (cell < 0) continue;\n                int ci = cid[cell];\n                if (ci < 0) continue;\n                int nm = mask ^ (1 << ci);\n                found = tryAdd(id, phase, nm, v, enc(2, d));\n            }\n        }\n\n        if (!found || dist[goalState] < 0) return orig;\n        if (dist[goalState] >= (int)orig.size()) return orig;\n\n        string res;\n        int id = goalState;\n        while (id != startState) {\n            res.push_back(char(pact[id]));\n            id = par[id];\n            if (id < 0) return orig;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    string optimizeMultiSegments(const vector<SegInfo>& ss, const string& orig, double endTime, int CAP = 9) {\n        int P = (int)ss.size();\n        if (P < 3 || (int)orig.size() <= P) return orig;\n        if (elapsed() > endTime) return orig;\n\n        int k = ss[0].k;\n        int start = pos[k];\n        int finalGoal = pos[k + P];\n\n        array<int, MAXV> mark;\n        mark.fill(-1);\n        vector<int> cells;\n\n        auto addCell = [&](int v) {\n            if (v < 0) return;\n            if (mark[v] == -1) {\n                mark[v] = (int)cells.size();\n                cells.push_back(v);\n            }\n        };\n\n        Grid tg = ss[0].sg;\n        int p = start;\n        int nxt = k + 1;\n        vector<int> stops;\n        stops.push_back(p);\n\n        for (unsigned char ch : orig) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n\n            if (type == 0) {\n                int to = mv[p][d];\n                if (to < 0 || isBlocked(tg, to)) return orig;\n                p = to;\n            } else if (type == 1) {\n                p = slideDest(tg, p, d);\n            } else {\n                int q = mv[p][d];\n                if (q < 0) return orig;\n                addCell(q);\n                toggleBlock(tg, q);\n            }\n\n            stops.push_back(p);\n\n            if (type != 2 && nxt <= k + P && p == pos[nxt]) {\n                nxt++;\n            }\n        }\n\n        if (p != finalGoal || nxt != k + P + 1) return orig;\n        if (!sameGrid(tg, ss.back().eg)) return orig;\n\n        for (int v = 0; v < V; v++) {\n            if (isBlocked(ss[0].sg, v) != isBlocked(ss.back().eg, v)) addCell(v);\n        }\n\n        if ((int)cells.size() > CAP) return orig;\n\n        array<char, MAXV> exSeen{};\n        vector<pair<int, int>> extras;\n\n        for (int st : stops) {\n            for (int d = 0; d < 4; d++) {\n                int q = mv[st][d];\n                if (q < 0) continue;\n                if (mark[q] != -1 || exSeen[q]) continue;\n                exSeen[q] = 1;\n\n                int sc = adjVal[k][q];\n                if (isBlocked(ss[0].sg, q)) sc += 35;\n                if (isBlocked(ss.back().eg, q)) sc += 20;\n\n                for (int t = k + 1; t <= k + P; t++) {\n                    int dt = abs(rr[q] - rr[pos[t]]) + abs(cc[q] - cc[pos[t]]);\n                    if (dt == 1) sc += 4;\n                }\n\n                if (targetIdx[q] >= k + 1) sc -= 8;\n                extras.push_back({-sc, q});\n            }\n        }\n\n        sort(extras.begin(), extras.end());\n\n        int baseK = (int)cells.size();\n        int neutralLimit = min(CAP, baseK + 2);\n        for (auto [negSc, q] : extras) {\n            if ((int)cells.size() >= CAP) break;\n            int sc = -negSc;\n            bool safeNeutral = (targetIdx[q] < k + 1);\n            if (sc > 0 || ((int)cells.size() < neutralLimit && safeNeutral)) {\n                addCell(q);\n            }\n        }\n\n        int K = (int)cells.size();\n        if (K > CAP) return orig;\n        int S = 1 << K;\n\n        array<int, MAXV> cid;\n        cid.fill(-1);\n        for (int i = 0; i < K; i++) cid[cells[i]] = i;\n\n        int endMask = 0;\n        for (int i = 0; i < K; i++) {\n            int v = cells[i];\n            if (isBlocked(ss[0].sg, v) != isBlocked(ss.back().eg, v)) endMask |= (1 << i);\n        }\n\n        vector<array<uint32_t, MAXN>> rows(S), cols(S);\n        for (int r = 0; r < N; r++) rows[0][r] = ss[0].sg.row[r];\n        for (int c = 0; c < N; c++) cols[0][c] = ss[0].sg.col[c];\n\n        for (int m = 1; m < S; m++) {\n            int b = __builtin_ctz((unsigned)m);\n            int pm = m & (m - 1);\n            rows[m] = rows[pm];\n            cols[m] = cols[pm];\n\n            int v = cells[b];\n            rows[m][rr[v]] ^= (1u << cc[v]);\n            cols[m][cc[v]] ^= (1u << rr[v]);\n        }\n\n        auto blockedM = [&](int mask, int v) -> bool {\n            return (rows[mask][rr[v]] >> cc[v]) & 1u;\n        };\n\n        if (blockedM(0, start)) return orig;\n        if (blockedM(endMask, finalGoal)) return orig;\n\n        auto slideM = [&](int mask, int v, int d) -> int {\n            int r = rr[v], c = cc[v];\n            if (d == 0) {\n                uint32_t bits = cols[mask][c] & ((1u << r) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return (b + 1) * N + c;\n                }\n                return c;\n            } else if (d == 1) {\n                uint32_t bits = cols[mask][c] & (FULL ^ ((1u << (r + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return (b - 1) * N + c;\n                }\n                return (N - 1) * N + c;\n            } else if (d == 2) {\n                uint32_t bits = rows[mask][r] & ((1u << c) - 1u);\n                if (bits) {\n                    int b = highestBit(bits);\n                    return r * N + (b + 1);\n                }\n                return r * N;\n            } else {\n                uint32_t bits = rows[mask][r] & (FULL ^ ((1u << (c + 1)) - 1u));\n                if (bits) {\n                    int b = __builtin_ctz(bits);\n                    return r * N + (b - 1);\n                }\n                return r * N + (N - 1);\n            }\n        };\n\n        int phaseCount = P;\n        int phaseMul = S * V;\n        int total = phaseCount * phaseMul;\n\n        vector<int> dist(total, -1), par(total, -1);\n        vector<unsigned char> pact(total, 255);\n        vector<int> q;\n        q.reserve(min(total, 200000));\n\n        auto stateId = [&](int phase, int mask, int v) {\n            return phase * phaseMul + mask * V + v;\n        };\n\n        int startState = stateId(0, 0, start);\n        int goalState = stateId(P - 1, endMask, finalGoal);\n\n        dist[startState] = 0;\n        q.push_back(startState);\n\n        bool found = (startState == goalState);\n        int head = 0;\n        int maxDepth = (int)orig.size() - 1;\n\n        auto advancePhase = [&](int phase, int to) {\n            if (phase < P - 1 && to == pos[k + phase + 1]) return phase + 1;\n            return phase;\n        };\n\n        auto tryAdd = [&](int id, int nphase, int nm, int np, unsigned char ac) -> bool {\n            if (nphase == P - 1 && np == finalGoal && nm != endMask) return false;\n\n            int nid = stateId(nphase, nm, np);\n            if (dist[nid] != -1) return false;\n\n            dist[nid] = dist[id] + 1;\n            par[nid] = id;\n            pact[nid] = ac;\n\n            if (nid == goalState) return true;\n            q.push_back(nid);\n            return false;\n        };\n\n        while (head < (int)q.size() && !found) {\n            if (elapsed() > endTime) return orig;\n            int id = q[head++];\n\n            int phase = id / phaseMul;\n            int rem = id - phase * phaseMul;\n            int mask = rem / V;\n            int v = rem - mask * V;\n\n            if (dist[id] >= maxDepth) continue;\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = slideM(mask, v, d);\n                if (to == v) continue;\n                int np = advancePhase(phase, to);\n                found = tryAdd(id, np, mask, to, enc(1, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int to = mv[v][d];\n                if (to < 0 || blockedM(mask, to)) continue;\n                int np = advancePhase(phase, to);\n                found = tryAdd(id, np, mask, to, enc(0, d));\n            }\n\n            for (int d = 0; d < 4 && !found; d++) {\n                int cell = mv[v][d];\n                if (cell < 0) continue;\n                int ci = cid[cell];\n                if (ci < 0) continue;\n                int nm = mask ^ (1 << ci);\n                found = tryAdd(id, phase, nm, v, enc(2, d));\n            }\n        }\n\n        if (!found || dist[goalState] < 0) return orig;\n        if (dist[goalState] >= (int)orig.size()) return orig;\n\n        string res;\n        int id = goalState;\n        while (id != startState) {\n            res.push_back(char(pact[id]));\n            id = par[id];\n            if (id < 0) return orig;\n        }\n        reverse(res.begin(), res.end());\n        return res;\n    }\n\n    string segmentOptimize(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        string originalAll = a;\n\n        for (int pass = 0; pass < 3; pass++) {\n            vector<SegInfo> segs;\n            if (!simulateSegments(a, segs)) return originalAll;\n            if ((int)segs.size() != M - 1) return originalAll;\n\n            bool changed = false;\n            int shift = 0;\n\n            for (int si = 0; si < (int)segs.size() && elapsed() < endTime; si++) {\n                int l = segs[si].l + shift;\n                int r = segs[si].r + shift;\n                if (l < 0 || r < l || r > (int)a.size()) return originalAll;\n\n                string orig = a.substr(l, r - l);\n                string rep = optimizeOneSegment(segs[si], orig, endTime);\n\n                if (rep.size() < orig.size()) {\n                    a.replace(l, orig.size(), rep);\n                    shift += (int)rep.size() - (int)orig.size();\n                    changed = true;\n                }\n            }\n\n            int p = firstCompletionPrefix(a);\n            if (p < 0 || p > LIMIT) return originalAll;\n            a.resize(p);\n\n            if (!changed) break;\n        }\n\n        return a;\n    }\n\n    string pairSegmentOptimize(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        string originalAll = a;\n\n        for (int pass = 0; pass < 2; pass++) {\n            vector<SegInfo> segs;\n            if (!simulateSegments(a, segs)) return originalAll;\n            if ((int)segs.size() != M - 1) return originalAll;\n\n            bool changed = false;\n            int shift = 0;\n\n            for (int si = 0; si + 1 < (int)segs.size() && elapsed() < endTime; si++) {\n                int l = segs[si].l + shift;\n                int r = segs[si + 1].r + shift;\n                if (l < 0 || r < l || r > (int)a.size()) return originalAll;\n\n                string orig = a.substr(l, r - l);\n                string rep = optimizeOnePair(segs[si], segs[si + 1], orig, endTime);\n\n                if (rep.size() < orig.size()) {\n                    a.replace(l, orig.size(), rep);\n                    shift += (int)rep.size() - (int)orig.size();\n                    changed = true;\n                    si++;\n                }\n            }\n\n            int p = firstCompletionPrefix(a);\n            if (p < 0 || p > LIMIT) return originalAll;\n            a.resize(p);\n\n            if (!changed) break;\n        }\n\n        return a;\n    }\n\n    string tripleSegmentOptimize(string a, double endTime) {\n        int pref = firstCompletionPrefix(a);\n        if (pref < 0) return a;\n        a.resize(pref);\n        string originalAll = a;\n\n        for (int pass = 0; pass < 1; pass++) {\n            vector<SegInfo> segs;\n            if (!simulateSegments(a, segs)) return originalAll;\n            if ((int)segs.size() != M - 1) return originalAll;\n\n            bool changed = false;\n            int shift = 0;\n\n            for (int si = 0; si + 2 < (int)segs.size() && elapsed() < endTime; si++) {\n                int l = segs[si].l + shift;\n                int r = segs[si + 2].r + shift;\n                if (l < 0 || r < l || r > (int)a.size()) return originalAll;\n\n                vector<SegInfo> group = {segs[si], segs[si + 1], segs[si + 2]};\n                string orig = a.substr(l, r - l);\n                string rep = optimizeMultiSegments(group, orig, endTime, 9);\n\n                if (rep.size() < orig.size()) {\n                    a.replace(l, orig.size(), rep);\n                    shift += (int)rep.size() - (int)orig.size();\n                    changed = true;\n                    si += 2;\n                }\n            }\n\n            int p = firstCompletionPrefix(a);\n            if (p < 0 || p > LIMIT) return originalAll;\n            a.resize(p);\n\n            if (!changed) break;\n        }\n\n        return a;\n    }\n\n    int dirToward(int a, int b) const {\n        int vr = rr[b] - rr[a];\n        int vc = cc[b] - cc[a];\n        if (abs(vr) >= abs(vc)) {\n            if (vr < 0) return 0;\n            if (vr > 0) return 1;\n        }\n        if (vc < 0) return 2;\n        if (vc > 0) return 3;\n        return 0;\n    }\n\n    int evalPlan(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int dist = bfsDist(g, p, pos[k + 1]);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    bool buildFromMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            int bestDir = -1;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    if (isBlocked(tg, p)) continue;\n                    setBlock(tg, p);\n\n                    int dist = bfsDist(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                acts.push_back(enc(0, bestDir));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    vector<int> makeZeroMasks() {\n        return vector<int>(M - 1, 0);\n    }\n\n    vector<int> makeDenseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeExitMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int m = validBits[k];\n            int ex = dirToward(pos[k], pos[k + 1]);\n            m &= ~(1 << ex);\n\n            while (!isPlanOpt[k][m]) {\n                bool removed = false;\n                for (int d = 0; d < 4; d++) {\n                    if (m & (1 << d)) {\n                        m &= ~(1 << d);\n                        removed = true;\n                        break;\n                    }\n                }\n                if (!removed) {\n                    m = 0;\n                    break;\n                }\n            }\n            masks[k] = m;\n        }\n        return masks;\n    }\n\n    vector<int> makeSparseMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 100;\n            for (int m : planOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = abs(pc - 1);\n                if (sc < bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeValueMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n            for (int m : planOpts[k]) {\n                int val = 0;\n                int pc = __builtin_popcount((unsigned)m);\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q >= 0) val += adjVal[k][q];\n                }\n                int sc = val * 4 - pc * 5;\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planOpts[k].size());\n            masks[k] = planOpts[k][id];\n        }\n        return masks;\n    }\n\n    pair<int, vector<int>> coordinateDescent(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlan(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlan(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    int evalPlan2(const vector<int>& masks, const vector<int>& leaves, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p) || isBlocked(g, goal)) return INF;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            int ld = leaves[k];\n            if (ld >= 0) {\n                int nb = mv[p][ld];\n                if (nb < 0 || isBlocked(g, nb)) return INF;\n                cost++;\n                setBlock(g, p);\n                cost++;\n                if (cost >= cutoff) return cost;\n\n                int dist = bfsDist(g, nb, goal);\n                if (dist >= INF) return INF;\n                cost += dist;\n            } else {\n                int dist = bfsDist(g, p, goal);\n                if (dist >= INF) return INF;\n                cost += dist;\n            }\n\n            if (cost >= cutoff) return cost;\n        }\n\n        return cost;\n    }\n\n    vector<int> makeGreedyLeaves(const vector<int>& masks, double beta) {\n        vector<int> leaves(M - 1, -1);\n        Grid g;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) break;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) setBlock(g, q);\n            }\n\n            int noDist = bfsDist(g, p, goal);\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n            int bestDir = -1;\n\n            for (int d = 0; d < 4; d++) {\n                int nb = mv[p][d];\n                if (nb < 0 || isBlocked(g, nb)) continue;\n\n                Grid tg = g;\n                setBlock(tg, p);\n                int dist = bfsDist(tg, nb, goal);\n                if (dist >= INF) continue;\n\n                double score = double(2 + dist) - beta;\n                if (score < bestScore - 1e-9) {\n                    bestScore = score;\n                    bestDir = d;\n                }\n            }\n\n            leaves[k] = bestDir;\n            if (bestDir >= 0) setBlock(g, p);\n        }\n\n        return leaves;\n    }\n\n    vector<int> makeTowardLeaves(const vector<int>& masks) {\n        vector<int> leaves(M - 1, -1);\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int d0 = dirToward(pos[k], pos[k + 1]);\n            if (mv[p][d0] >= 0 && !(masks[k] & (1 << d0))) {\n                leaves[k] = d0;\n            } else {\n                for (int d = 0; d < 4; d++) {\n                    if (mv[p][d] >= 0 && !(masks[k] & (1 << d))) {\n                        leaves[k] = d;\n                        break;\n                    }\n                }\n            }\n        }\n        return leaves;\n    }\n\n    vector<int> makeRandomLeaves(const vector<int>& masks) {\n        vector<int> leaves(M - 1, -1);\n        for (int k = 0; k < M - 1; k++) {\n            vector<int> opts;\n            opts.push_back(-1);\n            opts.push_back(-1);\n            int p = pos[k];\n            for (int d = 0; d < 4; d++) {\n                if (mv[p][d] >= 0 && !(masks[k] & (1 << d))) opts.push_back(d);\n            }\n            leaves[k] = opts[rnd() % opts.size()];\n        }\n        return leaves;\n    }\n\n    struct Plan2Result {\n        int cost;\n        vector<int> masks;\n        vector<int> leaves;\n    };\n\n    Plan2Result coordinateDescent2(vector<int> masks, vector<int> leaves, int maxPass, double endTime) {\n        int curr = evalPlan2(masks, leaves);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldM = masks[k];\n                int oldL = leaves[k];\n                int bestM = oldM;\n                int bestL = oldL;\n                int bestCost = curr;\n\n                for (const auto& op : plan2Opts[k]) {\n                    if (op.mask == oldM && op.leave == oldL) continue;\n                    masks[k] = op.mask;\n                    leaves[k] = op.leave;\n                    int c = evalPlan2(masks, leaves, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestM = op.mask;\n                        bestL = op.leave;\n                    }\n                }\n\n                masks[k] = bestM;\n                leaves[k] = bestL;\n\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks, leaves};\n    }\n\n    bool buildPlan2(const vector<int>& masks, const vector<int>& leaves, string& acts) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & validBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0 || future[k][q]) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int ld = leaves[k];\n            if (ld >= 0) {\n                int nb = mv[p][ld];\n                if (nb < 0 || isBlocked(g, nb)) return false;\n\n                acts.push_back(enc(0, ld));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[ld]));\n\n                string path;\n                if (!bfsPath(g, nb, goal, path)) return false;\n                acts += path;\n            } else {\n                string path;\n                if (!bfsPath(g, p, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    int distMaybeBlockedGoal(const Grid& g, int s, int goal) {\n        if (s < 0 || goal < 0) return INF;\n        if (isBlocked(g, s)) return INF;\n\n        if (!isBlocked(g, goal)) return bfsDist(g, s, goal);\n\n        int best = INF;\n        for (int gd = 0; gd < 4; gd++) {\n            int nb = mv[goal][gd];\n            if (nb < 0 || isBlocked(g, nb)) continue;\n            int d = bfsDist(g, s, nb);\n            if (d < INF) best = min(best, d + 2);\n        }\n        return best;\n    }\n\n    bool pathMaybeBlockedGoal(Grid& g, int s, int goal, string& out) {\n        out.clear();\n        if (s < 0 || goal < 0) return false;\n        if (isBlocked(g, s)) return false;\n\n        if (!isBlocked(g, goal)) {\n            return bfsPath(g, s, goal, out);\n        }\n\n        int best = INF;\n        int bestNb = -1;\n        int bestEnter = -1;\n\n        for (int gd = 0; gd < 4; gd++) {\n            int nb = mv[goal][gd];\n            if (nb < 0 || isBlocked(g, nb)) continue;\n            int d = bfsDist(g, s, nb);\n            if (d < best) {\n                best = d;\n                bestNb = nb;\n                bestEnter = opp[gd];\n            }\n        }\n\n        if (bestNb < 0) return false;\n\n        string path;\n        if (!bfsPath(g, s, bestNb, path)) return false;\n        out += path;\n\n        out.push_back(enc(2, bestEnter));\n        clearBlock(g, goal);\n        out.push_back(enc(0, bestEnter));\n        return true;\n    }\n\n    int evalPlanF(const vector<int>& masks, int cutoff = INF) {\n        Grid g;\n        int cost = 0;\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return INF;\n\n            int mask = masks[k] & inBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    cost++;\n                    if (cost >= cutoff) return cost;\n                }\n            }\n\n            bool goalWasBlocked = isBlocked(g, goal);\n            int dist = distMaybeBlockedGoal(g, p, goal);\n            if (dist >= INF) return INF;\n            cost += dist;\n            if (cost >= cutoff) return cost;\n\n            if (goalWasBlocked) clearBlock(g, goal);\n        }\n\n        return cost;\n    }\n\n    pair<int, vector<int>> coordinateDescentF(vector<int> masks, int maxPass, double endTime) {\n        int curr = evalPlanF(masks);\n\n        vector<int> order(M - 1);\n        iota(order.begin(), order.end(), 0);\n\n        for (int pass = 0; pass < maxPass; pass++) {\n            if (elapsed() > endTime) break;\n\n            for (int i = (int)order.size() - 1; i > 0; i--) {\n                int j = int(rnd() % (i + 1));\n                swap(order[i], order[j]);\n            }\n\n            bool improved = false;\n\n            for (int k : order) {\n                if (elapsed() > endTime) break;\n\n                int oldMask = masks[k];\n                int bestMask = oldMask;\n                int bestCost = curr;\n\n                for (int opt : planFOpts[k]) {\n                    if (opt == oldMask) continue;\n                    masks[k] = opt;\n                    int c = evalPlanF(masks, bestCost);\n                    if (c < bestCost) {\n                        bestCost = c;\n                        bestMask = opt;\n                    }\n                }\n\n                masks[k] = bestMask;\n                if (bestCost < curr) {\n                    curr = bestCost;\n                    improved = true;\n                }\n            }\n\n            if (!improved) break;\n        }\n\n        return {curr, masks};\n    }\n\n    vector<int> makeDenseFMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestPc = -1;\n            for (int m : planFOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                if (pc > bestPc) {\n                    bestPc = pc;\n                    best = m;\n                }\n            }\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeValueFMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n\n            for (int m : planFOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = -5 * pc;\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q < 0) continue;\n                    sc += 4 * adjVal[k][q];\n\n                    int ti = targetIdx[q];\n                    if (ti > k + 1) sc += 18;\n                    else if (ti == k + 1) sc -= 24;\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeFutureTargetMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int best = 0;\n            int bestScore = 0;\n\n            for (int m : planFOpts[k]) {\n                int pc = __builtin_popcount((unsigned)m);\n                int sc = -6 * pc;\n                for (int d = 0; d < 4; d++) {\n                    if (!(m & (1 << d))) continue;\n                    int q = mv[pos[k]][d];\n                    if (q < 0) continue;\n                    int ti = targetIdx[q];\n                    if (ti > k + 1) sc += 35 - min(20, ti - k);\n                    else if (ti == k + 1) sc -= 40;\n                    sc += adjVal[k][q];\n                }\n                if (sc > bestScore) {\n                    bestScore = sc;\n                    best = m;\n                }\n            }\n\n            masks[k] = best;\n        }\n        return masks;\n    }\n\n    vector<int> makeRandomFMasks() {\n        vector<int> masks(M - 1, 0);\n        for (int k = 0; k < M - 1; k++) {\n            int id = int(rnd() % planFOpts[k].size());\n            masks[k] = planFOpts[k][id];\n        }\n        return masks;\n    }\n\n    bool buildFromFutureMasks(const vector<int>& masks, double backBeta, string& acts) {\n        Grid g;\n        acts.clear();\n        bool allowBack = (backBeta >= -0.5);\n\n        for (int k = 0; k < M - 1; k++) {\n            int p = pos[k];\n            int goal = pos[k + 1];\n            if (isBlocked(g, p)) return false;\n\n            int mask = masks[k] & inBits[k];\n            for (int d = 0; d < 4; d++) {\n                if (!(mask & (1 << d))) continue;\n                int q = mv[p][d];\n                if (q < 0) continue;\n                if (!isBlocked(g, q)) {\n                    setBlock(g, q);\n                    acts.push_back(enc(2, d));\n                }\n            }\n\n            int noDist = distMaybeBlockedGoal(g, p, goal);\n            int bestDir = -1;\n            double bestScore = (noDist >= INF ? 1e18 : double(noDist));\n\n            if (allowBack) {\n                double beta = (k == M - 2 ? 0.0 : backBeta);\n                for (int d = 0; d < 4; d++) {\n                    int nb = mv[p][d];\n                    if (nb < 0 || isBlocked(g, nb)) continue;\n\n                    Grid tg = g;\n                    setBlock(tg, p);\n\n                    int dist = distMaybeBlockedGoal(tg, nb, goal);\n                    if (dist >= INF) continue;\n\n                    int actual = 2 + dist;\n                    double score = double(actual) - beta;\n                    if (score + 1e-9 < bestScore) {\n                        bestScore = score;\n                        bestDir = d;\n                    }\n                }\n            }\n\n            if (bestDir < 0) {\n                if (noDist >= INF) return false;\n                string path;\n                if (!pathMaybeBlockedGoal(g, p, goal, path)) return false;\n                acts += path;\n            } else {\n                int nb = mv[p][bestDir];\n                if (nb < 0 || isBlocked(g, nb)) return false;\n\n                acts.push_back(enc(0, bestDir));\n                setBlock(g, p);\n                acts.push_back(enc(2, opp[bestDir]));\n\n                string path;\n                if (!pathMaybeBlockedGoal(g, nb, goal, path)) return false;\n                acts += path;\n            }\n\n            if ((int)acts.size() > LIMIT) return false;\n        }\n\n        return true;\n    }\n\n    struct Node {\n        int parent;\n        string add;\n    };\n\n    struct BeamState {\n        Grid g;\n        int cost;\n        int node;\n        int val;\n    };\n\n    string solveBeam(int keepCount, int keepValue) {\n        vector<Node> nodes;\n        nodes.push_back({-1, \"\"});\n\n        BeamState init;\n        init.cost = 0;\n        init.node = 0;\n        init.val = 0;\n\n        vector<BeamState> beam;\n        beam.push_back(init);\n\n        for (int k = 0; k < M - 1; k++) {\n            vector<BeamState> gen;\n            gen.reserve(beam.size() * 45);\n\n            unordered_map<uint64_t, int> mp;\n            mp.reserve(beam.size() * 90 + 100);\n            mp.max_load_factor(0.7);\n\n            int p = pos[k];\n            int goal = pos[k + 1];\n\n            auto addState = [&](const BeamState& parent, const Grid& ng, int newCost, const string& app) {\n                if (newCost > LIMIT) return;\n\n                auto it = mp.find(ng.hash);\n                if (it != mp.end()) {\n                    int idx = it->second;\n                    if (newCost >= gen[idx].cost) return;\n                }\n\n                int nodeId = (int)nodes.size();\n                nodes.push_back({parent.node, app});\n\n                BeamState ns;\n                ns.g = ng;\n                ns.cost = newCost;\n                ns.node = nodeId;\n                ns.val = gridValue(ng, k + 1);\n\n                if (it == mp.end()) {\n                    mp[ng.hash] = (int)gen.size();\n                    gen.push_back(ns);\n                } else {\n                    gen[it->second] = ns;\n                }\n            };\n\n            for (const BeamState& st : beam) {\n                int candBits = 0;\n                for (int d = 0; d < 4; d++) {\n                    int q = mv[p][d];\n                    if (q < 0) continue;\n                    bool blk = isBlocked(st.g, q);\n                    if (blk || !future[k][q]) candBits |= (1 << d);\n                }\n\n                for (int sub = candBits;; sub = (sub - 1) & candBits) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    string path;\n                    if (bfsPath(ng, p, goal, path)) {\n                        string app = prep + path;\n                        addState(st, ng, st.cost + (int)app.size(), app);\n                    }\n\n                    if (sub == 0) break;\n                }\n\n                vector<int> backSubs;\n                backSubs.push_back(0);\n                for (int d = 0; d < 4; d++) {\n                    if (candBits & (1 << d)) backSubs.push_back(1 << d);\n                }\n\n                for (int sub : backSubs) {\n                    Grid ng = st.g;\n                    string prep;\n\n                    for (int d = 0; d < 4; d++) {\n                        if (!(sub & (1 << d))) continue;\n                        int q = mv[p][d];\n                        if (q < 0) continue;\n                        toggleBlock(ng, q);\n                        prep.push_back(enc(2, d));\n                    }\n\n                    if (isBlocked(ng, p)) continue;\n\n                    for (int e = 0; e < 4; e++) {\n                        int nb = mv[p][e];\n                        if (nb < 0 || isBlocked(ng, nb)) continue;\n\n                        Grid bg = ng;\n                        setBlock(bg, p);\n\n                        string path;\n                        if (!bfsPath(bg, nb, goal, path)) continue;\n\n                        string app = prep;\n                        app.push_back(enc(0, e));\n                        app.push_back(enc(2, opp[e]));\n                        app += path;\n\n                        addState(st, bg, st.cost + (int)app.size(), app);\n                    }\n                }\n            }\n\n            if (gen.empty()) return \"\";\n\n            if (k == M - 2) {\n                int best = 0;\n                for (int i = 1; i < (int)gen.size(); i++) {\n                    if (gen[i].cost < gen[best].cost) best = i;\n                }\n\n                vector<int> chain;\n                for (int id = gen[best].node; id != -1; id = nodes[id].parent) {\n                    chain.push_back(id);\n                }\n                reverse(chain.begin(), chain.end());\n\n                string res;\n                for (int id : chain) res += nodes[id].add;\n                return res;\n            }\n\n            struct Key {\n                int bc;\n                int bv;\n                int K;\n            };\n\n            vector<Key> keys = {\n                {0, 0, keepCount},\n                {70, 0, keepCount},\n                {130, 0, keepCount},\n                {190, 0, keepCount},\n                {250, 0, keepCount},\n                {0, 18, keepValue},\n                {50, 10, keepValue},\n                {100, 12, keepValue},\n                {150, 16, keepValue},\n                {0, 28, keepValue}\n            };\n\n            vector<char> mark(gen.size(), 0);\n            vector<int> idx(gen.size());\n            iota(idx.begin(), idx.end(), 0);\n\n            for (auto key : keys) {\n                if (key.K <= 0) continue;\n                int K = min(key.K, (int)idx.size());\n\n                auto comp = [&](int a, int b) {\n                    long long ea = 100LL * gen[a].cost - 1LL * key.bc * gen[a].g.cnt - 1LL * key.bv * gen[a].val;\n                    long long eb = 100LL * gen[b].cost - 1LL * key.bc * gen[b].g.cnt - 1LL * key.bv * gen[b].val;\n                    if (ea != eb) return ea < eb;\n                    if (gen[a].cost != gen[b].cost) return gen[a].cost < gen[b].cost;\n                    return gen[a].val > gen[b].val;\n                };\n\n                if (K < (int)idx.size()) {\n                    nth_element(idx.begin(), idx.begin() + K, idx.end(), comp);\n                }\n\n                for (int i = 0; i < K; i++) mark[idx[i]] = 1;\n            }\n\n            vector<BeamState> nxt;\n            nxt.reserve(keepCount * 5 + keepValue * 5 + 5);\n\n            for (int i = 0; i < (int)gen.size(); i++) {\n                if (mark[i]) nxt.push_back(gen[i]);\n            }\n\n            if (nxt.empty()) {\n                int best = min_element(gen.begin(), gen.end(), [](const BeamState& a, const BeamState& b) {\n                    return a.cost < b.cost;\n                }) - gen.begin();\n                nxt.push_back(gen[best]);\n            }\n\n            beam.swap(nxt);\n        }\n\n        return \"\";\n    }\n\n    struct LocalNode {\n        Grid g;\n        int p;\n        int parent;\n        int dist;\n        int altCnt;\n        int valDelta;\n        unsigned char act;\n    };\n\n    inline uint64_t localKey(uint64_t h, int p) const {\n        return h ^ (0x9e3779b97f4a7c15ULL * uint64_t(p + 1));\n    }\n\n    bool localSegmentSearch(\n        const Grid& startG,\n        int s,\n        int goal,\n        int k,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& path,\n        Grid& outG\n    ) {\n        if (elapsed() > endTime) return false;\n        if (isBlocked(startG, s) || isBlocked(startG, goal)) return false;\n        if (s == goal) {\n            path.clear();\n            outG = startG;\n            return true;\n        }\n\n        int base = bfsDist(startG, s, goal);\n        int maxDepth = 24;\n        if (base < INF) maxDepth = min(24, base + slack + 3);\n        maxDepth = max(maxDepth, 8);\n\n        vector<LocalNode> nodes;\n        nodes.reserve(maxNodes + 5);\n        vector<int> q;\n        q.reserve(maxNodes + 5);\n\n        unordered_map<uint64_t, int> mp;\n        mp.reserve(maxNodes * 2 + 100);\n        mp.max_load_factor(0.7);\n\n        LocalNode root;\n        root.g = startG;\n        root.p = s;\n        root.parent = -1;\n        root.dist = 0;\n        root.altCnt = 0;\n        root.valDelta = 0;\n        root.act = 255;\n        nodes.push_back(root);\n        q.push_back(0);\n        mp[localKey(startG.hash, s)] = 0;\n\n        int startCnt = startG.cnt;\n        int bestGoalId = -1;\n        int bestGoalDist = INF;\n        int bestGoalCost = INF;\n        double bestScore = 1e100;\n\n        auto recordGoal = [&](int id) {\n            const LocalNode& nd = nodes[id];\n            bestGoalDist = min(bestGoalDist, nd.dist);\n            double sc = double(nd.dist)\n                - betaCnt * double(nd.g.cnt - startCnt)\n                - betaVal * double(nd.valDelta);\n            if (sc < bestScore - 1e-9 ||\n                (fabs(sc - bestScore) <= 1e-9 && nd.dist < bestGoalCost)) {\n                bestScore = sc;\n                bestGoalId = id;\n                bestGoalCost = nd.dist;\n            }\n        };\n\n        auto addNode = [&](const Grid& ng, int np, int parent, unsigned char act, int ndist, int nalt, int nval) -> int {\n            if ((int)nodes.size() >= maxNodes) return -1;\n            uint64_t key = localKey(ng.hash, np);\n            if (mp.find(key) != mp.end()) return -1;\n\n            int id = (int)nodes.size();\n            LocalNode node;\n            node.g = ng;\n            node.p = np;\n            node.parent = parent;\n            node.dist = ndist;\n            node.altCnt = nalt;\n            node.valDelta = nval;\n            node.act = act;\n            nodes.push_back(node);\n            mp[key] = id;\n            q.push_back(id);\n\n            if (np == goal) recordGoal(id);\n            return id;\n        };\n\n        int head = 0;\n        while (head < (int)q.size()) {\n            if (elapsed() > endTime) return false;\n\n            int id = q[head++];\n            LocalNode cur = nodes[id];\n\n            if (cur.p == goal) continue;\n            if (cur.dist >= maxDepth) continue;\n            if (bestGoalDist < INF && cur.dist >= bestGoalDist + slack) continue;\n\n            int ndist = cur.dist + 1;\n\n            for (int d = 0; d < 4; d++) {\n                int to = slideDest(cur.g, cur.p, d);\n                if (to == cur.p) continue;\n                addNode(cur.g, to, id, enc(1, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int to = mv[cur.p][d];\n                if (to < 0 || isBlocked(cur.g, to)) continue;\n                addNode(cur.g, to, id, enc(0, d), ndist, cur.altCnt, cur.valDelta);\n            }\n\n            for (int d = 0; d < 4; d++) {\n                int cell = mv[cur.p][d];\n                if (cell < 0) continue;\n\n                bool blk = isBlocked(cur.g, cell);\n                if (!blk && future[k][cell]) continue;\n\n                bool startBlk = isBlocked(startG, cell);\n                bool beforeDiff = (blk != startBlk);\n                int nalt = cur.altCnt + (beforeDiff ? -1 : 1);\n                if (nalt > maxAlt) continue;\n\n                Grid ng = cur.g;\n                toggleBlock(ng, cell);\n\n                int nval = cur.valDelta + (blk ? -adjVal[k][cell] : adjVal[k][cell]);\n                addNode(ng, cur.p, id, enc(2, d), ndist, nalt, nval);\n            }\n        }\n\n        if (bestGoalId < 0) return false;\n\n        path.clear();\n        for (int id = bestGoalId; nodes[id].parent != -1; id = nodes[id].parent) {\n            path.push_back(char(nodes[id].act));\n        }\n        reverse(path.begin(), path.end());\n        outG = nodes[bestGoalId].g;\n        return true;\n    }\n\n    bool buildGreedyActionWithMasks(\n        const vector<int>* masksPtr,\n        double betaCnt,\n        double betaVal,\n        int maxAlt,\n        int slack,\n        int maxNodes,\n        double endTime,\n        string& acts\n    ) {\n        Grid g;\n        acts.clear();\n\n        for (int k = 0; k < M - 1; k++) {\n            if (elapsed() > endTime) return false;\n\n            if (masksPtr) {\n                int p = pos[k];\n                if (isBlocked(g, p)) return false;\n\n                int mask = (*masksPtr)[k] & validBits[k];\n                for (int d = 0; d < 4; d++) {\n                    if (!(mask & (1 << d))) continue;\n                    int q = mv[p][d];\n                    if (q < 0 || future[k][q]) continue;\n                    if (!isBlocked(g, q)) {\n                        setBlock(g, q);\n                        acts.push_back(enc(2, d));\n                    }\n                }\n            }\n\n            string seg;\n            Grid ng;\n            bool ok = localSegmentSearch(\n                g, pos[k], pos[k + 1], k,\n                betaCnt, betaVal, maxAlt, slack, maxNodes,\n                endTime, seg, ng\n            );\n\n            if (!ok) {\n                if (!bfsPath(g, pos[k], pos[k + 1], seg)) return false;\n                ng = g;\n            }\n\n            acts += seg;\n            g = ng;\n            if ((int)acts.size() > LIMIT) return false;\n        }\n        return true;\n    }\n\n    void solve() {\n        cin >> N >> M;\n        pos.resize(M);\n        for (int i = 0; i < M; i++) {\n            int r, c;\n            cin >> r >> c;\n            pos[i] = r * N + c;\n        }\n\n        startTime = chrono::steady_clock::now();\n        init();\n\n        pureFallback = makePureMoves();\n        addCandidate(pureFallback);\n\n        string beamAns = solveBeam(25, 8);\n        if (!beamAns.empty()) addCandidate(beamAns);\n\n        vector<pair<int, vector<int>>> maskCands;\n\n        vector<vector<int>> starts;\n        starts.push_back(makeZeroMasks());\n        starts.push_back(makeDenseMasks());\n        starts.push_back(makeExitMasks());\n        starts.push_back(makeSparseMasks());\n        starts.push_back(makeValueMasks());\n        for (int i = 0; i < 5; i++) starts.push_back(makeRandomMasks());\n\n        double planEnd = 1.42;\n\n        for (auto st : starts) {\n            if (elapsed() > planEnd) break;\n            auto res = coordinateDescent(st, 3, planEnd);\n            maskCands.push_back(res);\n        }\n\n        if (maskCands.empty()) {\n            vector<int> z = makeZeroMasks();\n            maskCands.push_back({evalPlan(z), z});\n        }\n\n        sort(maskCands.begin(), maskCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedMaskKeys;\n        vector<double> backBetas = {-1.0, 0.0, 1.0, 1.5, 2.0, 2.5, 3.0};\n\n        int used = 0;\n        for (auto& pr : maskCands) {\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedMaskKeys.count(key)) continue;\n            usedMaskKeys.insert(key);\n\n            for (double beta : backBetas) {\n                string acts;\n                if (buildFromMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            used++;\n            if (used >= 8) break;\n        }\n\n        double plan2End = 1.65;\n        set<string> usedPlan2Keys;\n        int plan2Runs = 0;\n\n        for (int id = 0; id < (int)maskCands.size() && id < 5; id++) {\n            if (elapsed() > plan2End) break;\n\n            vector<vector<int>> leaveStarts;\n            leaveStarts.push_back(vector<int>(M - 1, -1));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 1.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 2.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 3.0));\n            leaveStarts.push_back(makeGreedyLeaves(maskCands[id].second, 4.5));\n            leaveStarts.push_back(makeTowardLeaves(maskCands[id].second));\n            if (id < 2) leaveStarts.push_back(makeRandomLeaves(maskCands[id].second));\n\n            for (auto leaves : leaveStarts) {\n                if (elapsed() > plan2End) break;\n\n                string key;\n                key.reserve(2 * (M - 1));\n                for (int k = 0; k < M - 1; k++) {\n                    key.push_back(char(maskCands[id].second[k]));\n                    key.push_back(char(leaves[k] + 1));\n                }\n                if (usedPlan2Keys.count(key)) continue;\n                usedPlan2Keys.insert(key);\n\n                auto res = coordinateDescent2(maskCands[id].second, leaves, 2, plan2End);\n                string acts;\n                if (buildPlan2(res.masks, res.leaves, acts)) {\n                    addCandidate(acts);\n                }\n\n                plan2Runs++;\n                if (plan2Runs >= 10) break;\n            }\n            if (plan2Runs >= 10) break;\n        }\n\n        double futureEnd = 1.71;\n        vector<pair<int, vector<int>>> futureCands;\n        vector<vector<int>> fstarts;\n\n        for (int i = 0; i < (int)maskCands.size() && i < 2; i++) {\n            fstarts.push_back(maskCands[i].second);\n        }\n        fstarts.push_back(makeValueFMasks());\n        fstarts.push_back(makeFutureTargetMasks());\n        fstarts.push_back(makeDenseFMasks());\n        fstarts.push_back(makeRandomFMasks());\n\n        for (auto st : fstarts) {\n            if (elapsed() > futureEnd) break;\n            auto res = coordinateDescentF(st, 1, futureEnd);\n            futureCands.push_back(res);\n        }\n\n        sort(futureCands.begin(), futureCands.end(), [](const auto& a, const auto& b) {\n            return a.first < b.first;\n        });\n\n        set<string> usedFutureKeys;\n        int fUsed = 0;\n        vector<double> fBetas = {-1.0, 0.5, 1.5, 2.5};\n\n        for (auto& pr : futureCands) {\n            if (elapsed() > futureEnd + 0.01) break;\n\n            string key;\n            key.reserve(M - 1);\n            for (int x : pr.second) key.push_back(char(x));\n            if (usedFutureKeys.count(key)) continue;\n            usedFutureKeys.insert(key);\n\n            for (double beta : fBetas) {\n                string acts;\n                if (buildFromFutureMasks(pr.second, beta, acts)) {\n                    addCandidate(acts);\n                }\n            }\n\n            fUsed++;\n            if (fUsed >= 3) break;\n        }\n\n        vector<tuple<double, double, int, int, int>> localCfgs = {\n            {0.0, 0.00, 3, 1, 1500},\n            {0.8, 0.09, 4, 2, 2100},\n            {1.1, 0.13, 5, 3, 2500},\n        };\n\n        double localEnd = 1.78;\n        for (auto [bc, bv, ma, sl, mn] : localCfgs) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyActionWithMasks(nullptr, bc, bv, ma, sl, mn, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        for (int id = 0; id < (int)maskCands.size() && id < 2; id++) {\n            if (elapsed() > localEnd) break;\n            string acts;\n            if (buildGreedyActionWithMasks(&maskCands[id].second, 0.7, 0.08, 4, 2, 1800, localEnd, acts)) {\n                addCandidate(acts);\n            }\n        }\n\n        if (candidates.empty()) candidates.push_back(pureFallback);\n\n        string best = candidates[0];\n        for (const string& s : candidates) {\n            if (s.size() < best.size()) best = s;\n        }\n\n        vector<int> order(candidates.size());\n        iota(order.begin(), order.end(), 0);\n        sort(order.begin(), order.end(), [&](int a, int b) {\n            return candidates[a].size() < candidates[b].size();\n        });\n\n        vector<string> postCands;\n\n        for (int id : order) {\n            if (elapsed() > 1.865) break;\n            string improved = greedyDelete(candidates[id], 1.865);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n                if ((int)postCands.size() < 8) postCands.push_back(improved);\n            }\n        }\n\n        if (elapsed() < 1.91) {\n            string improved = replaceImprove(best, 1.94);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n                postCands.push_back(improved);\n            }\n        }\n\n        if (elapsed() < 1.94) {\n            vector<string> segTry;\n            segTry.push_back(best);\n            sort(postCands.begin(), postCands.end(), [](const string& a, const string& b) {\n                return a.size() < b.size();\n            });\n\n            for (const string& s : postCands) {\n                if ((int)segTry.size() >= 4) break;\n                if (s.size() <= best.size() + 5) segTry.push_back(s);\n            }\n\n            set<string> usedSeg;\n            for (const string& cand : segTry) {\n                if (elapsed() > 1.957) break;\n                if (usedSeg.count(cand)) continue;\n                usedSeg.insert(cand);\n\n                string improved = segmentOptimize(cand, 1.976);\n                int p = firstCompletionPrefix(improved);\n                if (p >= 0 && p <= LIMIT) {\n                    improved.resize(p);\n                    if (improved.size() < best.size()) best = improved;\n                }\n            }\n        }\n\n        if (elapsed() < 1.965) {\n            string improved = pairSegmentOptimize(best, 1.984);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        if (elapsed() < 1.976) {\n            string improved = tripleSegmentOptimize(best, 1.992);\n            int p = firstCompletionPrefix(improved);\n            if (p >= 0 && p <= LIMIT) {\n                improved.resize(p);\n                if (improved.size() < best.size()) best = improved;\n            }\n        }\n\n        int pp = firstCompletionPrefix(best);\n        if (pp >= 0 && pp <= LIMIT) {\n            best.resize(pp);\n        } else {\n            best = pureFallback;\n        }\n\n        const string A = \"MSA\";\n        const string D = \"UDLR\";\n\n        for (unsigned char ch : best) {\n            int code = ch;\n            int type = code / 4;\n            int d = code % 4;\n            cout << A[type] << ' ' << D[d] << '\\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\n    return 0;\n}"}}}